@enbox/api 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +140 -159
- package/dist/browser.mjs +23 -13
- package/dist/browser.mjs.map +4 -4
- package/dist/esm/advanced.js +11 -0
- package/dist/esm/advanced.js.map +1 -0
- package/dist/esm/define-protocol.js +3 -3
- package/dist/esm/dwn-api.js +55 -107
- package/dist/esm/dwn-api.js.map +1 -1
- package/dist/esm/dwn-reader-api.js +128 -0
- package/dist/esm/dwn-reader-api.js.map +1 -0
- package/dist/esm/index.js +3 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/live-query.js +5 -4
- package/dist/esm/live-query.js.map +1 -1
- package/dist/esm/read-only-record.js +255 -0
- package/dist/esm/read-only-record.js.map +1 -0
- package/dist/esm/record.js +46 -57
- package/dist/esm/record.js.map +1 -1
- package/dist/esm/typed-web5.js +242 -0
- package/dist/esm/typed-web5.js.map +1 -0
- package/dist/esm/web5.js +71 -3
- package/dist/esm/web5.js.map +1 -1
- package/dist/types/advanced.d.ts +12 -0
- package/dist/types/advanced.d.ts.map +1 -0
- package/dist/types/define-protocol.d.ts +3 -3
- package/dist/types/dwn-api.d.ts +12 -89
- package/dist/types/dwn-api.d.ts.map +1 -1
- package/dist/types/dwn-reader-api.d.ts +138 -0
- package/dist/types/dwn-reader-api.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/live-query.d.ts +13 -1
- package/dist/types/live-query.d.ts.map +1 -1
- package/dist/types/protocol-types.d.ts +2 -2
- package/dist/types/read-only-record.d.ts +133 -0
- package/dist/types/read-only-record.d.ts.map +1 -0
- package/dist/types/record.d.ts +37 -17
- package/dist/types/record.d.ts.map +1 -1
- package/dist/types/{typed-dwn-api.d.ts → typed-web5.d.ts} +70 -73
- package/dist/types/typed-web5.d.ts.map +1 -0
- package/dist/types/web5.d.ts +79 -3
- package/dist/types/web5.d.ts.map +1 -1
- package/package.json +9 -5
- package/src/advanced.ts +29 -0
- package/src/define-protocol.ts +3 -3
- package/src/dwn-api.ts +88 -222
- package/src/dwn-reader-api.ts +255 -0
- package/src/index.ts +3 -2
- package/src/live-query.ts +20 -4
- package/src/protocol-types.ts +2 -2
- package/src/read-only-record.ts +328 -0
- package/src/record.ts +116 -86
- package/src/typed-web5.ts +445 -0
- package/src/web5.ts +104 -5
- package/dist/esm/typed-dwn-api.js +0 -182
- package/dist/esm/typed-dwn-api.js.map +0 -1
- package/dist/types/typed-dwn-api.d.ts.map +0 -1
- package/src/typed-dwn-api.ts +0 -370
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @enbox/api
|
|
2
2
|
|
|
3
|
-
> **Research Preview**
|
|
3
|
+
> **Research Preview** -- Enbox is under active development. APIs may change without notice.
|
|
4
4
|
|
|
5
5
|
[](https://github.com/enboxorg/enbox/actions/workflows/ci.yml)
|
|
6
6
|
|
|
7
|
-
The high-level SDK for building decentralized applications with
|
|
7
|
+
The high-level SDK for building decentralized applications with protocol-first data management.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
|
@@ -14,233 +14,214 @@ bun add @enbox/api
|
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
|
-
```
|
|
18
|
-
import {
|
|
17
|
+
```ts
|
|
18
|
+
import { defineProtocol, Web5 } from '@enbox/api';
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
// 1. Connect
|
|
21
|
+
const { web5, did: myDid } = await Web5.connect();
|
|
21
22
|
|
|
22
|
-
//
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
// 2. Define a protocol with typed data shapes
|
|
24
|
+
const NotesProtocol = defineProtocol({
|
|
25
|
+
protocol : 'https://example.com/notes',
|
|
26
|
+
published : true,
|
|
27
|
+
types : {
|
|
28
|
+
note: {
|
|
29
|
+
schema : 'https://example.com/schemas/note',
|
|
30
|
+
dataFormats : ['application/json'],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
structure: {
|
|
34
|
+
note: {},
|
|
35
|
+
},
|
|
36
|
+
} as const, {} as {
|
|
37
|
+
note: { title: string; body: string };
|
|
26
38
|
});
|
|
27
39
|
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## API Documentation
|
|
40
|
+
// 3. Scope all operations to the protocol
|
|
41
|
+
const notes = web5.using(NotesProtocol);
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
// 4. Install the protocol
|
|
44
|
+
await notes.configure();
|
|
35
45
|
|
|
36
|
-
|
|
46
|
+
// 5. Write a record (path, data, and schema are type-checked)
|
|
47
|
+
const { record } = await notes.records.write('note', {
|
|
48
|
+
data: { title: 'Hello', body: 'World' },
|
|
49
|
+
});
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
|
|
51
|
+
// 6. Send to your remote DWN
|
|
52
|
+
await record.send(myDid);
|
|
40
53
|
```
|
|
41
54
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- **`agent`** - `EnboxAgent` instance. Defaults to a local `EnboxUserAgent`.
|
|
45
|
-
- **`connectedDid`** - `string`: an existing DID to connect to.
|
|
46
|
-
- **`sync`** - `string`: sync interval (any value accepted by [`ms`](https://www.npmjs.com/package/ms)), or `'off'` to disable. Default: `'2m'`.
|
|
47
|
-
- **`techPreview.dwnEndpoints`** - `string[]`: DWN endpoints for the created DID. Default: `['https://enbox-dwn.fly.dev']`.
|
|
48
|
-
|
|
49
|
-
#### Response
|
|
55
|
+
## Core Concepts
|
|
50
56
|
|
|
51
|
-
|
|
52
|
-
- **`did`** - `string`: the DID that was created or connected to.
|
|
57
|
+
### `Web5.connect(options?)`
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
Connects to a local identity agent or generates an in-app DID.
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
```ts
|
|
62
|
+
const { web5, did, recoveryPhrase } = await Web5.connect();
|
|
63
|
+
```
|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
**Options** (all optional):
|
|
59
66
|
|
|
60
|
-
|
|
67
|
+
| Option | Type | Description |
|
|
68
|
+
|--------|------|-------------|
|
|
69
|
+
| `agent` | `Web5Agent` | Custom agent instance. Defaults to a local `Web5UserAgent`. |
|
|
70
|
+
| `connectedDid` | `string` | Existing DID to connect to. |
|
|
71
|
+
| `password` | `string` | Password to protect the local identity vault. |
|
|
72
|
+
| `recoveryPhrase` | `string` | 12-word BIP-39 phrase for vault recovery. |
|
|
73
|
+
| `sync` | `string` | Sync interval (e.g. `'2m'`) or `'off'`. Default: `'2m'`. |
|
|
74
|
+
| `didCreateOptions.dwnEndpoints` | `string[]` | DWN endpoints for the created DID. |
|
|
75
|
+
| `walletConnectOptions` | `ConnectOptions` | Trigger external wallet connect flow. |
|
|
61
76
|
|
|
62
|
-
**
|
|
63
|
-
- **`data.blob()`** / **`data.bytes()`** / **`data.json()`** / **`data.stream()`** / **`data.text()`** - read record data in various formats.
|
|
64
|
-
- **`send(did)`** - send the record to a DID's DWN endpoints.
|
|
65
|
-
- **`update(request)`** - overwrite the record with new data.
|
|
77
|
+
**Returns** `{ web5, did, recoveryPhrase?, delegateDid? }`.
|
|
66
78
|
|
|
67
79
|
---
|
|
68
80
|
|
|
69
|
-
###
|
|
81
|
+
### `Web5.anonymous(options?)`
|
|
70
82
|
|
|
71
|
-
|
|
83
|
+
Creates a lightweight, read-only instance for querying public DWN data. No identity, vault, or signing keys are required.
|
|
72
84
|
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
const { records } = await enbox.dwn.records.query({
|
|
76
|
-
message: {
|
|
77
|
-
filter: {
|
|
78
|
-
schema : 'https://schema.org/Playlist',
|
|
79
|
-
dataFormat : 'application/json',
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
});
|
|
85
|
+
```ts
|
|
86
|
+
const { dwn } = Web5.anonymous();
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
message: {
|
|
88
|
-
filter: {
|
|
89
|
-
protocol : 'https://music.org/protocol',
|
|
90
|
-
schema : 'https://schema.org/Playlist',
|
|
91
|
-
dataFormat : 'application/json',
|
|
92
|
-
},
|
|
93
|
-
},
|
|
88
|
+
const { records } = await dwn.records.query({
|
|
89
|
+
from : 'did:dht:alice...',
|
|
90
|
+
filter : { protocol: 'https://example.com/notes', protocolPath: 'note' },
|
|
94
91
|
});
|
|
95
|
-
```
|
|
96
92
|
|
|
97
|
-
|
|
93
|
+
for (const record of records) {
|
|
94
|
+
console.log(record.id, await record.data.text());
|
|
95
|
+
}
|
|
96
|
+
```
|
|
98
97
|
|
|
99
|
-
|
|
98
|
+
Returns a `{ dwn: DwnReaderApi }` with read-only `records.query()` and `records.read()`.
|
|
100
99
|
|
|
101
100
|
---
|
|
102
101
|
|
|
103
|
-
###
|
|
102
|
+
### `web5.using(protocol)`
|
|
104
103
|
|
|
105
|
-
|
|
104
|
+
The **primary interface** for all record operations. Returns a `TypedWeb5` instance scoped to the given protocol.
|
|
106
105
|
|
|
107
|
-
```
|
|
108
|
-
const
|
|
109
|
-
message: {
|
|
110
|
-
filter: { protocol: 'https://schema.org/protocols/social' },
|
|
111
|
-
},
|
|
112
|
-
subscriptionHandler: (record) => {
|
|
113
|
-
console.log('received', record);
|
|
114
|
-
},
|
|
115
|
-
});
|
|
106
|
+
```ts
|
|
107
|
+
const notes = web5.using(NotesProtocol);
|
|
116
108
|
```
|
|
117
109
|
|
|
118
|
-
|
|
110
|
+
The returned object provides:
|
|
119
111
|
|
|
120
|
-
|
|
112
|
+
- **`notes.configure()`** -- Install the protocol on the local DWN.
|
|
113
|
+
- **`notes.records.write(path, request)`** -- Write a record at a protocol path.
|
|
114
|
+
- **`notes.records.query(path, request?)`** -- Query records at a path.
|
|
115
|
+
- **`notes.records.read(path, request)`** -- Read a single record.
|
|
116
|
+
- **`notes.records.delete(path, request)`** -- Delete a record by ID.
|
|
117
|
+
- **`notes.records.subscribe(path, request?)`** -- Subscribe to real-time changes (returns a `LiveQuery`).
|
|
121
118
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
```javascript
|
|
125
|
-
const { record } = await enbox.dwn.records.create({
|
|
126
|
-
data : 'Hello World!',
|
|
127
|
-
message : { dataFormat: 'text/plain' },
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
await record.send(myDid); // send to your remote DWN
|
|
131
|
-
await record.send('did:example:bob'); // send to Bob's DWN
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
Pass `store: false` to create without storing locally (e.g., for records you only send to others).
|
|
119
|
+
Protocol URI, protocolPath, and schema are automatically injected into every operation.
|
|
135
120
|
|
|
136
121
|
---
|
|
137
122
|
|
|
138
|
-
###
|
|
139
|
-
|
|
140
|
-
Alias for `create()` — same request object.
|
|
141
|
-
|
|
142
|
-
---
|
|
123
|
+
### `defineProtocol(definition, schemaMap?)`
|
|
143
124
|
|
|
144
|
-
|
|
125
|
+
Creates a typed protocol definition that enables compile-time path autocompletion and data type checking.
|
|
145
126
|
|
|
146
|
-
|
|
127
|
+
```ts
|
|
128
|
+
import type { ProtocolDefinition } from '@enbox/dwn-sdk-js';
|
|
147
129
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
130
|
+
const SocialProtocol = defineProtocol({
|
|
131
|
+
protocol : 'https://social.example/protocol',
|
|
132
|
+
published : true,
|
|
133
|
+
types: {
|
|
134
|
+
profile : { schema: 'https://social.example/schemas/profile', dataFormats: ['application/json'] },
|
|
135
|
+
post : { schema: 'https://social.example/schemas/post', dataFormats: ['application/json'] },
|
|
136
|
+
reply : { schema: 'https://social.example/schemas/reply', dataFormats: ['application/json'] },
|
|
137
|
+
},
|
|
138
|
+
structure: {
|
|
139
|
+
profile : {},
|
|
140
|
+
post : {
|
|
141
|
+
reply: {},
|
|
142
|
+
},
|
|
152
143
|
},
|
|
144
|
+
} as const satisfies ProtocolDefinition, {} as {
|
|
145
|
+
profile : { displayName: string; bio?: string };
|
|
146
|
+
post : { title: string; body: string };
|
|
147
|
+
reply : { body: string };
|
|
153
148
|
});
|
|
154
|
-
|
|
155
|
-
console.log(await record.data.text());
|
|
156
149
|
```
|
|
157
150
|
|
|
158
|
-
|
|
151
|
+
The `schemaMap` is a phantom type -- it exists only at compile time. Pass `{} as YourSchemaMap` as the second argument.
|
|
159
152
|
|
|
160
153
|
---
|
|
161
154
|
|
|
162
|
-
###
|
|
155
|
+
### Record Instances
|
|
163
156
|
|
|
164
|
-
|
|
157
|
+
Methods like `write`, `query`, and `read` return `Record` instances.
|
|
165
158
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
159
|
+
**Properties**: `id`, `contextId`, `dataFormat`, `dateCreated`, `timestamp`, `datePublished`, `protocol`, `protocolPath`, `recipient`, `schema`, `dataCid`, `dataSize`, `published`.
|
|
160
|
+
|
|
161
|
+
**Data accessors**:
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
await record.data.text(); // string
|
|
165
|
+
await record.data.json<MyType>(); // typed JSON
|
|
166
|
+
await record.data.blob(); // Blob
|
|
167
|
+
await record.data.bytes(); // Uint8Array
|
|
168
|
+
await record.data.stream(); // ReadableStream
|
|
170
169
|
```
|
|
171
170
|
|
|
172
|
-
|
|
171
|
+
**Mutators** (return a new `Record` instance):
|
|
173
172
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
message: {
|
|
181
|
-
definition: {
|
|
182
|
-
protocol : 'https://photos.org/protocol',
|
|
183
|
-
published : true,
|
|
184
|
-
types: {
|
|
185
|
-
album : { schema: 'https://photos.org/album', dataFormats: ['application/json'] },
|
|
186
|
-
photo : { schema: 'https://photos.org/photo', dataFormats: ['application/json'] },
|
|
187
|
-
image : { dataFormats: ['image/png', 'image/jpeg', 'image/gif'] },
|
|
188
|
-
},
|
|
189
|
-
structure: {
|
|
190
|
-
album: {
|
|
191
|
-
$actions: [{ who: 'recipient', can: 'read' }],
|
|
192
|
-
},
|
|
193
|
-
photo: {
|
|
194
|
-
$actions: [{ who: 'recipient', can: 'read' }],
|
|
195
|
-
image: {
|
|
196
|
-
$actions: [{ who: 'author', of: 'photo', can: 'write' }],
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
});
|
|
173
|
+
```ts
|
|
174
|
+
const { record: updated } = await record.update({ data: { title: 'New Title', body: '...' } });
|
|
175
|
+
const { status } = await record.delete();
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Side-effect methods** (return status only):
|
|
203
179
|
|
|
204
|
-
|
|
180
|
+
```ts
|
|
181
|
+
await record.send(targetDid); // send to a remote DWN
|
|
182
|
+
await record.store(); // persist locally
|
|
183
|
+
await record.import(); // import from a remote DWN
|
|
205
184
|
```
|
|
206
185
|
|
|
207
186
|
---
|
|
208
187
|
|
|
209
|
-
###
|
|
188
|
+
### LiveQuery (Subscriptions)
|
|
210
189
|
|
|
211
|
-
|
|
190
|
+
`records.subscribe()` returns a `LiveQuery` that provides an initial snapshot plus real-time deduplicated change events.
|
|
212
191
|
|
|
213
|
-
```
|
|
214
|
-
const {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
192
|
+
```ts
|
|
193
|
+
const { liveQuery } = await notes.records.subscribe('post');
|
|
194
|
+
|
|
195
|
+
liveQuery.on('create', (record) => { /* new record */ });
|
|
196
|
+
liveQuery.on('update', (record) => { /* updated record */ });
|
|
197
|
+
liveQuery.on('delete', (record) => { /* deleted record */ });
|
|
198
|
+
|
|
199
|
+
// Clean up
|
|
200
|
+
await liveQuery.close();
|
|
220
201
|
```
|
|
221
202
|
|
|
222
203
|
---
|
|
223
204
|
|
|
224
|
-
|
|
205
|
+
## Advanced Usage
|
|
225
206
|
|
|
226
|
-
|
|
207
|
+
For power users who need direct, unscoped DWN access (e.g. cross-protocol queries, raw permission management), import from the `@enbox/api/advanced` sub-path:
|
|
227
208
|
|
|
228
|
-
```
|
|
229
|
-
|
|
209
|
+
```ts
|
|
210
|
+
import { DwnApi } from '@enbox/api/advanced';
|
|
230
211
|
```
|
|
231
212
|
|
|
232
|
-
|
|
213
|
+
The `DwnApi` class provides raw `records`, `protocols`, and `permissions` accessors without protocol scoping. Most applications should use `web5.using()` instead.
|
|
233
214
|
|
|
234
215
|
---
|
|
235
216
|
|
|
236
|
-
|
|
217
|
+
## DID Operations
|
|
237
218
|
|
|
238
|
-
|
|
219
|
+
```ts
|
|
220
|
+
// Create a DID
|
|
221
|
+
const myDid = await web5.did.create('dht');
|
|
239
222
|
|
|
240
|
-
|
|
241
|
-
const { didDocument } = await
|
|
242
|
-
'did:dht:qftx7z968xcpfy1a1diu75pg5meap3gdtg6ezagaw849wdh6oubo'
|
|
243
|
-
);
|
|
223
|
+
// Resolve a DID
|
|
224
|
+
const { didDocument } = await web5.did.resolve('did:dht:abc...');
|
|
244
225
|
```
|
|
245
226
|
|
|
246
227
|
## License
|