@dxos/echo-pipeline 0.4.8-next.fff1521 → 0.4.8

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.
Files changed (34) hide show
  1. package/dist/lib/browser/{chunk-3FVT6KX6.mjs → chunk-WAN2XUWE.mjs} +38 -698
  2. package/dist/lib/browser/chunk-WAN2XUWE.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +633 -6
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +2 -274
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/node/{chunk-WZ4WTAN6.cjs → chunk-U6J2HC4T.cjs} +39 -689
  9. package/dist/lib/node/chunk-U6J2HC4T.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +647 -30
  11. package/dist/lib/node/index.cjs.map +4 -4
  12. package/dist/lib/node/meta.json +1 -1
  13. package/dist/lib/node/testing/index.cjs +12 -282
  14. package/dist/lib/node/testing/index.cjs.map +4 -4
  15. package/dist/types/src/space/control-pipeline.d.ts.map +1 -1
  16. package/dist/types/src/space/data-pipeline.d.ts +0 -1
  17. package/dist/types/src/space/data-pipeline.d.ts.map +1 -1
  18. package/dist/types/src/testing/index.d.ts +0 -1
  19. package/dist/types/src/testing/index.d.ts.map +1 -1
  20. package/dist/types/src/testing/util.d.ts +2 -6
  21. package/dist/types/src/testing/util.d.ts.map +1 -1
  22. package/package.json +33 -33
  23. package/src/space/control-pipeline.ts +3 -1
  24. package/src/space/data-pipeline.ts +1 -44
  25. package/src/testing/index.ts +0 -1
  26. package/src/testing/util.ts +2 -26
  27. package/dist/lib/browser/chunk-3FVT6KX6.mjs.map +0 -7
  28. package/dist/lib/node/chunk-WZ4WTAN6.cjs.map +0 -7
  29. package/dist/types/src/testing/database-test-rig.d.ts +0 -67
  30. package/dist/types/src/testing/database-test-rig.d.ts.map +0 -1
  31. package/dist/types/src/tests/database.test.d.ts +0 -2
  32. package/dist/types/src/tests/database.test.d.ts.map +0 -1
  33. package/src/testing/database-test-rig.ts +0 -289
  34. package/src/tests/database.test.ts +0 -100
