Skip to content

Commit f65c778

Browse files
committed
feat: uri docs
1 parent b89164b commit f65c778

1 file changed

Lines changed: 107 additions & 0 deletions

File tree

docs/docs/W3DS Protocol/File-URIs.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,81 @@ Uploads are performed through the eVault `uploadFile` GraphQL mutation, which
4545
takes base64 content and returns the `w3ds://file` URI, the Meta Envelope ID,
4646
and the public object-storage URL.
4747

48+
## The `uploadFile` mutation
49+
50+
```graphql
51+
uploadFile(input: UploadFileInput!): UploadFilePayload!
52+
```
53+
54+
Uploads a file to object storage and creates an addressable **File Meta
55+
Envelope** (ontology `w3ds-file-v1`). The request **must** carry an
56+
`X-ENAME: @<user-ename>` header — uploads are rejected without it. Object
57+
storage must be configured on the eVault (DigitalOcean Spaces / S3-compatible);
58+
otherwise the mutation returns an error.
59+
60+
### Input — `UploadFileInput`
61+
62+
| Field | Type | Description |
63+
| ------------- | ----------- | -------------------------------------------------------------------- |
64+
| `filename` | `String!` | Original file name. |
65+
| `contentType` | `String!` | MIME type of the file. |
66+
| `content` | `String!` | Base64-encoded file content — raw base64 **or** a `data:` URI. |
67+
| `acl` | `[String!]!`| Access-control list for the created File Meta Envelope (e.g. `["*"]`).|
68+
69+
Constraints: content must be valid base64 (malformed input is rejected) and the
70+
decoded size must not exceed **50 MB**.
71+
72+
### Payload — `UploadFilePayload`
73+
74+
| Field | Type | Description |
75+
| ---------------- | -------------- | ----------------------------------------------------------------- |
76+
| `uri` | `String` | The `w3ds://file` URI addressing the upload; `null` on error. |
77+
| `metaEnvelopeId` | `String` | ID of the File Meta Envelope describing the upload. |
78+
| `publicUrl` | `String` | Public object-storage URL of the file. |
79+
| `errors` | `[UserError!]` | Errors that occurred during the upload (`field`, `message`, `code`).|
80+
81+
### Stored Meta Envelope payload
82+
83+
The mutation persists a Meta Envelope with ontology `w3ds-file-v1` and payload:
84+
85+
```json
86+
{ "filename", "contentType", "size", "blobKey", "publicUrl", "uploadedAt" }
87+
```
88+
89+
where `size` is the decoded byte length, `blobKey` is the object-storage key
90+
(`files/{owner}/{id}-{filename}`), and `uploadedAt` is an ISO-8601 timestamp.
91+
92+
> **Note:** this `w3ds-file-v1` storage envelope is **not** the same as the
93+
> platform-level `File` ontology (`a1b2c3d4-e5f6-7890-abcd-ef1234567890`). See
94+
> [File ontology vs. `w3ds-file-v1`](#file-ontology-vs-w3ds-file-v1) below.
95+
96+
### Example
97+
98+
```graphql
99+
mutation UploadFile($input: UploadFileInput!) {
100+
uploadFile(input: $input) {
101+
uri
102+
metaEnvelopeId
103+
publicUrl
104+
errors { field message code }
105+
}
106+
}
107+
```
108+
109+
```json
110+
{
111+
"input": {
112+
"filename": "contract.pdf",
113+
"contentType": "application/pdf",
114+
"content": "data:application/pdf;base64,JVBERi0x...",
115+
"acl": ["*"]
116+
}
117+
}
118+
```
119+
120+
On failure after the blob is written, the orphaned object is deleted
121+
(compensating cleanup), so a failed upload leaves no dangling storage object.
122+
48123
## Resolving (dereferencing) a URI
49124

50125
There are two dereferencers.
@@ -87,6 +162,38 @@ or `Error` for:
87162
- A non-existent `ename` (eVault cannot be resolved).
88163
- A non-existent or non-file Meta Envelope.
89164

165+
## File ontology vs. `w3ds-file-v1`
166+
167+
There are **two distinct file schemas** in the system. They are easy to confuse
168+
but serve different layers, and conflating them is a common source of bugs.
169+
170+
| | `w3ds-file-v1` | `File` ontology |
171+
| --- | --- | --- |
172+
| **Identifier** | `w3ds-file-v1` (string) | `a1b2c3d4-e5f6-7890-abcd-ef1234567890` (UUID) |
173+
| **Created by** | `uploadFile` mutation, at upload time | Platform apps (file-manager, esigner) via the Web3 Adapter mapping |
174+
| **Layer** | Storage / transport — describes a blob in object storage | Application domain — a file record in a platform's database |
175+
| **Payload** | `filename`, `contentType`, `size`, `blobKey`, `publicUrl`, `uploadedAt` | `id`, `name`, `displayName`, `description`, `mimeType`, `size`, `md5Hash`, `data`, `url`, `ownerId`, `folderId`, `createdAt`, `updatedAt` |
176+
| **Addressed by** | `w3ds://file?id=@ename/<meta-envelope-id>` | Synced as a normal Meta Envelope through platform mappings |
177+
| **Defined in** | `evault-core/src/core/utils/w3ds-uri.ts` (`FILE_SCHEMA_ID`) | `services/ontology/schemas/file.json` |
178+
179+
**They are not the same envelope.** The payload documented above
180+
(`{ filename, contentType, size, blobKey, publicUrl, uploadedAt }`) belongs to
181+
`w3ds-file-v1` only — it is the low-level record the `uploadFile` mutation
182+
creates so a blob can be dereferenced via a `w3ds://file` URI.
183+
184+
The `File` ontology (`a1b2c3d4-...`) is a higher-level platform concept: a
185+
file-manager/esigner record with folders, owners, display names and an MD5
186+
hash, mapped to/from the global layer by the Web3 Adapter (see
187+
`platforms/file-manager/api/src/web3adapter/mappings/file.mapping.json`). Note
188+
the field names differ — e.g. `name` vs `filename`, `mimeType` vs
189+
`contentType`, `url` vs `publicUrl`/`blobKey` — so they are **not**
190+
interchangeable payloads.
191+
192+
In short: use `w3ds-file-v1` + `w3ds://file` URIs to store and dereference raw
193+
blobs; use the `File` ontology when modelling a platform's file records. A
194+
single user-facing "file" may involve both — a `File` ontology record whose
195+
`url` points at a blob uploaded via `uploadFile`.
196+
90197
## Mapper integration
91198

92199
The [Web3 Adapter](/docs/Infrastructure/Web3-Adapter) exposes a `__file()`

0 commit comments

Comments
 (0)