dignity.js 0.3.0 → 0.4.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 +60 -3
- package/dist/dignity.cjs.js +227 -0
- package/dist/dignity.cjs.js.map +4 -4
- package/dist/dignity.esm.js +227 -0
- package/dist/dignity.esm.js.map +3 -3
- package/dist/dignity.min.js +5 -5
- package/docs/assets/docs.js +47 -0
- package/docs/assets/highlight/github-dark.min.css +10 -0
- package/docs/assets/highlight/github.min.css +10 -0
- package/docs/assets/highlight/highlight.min.js +1244 -0
- package/docs/assets/styles.css +449 -38
- package/docs/index.html +601 -81
- package/docs/openapi-like.json +44 -6
- package/package.json +21 -3
- package/src/core/dignity-p2p.js +79 -0
- package/src/index.js +2 -0
- package/src/persistence/indexeddb-persistence.js +182 -0
- package/src/react/index.js +114 -0
package/docs/index.html
CHANGED
|
@@ -3,27 +3,107 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<
|
|
6
|
+
<meta name="description" content="dignity.js v0.4.0 — REST-like P2P object API for decentralized JavaScript applications." />
|
|
7
|
+
<title>dignity.js · Documentation</title>
|
|
8
|
+
<link rel="stylesheet" href="./assets/highlight/github.min.css" media="(prefers-color-scheme: light)" />
|
|
9
|
+
<link rel="stylesheet" href="./assets/highlight/github-dark.min.css" media="(prefers-color-scheme: dark)" />
|
|
7
10
|
<link rel="stylesheet" href="./assets/styles.css" />
|
|
8
11
|
</head>
|
|
9
12
|
<body>
|
|
10
|
-
<
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<
|
|
13
|
+
<header class="site-header">
|
|
14
|
+
<a class="site-header__brand" href="#overview">
|
|
15
|
+
<img src="./assets/dignity-logo.svg" alt="" width="344" height="80" />
|
|
16
|
+
<!-- <span>dignity.js</span> -->
|
|
17
|
+
<span class="site-header__version">v0.4.0</span>
|
|
18
|
+
</a>
|
|
19
|
+
<div class="site-header__links">
|
|
20
|
+
<a href="https://www.npmjs.com/package/dignity.js" target="_blank" rel="noopener noreferrer">npm</a>
|
|
21
|
+
<a href="https://github.com/jose-compu/dignity.js" target="_blank" rel="noopener noreferrer">GitHub</a>
|
|
22
|
+
<a href="./openapi-like.json">API JSON</a>
|
|
23
|
+
</div>
|
|
24
|
+
<button class="menu-toggle" type="button" aria-label="Toggle navigation">Menu</button>
|
|
25
|
+
</header>
|
|
26
|
+
|
|
27
|
+
<div class="layout">
|
|
28
|
+
<aside class="sidebar">
|
|
29
|
+
<div class="sidebar__group">
|
|
30
|
+
<div class="sidebar__label">Getting started</div>
|
|
31
|
+
<nav>
|
|
32
|
+
<a href="#overview">Overview</a>
|
|
33
|
+
<a href="#installation">Installation</a>
|
|
34
|
+
<a href="#quick-start">Quick start</a>
|
|
35
|
+
<a href="#browser">Browser usage</a>
|
|
36
|
+
</nav>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="sidebar__group">
|
|
39
|
+
<div class="sidebar__label">Guide</div>
|
|
40
|
+
<nav>
|
|
41
|
+
<a href="#object-api">Object API</a>
|
|
42
|
+
<a href="#discovery">Room discovery</a>
|
|
43
|
+
<a href="#messaging">Direct messaging</a>
|
|
44
|
+
<a href="#concurrency">Concurrency</a>
|
|
45
|
+
<a href="#security">Security model</a>
|
|
46
|
+
<a href="#persistence">IndexedDB persistence</a>
|
|
47
|
+
<a href="#react">React hooks</a>
|
|
48
|
+
<a href="#signaling">Signaling</a>
|
|
49
|
+
</nav>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="sidebar__group">
|
|
52
|
+
<div class="sidebar__label">Reference</div>
|
|
53
|
+
<nav>
|
|
54
|
+
<a href="#api-reference">API reference</a>
|
|
55
|
+
<a href="#events">Events</a>
|
|
56
|
+
<a href="#exports">Package exports</a>
|
|
57
|
+
<a href="#examples">Examples</a>
|
|
58
|
+
<a href="#development">Development</a>
|
|
59
|
+
</nav>
|
|
60
|
+
</div>
|
|
61
|
+
</aside>
|
|
62
|
+
|
|
63
|
+
<main class="content">
|
|
64
|
+
<div class="content__inner">
|
|
65
|
+
<section id="overview" class="section">
|
|
66
|
+
<h1 class="page-title">Documentation</h1>
|
|
67
|
+
<p class="lead">
|
|
68
|
+
<strong>dignity.js</strong> is a REST-like P2P object API for decentralized JavaScript
|
|
69
|
+
applications. Synchronize shared objects across browsers with owner authorization,
|
|
70
|
+
scoped broadcast encryption, and built-in anti-abuse controls.
|
|
71
|
+
</p>
|
|
72
|
+
|
|
73
|
+
<div class="card-grid">
|
|
74
|
+
<article class="card">
|
|
75
|
+
<h3>Object CRUD</h3>
|
|
76
|
+
<p><code>create</code>, <code>read</code>, <code>list</code>, <code>update</code>, <code>remove</code> over P2P replication.</p>
|
|
77
|
+
</article>
|
|
78
|
+
<article class="card">
|
|
79
|
+
<h3>Security default-on</h3>
|
|
80
|
+
<p>Signing, encryption, Sloth VDF proof-of-work, and automatic peer bans.</p>
|
|
81
|
+
</article>
|
|
82
|
+
<article class="card">
|
|
83
|
+
<h3>Browser-first</h3>
|
|
84
|
+
<p>IIFE, ESM, and CJS bundles. Optional IndexedDB persistence and React hooks.</p>
|
|
85
|
+
</article>
|
|
86
|
+
</div>
|
|
87
|
+
</section>
|
|
88
|
+
|
|
89
|
+
<section id="installation" class="section">
|
|
90
|
+
<h2>Installation</h2>
|
|
91
|
+
<div class="code-block">
|
|
92
|
+
<span class="code-block__label">npm</span>
|
|
93
|
+
<pre><code class="language-bash">npm install dignity.js</code></pre>
|
|
94
|
+
</div>
|
|
95
|
+
<p>For React hooks, install React 18+ as a peer dependency:</p>
|
|
96
|
+
<div class="code-block">
|
|
97
|
+
<pre><code class="language-bash">npm install dignity.js react react-dom</code></pre>
|
|
98
|
+
</div>
|
|
99
|
+
</section>
|
|
100
|
+
|
|
101
|
+
<section id="quick-start" class="section">
|
|
102
|
+
<h2>Quick start</h2>
|
|
103
|
+
<p>Create a node, join a room, and replicate an object between two peers:</p>
|
|
104
|
+
<div class="code-block">
|
|
105
|
+
<span class="code-block__label">Node.js / ESM</span>
|
|
106
|
+
<pre><code class="language-javascript">const {
|
|
27
107
|
DignityP2P,
|
|
28
108
|
InMemoryNetworkHub,
|
|
29
109
|
InMemoryNetworkAdapter
|
|
@@ -33,52 +113,342 @@ const hub = new InMemoryNetworkHub();
|
|
|
33
113
|
|
|
34
114
|
const alice = new DignityP2P({
|
|
35
115
|
nodeId: 'alice',
|
|
36
|
-
networkAdapter: new InMemoryNetworkAdapter(hub)
|
|
116
|
+
networkAdapter: new InMemoryNetworkAdapter(hub),
|
|
117
|
+
security: {
|
|
118
|
+
appPassword: 'shared-out-of-band-password',
|
|
119
|
+
powSteps: 22
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const bob = new DignityP2P({
|
|
124
|
+
nodeId: 'bob',
|
|
125
|
+
networkAdapter: new InMemoryNetworkAdapter(hub),
|
|
126
|
+
security: {
|
|
127
|
+
appPassword: 'shared-out-of-band-password',
|
|
128
|
+
powSteps: 22
|
|
129
|
+
}
|
|
37
130
|
});
|
|
38
131
|
|
|
39
132
|
await alice.start();
|
|
40
|
-
await
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
133
|
+
await bob.start();
|
|
134
|
+
|
|
135
|
+
await alice.joinDiscovery('main', { metadata: { nickname: 'alice' } });
|
|
136
|
+
await bob.joinDiscovery('main', { metadata: { nickname: 'bob' } });
|
|
137
|
+
|
|
138
|
+
await alice.create('notes', { title: 'hello decentralized world' }, {
|
|
139
|
+
id: 'note-1',
|
|
140
|
+
broadcastScope: 'main'
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
console.log(bob.read('notes', 'note-1'));
|
|
144
|
+
|
|
145
|
+
await alice.leaveDiscovery('main');
|
|
146
|
+
await bob.leaveDiscovery('main');
|
|
147
|
+
await alice.stop();
|
|
148
|
+
await bob.stop();</code></pre>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="callout">
|
|
151
|
+
<strong>In-memory adapter</strong>
|
|
152
|
+
<code>InMemoryNetworkAdapter</code> is for tests and local demos. Production browser apps use a WebRTC network adapter (see project issues for the browser transport roadmap).
|
|
153
|
+
</div>
|
|
154
|
+
</section>
|
|
155
|
+
|
|
156
|
+
<section id="browser" class="section">
|
|
157
|
+
<h2>Browser usage</h2>
|
|
158
|
+
<p>Pre-built bundles are published to npm and available via CDN:</p>
|
|
159
|
+
<div class="code-block">
|
|
160
|
+
<span class="code-block__label">IIFE (global <code>DignityJS</code>)</span>
|
|
161
|
+
<pre><code class="language-xml"><script src="https://unpkg.com/dignity.js/dist/dignity.min.js"></script>
|
|
162
|
+
<script>
|
|
163
|
+
const { DignityP2P } = DignityJS;
|
|
164
|
+
</script></code></pre>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="table-wrap">
|
|
167
|
+
<table>
|
|
168
|
+
<thead>
|
|
169
|
+
<tr>
|
|
170
|
+
<th>Bundle</th>
|
|
171
|
+
<th>Path</th>
|
|
172
|
+
<th>Format</th>
|
|
173
|
+
</tr>
|
|
174
|
+
</thead>
|
|
175
|
+
<tbody>
|
|
176
|
+
<tr>
|
|
177
|
+
<td>Minified browser</td>
|
|
178
|
+
<td><code>dist/dignity.min.js</code></td>
|
|
179
|
+
<td>IIFE</td>
|
|
180
|
+
</tr>
|
|
181
|
+
<tr>
|
|
182
|
+
<td>ES modules</td>
|
|
183
|
+
<td><code>dist/dignity.esm.js</code></td>
|
|
184
|
+
<td>ESM</td>
|
|
185
|
+
</tr>
|
|
186
|
+
<tr>
|
|
187
|
+
<td>Node / CommonJS</td>
|
|
188
|
+
<td><code>dist/dignity.cjs.js</code></td>
|
|
189
|
+
<td>CJS</td>
|
|
190
|
+
</tr>
|
|
191
|
+
</tbody>
|
|
192
|
+
</table>
|
|
193
|
+
</div>
|
|
194
|
+
</section>
|
|
195
|
+
|
|
196
|
+
<section id="object-api" class="section">
|
|
197
|
+
<h2>Object API</h2>
|
|
198
|
+
<p>
|
|
199
|
+
The core API mirrors REST semantics. Each object belongs to a <strong>collection</strong>.
|
|
200
|
+
The peer that creates an object becomes its <strong>owner</strong> — only the owner may update or delete it.
|
|
201
|
+
</p>
|
|
202
|
+
|
|
203
|
+
<div class="table-wrap">
|
|
204
|
+
<table>
|
|
205
|
+
<thead>
|
|
206
|
+
<tr>
|
|
207
|
+
<th>Method</th>
|
|
208
|
+
<th>Description</th>
|
|
209
|
+
<th>Authorization</th>
|
|
210
|
+
</tr>
|
|
211
|
+
</thead>
|
|
212
|
+
<tbody>
|
|
213
|
+
<tr>
|
|
214
|
+
<td><code>create(collection, data, options?)</code></td>
|
|
215
|
+
<td>Create a new object. Returns the normalized record.</td>
|
|
216
|
+
<td>Creator becomes owner</td>
|
|
217
|
+
</tr>
|
|
218
|
+
<tr>
|
|
219
|
+
<td><code>read(collection, id)</code></td>
|
|
220
|
+
<td>Read one object, or <code>null</code> if missing/deleted.</td>
|
|
221
|
+
<td>—</td>
|
|
222
|
+
</tr>
|
|
223
|
+
<tr>
|
|
224
|
+
<td><code>list(collection, options?)</code></td>
|
|
225
|
+
<td>List objects. Set <code>includeDeleted: true</code> for tombstones.</td>
|
|
226
|
+
<td>—</td>
|
|
227
|
+
</tr>
|
|
228
|
+
<tr>
|
|
229
|
+
<td><code>update(collection, id, patch, options?)</code></td>
|
|
230
|
+
<td>Merge <code>patch</code> into object data and increment version.</td>
|
|
231
|
+
<td>Owner only</td>
|
|
232
|
+
</tr>
|
|
233
|
+
<tr>
|
|
234
|
+
<td><code>updateWithRetry(collection, id, patchFn, options?)</code></td>
|
|
235
|
+
<td>Read-modify-write with automatic retry on version conflicts.</td>
|
|
236
|
+
<td>Owner only</td>
|
|
237
|
+
</tr>
|
|
238
|
+
<tr>
|
|
239
|
+
<td><code>remove(collection, id, options?)</code></td>
|
|
240
|
+
<td>Soft-delete the object (tombstone).</td>
|
|
241
|
+
<td>Owner only</td>
|
|
242
|
+
</tr>
|
|
243
|
+
</tbody>
|
|
244
|
+
</table>
|
|
245
|
+
</div>
|
|
246
|
+
|
|
247
|
+
<h3>Scoped broadcast</h3>
|
|
248
|
+
<p>Pass <code>broadcastScope</code> on create/update to select a team or room password namespace:</p>
|
|
249
|
+
<div class="code-block">
|
|
250
|
+
<pre><code class="language-javascript">await node.create('matches', { mode: 'coop' }, {
|
|
251
|
+
id: 'm-1',
|
|
252
|
+
broadcastScope: 'coop:red'
|
|
253
|
+
});</code></pre>
|
|
254
|
+
</div>
|
|
255
|
+
<p>Configure per-scope passwords via <code>security.broadcastPasswords</code>.</p>
|
|
256
|
+
</section>
|
|
257
|
+
|
|
258
|
+
<section id="discovery" class="section">
|
|
259
|
+
<h2>Room / team discovery</h2>
|
|
260
|
+
<p>Discover active peers in a named scope (room, team, raid, etc.):</p>
|
|
261
|
+
<div class="code-block">
|
|
262
|
+
<pre><code class="language-javascript">await node.joinDiscovery('team:red', {
|
|
263
|
+
metadata: { nickname: 'alice' },
|
|
264
|
+
heartbeatIntervalMs: 15000,
|
|
265
|
+
ttlMs: 45000
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
const peers = node.listPeers('team:red', { includeSelf: false });
|
|
269
|
+
|
|
270
|
+
await node.leaveDiscovery('team:red');</code></pre>
|
|
271
|
+
</div>
|
|
272
|
+
</section>
|
|
273
|
+
|
|
274
|
+
<section id="messaging" class="section">
|
|
275
|
+
<h2>Direct secure messaging</h2>
|
|
276
|
+
<p>Send end-to-end encrypted messages to a specific peer:</p>
|
|
277
|
+
<div class="code-block">
|
|
278
|
+
<pre><code class="language-javascript">alice.registerPeerPublicKey('bob', bob.getPublicKey());
|
|
279
|
+
bob.registerPeerPublicKey('alice', alice.getPublicKey());
|
|
280
|
+
|
|
281
|
+
await alice.sendDirectMessage('bob', 'dm', { text: 'private payload' });</code></pre>
|
|
282
|
+
</div>
|
|
283
|
+
</section>
|
|
284
|
+
|
|
285
|
+
<section id="concurrency" class="section">
|
|
286
|
+
<h2>Optimistic concurrency</h2>
|
|
287
|
+
<p>
|
|
288
|
+
Every update carries a monotonic <code>version</code>. Stale operations are rejected when
|
|
289
|
+
<code>baseVersion</code> does not match. Listen for <code>conflict</code> events or use
|
|
290
|
+
built-in helpers:
|
|
291
|
+
</p>
|
|
292
|
+
<div class="code-block">
|
|
293
|
+
<pre><code class="language-javascript">node.on('conflict', (event) => {
|
|
294
|
+
// event.phase: 'local' | 'remote'
|
|
295
|
+
console.log(event.expectedVersion, event.currentVersion);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// Fail fast on stale local writes
|
|
299
|
+
await node.update('games', 'g1', { score: 10 }, { expectedVersion: 3 });
|
|
300
|
+
|
|
301
|
+
// Automatic retry for read-modify-write loops
|
|
302
|
+
await node.updateWithRetry('games', 'g1', (current) => ({
|
|
303
|
+
score: current.data.score + 1
|
|
304
|
+
}));</code></pre>
|
|
305
|
+
</div>
|
|
306
|
+
</section>
|
|
307
|
+
|
|
308
|
+
<section id="security" class="section">
|
|
309
|
+
<h2>Security model</h2>
|
|
310
|
+
<p>All security features are enabled by default. Configure via the <code>security</code> constructor option.</p>
|
|
311
|
+
|
|
312
|
+
<div class="table-wrap">
|
|
313
|
+
<table>
|
|
314
|
+
<thead>
|
|
315
|
+
<tr>
|
|
316
|
+
<th>Feature</th>
|
|
317
|
+
<th>Default</th>
|
|
318
|
+
<th>Details</th>
|
|
319
|
+
</tr>
|
|
320
|
+
</thead>
|
|
321
|
+
<tbody>
|
|
322
|
+
<tr>
|
|
323
|
+
<td>Signing</td>
|
|
324
|
+
<td>On</td>
|
|
325
|
+
<td>Ed25519 signature on every message</td>
|
|
326
|
+
</tr>
|
|
327
|
+
<tr>
|
|
328
|
+
<td>Broadcast encryption</td>
|
|
329
|
+
<td>On</td>
|
|
330
|
+
<td>AES secretbox; PBKDF2-SHA256 key from <code>appPassword</code> (100k iterations)</td>
|
|
331
|
+
</tr>
|
|
332
|
+
<tr>
|
|
333
|
+
<td>Direct encryption</td>
|
|
334
|
+
<td>On</td>
|
|
335
|
+
<td>NaCl box (X25519) — true E2E to recipient public key</td>
|
|
336
|
+
</tr>
|
|
337
|
+
<tr>
|
|
338
|
+
<td>Proof-of-work</td>
|
|
339
|
+
<td>On</td>
|
|
340
|
+
<td>Sloth VDF; default <code>powSteps: 22</code> (~1s on reference hardware)</td>
|
|
341
|
+
</tr>
|
|
342
|
+
<tr>
|
|
343
|
+
<td>Peer bans</td>
|
|
344
|
+
<td>On</td>
|
|
345
|
+
<td>Invalid signature or PoW → 48h ban (configurable)</td>
|
|
346
|
+
</tr>
|
|
347
|
+
</tbody>
|
|
348
|
+
</table>
|
|
349
|
+
</div>
|
|
350
|
+
|
|
351
|
+
<div class="callout callout--warn">
|
|
352
|
+
<strong>Broadcast mode is not E2E</strong>
|
|
353
|
+
All peers that know the scope password can decrypt broadcast traffic. Use direct mode for sensitive per-peer data.
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
<h3>Security configuration</h3>
|
|
357
|
+
<div class="code-block">
|
|
358
|
+
<pre><code class="language-javascript">const node = new DignityP2P({
|
|
359
|
+
nodeId: 'alice',
|
|
360
|
+
networkAdapter,
|
|
361
|
+
security: {
|
|
362
|
+
appPassword: 'shared-out-of-band-password',
|
|
363
|
+
broadcastPasswords: {
|
|
364
|
+
'coop:red': 'red-team-secret',
|
|
365
|
+
'coop:blue': 'blue-team-secret'
|
|
366
|
+
},
|
|
367
|
+
powSteps: 22,
|
|
368
|
+
kdfIterations: 100000,
|
|
369
|
+
banDurationMs: 48 * 60 * 60 * 1000
|
|
370
|
+
}
|
|
371
|
+
});</code></pre>
|
|
372
|
+
</div>
|
|
373
|
+
</section>
|
|
374
|
+
|
|
375
|
+
<section id="persistence" class="section">
|
|
376
|
+
<h2>IndexedDB persistence</h2>
|
|
377
|
+
<p>Survive page reloads by persisting replicated object state to IndexedDB:</p>
|
|
378
|
+
<div class="code-block">
|
|
379
|
+
<pre><code class="language-javascript">const { DignityP2P, IndexedDBPersistence } = require('dignity.js');
|
|
380
|
+
|
|
381
|
+
const node = new DignityP2P({ nodeId, networkAdapter, security });
|
|
382
|
+
const persistence = new IndexedDBPersistence({
|
|
383
|
+
dbName: 'my-app',
|
|
384
|
+
collections: ['games', 'matches'] // omit to persist all collections
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
await node.start();
|
|
388
|
+
await persistence.attach(node);
|
|
389
|
+
|
|
390
|
+
// Later
|
|
391
|
+
await persistence.detach();</code></pre>
|
|
392
|
+
</div>
|
|
393
|
+
</section>
|
|
394
|
+
|
|
395
|
+
<section id="react" class="section">
|
|
396
|
+
<h2>React hooks</h2>
|
|
397
|
+
<p>Optional integration via <code>dignity.js/react</code> (requires React ≥ 18):</p>
|
|
398
|
+
<div class="code-block">
|
|
399
|
+
<pre><code class="language-javascript">import { useDignity, useCollection, usePeers } from 'dignity.js/react';
|
|
400
|
+
|
|
401
|
+
function Room() {
|
|
402
|
+
const { node, status, error } = useDignity(config);
|
|
403
|
+
const games = useCollection(node, 'games');
|
|
404
|
+
const peers = usePeers(node, 'room:chess', { includeSelf: false });
|
|
405
|
+
|
|
406
|
+
if (status === 'starting') return <p>Connecting…</p>;
|
|
407
|
+
if (error) return <p>Error: {error.message}</p>;
|
|
408
|
+
|
|
409
|
+
return (
|
|
410
|
+
<pre>{JSON.stringify({ status, games, peers }, null, 2)}</pre>
|
|
411
|
+
);
|
|
412
|
+
}</code></pre>
|
|
413
|
+
</div>
|
|
414
|
+
|
|
415
|
+
<div class="table-wrap">
|
|
416
|
+
<table>
|
|
417
|
+
<thead>
|
|
418
|
+
<tr>
|
|
419
|
+
<th>Hook</th>
|
|
420
|
+
<th>Returns</th>
|
|
421
|
+
</tr>
|
|
422
|
+
</thead>
|
|
423
|
+
<tbody>
|
|
424
|
+
<tr>
|
|
425
|
+
<td><code>useDignity(config)</code></td>
|
|
426
|
+
<td><code>{ node, status, error }</code> — starts/stops node on mount/unmount</td>
|
|
427
|
+
</tr>
|
|
428
|
+
<tr>
|
|
429
|
+
<td><code>useCollection(node, name)</code></td>
|
|
430
|
+
<td>Reactive array from <code>node.list(name)</code></td>
|
|
431
|
+
</tr>
|
|
432
|
+
<tr>
|
|
433
|
+
<td><code>usePeers(node, scope, options?)</code></td>
|
|
434
|
+
<td>Reactive peer list from discovery</td>
|
|
435
|
+
</tr>
|
|
436
|
+
</tbody>
|
|
437
|
+
</table>
|
|
438
|
+
</div>
|
|
439
|
+
</section>
|
|
440
|
+
|
|
441
|
+
<section id="signaling" class="section">
|
|
442
|
+
<h2>Signaling</h2>
|
|
443
|
+
<p>Default PeerJS-compatible signaling endpoints are included. Customize with <code>createDefaultSignalingPool</code>:</p>
|
|
444
|
+
<div class="code-block">
|
|
445
|
+
<pre><code class="language-javascript">const {
|
|
76
446
|
createDefaultSignalingPool,
|
|
77
447
|
WebSocketSignalingProvider
|
|
78
448
|
} = require('dignity.js');
|
|
79
449
|
|
|
80
450
|
const pool = createDefaultSignalingPool({
|
|
81
|
-
cloudflareUrls: ['wss://your-
|
|
451
|
+
cloudflareUrls: ['wss://your-endpoint.example/peerjs?key=peerjs'],
|
|
82
452
|
fallbackUrls: ['wss://relay-a.example', 'wss://relay-b.example'],
|
|
83
453
|
customProviders: [
|
|
84
454
|
new WebSocketSignalingProvider({
|
|
@@ -88,30 +458,180 @@ const pool = createDefaultSignalingPool({
|
|
|
88
458
|
})
|
|
89
459
|
]
|
|
90
460
|
});</code></pre>
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
461
|
+
</div>
|
|
462
|
+
<p>Default public endpoints:</p>
|
|
463
|
+
<ul>
|
|
464
|
+
<li><code>wss://peerjs.92k.de/peerjs?key=peerjs</code></li>
|
|
465
|
+
<li><code>wss://0.peerjs.com/peerjs?key=peerjs</code></li>
|
|
466
|
+
</ul>
|
|
467
|
+
</section>
|
|
468
|
+
|
|
469
|
+
<section id="api-reference" class="section">
|
|
470
|
+
<h2>API reference</h2>
|
|
471
|
+
<p>Primary class: <code>DignityP2P</code></p>
|
|
472
|
+
|
|
473
|
+
<h3>Constructor</h3>
|
|
474
|
+
<div class="code-block">
|
|
475
|
+
<pre><code class="language-javascript">new DignityP2P({
|
|
476
|
+
nodeId, // required — unique peer identifier
|
|
477
|
+
networkAdapter, // required — transport implementation
|
|
478
|
+
security, // optional — MessageSecurityService options
|
|
479
|
+
now, // optional — clock injection (tests)
|
|
480
|
+
idGenerator // optional — custom operation id factory
|
|
481
|
+
})</code></pre>
|
|
482
|
+
</div>
|
|
483
|
+
|
|
484
|
+
<h3>Lifecycle</h3>
|
|
485
|
+
<div class="table-wrap">
|
|
486
|
+
<table>
|
|
487
|
+
<thead>
|
|
488
|
+
<tr>
|
|
489
|
+
<th>Method</th>
|
|
490
|
+
<th>Description</th>
|
|
491
|
+
</tr>
|
|
492
|
+
</thead>
|
|
493
|
+
<tbody>
|
|
494
|
+
<tr><td><code>start()</code></td><td>Connect adapter and begin receiving messages</td></tr>
|
|
495
|
+
<tr><td><code>stop()</code></td><td>Leave discovery scopes and disconnect</td></tr>
|
|
496
|
+
<tr><td><code>getPublicKey()</code></td><td>Return this node's public key bundle</td></tr>
|
|
497
|
+
<tr><td><code>registerPeerPublicKey(id, key)</code></td><td>Trust a remote peer's keys</td></tr>
|
|
498
|
+
</tbody>
|
|
499
|
+
</table>
|
|
500
|
+
</div>
|
|
501
|
+
|
|
502
|
+
<p>
|
|
503
|
+
Machine-readable metadata:
|
|
504
|
+
<a href="./openapi-like.json">openapi-like.json</a>
|
|
505
|
+
</p>
|
|
506
|
+
</section>
|
|
507
|
+
|
|
508
|
+
<section id="events" class="section">
|
|
509
|
+
<h2>Events</h2>
|
|
510
|
+
<p><code>DignityP2P</code> extends <code>EventEmitter</code>. Common events:</p>
|
|
511
|
+
<div class="table-wrap">
|
|
512
|
+
<table>
|
|
513
|
+
<thead>
|
|
514
|
+
<tr>
|
|
515
|
+
<th>Event</th>
|
|
516
|
+
<th>Payload</th>
|
|
517
|
+
</tr>
|
|
518
|
+
</thead>
|
|
519
|
+
<tbody>
|
|
520
|
+
<tr>
|
|
521
|
+
<td><span class="tag tag--event">change</span></td>
|
|
522
|
+
<td><code>{ kind, collection, id }</code> — object created, updated, or deleted</td>
|
|
523
|
+
</tr>
|
|
524
|
+
<tr>
|
|
525
|
+
<td><span class="tag tag--event">conflict</span></td>
|
|
526
|
+
<td><code>{ kind, collection, id, expectedVersion, currentVersion, phase }</code></td>
|
|
527
|
+
</tr>
|
|
528
|
+
<tr>
|
|
529
|
+
<td><span class="tag tag--event">peerdiscovered</span></td>
|
|
530
|
+
<td><code>{ scope, peerId, metadata }</code></td>
|
|
531
|
+
</tr>
|
|
532
|
+
<tr>
|
|
533
|
+
<td><span class="tag tag--event">peerleft</span></td>
|
|
534
|
+
<td><code>{ scope, peerId, reason }</code></td>
|
|
535
|
+
</tr>
|
|
536
|
+
<tr>
|
|
537
|
+
<td><span class="tag tag--event">message</span></td>
|
|
538
|
+
<td><code>{ senderId, targetId, type, payload }</code> — custom decrypted messages</td>
|
|
539
|
+
</tr>
|
|
540
|
+
<tr>
|
|
541
|
+
<td><span class="tag tag--event">securityerror</span></td>
|
|
542
|
+
<td><code>{ senderId, error }</code></td>
|
|
543
|
+
</tr>
|
|
544
|
+
<tr>
|
|
545
|
+
<td><span class="tag tag--event">warning</span></td>
|
|
546
|
+
<td><code>{ type, ... }</code> — non-fatal issues (heartbeat, persistence, etc.)</td>
|
|
547
|
+
</tr>
|
|
548
|
+
</tbody>
|
|
549
|
+
</table>
|
|
550
|
+
</div>
|
|
551
|
+
</section>
|
|
552
|
+
|
|
553
|
+
<section id="exports" class="section">
|
|
554
|
+
<h2>Package exports</h2>
|
|
555
|
+
<div class="table-wrap">
|
|
556
|
+
<table>
|
|
557
|
+
<thead>
|
|
558
|
+
<tr>
|
|
559
|
+
<th>Import path</th>
|
|
560
|
+
<th>Exports</th>
|
|
561
|
+
</tr>
|
|
562
|
+
</thead>
|
|
563
|
+
<tbody>
|
|
564
|
+
<tr>
|
|
565
|
+
<td><code>dignity.js</code></td>
|
|
566
|
+
<td><code>DignityP2P</code>, <code>IndexedDBPersistence</code>, signaling providers, in-memory adapters, security utilities</td>
|
|
567
|
+
</tr>
|
|
568
|
+
<tr>
|
|
569
|
+
<td><code>dignity.js/react</code></td>
|
|
570
|
+
<td><code>useDignity</code>, <code>useCollection</code>, <code>usePeers</code></td>
|
|
571
|
+
</tr>
|
|
572
|
+
</tbody>
|
|
573
|
+
</table>
|
|
574
|
+
</div>
|
|
575
|
+
</section>
|
|
576
|
+
|
|
577
|
+
<section id="examples" class="section">
|
|
578
|
+
<h2>Examples</h2>
|
|
579
|
+
<div class="table-wrap">
|
|
580
|
+
<table>
|
|
581
|
+
<thead>
|
|
582
|
+
<tr>
|
|
583
|
+
<th>Script</th>
|
|
584
|
+
<th>Description</th>
|
|
585
|
+
<th>Run</th>
|
|
586
|
+
</tr>
|
|
587
|
+
</thead>
|
|
588
|
+
<tbody>
|
|
589
|
+
<tr>
|
|
590
|
+
<td><code>examples/decentralized-tictactoe.js</code></td>
|
|
591
|
+
<td>Replicated board state and owner authorization</td>
|
|
592
|
+
<td><code>npm run example:tictactoe</code></td>
|
|
593
|
+
</tr>
|
|
594
|
+
<tr>
|
|
595
|
+
<td><code>examples/decentralized-chess-lite.js</code></td>
|
|
596
|
+
<td>Replicated move history with compact board model</td>
|
|
597
|
+
<td><code>npm run example:chess</code></td>
|
|
598
|
+
</tr>
|
|
599
|
+
</tbody>
|
|
600
|
+
</table>
|
|
601
|
+
</div>
|
|
602
|
+
</section>
|
|
603
|
+
|
|
604
|
+
<section id="development" class="section">
|
|
605
|
+
<h2>Development</h2>
|
|
606
|
+
<div class="code-block">
|
|
607
|
+
<pre><code class="language-bash"># Run tests (177+ passing, ~99.5% line coverage)
|
|
608
|
+
npm test
|
|
609
|
+
|
|
610
|
+
# Build browser + Node bundles
|
|
611
|
+
npm run build
|
|
612
|
+
|
|
613
|
+
# Serve docs locally
|
|
614
|
+
npm run docs:serve
|
|
615
|
+
|
|
616
|
+
# Run examples
|
|
617
|
+
npm run example:tictactoe
|
|
618
|
+
npm run example:chess</code></pre>
|
|
619
|
+
</div>
|
|
620
|
+
</section>
|
|
621
|
+
|
|
622
|
+
<footer class="site-footer">
|
|
623
|
+
<p>
|
|
624
|
+
dignity.js v0.4.0 ·
|
|
625
|
+
<a href="https://github.com/jose-compu/dignity.js/blob/main/LICENSE">Apache 2.0</a> ·
|
|
626
|
+
<a href="https://github.com/jose-compu/dignity.js">GitHub</a> ·
|
|
627
|
+
<a href="https://www.npmjs.com/package/dignity.js">npm</a>
|
|
628
|
+
</p>
|
|
629
|
+
</footer>
|
|
630
|
+
</div>
|
|
631
|
+
</main>
|
|
632
|
+
</div>
|
|
633
|
+
|
|
634
|
+
<script src="./assets/highlight/highlight.min.js"></script>
|
|
635
|
+
<script src="./assets/docs.js"></script>
|
|
116
636
|
</body>
|
|
117
637
|
</html>
|