@@ -2,17 +2,13 @@ import "@dxos/node-std/globals";
2
2
  import {
3
3
  AuthExtension,
4
4
  AuthStatus,
5
- AutomergeHost,
6
- AutomergeStorageAdapter,
7
5
  DataPipeline,
8
6
  DataServiceHost,
9
7
  DataServiceImpl,
10
8
  DataServiceSubscriptions,
11
9
  DatabaseHost,
12
- LocalHostNetworkAdapter,
13
10
  MOCK_AUTH_PROVIDER,
14
11
  MOCK_AUTH_VERIFIER,
15
- MeshNetworkAdapter,
16
12
  MetadataStore,
17
13
  Pipeline,
18
14
  SnapshotManager,
@@ -24,12 +20,643 @@ import {
24
20
  TimeframeClock,
25
21
  codec,
26
22
  createMappedFeedWriter,
27
- getSpaceKeyFromDoc,
28
23
  mapFeedIndexesToTimeframe,
29
24
  mapTimeframeToFeedIndexes,
30
25
  startAfter,
31
26
  valueEncoding
32
- } from "./chunk-3FVT6KX6.mjs";
27
+ } from "./chunk-WAN2XUWE.mjs";
28
+
29
+ // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
30
+ import { next as automerge, getHeads } from "@dxos/automerge/automerge";
31
+ import { Repo } from "@dxos/automerge/automerge-repo";
32
+ import { IndexedDBStorageAdapter } from "@dxos/automerge/automerge-repo-storage-indexeddb";
33
+ import { Context } from "@dxos/context";
34
+ import { PublicKey } from "@dxos/keys";
35
+ import { log as log3 } from "@dxos/log";
36
+ import { idCodec } from "@dxos/protocols";
37
+ import { StorageType } from "@dxos/random-access-storage";
38
+ import { trace } from "@dxos/tracing";
39
+ import { ComplexMap, ComplexSet, defaultMap, mapValues } from "@dxos/util";
40
+
41
+ // packages/core/echo/echo-pipeline/src/automerge/automerge-storage-adapter.ts
42
+ import { arrayToBuffer, bufferToArray } from "@dxos/util";
43
+ var AutomergeStorageAdapter = class {
44
+ constructor(_directory) {
45
+ this._directory = _directory;
46
+ this._state = "opened";
47
+ }
48
+ async load(key) {
49
+ if (this._state !== "opened") {
50
+ return void 0;
51
+ }
52
+ const filename = this._getFilename(key);
53
+ const file = this._directory.getOrCreateFile(filename);
54
+ const { size } = await file.stat();
55
+ if (!size || size === 0) {
56
+ return void 0;
57
+ }
58
+ const buffer = await file.read(0, size);
59
+ return bufferToArray(buffer);
60
+ }
61
+ async save(key, data) {
62
+ if (this._state !== "opened") {
63
+ return void 0;
64
+ }
65
+ const filename = this._getFilename(key);
66
+ const file = this._directory.getOrCreateFile(filename);
67
+ await file.write(0, arrayToBuffer(data));
68
+ await file.truncate?.(data.length);
69
+ await file.flush?.();
70
+ }
71
+ async remove(key) {
72
+ if (this._state !== "opened") {
73
+ return void 0;
74
+ }
75
+ const filename = this._getFilename(key);
76
+ const file = this._directory.getOrCreateFile(filename);
77
+ await file.destroy();
78
+ }
79
+ async loadRange(keyPrefix) {
80
+ if (this._state !== "opened") {
81
+ return [];
82
+ }
83
+ const filename = this._getFilename(keyPrefix);
84
+ const entries = await this._directory.list();
85
+ return Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
86
+ const file = this._directory.getOrCreateFile(entry);
87
+ const { size } = await file.stat();
88
+ const buffer = await file.read(0, size);
89
+ return {
90
+ key: this._getKeyFromFilename(entry),
91
+ data: bufferToArray(buffer)
92
+ };
93
+ }));
94
+ }
95
+ async removeRange(keyPrefix) {
96
+ if (this._state !== "opened") {
97
+ return void 0;
98
+ }
99
+ const filename = this._getFilename(keyPrefix);
100
+ const entries = await this._directory.list();
101
+ await Promise.all(entries.filter((entry) => entry.startsWith(filename)).map(async (entry) => {
102
+ const file = this._directory.getOrCreateFile(entry);
103
+ await file.destroy();
104
+ }));
105
+ }
106
+ async close() {
107
+ this._state = "closed";
108
+ }
109
+ _getFilename(key) {
110
+ return key.map((k) => k.replaceAll("%", "%25").replaceAll("-", "%2D")).join("-");
111
+ }
112
+ _getKeyFromFilename(filename) {
113
+ return filename.split("-").map((k) => k.replaceAll("%2D", "-").replaceAll("%25", "%"));
114
+ }
115
+ };
116
+
117
+ // packages/core/echo/echo-pipeline/src/automerge/automerge-storage–wrapper.ts
118
+ var AutomergeStorageWrapper = class {
119
+ constructor({ storage, callbacks }) {
120
+ this._storage = storage;
121
+ this._callbacks = callbacks;
122
+ }
123
+ async load(key) {
124
+ return this._storage.load(key);
125
+ }
126
+ async save(key, value) {
127
+ await this._callbacks.beforeSave?.(key);
128
+ await this._storage.save(key, value);
129
+ await this._callbacks.afterSave?.(key);
130
+ }
131
+ async remove(key) {
132
+ return this._storage.remove(key);
133
+ }
134
+ async loadRange(keyPrefix) {
135
+ return this._storage.loadRange(keyPrefix);
136
+ }
137
+ async removeRange(keyPrefix) {
138
+ return this._storage.removeRange(keyPrefix);
139
+ }
140
+ async close() {
141
+ if (this._storage instanceof AutomergeStorageAdapter) {
142
+ return this._storage.close();
143
+ }
144
+ }
145
+ };
146
+
147
+ // packages/core/echo/echo-pipeline/src/automerge/local-host-network-adapter.ts
148
+ import { Trigger } from "@dxos/async";
149
+ import { NetworkAdapter, cbor } from "@dxos/automerge/automerge-repo";
150
+ import { Stream } from "@dxos/codec-protobuf";
151
+ import { invariant } from "@dxos/invariant";
152
+ import { log } from "@dxos/log";
153
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/local-host-network-adapter.ts";
154
+ var LocalHostNetworkAdapter = class extends NetworkAdapter {
155
+ constructor() {
156
+ super(...arguments);
157
+ this._peers = /* @__PURE__ */ new Map();
158
+ this._connected = new Trigger();
159
+ }
160
+ /**
161
+ * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
162
+ */
163
+ ready() {
164
+ this.emit("ready", {
165
+ network: this
166
+ });
167
+ }
168
+ connect(peerId) {
169
+ this.peerId = peerId;
170
+ this._connected.wake();
171
+ }
172
+ send(message) {
173
+ const peer = this._peers.get(message.targetId);
174
+ invariant(peer, "Peer not found.", {
175
+ F: __dxlog_file,
176
+ L: 45,
177
+ S: this,
178
+ A: [
179
+ "peer",
180
+ "'Peer not found.'"
181
+ ]
182
+ });
183
+ peer.send(message);
184
+ }
185
+ async close() {
186
+ this._peers.forEach((peer) => peer.disconnect());
187
+ this.emit("close");
188
+ }
189
+ disconnect() {
190
+ }
191
+ syncRepo({ id, syncMessage }) {
192
+ const peerId = this._getPeerId(id);
193
+ return new Stream(({ next, close }) => {
194
+ invariant(!this._peers.has(peerId), "Peer already connected.", {
195
+ F: __dxlog_file,
196
+ L: 63,
197
+ S: this,
198
+ A: [
199
+ "!this._peers.has(peerId)",
200
+ "'Peer already connected.'"
201
+ ]
202
+ });
203
+ this._peers.set(peerId, {
204
+ connected: true,
205
+ send: (message) => {
206
+ next({
207
+ syncMessage: cbor.encode(message)
208
+ });
209
+ },
210
+ disconnect: () => {
211
+ this._peers.delete(peerId);
212
+ close();
213
+ this.emit("peer-disconnected", {
214
+ peerId
215
+ });
216
+ }
217
+ });
218
+ this._connected.wait({
219
+ timeout: 1e3
220
+ }).then(() => {
221
+ this.emit("peer-candidate", {
222
+ peerMetadata: {},
223
+ peerId
224
+ });
225
+ }).catch((err) => log.catch(err, void 0, {
226
+ F: __dxlog_file,
227
+ L: 88,
228
+ S: this,
229
+ C: (f, a) => f(...a)
230
+ }));
231
+ });
232
+ }
233
+ async sendSyncMessage({ id, syncMessage }) {
234
+ await this._connected.wait({
235
+ timeout: 1e3
236
+ });
237
+ const message = cbor.decode(syncMessage);
238
+ this.emit("message", message);
239
+ }
240
+ async getHostInfo() {
241
+ await this._connected.wait({
242
+ timeout: 1e3
243
+ });
244
+ invariant(this.peerId, "Peer id not set.", {
245
+ F: __dxlog_file,
246
+ L: 100,
247
+ S: this,
248
+ A: [
249
+ "this.peerId",
250
+ "'Peer id not set.'"
251
+ ]
252
+ });
253
+ return {
254
+ peerId: this.peerId
255
+ };
256
+ }
257
+ _getPeerId(id) {
258
+ return id;
259
+ }
260
+ };
261
+
262
+ // packages/core/echo/echo-pipeline/src/automerge/mesh-network-adapter.ts
263
+ import { Trigger as Trigger2 } from "@dxos/async";
264
+ import { NetworkAdapter as NetworkAdapter2, cbor as cbor2 } from "@dxos/automerge/automerge-repo";
265
+ import { invariant as invariant2 } from "@dxos/invariant";
266
+ import { log as log2 } from "@dxos/log";
267
+ import { AutomergeReplicator } from "@dxos/teleport-extension-automerge-replicator";
268
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/mesh-network-adapter.ts";
269
+ var MeshNetworkAdapter = class extends NetworkAdapter2 {
270
+ constructor() {
271
+ super(...arguments);
272
+ this._extensions = /* @__PURE__ */ new Map();
273
+ this._connected = new Trigger2();
274
+ }
275
+ /**
276
+ * Emits `ready` event. That signals to `Repo` that it can start using the adapter.
277
+ */
278
+ ready() {
279
+ this.emit("ready", {
280
+ network: this
281
+ });
282
+ }
283
+ connect(peerId) {
284
+ this.peerId = peerId;
285
+ this._connected.wake();
286
+ }
287
+ send(message) {
288
+ const receiverId = message.targetId;
289
+ const extension = this._extensions.get(receiverId);
290
+ invariant2(extension, "Extension not found.", {
291
+ F: __dxlog_file2,
292
+ L: 38,
293
+ S: this,
294
+ A: [
295
+ "extension",
296
+ "'Extension not found.'"
297
+ ]
298
+ });
299
+ extension.sendSyncMessage({
300
+ payload: cbor2.encode(message)
301
+ }).catch((err) => log2.catch(err, void 0, {
302
+ F: __dxlog_file2,
303
+ L: 39,
304
+ S: this,
305
+ C: (f, a) => f(...a)
306
+ }));
307
+ }
308
+ disconnect() {
309
+ }
310
+ createExtension() {
311
+ invariant2(this.peerId, "Peer id not set.", {
312
+ F: __dxlog_file2,
313
+ L: 47,
314
+ S: this,
315
+ A: [
316
+ "this.peerId",
317
+ "'Peer id not set.'"
318
+ ]
319
+ });
320
+ let peerInfo;
321
+ const extension = new AutomergeReplicator({
322
+ peerId: this.peerId
323
+ }, {
324
+ onStartReplication: async (info, remotePeerId) => {
325
+ await this._connected.wait();
326
+ log2("onStartReplication", {
327
+ id: info.id,
328
+ thisPeerId: this.peerId,
329
+ remotePeerId: remotePeerId.toHex()
330
+ }, {
331
+ F: __dxlog_file2,
332
+ L: 70,
333
+ S: this,
334
+ C: (f, a) => f(...a)
335
+ });
336
+ if (!this._extensions.has(info.id)) {
337
+ peerInfo = info;
338
+ this._extensions.set(info.id, extension);
339
+ log2("peer-candidate", {
340
+ id: info.id,
341
+ thisPeerId: this.peerId,
342
+ remotePeerId: remotePeerId.toHex()
343
+ }, {
344
+ F: __dxlog_file2,
345
+ L: 76,
346
+ S: this,
347
+ C: (f, a) => f(...a)
348
+ });
349
+ this.emit("peer-candidate", {
350
+ // TODO(mykola): Hack, stop abusing `peerMetadata` field.
351
+ peerMetadata: {
352
+ dxos_deviceKey: remotePeerId.toHex()
353
+ },
354
+ peerId: info.id
355
+ });
356
+ }
357
+ },
358
+ onSyncMessage: async ({ payload }) => {
359
+ if (!peerInfo) {
360
+ return;
361
+ }
362
+ const message = cbor2.decode(payload);
363
+ this.emit("message", message);
364
+ },
365
+ onClose: async () => {
366
+ if (!peerInfo) {
367
+ return;
368
+ }
369
+ this.emit("peer-disconnected", {
370
+ peerId: peerInfo.id
371
+ });
372
+ this._extensions.delete(peerInfo.id);
373
+ }
374
+ });
375
+ return extension;
376
+ }
377
+ };
378
+
379
+ // packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
380
+ function _ts_decorate(decorators, target, key, desc) {
381
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
382
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
383
+ r = Reflect.decorate(decorators, target, key, desc);
384
+ else
385
+ for (var i = decorators.length - 1; i >= 0; i--)
386
+ if (d = decorators[i])
387
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
388
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
389
+ }
390
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts";
391
+ var AutomergeHost = class {
392
+ constructor({ directory, metadata }) {
393
+ this._ctx = new Context();
394
+ /**
395
+ * spaceKey -> deviceKey[]
396
+ */
397
+ this._authorizedDevices = new ComplexMap(PublicKey.hash);
398
+ this._updatingMetadata = /* @__PURE__ */ new Map();
399
+ this._requestedDocs = /* @__PURE__ */ new Set();
400
+ this._metadata = metadata;
401
+ this._meshNetwork = new MeshNetworkAdapter();
402
+ this._clientNetwork = new LocalHostNetworkAdapter();
403
+ this._storage = new AutomergeStorageWrapper({
404
+ storage: (
405
+ // TODO(mykola): Delete specific handling of IDB storage.
406
+ directory.type === StorageType.IDB ? new IndexedDBStorageAdapter(directory.path, "data") : new AutomergeStorageAdapter(directory)
407
+ ),
408
+ callbacks: {
409
+ beforeSave: (params) => this._beforeSave(params)
410
+ }
411
+ });
412
+ this._peerId = `host-${PublicKey.random().toHex()}`;
413
+ this._repo = new Repo({
414
+ peerId: this._peerId,
415
+ network: [
416
+ this._clientNetwork,
417
+ this._meshNetwork
418
+ ],
419
+ storage: this._storage,
420
+ // TODO(dmaretskyi): Share based on HALO permissions and space affinity.
421
+ // Hosts, running in the worker, don't share documents unless requested by other peers.
422
+ sharePolicy: async (peerId, documentId) => {
423
+ if (peerId.startsWith("client-")) {
424
+ return false;
425
+ }
426
+ if (!documentId) {
427
+ return false;
428
+ }
429
+ const doc = this._repo.handles[documentId]?.docSync();
430
+ if (!doc) {
431
+ const isRequested = this._requestedDocs.has(`automerge:${documentId}`);
432
+ log3("doc share policy check", {
433
+ peerId,
434
+ documentId,
435
+ isRequested
436
+ }, {
437
+ F: __dxlog_file3,
438
+ L: 96,
439
+ S: this,
440
+ C: (f, a) => f(...a)
441
+ });
442
+ return isRequested;
443
+ }
444
+ try {
445
+ const spaceKey = getSpaceKeyFromDoc(doc);
446
+ if (!spaceKey) {
447
+ log3("space key not found for share policy check", {
448
+ peerId,
449
+ documentId
450
+ }, {
451
+ F: __dxlog_file3,
452
+ L: 103,
453
+ S: this,
454
+ C: (f, a) => f(...a)
455
+ });
456
+ return false;
457
+ }
458
+ const authorizedDevices = this._authorizedDevices.get(PublicKey.from(spaceKey));
459
+ const deviceKeyHex = this.repo.peerMetadataByPeerId[peerId]?.dxos_deviceKey;
460
+ if (!deviceKeyHex) {
461
+ log3("device key not found for share policy check", {
462
+ peerId,
463
+ documentId
464
+ }, {
465
+ F: __dxlog_file3,
466
+ L: 112,
467
+ S: this,
468
+ C: (f, a) => f(...a)
469
+ });
470
+ return false;
471
+ }
472
+ const deviceKey = PublicKey.from(deviceKeyHex);
473
+ const isAuthorized = authorizedDevices?.has(deviceKey) ?? false;
474
+ log3("share policy check", {
475
+ localPeer: this._peerId,
476
+ remotePeer: peerId,
477
+ documentId,
478
+ deviceKey,
479
+ spaceKey,
480
+ isAuthorized
481
+ }, {
482
+ F: __dxlog_file3,
483
+ L: 118,
484
+ S: this,
485
+ C: (f, a) => f(...a)
486
+ });
487
+ return isAuthorized;
488
+ } catch (err) {
489
+ log3.catch(err, void 0, {
490
+ F: __dxlog_file3,
491
+ L: 128,
492
+ S: this,
493
+ C: (f, a) => f(...a)
494
+ });
495
+ return false;
496
+ }
497
+ }
498
+ });
499
+ this._clientNetwork.ready();
500
+ this._meshNetwork.ready();
501
+ {
502
+ const listener = ({ handle }) => this._onDocument(handle);
503
+ this._repo.on("document", listener);
504
+ this._ctx.onDispose(() => {
505
+ this._repo.off("document", listener);
506
+ });
507
+ }
508
+ }
509
+ get repo() {
510
+ return this._repo;
511
+ }
512
+ async _beforeSave(path) {
513
+ const id = path[0];
514
+ if (this._updatingMetadata.has(id)) {
515
+ return this._updatingMetadata.get(id);
516
+ }
517
+ }
518
+ _onDocument(handle) {
519
+ const listener = (event) => this._onUpdate(event);
520
+ handle.on("change", listener);
521
+ this._ctx.onDispose(() => {
522
+ handle.off("change", listener);
523
+ });
524
+ }
525
+ _onUpdate(event) {
526
+ if (this._metadata == null) {
527
+ return;
528
+ }
529
+ const objectIds = getInlineChanges(event);
530
+ if (objectIds.length === 0) {
531
+ return;
532
+ }
533
+ const heads = getHeads(event.doc);
534
+ const lastAvailableHash = heads.at(-1);
535
+ if (!lastAvailableHash) {
536
+ return;
537
+ }
538
+ const encodedIds = objectIds.map((objectId) => idCodec.encode({
539
+ documentId: event.handle.documentId,
540
+ objectId
541
+ }));
542
+ const idToLastHash = new Map(encodedIds.map((id) => [
543
+ id,
544
+ lastAvailableHash
545
+ ]));
546
+ const markingDirtyPromise = this._metadata.markDirty(idToLastHash).then(() => {
547
+ this._updatingMetadata.delete(event.handle.documentId);
548
+ }).catch((err) => {
549
+ this._ctx.disposed && log3.catch(err, void 0, {
550
+ F: __dxlog_file3,
551
+ L: 188,
552
+ S: this,
553
+ C: (f, a) => f(...a)
554
+ });
555
+ });
556
+ this._updatingMetadata.set(event.handle.documentId, markingDirtyPromise);
557
+ }
558
+ _automergeDocs() {
559
+ return mapValues(this._repo.handles, (handle) => ({
560
+ state: handle.state,
561
+ hasDoc: !!handle.docSync(),
562
+ heads: handle.docSync() ? automerge.getHeads(handle.docSync()) : null,
563
+ data: handle.docSync()?.doc && mapValues(handle.docSync()?.doc, (value, key) => {
564
+ try {
565
+ switch (key) {
566
+ case "access":
567
+ case "links":
568
+ return value;
569
+ case "objects":
570
+ return Object.keys(value);
571
+ default:
572
+ return `${value}`;
573
+ }
574
+ } catch (err) {
575
+ return `${err}`;
576
+ }
577
+ })
578
+ }));
579
+ }
580
+ _automergePeers() {
581
+ return this._repo.peers;
582
+ }
583
+ async close() {
584
+ await this._storage.close();
585
+ await this._clientNetwork.close();
586
+ await this._ctx.dispose();
587
+ }
588
+ //
589
+ // Methods for client-services.
590
+ //
591
+ syncRepo(request) {
592
+ return this._clientNetwork.syncRepo(request);
593
+ }
594
+ sendSyncMessage(request) {
595
+ return this._clientNetwork.sendSyncMessage(request);
596
+ }
597
+ async getHostInfo() {
598
+ return this._clientNetwork.getHostInfo();
599
+ }
600
+ //
601
+ // Mesh replication.
602
+ //
603
+ createExtension() {
604
+ return this._meshNetwork.createExtension();
605
+ }
606
+ authorizeDevice(spaceKey, deviceKey) {
607
+ log3("authorizeDevice", {
608
+ spaceKey,
609
+ deviceKey
610
+ }, {
611
+ F: __dxlog_file3,
612
+ L: 255,
613
+ S: this,
614
+ C: (f, a) => f(...a)
615
+ });
616
+ defaultMap(this._authorizedDevices, spaceKey, () => new ComplexSet(PublicKey.hash)).add(deviceKey);
617
+ }
618
+ };
619
+ _ts_decorate([
620
+ trace.info()
621
+ ], AutomergeHost.prototype, "_peerId", void 0);
622
+ _ts_decorate([
623
+ trace.info({
624
+ depth: null
625
+ })
626
+ ], AutomergeHost.prototype, "_automergeDocs", null);
627
+ _ts_decorate([
628
+ trace.info({
629
+ depth: null
630
+ })
631
+ ], AutomergeHost.prototype, "_automergePeers", null);
632
+ AutomergeHost = _ts_decorate([
633
+ trace.resource()
634
+ ], AutomergeHost);
635
+ var getInlineChanges = (event) => {
636
+ const inlineChangedObjectIds = /* @__PURE__ */ new Set();
637
+ for (const { path } of event.patches) {
638
+ if (path.length < 2) {
639
+ continue;
640
+ }
641
+ switch (path[0]) {
642
+ case "objects":
643
+ if (path.length >= 2) {
644
+ inlineChangedObjectIds.add(path[1]);
645
+ }
646
+ break;
647
+ }
648
+ }
649
+ return [
650
+ ...inlineChangedObjectIds
651
+ ];
652
+ };
653
+ var getSpaceKeyFromDoc = (doc) => {
654
+ const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;
655
+ if (rawSpaceKey == null) {
656
+ return null;
657
+ }
658
+ return String(rawSpaceKey);
659
+ };
33
660
  export {
34
661
  AuthExtension,
35
662
  AuthStatus,