@dxos/echo-pipeline 0.5.8 → 0.5.9-main.2d0a5e6
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/dist/lib/browser/{chunk-GANAND63.mjs → chunk-I2J5TTHJ.mjs} +48 -23
- package/dist/lib/browser/{chunk-GANAND63.mjs.map → chunk-I2J5TTHJ.mjs.map} +3 -3
- package/dist/lib/browser/index.mjs +31 -26
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +99 -4
- package/dist/lib/browser/testing/index.mjs.map +4 -4
- package/dist/lib/node/{chunk-M475BGBI.cjs → chunk-QPCNQ4ZK.cjs} +51 -25
- package/dist/lib/node/chunk-QPCNQ4ZK.cjs.map +7 -0
- package/dist/lib/node/index.cjs +52 -47
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +107 -13
- package/dist/lib/node/testing/index.cjs.map +4 -4
- package/dist/types/src/automerge/automerge-doc-loader.d.ts +7 -3
- package/dist/types/src/automerge/automerge-doc-loader.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-host.d.ts.map +1 -1
- package/dist/types/src/automerge/migrations.d.ts.map +1 -1
- package/dist/types/src/space/space-manager.d.ts +2 -2
- package/dist/types/src/space/space-manager.d.ts.map +1 -1
- package/dist/types/src/space/space-protocol.d.ts +2 -2
- package/dist/types/src/space/space-protocol.d.ts.map +1 -1
- package/dist/types/src/space/space.d.ts +9 -1
- package/dist/types/src/space/space.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/test-agent-builder.d.ts +2 -2
- package/dist/types/src/testing/test-agent-builder.d.ts.map +1 -1
- package/dist/types/src/testing/test-network-adapter.d.ts +18 -0
- package/dist/types/src/testing/test-network-adapter.d.ts.map +1 -0
- package/package.json +33 -33
- package/src/automerge/automerge-doc-loader.test.ts +5 -2
- package/src/automerge/automerge-doc-loader.ts +6 -4
- package/src/automerge/automerge-host.test.ts +1 -553
- package/src/automerge/automerge-host.ts +12 -5
- package/src/automerge/automerge-repo.test.ts +450 -2
- package/src/automerge/migrations.ts +2 -1
- package/src/automerge/storage-adapter.test.ts +81 -15
- package/src/space/space-manager.ts +6 -4
- package/src/space/space-protocol.test.ts +3 -3
- package/src/space/space-protocol.ts +3 -3
- package/src/space/space.ts +32 -2
- package/src/testing/index.ts +1 -0
- package/src/testing/test-agent-builder.ts +4 -4
- package/src/testing/test-network-adapter.ts +62 -0
- package/dist/lib/node/chunk-M475BGBI.cjs.map +0 -7
|
@@ -16,13 +16,14 @@ import {
|
|
|
16
16
|
SpaceProtocolSession,
|
|
17
17
|
TimeframeClock,
|
|
18
18
|
codec,
|
|
19
|
+
createIdFromSpaceKey,
|
|
19
20
|
createMappedFeedWriter,
|
|
20
21
|
hasInvitationExpired,
|
|
21
22
|
mapFeedIndexesToTimeframe,
|
|
22
23
|
mapTimeframeToFeedIndexes,
|
|
23
24
|
startAfter,
|
|
24
25
|
valueEncoding
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-I2J5TTHJ.mjs";
|
|
26
27
|
|
|
27
28
|
// packages/core/echo/echo-pipeline/src/automerge/automerge-host.ts
|
|
28
29
|
import { Event } from "@dxos/async";
|
|
@@ -641,7 +642,7 @@ var levelMigration = async ({ db, directory }) => {
|
|
|
641
642
|
chunks: chunks.length
|
|
642
643
|
}, {
|
|
643
644
|
F: __dxlog_file3,
|
|
644
|
-
L:
|
|
645
|
+
L: 37,
|
|
645
646
|
S: void 0,
|
|
646
647
|
C: (f, a) => f(...a)
|
|
647
648
|
});
|
|
@@ -677,6 +678,7 @@ var AutomergeHost = class {
|
|
|
677
678
|
this._indexMetadataStore = indexMetadataStore;
|
|
678
679
|
}
|
|
679
680
|
async open() {
|
|
681
|
+
this._peerId = `host-${PublicKey.random().toHex()}`;
|
|
680
682
|
this._directory && await levelMigration({
|
|
681
683
|
db: this._db,
|
|
682
684
|
directory: this._directory
|
|
@@ -689,16 +691,17 @@ var AutomergeHost = class {
|
|
|
689
691
|
}
|
|
690
692
|
});
|
|
691
693
|
await this._storage.open?.();
|
|
692
|
-
this._peerId = `host-${PublicKey.random().toHex()}`;
|
|
693
694
|
this._clientNetwork = new LocalHostNetworkAdapter();
|
|
694
695
|
this._repo = new Repo({
|
|
695
696
|
peerId: this._peerId,
|
|
697
|
+
sharePolicy: this._sharePolicy.bind(this),
|
|
698
|
+
storage: this._storage,
|
|
696
699
|
network: [
|
|
700
|
+
// Downstream client.
|
|
697
701
|
this._clientNetwork,
|
|
702
|
+
// Upstream swarm.
|
|
698
703
|
this._echoNetworkAdapter
|
|
699
|
-
]
|
|
700
|
-
storage: this._storage,
|
|
701
|
-
sharePolicy: this._sharePolicy.bind(this)
|
|
704
|
+
]
|
|
702
705
|
});
|
|
703
706
|
this._clientNetwork.ready();
|
|
704
707
|
await this._echoNetworkAdapter.open();
|
|
@@ -740,7 +743,7 @@ var AutomergeHost = class {
|
|
|
740
743
|
isRequested
|
|
741
744
|
}, {
|
|
742
745
|
F: __dxlog_file4,
|
|
743
|
-
L:
|
|
746
|
+
L: 156,
|
|
744
747
|
S: this,
|
|
745
748
|
C: (f, a) => f(...a)
|
|
746
749
|
});
|
|
@@ -826,7 +829,7 @@ var AutomergeHost = class {
|
|
|
826
829
|
await Promise.all(states?.map(async ({ heads, documentId }) => {
|
|
827
830
|
invariant3(heads, "heads are required for flush", {
|
|
828
831
|
F: __dxlog_file4,
|
|
829
|
-
L:
|
|
832
|
+
L: 250,
|
|
830
833
|
S: this,
|
|
831
834
|
A: [
|
|
832
835
|
"heads",
|
|
@@ -914,9 +917,10 @@ function _ts_decorate3(decorators, target, key, desc) {
|
|
|
914
917
|
}
|
|
915
918
|
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/core/echo/echo-pipeline/src/automerge/automerge-doc-loader.ts";
|
|
916
919
|
var AutomergeDocumentLoaderImpl = class {
|
|
917
|
-
constructor(
|
|
918
|
-
this.
|
|
920
|
+
constructor(_spaceId, _repo, _spaceKey) {
|
|
921
|
+
this._spaceId = _spaceId;
|
|
919
922
|
this._repo = _repo;
|
|
923
|
+
this._spaceKey = _spaceKey;
|
|
920
924
|
this._spaceRootDocHandle = null;
|
|
921
925
|
this._objectDocumentHandles = /* @__PURE__ */ new Map();
|
|
922
926
|
this._objectsPendingDocumentLoad = /* @__PURE__ */ new Set();
|
|
@@ -934,10 +938,10 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
934
938
|
}
|
|
935
939
|
if (!spaceState.rootUrl) {
|
|
936
940
|
log4.error("Database opened with no rootUrl", {
|
|
937
|
-
|
|
941
|
+
spaceId: this._spaceId
|
|
938
942
|
}, {
|
|
939
943
|
F: __dxlog_file5,
|
|
940
|
-
L:
|
|
944
|
+
L: 72,
|
|
941
945
|
S: this,
|
|
942
946
|
C: (f, a) => f(...a)
|
|
943
947
|
});
|
|
@@ -947,7 +951,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
947
951
|
const doc = existingDocHandle.docSync();
|
|
948
952
|
invariant4(doc, void 0, {
|
|
949
953
|
F: __dxlog_file5,
|
|
950
|
-
L:
|
|
954
|
+
L: 77,
|
|
951
955
|
S: this,
|
|
952
956
|
A: [
|
|
953
957
|
"doc",
|
|
@@ -969,7 +973,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
969
973
|
for (const objectId of objectIds) {
|
|
970
974
|
invariant4(this._spaceRootDocHandle, void 0, {
|
|
971
975
|
F: __dxlog_file5,
|
|
972
|
-
L:
|
|
976
|
+
L: 90,
|
|
973
977
|
S: this,
|
|
974
978
|
A: [
|
|
975
979
|
"this._spaceRootDocHandle",
|
|
@@ -982,7 +986,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
982
986
|
const spaceRootDoc = this._spaceRootDocHandle.docSync();
|
|
983
987
|
invariant4(spaceRootDoc, void 0, {
|
|
984
988
|
F: __dxlog_file5,
|
|
985
|
-
L:
|
|
989
|
+
L: 95,
|
|
986
990
|
S: this,
|
|
987
991
|
A: [
|
|
988
992
|
"spaceRootDoc",
|
|
@@ -996,7 +1000,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
996
1000
|
objectId
|
|
997
1001
|
}, {
|
|
998
1002
|
F: __dxlog_file5,
|
|
999
|
-
L:
|
|
1003
|
+
L: 99,
|
|
1000
1004
|
S: this,
|
|
1001
1005
|
C: (f, a) => f(...a)
|
|
1002
1006
|
});
|
|
@@ -1020,7 +1024,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1020
1024
|
getSpaceRootDocHandle() {
|
|
1021
1025
|
invariant4(this._spaceRootDocHandle, void 0, {
|
|
1022
1026
|
F: __dxlog_file5,
|
|
1023
|
-
L:
|
|
1027
|
+
L: 122,
|
|
1024
1028
|
S: this,
|
|
1025
1029
|
A: [
|
|
1026
1030
|
"this._spaceRootDocHandle",
|
|
@@ -1032,7 +1036,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1032
1036
|
createDocumentForObject(objectId) {
|
|
1033
1037
|
invariant4(this._spaceRootDocHandle, void 0, {
|
|
1034
1038
|
F: __dxlog_file5,
|
|
1035
|
-
L:
|
|
1039
|
+
L: 127,
|
|
1036
1040
|
S: this,
|
|
1037
1041
|
A: [
|
|
1038
1042
|
"this._spaceRootDocHandle",
|
|
@@ -1075,7 +1079,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1075
1079
|
actualDocumentUrl: objectDocumentHandle.url
|
|
1076
1080
|
}, {
|
|
1077
1081
|
F: __dxlog_file5,
|
|
1078
|
-
L:
|
|
1082
|
+
L: 157,
|
|
1079
1083
|
S: this,
|
|
1080
1084
|
C: (f, a) => f(...a)
|
|
1081
1085
|
});
|
|
@@ -1084,7 +1088,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1084
1088
|
if (objectDocumentHandle?.url === automergeUrl) {
|
|
1085
1089
|
log4.warn("object document was already loaded", logMeta, {
|
|
1086
1090
|
F: __dxlog_file5,
|
|
1087
|
-
L:
|
|
1091
|
+
L: 164,
|
|
1088
1092
|
S: this,
|
|
1089
1093
|
C: (f, a) => f(...a)
|
|
1090
1094
|
});
|
|
@@ -1093,7 +1097,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1093
1097
|
const handle = this._repo.find(automergeUrl);
|
|
1094
1098
|
log4.debug("document loading triggered", logMeta, {
|
|
1095
1099
|
F: __dxlog_file5,
|
|
1096
|
-
L:
|
|
1100
|
+
L: 168,
|
|
1097
1101
|
S: this,
|
|
1098
1102
|
C: (f, a) => f(...a)
|
|
1099
1103
|
});
|
|
@@ -1105,7 +1109,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1105
1109
|
const docHandle = this._repo.find(url);
|
|
1106
1110
|
while (true) {
|
|
1107
1111
|
try {
|
|
1108
|
-
await warnAfterTimeout(5e3, "Automerge root doc load timeout (
|
|
1112
|
+
await warnAfterTimeout(5e3, "Automerge root doc load timeout (CoreDatabase)", async () => {
|
|
1109
1113
|
await cancelWithContext(ctx, docHandle.whenReady());
|
|
1110
1114
|
});
|
|
1111
1115
|
break;
|
|
@@ -1116,7 +1120,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1116
1120
|
state: docHandle.state
|
|
1117
1121
|
}, {
|
|
1118
1122
|
F: __dxlog_file5,
|
|
1119
|
-
L:
|
|
1123
|
+
L: 184,
|
|
1120
1124
|
S: this,
|
|
1121
1125
|
C: (f, a) => f(...a)
|
|
1122
1126
|
});
|
|
@@ -1158,7 +1162,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1158
1162
|
if (this.onObjectDocumentLoaded.listenerCount() === 0) {
|
|
1159
1163
|
log4.info("document loaded after all listeners were removed", logMeta, {
|
|
1160
1164
|
F: __dxlog_file5,
|
|
1161
|
-
L:
|
|
1165
|
+
L: 220,
|
|
1162
1166
|
S: this,
|
|
1163
1167
|
C: (f, a) => f(...a)
|
|
1164
1168
|
});
|
|
@@ -1168,7 +1172,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1168
1172
|
if (objectDocHandle?.url !== handle.url) {
|
|
1169
1173
|
log4.warn("object was rebound while a document was loading, discarding handle", logMeta, {
|
|
1170
1174
|
F: __dxlog_file5,
|
|
1171
|
-
L:
|
|
1175
|
+
L: 225,
|
|
1172
1176
|
S: this,
|
|
1173
1177
|
C: (f, a) => f(...a)
|
|
1174
1178
|
});
|
|
@@ -1187,7 +1191,7 @@ var AutomergeDocumentLoaderImpl = class {
|
|
|
1187
1191
|
err
|
|
1188
1192
|
}, {
|
|
1189
1193
|
F: __dxlog_file5,
|
|
1190
|
-
L:
|
|
1194
|
+
L: 231,
|
|
1191
1195
|
S: this,
|
|
1192
1196
|
C: (f, a) => f(...a)
|
|
1193
1197
|
});
|
|
@@ -1493,6 +1497,7 @@ export {
|
|
|
1493
1497
|
SpaceProtocolSession,
|
|
1494
1498
|
TimeframeClock,
|
|
1495
1499
|
codec,
|
|
1500
|
+
createIdFromSpaceKey,
|
|
1496
1501
|
createMappedFeedWriter,
|
|
1497
1502
|
encodingOptions,
|
|
1498
1503
|
getSpaceKeyFromDoc,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/automerge/automerge-host.ts", "../../../src/automerge/echo-network-adapter.ts", "../../../src/automerge/leveldb-storage-adapter.ts", "../../../src/automerge/local-host-network-adapter.ts", "../../../src/automerge/migrations.ts", "../../../src/automerge/automerge-storage-adapter.ts", "../../../src/automerge/automerge-doc-loader.ts", "../../../src/automerge/mesh-echo-replicator.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Event } from '@dxos/async';\nimport { next as automerge, getBackend, getHeads, type Doc, type Heads } from '@dxos/automerge/automerge';\nimport {\n Repo,\n type DocHandle,\n type DocHandleChangePayload,\n type DocumentId,\n type PeerId,\n type StorageAdapterInterface,\n} from '@dxos/automerge/automerge-repo';\nimport { type Stream } from '@dxos/codec-protobuf';\nimport { Context, type Lifecycle } from '@dxos/context';\nimport { type SpaceDoc } from '@dxos/echo-protocol';\nimport { type IndexMetadataStore } from '@dxos/indexing';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { type SublevelDB } from '@dxos/kv-store';\nimport { log } from '@dxos/log';\nimport { objectPointerCodec } from '@dxos/protocols';\nimport {\n type FlushRequest,\n type HostInfo,\n type SyncRepoRequest,\n type SyncRepoResponse,\n} from '@dxos/protocols/proto/dxos/echo/service';\nimport { type Directory } from '@dxos/random-access-storage';\nimport { trace } from '@dxos/tracing';\nimport { mapValues } from '@dxos/util';\n\nimport { EchoNetworkAdapter } from './echo-network-adapter';\nimport { type EchoReplicator } from './echo-replicator';\nimport { LevelDBStorageAdapter, type BeforeSaveParams } from './leveldb-storage-adapter';\nimport { LocalHostNetworkAdapter } from './local-host-network-adapter';\nimport { levelMigration } from './migrations';\n\n// TODO: Remove\nexport type { DocumentId };\n\nexport type AutomergeHostParams = {\n db: SublevelDB;\n /**\n * For migration purposes.\n */\n directory?: Directory;\n\n indexMetadataStore: IndexMetadataStore;\n};\n\n@trace.resource()\nexport class AutomergeHost {\n private readonly _indexMetadataStore: IndexMetadataStore;\n private readonly _ctx = new Context();\n private readonly _directory?: Directory;\n private readonly _db: SublevelDB;\n private readonly _echoNetworkAdapter = new EchoNetworkAdapter({\n getContainingSpaceForDocument: this._getContainingSpaceForDocument.bind(this),\n });\n\n private _repo!: Repo;\n private _clientNetwork!: LocalHostNetworkAdapter;\n private _storage!: StorageAdapterInterface & Lifecycle;\n\n @trace.info()\n private _peerId!: string;\n\n public _requestedDocs = new Set<string>();\n\n constructor({ directory, db, indexMetadataStore }: AutomergeHostParams) {\n this._directory = directory;\n this._db = db;\n this._indexMetadataStore = indexMetadataStore;\n }\n\n async open() {\n // TODO(mykola): remove this before 0.6 release.\n this._directory && (await levelMigration({ db: this._db, directory: this._directory }));\n this._storage = new LevelDBStorageAdapter({\n db: this._db,\n callbacks: {\n beforeSave: async (params) => this._beforeSave(params),\n afterSave: async () => this._afterSave(),\n },\n });\n await this._storage.open?.();\n this._peerId = `host-${PublicKey.random().toHex()}` as PeerId;\n\n this._clientNetwork = new LocalHostNetworkAdapter();\n\n this._repo = new Repo({\n peerId: this._peerId as PeerId,\n network: [this._clientNetwork, this._echoNetworkAdapter],\n storage: this._storage,\n\n sharePolicy: this._sharePolicy.bind(this),\n });\n this._clientNetwork.ready();\n await this._echoNetworkAdapter.open();\n\n await this._clientNetwork.whenConnected();\n await this._echoNetworkAdapter.whenConnected();\n }\n\n async close() {\n await this._storage.close?.();\n await this._clientNetwork.close();\n await this._echoNetworkAdapter.close();\n await this._ctx.dispose();\n }\n\n get repo(): Repo {\n return this._repo;\n }\n\n async addReplicator(replicator: EchoReplicator) {\n await this._echoNetworkAdapter.addReplicator(replicator);\n }\n\n async removeReplicator(replicator: EchoReplicator) {\n await this._echoNetworkAdapter.removeReplicator(replicator);\n }\n\n // TODO(dmaretskyi): Share based on HALO permissions and space affinity.\n // Hosts, running in the worker, don't share documents unless requested by other peers.\n // NOTE: If both peers return sharePolicy=false the replication will not happen\n // https://github.com/automerge/automerge-repo/pull/292\n private async _sharePolicy(\n peerId: PeerId /* device key */,\n documentId?: DocumentId /* space key */,\n ): Promise<boolean> {\n if (peerId.startsWith('client-')) {\n return false; // Only send docs to clients if they are requested.\n }\n\n if (!documentId) {\n return false;\n }\n\n // Workaround for https://github.com/automerge/automerge-repo/pull/292\n // NOTE: This must override the per-connection policy.\n const doc = this._repo.handles[documentId]?.docSync();\n if (!doc) {\n // TODO(dmaretskyi): Verify that this works as intended.\n // TODO(dmaretskyi): Move to MESH replicator?\n const isRequested = this._requestedDocs.has(`automerge:${documentId}`);\n log('doc share policy check', { peerId, documentId, isRequested });\n return isRequested;\n }\n\n const peerMetadata = this.repo.peerMetadataByPeerId[peerId];\n if ((peerMetadata as any)?.dxos_peerSource === 'EchoNetworkAdapter') {\n return this._echoNetworkAdapter.shouldAdvertize(peerId, { documentId });\n }\n\n return false;\n }\n\n private async _beforeSave({ path, batch }: BeforeSaveParams) {\n const handle = this._repo.handles[path[0] as DocumentId];\n if (!handle) {\n return;\n }\n const doc = handle.docSync();\n if (!doc) {\n return;\n }\n\n const spaceKey = getSpaceKeyFromDoc(doc) ?? undefined;\n\n const lastAvailableHash = getHeads(doc);\n\n const objectIds = Object.keys(doc.objects ?? {});\n const encodedIds = objectIds.map((objectId) =>\n objectPointerCodec.encode({ documentId: handle.documentId, objectId, spaceKey }),\n );\n const idToLastHash = new Map(encodedIds.map((id) => [id, lastAvailableHash]));\n this._indexMetadataStore.markDirty(idToLastHash, batch);\n }\n\n /**\n * Called by AutomergeStorageAdapter after levelDB batch commit.\n */\n private async _afterSave() {\n this._indexMetadataStore.notifyMarkedDirty();\n }\n\n @trace.info({ depth: null })\n private _automergeDocs() {\n return mapValues(this._repo.handles, (handle) => ({\n state: handle.state,\n hasDoc: !!handle.docSync(),\n heads: handle.docSync() ? automerge.getHeads(handle.docSync()) : null,\n data:\n handle.docSync() &&\n mapValues(handle.docSync(), (value, key) => {\n try {\n switch (key) {\n case 'access':\n case 'links':\n return value;\n case 'objects':\n return Object.keys(value as any);\n default:\n return `${value}`;\n }\n } catch (err) {\n return `${err}`;\n }\n }),\n }));\n }\n\n @trace.info({ depth: null })\n private _automergePeers() {\n return this._repo.peers;\n }\n\n private async _getContainingSpaceForDocument(documentId: string): Promise<PublicKey | null> {\n const doc = this._repo.handles[documentId as any]?.docSync();\n if (!doc) {\n return null;\n }\n\n const spaceKeyHex = getSpaceKeyFromDoc(doc);\n if (!spaceKeyHex) {\n return null;\n }\n\n return PublicKey.from(spaceKeyHex);\n }\n\n //\n // Methods for client-services.\n //\n @trace.span({ showInBrowserTimeline: true })\n async flush({ states }: FlushRequest): Promise<void> {\n // Note: Wait for all requested documents to be loaded/synced from thin-client.\n await Promise.all(\n states?.map(async ({ heads, documentId }) => {\n invariant(heads, 'heads are required for flush');\n const handle = this.repo.handles[documentId as DocumentId] ?? this._repo.find(documentId as DocumentId);\n await waitForHeads(handle, heads);\n }) ?? [],\n );\n\n await this._repo.flush(states?.map(({ documentId }) => documentId as DocumentId));\n }\n\n syncRepo(request: SyncRepoRequest): Stream<SyncRepoResponse> {\n return this._clientNetwork.syncRepo(request);\n }\n\n sendSyncMessage(request: SyncRepoRequest): Promise<void> {\n return this._clientNetwork.sendSyncMessage(request);\n }\n\n async getHostInfo(): Promise<HostInfo> {\n return this._clientNetwork.getHostInfo();\n }\n}\n\nexport const getSpaceKeyFromDoc = (doc: any): string | null => {\n // experimental_spaceKey is set on old documents, new ones are created with doc.access.spaceKey\n const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;\n if (rawSpaceKey == null) {\n return null;\n }\n\n return String(rawSpaceKey);\n};\n\nconst waitForHeads = async (handle: DocHandle<SpaceDoc>, heads: Heads) => {\n await handle.whenReady();\n const unavailableHeads = new Set(heads);\n\n await Event.wrap<DocHandleChangePayload<SpaceDoc>>(handle, 'change').waitForCondition(() => {\n // Check if unavailable heads became available.\n for (const changeHash of unavailableHeads.values()) {\n if (changeIsPresentInDoc(handle.docSync(), changeHash)) {\n unavailableHeads.delete(changeHash);\n }\n }\n\n if (unavailableHeads.size === 0) {\n return true;\n }\n return false;\n });\n};\n\nconst changeIsPresentInDoc = (doc: Doc<any>, changeHash: string): boolean => {\n return !!getBackend(doc).getChangeByHash(changeHash);\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { Trigger, synchronized } from '@dxos/async';\nimport { type Message, NetworkAdapter, type PeerId, type PeerMetadata } from '@dxos/automerge/automerge-repo';\nimport { LifecycleState } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\n\nimport { type EchoReplicator, type ReplicatorConnection, type ShouldAdvertizeParams } from './echo-replicator';\n\nexport type EchoNetworkAdapterParams = {\n getContainingSpaceForDocument: (documentId: string) => Promise<PublicKey | null>;\n};\n\n/**\n * Manages a set of {@link EchoReplicator} instances.\n */\nexport class EchoNetworkAdapter extends NetworkAdapter {\n private readonly _replicators = new Set<EchoReplicator>();\n /**\n * Remote peer id -> connection.\n */\n private readonly _connections = new Map<PeerId, ConnectionEntry>();\n private _lifecycleState: LifecycleState = LifecycleState.CLOSED;\n private readonly _connected = new Trigger();\n\n constructor(private readonly _params: EchoNetworkAdapterParams) {\n super();\n }\n\n override connect(peerId: PeerId, peerMetadata?: PeerMetadata | undefined): void {\n this.peerId = peerId;\n this.peerMetadata = peerMetadata;\n this._connected.wake();\n }\n\n override send(message: Message): void {\n const connectionEntry = this._connections.get(message.targetId);\n if (!connectionEntry) {\n throw new Error('Connection not found.');\n }\n\n // TODO(dmaretskyi): Find a way to enforce backpressure on AM-repo.\n connectionEntry.writer.write(message).catch((err) => {\n if (connectionEntry.isOpen) {\n log.catch(err);\n }\n });\n }\n\n override disconnect(): void {\n // No-op\n }\n\n @synchronized\n async open() {\n invariant(this._lifecycleState === LifecycleState.CLOSED);\n this._lifecycleState = LifecycleState.OPEN;\n\n log('emit ready');\n this.emit('ready', {\n network: this,\n });\n }\n\n @synchronized\n async close() {\n invariant(this._lifecycleState === LifecycleState.OPEN);\n\n for (const replicator of this._replicators) {\n await replicator.disconnect();\n }\n this._replicators.clear();\n\n this._lifecycleState = LifecycleState.CLOSED;\n }\n\n async whenConnected() {\n await this._connected.wait({ timeout: 10_000 });\n }\n\n @synchronized\n async addReplicator(replicator: EchoReplicator) {\n invariant(this._lifecycleState === LifecycleState.OPEN);\n invariant(this.peerId);\n invariant(!this._replicators.has(replicator));\n\n this._replicators.add(replicator);\n await replicator.connect({\n peerId: this.peerId,\n onConnectionOpen: this._onConnectionOpen.bind(this),\n onConnectionClosed: this._onConnectionClosed.bind(this),\n getContainingSpaceForDocument: this._params.getContainingSpaceForDocument,\n });\n }\n\n @synchronized\n async removeReplicator(replicator: EchoReplicator) {\n invariant(this._lifecycleState === LifecycleState.OPEN);\n invariant(this._replicators.has(replicator));\n ('');\n await replicator.disconnect();\n this._replicators.delete(replicator);\n }\n\n async shouldAdvertize(peerId: PeerId, params: ShouldAdvertizeParams): Promise<boolean> {\n const connection = this._connections.get(peerId);\n if (!connection) {\n return false;\n }\n\n return connection.connection.shouldAdvertize(params);\n }\n\n private _onConnectionOpen(connection: ReplicatorConnection) {\n log('Connection opened', { peerId: connection.peerId });\n invariant(!this._connections.has(connection.peerId as PeerId));\n const reader = connection.readable.getReader();\n const writer = connection.writable.getWriter();\n const connectionEntry: ConnectionEntry = { connection, reader, writer, isOpen: true };\n this._connections.set(connection.peerId as PeerId, connectionEntry);\n\n queueMicrotask(async () => {\n try {\n while (true) {\n // TODO(dmaretskyi): Find a way to enforce backpressure on AM-repo.\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n this.emit('message', value);\n }\n } catch (err) {\n if (connectionEntry.isOpen) {\n log.catch(err);\n }\n }\n });\n\n log('emit peer-candidate', { peerId: connection.peerId });\n this.emit('peer-candidate', {\n peerId: connection.peerId as PeerId,\n peerMetadata: {\n // TODO(dmaretskyi): Refactor this.\n dxos_peerSource: 'EchoNetworkAdapter',\n } as any,\n });\n }\n\n private _onConnectionClosed(connection: ReplicatorConnection) {\n log('Connection closed', { peerId: connection.peerId });\n const entry = this._connections.get(connection.peerId as PeerId);\n invariant(entry);\n\n entry.isOpen = false;\n this.emit('peer-disconnected', { peerId: connection.peerId as PeerId });\n\n void entry.reader.cancel().catch((err) => log.catch(err));\n void entry.writer.abort().catch((err) => log.catch(err));\n\n this._connections.delete(connection.peerId as PeerId);\n }\n}\n\ntype ConnectionEntry = {\n connection: ReplicatorConnection;\n reader: ReadableStreamDefaultReader<Message>;\n writer: WritableStreamDefaultWriter<Message>;\n isOpen: boolean;\n};\n", "//\n// Copyright 2024 DXOS.org\n// s\n\nimport { type MixedEncoding } from 'level-transcoder';\n\nimport { type StorageAdapterInterface, type Chunk, type StorageKey } from '@dxos/automerge/automerge-repo';\nimport { LifecycleState, Resource } from '@dxos/context';\nimport { type BatchLevel, type SublevelDB } from '@dxos/kv-store';\nimport { type MaybePromise } from '@dxos/util';\n\nexport type LevelDBStorageAdapterParams = {\n db: SublevelDB;\n callbacks?: StorageCallbacks;\n};\n\nexport type BeforeSaveParams = { path: StorageKey; batch: BatchLevel };\n\nexport interface StorageCallbacks {\n beforeSave(params: BeforeSaveParams): MaybePromise<void>;\n afterSave(path: StorageKey): MaybePromise<void>;\n}\n\nexport class LevelDBStorageAdapter extends Resource implements StorageAdapterInterface {\n constructor(private readonly _params: LevelDBStorageAdapterParams) {\n super();\n }\n\n async load(keyArray: StorageKey): Promise<Uint8Array | undefined> {\n try {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n // TODO(mykola): this should be an error.\n return undefined;\n }\n return await this._params.db.get<StorageKey, Uint8Array>(keyArray, { ...encodingOptions });\n } catch (err: any) {\n if (isLevelDbNotFoundError(err)) {\n return undefined;\n }\n throw err;\n }\n }\n\n async save(keyArray: StorageKey, binary: Uint8Array): Promise<void> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return undefined;\n }\n const batch = this._params.db.batch();\n\n await this._params.callbacks?.beforeSave?.({ path: keyArray, batch });\n batch.put<StorageKey, Uint8Array>(keyArray, Buffer.from(binary), {\n ...encodingOptions,\n });\n await batch.write();\n\n await this._params.callbacks?.afterSave?.(keyArray);\n }\n\n async remove(keyArray: StorageKey): Promise<void> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return undefined;\n }\n await this._params.db.del<StorageKey>(keyArray, { ...encodingOptions });\n }\n\n async loadRange(keyPrefix: StorageKey): Promise<Chunk[]> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return [];\n }\n const result: Chunk[] = [];\n for await (const [key, value] of this._params.db.iterator<StorageKey, Uint8Array>({\n gte: keyPrefix,\n lte: [...keyPrefix, '\\uffff'],\n ...encodingOptions,\n })) {\n result.push({\n key,\n data: value,\n });\n }\n return result;\n }\n\n async removeRange(keyPrefix: StorageKey): Promise<void> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return undefined;\n }\n const batch = this._params.db.batch();\n\n for await (const [key] of this._params.db.iterator<StorageKey, Uint8Array>({\n gte: keyPrefix,\n lte: [...keyPrefix, '\\uffff'],\n ...encodingOptions,\n })) {\n batch.del<StorageKey>(key, { ...encodingOptions });\n }\n await batch.write();\n }\n}\n\nconst keyEncoder: MixedEncoding<StorageKey, Uint8Array, StorageKey> = {\n encode: (key: StorageKey): Uint8Array =>\n Buffer.from(key.map((k) => k.replaceAll('%', '%25').replaceAll('-', '%2D')).join('-')),\n decode: (key: Uint8Array): StorageKey =>\n Buffer.from(key)\n .toString()\n .split('-')\n .map((k) => k.replaceAll('%2D', '-').replaceAll('%25', '%')),\n format: 'buffer',\n};\n\nexport const encodingOptions = {\n keyEncoding: keyEncoder,\n valueEncoding: 'buffer',\n};\n\nconst isLevelDbNotFoundError = (err: any): boolean => err.code === 'LEVEL_NOT_FOUND';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { Trigger } from '@dxos/async';\nimport { NetworkAdapter, type Message, type PeerId, cbor } from '@dxos/automerge/automerge-repo';\nimport { Stream } from '@dxos/codec-protobuf';\nimport { invariant } from '@dxos/invariant';\nimport { type HostInfo, type SyncRepoRequest, type SyncRepoResponse } from '@dxos/protocols/proto/dxos/echo/service';\n\ntype ClientSyncState = {\n connected: boolean;\n send: (message: Message) => void;\n disconnect: () => void;\n};\n\n/**\n * Used to replicate with apps running on the same device.\n */\nexport class LocalHostNetworkAdapter extends NetworkAdapter {\n private readonly _peers: Map<PeerId, ClientSyncState> = new Map();\n\n /**\n * Emits `ready` event. That signals to `Repo` that it can start using the adapter.\n */\n ready() {\n // NOTE: Emitting `ready` event in NetworkAdapter`s constructor causes a race condition\n // because `Repo` waits for `ready` event (which it never receives) before it starts using the adapter.\n this.emit('ready', {\n network: this,\n });\n }\n\n private readonly _connected = new Trigger();\n private _isConnected: boolean = false;\n\n /**\n * Called by `Repo` to connect to the network.\n *\n * @param peerId Our peer Id.\n */\n override connect(peerId: PeerId): void {\n this.peerId = peerId;\n this._isConnected = true;\n this._connected.wake();\n // No-op. Client always connects first\n }\n\n override send(message: Message): void {\n const peer = this._peers.get(message.targetId);\n invariant(peer, 'Peer not found.');\n peer.send(message);\n }\n\n async close() {\n this._peers.forEach((peer) => peer.disconnect());\n this.emit('close');\n }\n\n override disconnect(): void {\n // TODO(mykola): `disconnect` is not used anywhere in `Repo` from `@automerge/automerge-repo`. Should we remove it?\n // No-op\n }\n\n async whenConnected(): Promise<void> {\n await this._connected.wait({ timeout: 10_000 });\n }\n\n syncRepo({ id, syncMessage }: SyncRepoRequest): Stream<SyncRepoResponse> {\n const peerId = this._getPeerId(id);\n\n return new Stream(({ next, close }) => {\n invariant(!this._peers.has(peerId), 'Peer already connected.');\n this._peers.set(peerId, {\n connected: true,\n send: (message) => {\n next({\n syncMessage: cbor.encode(message),\n });\n },\n disconnect: () => {\n this._peers.delete(peerId);\n close();\n this.emit('peer-disconnected', {\n peerId,\n });\n },\n });\n\n invariant(this._isConnected);\n this.emit('peer-candidate', {\n peerMetadata: {},\n peerId,\n });\n });\n }\n\n async sendSyncMessage({ id, syncMessage }: SyncRepoRequest): Promise<void> {\n invariant(this._isConnected);\n const message = cbor.decode(syncMessage!) as Message;\n this.emit('message', message);\n }\n\n async getHostInfo(): Promise<HostInfo> {\n invariant(this._isConnected);\n invariant(this.peerId, 'Peer id not set.');\n return {\n peerId: this.peerId,\n };\n }\n\n private _getPeerId(id: string): PeerId {\n return id as PeerId;\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type StorageKey } from '@dxos/automerge/automerge-repo';\nimport { IndexedDBStorageAdapter } from '@dxos/automerge/automerge-repo-storage-indexeddb';\nimport { type SublevelDB } from '@dxos/kv-store';\nimport { log } from '@dxos/log';\nimport { StorageType, type Directory } from '@dxos/random-access-storage';\n\nimport { AutomergeStorageAdapter } from './automerge-storage-adapter';\nimport { encodingOptions } from './leveldb-storage-adapter';\n\nexport const levelMigration = async ({ db, directory }: { db: SublevelDB; directory: Directory }) => {\n // Note: Make automigration from previous storage to leveldb here.\n const isNewLevel = !(await db\n .iterator<StorageKey, Uint8Array>({\n ...encodingOptions,\n })\n .next());\n\n if (!isNewLevel) {\n return;\n }\n\n const oldStorageAdapter =\n directory.type === StorageType.IDB\n ? new IndexedDBStorageAdapter(directory.path, 'data')\n : new AutomergeStorageAdapter(directory);\n\n const chunks = await oldStorageAdapter.loadRange([]);\n if (chunks.length === 0) {\n return;\n }\n const batch = db.batch();\n log.info('found chunks on old storage adapter', { chunks: chunks.length });\n for (const { key, data } of await oldStorageAdapter.loadRange([])) {\n data && batch.put<StorageKey, Uint8Array>(key, data, { ...encodingOptions });\n }\n await batch.write();\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Chunk, type StorageKey, type StorageAdapterInterface } from '@dxos/automerge/automerge-repo';\nimport { type Directory } from '@dxos/random-access-storage';\nimport { arrayToBuffer, bufferToArray } from '@dxos/util';\n\nexport class AutomergeStorageAdapter implements StorageAdapterInterface {\n // TODO(mykola): Hack for restricting automerge Repo to access storage if Host is `closed`.\n // Automerge Repo do not have any lifetime management.\n private _state: 'opened' | 'closed' = 'opened';\n\n constructor(private readonly _directory: Directory) {}\n\n async load(key: StorageKey): Promise<Uint8Array | undefined> {\n if (this._state !== 'opened') {\n return undefined;\n }\n const filename = this._getFilename(key);\n const file = this._directory.getOrCreateFile(filename);\n const { size } = await file.stat();\n if (!size || size === 0) {\n return undefined;\n }\n const buffer = await file.read(0, size);\n return bufferToArray(buffer);\n }\n\n async save(key: StorageKey, data: Uint8Array): Promise<void> {\n if (this._state !== 'opened') {\n return undefined;\n }\n const filename = this._getFilename(key);\n const file = this._directory.getOrCreateFile(filename);\n await file.write(0, arrayToBuffer(data));\n await file.truncate?.(data.length);\n\n await file.flush?.();\n }\n\n async remove(key: StorageKey): Promise<void> {\n if (this._state !== 'opened') {\n return undefined;\n }\n // TODO(dmaretskyi): Better deletion.\n const filename = this._getFilename(key);\n const file = this._directory.getOrCreateFile(filename);\n await file.destroy();\n }\n\n async loadRange(keyPrefix: StorageKey): Promise<Chunk[]> {\n if (this._state !== 'opened') {\n return [];\n }\n const filename = this._getFilename(keyPrefix);\n const entries = await this._directory.list();\n return Promise.all(\n entries\n .filter((entry) => entry.startsWith(filename))\n .map(async (entry): Promise<Chunk> => {\n const file = this._directory.getOrCreateFile(entry);\n const { size } = await file.stat();\n const buffer = await file.read(0, size);\n return {\n key: this._getKeyFromFilename(entry),\n data: bufferToArray(buffer),\n };\n }),\n );\n }\n\n async removeRange(keyPrefix: StorageKey): Promise<void> {\n if (this._state !== 'opened') {\n return undefined;\n }\n const filename = this._getFilename(keyPrefix);\n const entries = await this._directory.list();\n await Promise.all(\n entries\n .filter((entry) => entry.startsWith(filename))\n .map(async (entry): Promise<void> => {\n const file = this._directory.getOrCreateFile(entry);\n await file.destroy();\n }),\n );\n }\n\n async close(): Promise<void> {\n this._state = 'closed';\n }\n\n private _getFilename(key: StorageKey): string {\n return key.map((k) => k.replaceAll('%', '%25').replaceAll('-', '%2D')).join('-');\n }\n\n private _getKeyFromFilename(filename: string): StorageKey {\n return filename.split('-').map((k) => k.replaceAll('%2D', '-').replaceAll('%25', '%'));\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { Event } from '@dxos/async';\nimport { type DocHandle, type AutomergeUrl, type DocumentId, type Repo } from '@dxos/automerge/automerge-repo';\nimport { cancelWithContext, type Context } from '@dxos/context';\nimport { warnAfterTimeout } from '@dxos/debug';\nimport { type SpaceState, type SpaceDoc } from '@dxos/echo-protocol';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { trace } from '@dxos/tracing';\n\ntype SpaceDocumentLinks = SpaceDoc['links'];\n\nexport interface AutomergeDocumentLoader {\n onObjectDocumentLoaded: Event<ObjectDocumentLoaded>;\n\n getAllHandles(): DocHandle<SpaceDoc>[];\n\n loadSpaceRootDocHandle(ctx: Context, spaceState: SpaceState): Promise<void>;\n loadObjectDocument(objectId: string | string[]): void;\n getSpaceRootDocHandle(): DocHandle<SpaceDoc>;\n createDocumentForObject(objectId: string): DocHandle<SpaceDoc>;\n onObjectLinksUpdated(links: SpaceDocumentLinks): void;\n onObjectBoundToDocument(handle: DocHandle<SpaceDoc>, objectId: string): void;\n\n /**\n * @returns objectIds for which we had document handles or were loading one.\n */\n clearHandleReferences(): string[];\n}\n\n/**\n * Manages object <-> docHandle binding and automerge document loading.\n */\n@trace.resource()\nexport class AutomergeDocumentLoaderImpl implements AutomergeDocumentLoader {\n private _spaceRootDocHandle: DocHandle<SpaceDoc> | null = null;\n /**\n * An object id pointer to a handle of the document where the object is stored inline.\n */\n private readonly _objectDocumentHandles = new Map<string, DocHandle<SpaceDoc>>();\n /**\n * If object was requested via loadObjectDocument but root document links weren't updated yet\n * loading will be triggered in onObjectLinksUpdated callback.\n */\n private readonly _objectsPendingDocumentLoad = new Set<string>();\n\n public readonly onObjectDocumentLoaded = new Event<ObjectDocumentLoaded>();\n\n constructor(\n private readonly _spaceKey: PublicKey,\n private readonly _repo: Repo,\n ) {}\n\n getAllHandles(): DocHandle<SpaceDoc>[] {\n return this._spaceRootDocHandle != null\n ? [this._spaceRootDocHandle, ...new Set(this._objectDocumentHandles.values())]\n : [];\n }\n\n @trace.span({ showInBrowserTimeline: true })\n public async loadSpaceRootDocHandle(ctx: Context, spaceState: SpaceState): Promise<void> {\n if (this._spaceRootDocHandle != null) {\n return;\n }\n if (!spaceState.rootUrl) {\n log.error('Database opened with no rootUrl', { spaceKey: this._spaceKey });\n this._createContextBoundSpaceRootDocument(ctx);\n } else {\n const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);\n const doc = existingDocHandle.docSync();\n invariant(doc);\n if (doc.access == null) {\n this._initDocAccess(existingDocHandle);\n }\n this._spaceRootDocHandle = existingDocHandle;\n }\n }\n\n public loadObjectDocument(objectIdOrMany: string | string[]) {\n const objectIds = Array.isArray(objectIdOrMany) ? objectIdOrMany : [objectIdOrMany];\n let hasUrlsToLoad = false;\n const urlsToLoad: SpaceDoc['links'] = {};\n for (const objectId of objectIds) {\n invariant(this._spaceRootDocHandle);\n if (this._objectDocumentHandles.has(objectId) || this._objectsPendingDocumentLoad.has(objectId)) {\n continue;\n }\n const spaceRootDoc = this._spaceRootDocHandle.docSync();\n invariant(spaceRootDoc);\n const documentUrl = (spaceRootDoc.links ?? {})[objectId];\n if (documentUrl == null) {\n this._objectsPendingDocumentLoad.add(objectId);\n log.info('loading delayed until object links are initialized', { objectId });\n } else {\n urlsToLoad[objectId] = documentUrl;\n hasUrlsToLoad = true;\n }\n }\n if (hasUrlsToLoad) {\n this._loadLinkedObjects(urlsToLoad);\n }\n }\n\n public onObjectLinksUpdated(links: SpaceDocumentLinks) {\n if (!links) {\n return;\n }\n const linksAwaitingLoad = Object.entries(links).filter(([objectId]) =>\n this._objectsPendingDocumentLoad.has(objectId),\n );\n this._loadLinkedObjects(Object.fromEntries(linksAwaitingLoad));\n linksAwaitingLoad.forEach(([objectId]) => this._objectsPendingDocumentLoad.delete(objectId));\n }\n\n public getSpaceRootDocHandle(): DocHandle<SpaceDoc> {\n invariant(this._spaceRootDocHandle);\n return this._spaceRootDocHandle;\n }\n\n public createDocumentForObject(objectId: string): DocHandle<SpaceDoc> {\n invariant(this._spaceRootDocHandle);\n const spaceDocHandle = this._repo.create<SpaceDoc>();\n this._initDocAccess(spaceDocHandle);\n this.onObjectBoundToDocument(spaceDocHandle, objectId);\n this._spaceRootDocHandle.change((newDoc: SpaceDoc) => {\n newDoc.links ??= {};\n newDoc.links[objectId] = spaceDocHandle.url;\n });\n return spaceDocHandle;\n }\n\n public onObjectBoundToDocument(handle: DocHandle<SpaceDoc>, objectId: string) {\n this._objectDocumentHandles.set(objectId, handle);\n }\n\n public clearHandleReferences(): string[] {\n const objectsWithHandles = [...this._objectDocumentHandles.keys()];\n this._objectDocumentHandles.clear();\n this._spaceRootDocHandle = null;\n return objectsWithHandles;\n }\n\n private _loadLinkedObjects(links: SpaceDocumentLinks) {\n if (!links) {\n return;\n }\n for (const [objectId, automergeUrl] of Object.entries(links)) {\n const logMeta = { objectId, automergeUrl };\n const objectDocumentHandle = this._objectDocumentHandles.get(objectId);\n if (objectDocumentHandle != null && objectDocumentHandle.url !== automergeUrl) {\n log.warn('object already inlined in a different document, ignoring the link', {\n ...logMeta,\n actualDocumentUrl: objectDocumentHandle.url,\n });\n continue;\n }\n if (objectDocumentHandle?.url === automergeUrl) {\n log.warn('object document was already loaded', logMeta);\n continue;\n }\n const handle = this._repo.find<SpaceDoc>(automergeUrl as DocumentId);\n log.debug('document loading triggered', logMeta);\n this._objectDocumentHandles.set(objectId, handle);\n void this._createObjectOnDocumentLoad(handle, objectId);\n }\n }\n\n private async _initDocHandle(ctx: Context, url: string) {\n const docHandle = this._repo.find<SpaceDoc>(url as DocumentId);\n while (true) {\n try {\n await warnAfterTimeout(5_000, 'Automerge root doc load timeout (AutomergeDb)', async () => {\n await cancelWithContext(ctx, docHandle.whenReady()); // TODO(dmaretskyi): Temporary 5s timeout for debugging.\n });\n break;\n } catch (err) {\n if (`${err}`.includes('Timeout')) {\n log.info('wraparound', { id: docHandle.documentId, state: docHandle.state });\n continue;\n }\n\n throw err;\n }\n }\n\n if (docHandle.state === 'unavailable') {\n throw new Error('Automerge document is unavailable');\n }\n\n return docHandle;\n }\n\n private _createContextBoundSpaceRootDocument(ctx: Context) {\n const docHandle = this._repo.create<SpaceDoc>();\n this._spaceRootDocHandle = docHandle;\n ctx.onDispose(() => {\n docHandle.delete();\n this._spaceRootDocHandle = null;\n });\n }\n\n private _initDocAccess(handle: DocHandle<SpaceDoc>) {\n handle.change((newDoc: SpaceDoc) => {\n newDoc.access ??= { spaceKey: this._spaceKey.toHex() };\n newDoc.access.spaceKey = this._spaceKey.toHex();\n });\n }\n\n private async _createObjectOnDocumentLoad(handle: DocHandle<SpaceDoc>, objectId: string) {\n try {\n await handle.doc(['ready']);\n const logMeta = { objectId, docUrl: handle.url };\n if (this.onObjectDocumentLoaded.listenerCount() === 0) {\n log.info('document loaded after all listeners were removed', logMeta);\n return;\n }\n const objectDocHandle = this._objectDocumentHandles.get(objectId);\n if (objectDocHandle?.url !== handle.url) {\n log.warn('object was rebound while a document was loading, discarding handle', logMeta);\n return;\n }\n this.onObjectDocumentLoaded.emit({ handle, objectId });\n } catch (err) {\n const shouldRetryLoading = this.onObjectDocumentLoaded.listenerCount() > 0;\n log.warn('failed to load a document', {\n objectId,\n automergeUrl: handle.url,\n retryLoading: shouldRetryLoading,\n err,\n });\n if (shouldRetryLoading) {\n await this._createObjectOnDocumentLoad(handle, objectId);\n }\n }\n }\n}\n\nexport interface ObjectDocumentLoaded {\n handle: DocHandle<SpaceDoc>;\n objectId: string;\n}\n\nexport interface DocumentChanges {\n createdObjectIds: string[];\n updatedObjectIds: string[];\n objectsToRebind: string[];\n linkedDocuments: {\n [echoId: string]: AutomergeUrl;\n };\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Message, cbor } from '@dxos/automerge/automerge-repo';\nimport { Resource } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { AutomergeReplicator } from '@dxos/teleport-extension-automerge-replicator';\nimport { ComplexMap, ComplexSet, defaultMap } from '@dxos/util';\n\nimport {\n type EchoReplicator,\n type EchoReplicatorContext,\n type ReplicatorConnection,\n type ShouldAdvertizeParams,\n} from './echo-replicator';\n\n// TODO(dmaretskyi): Move out of @dxos/echo-pipeline.\n\n/**\n * Used to replicate with other peers over the network.\n */\nexport class MeshEchoReplicator implements EchoReplicator {\n private readonly _connections = new Set<MeshReplicatorConnection>();\n /**\n * Using automerge peerId as a key.\n */\n private readonly _connectionsPerPeer = new Map<string, MeshReplicatorConnection>();\n\n /**\n * spaceKey -> deviceKey[]\n */\n private readonly _authorizedDevices = new ComplexMap<PublicKey, ComplexSet<PublicKey>>(PublicKey.hash);\n\n private _context: EchoReplicatorContext | null = null;\n\n async connect(context: EchoReplicatorContext): Promise<void> {\n this._context = context;\n }\n\n async disconnect() {\n for (const connection of this._connections) {\n await connection.close();\n }\n this._connections.clear();\n this._connectionsPerPeer.clear();\n\n this._context = null;\n }\n\n createExtension(): AutomergeReplicator {\n invariant(this._context);\n\n const connection: MeshReplicatorConnection = new MeshReplicatorConnection({\n ownPeerId: this._context.peerId,\n onRemoteConnected: async () => {\n log('onRemoteConnected', { peerId: connection.peerId });\n invariant(this._context);\n\n if (!this._connectionsPerPeer.has(connection.peerId)) {\n this._connectionsPerPeer.set(connection.peerId, connection);\n await connection.enable();\n this._context.onConnectionOpen(connection);\n }\n },\n onRemoteDisconnected: async () => {\n log('onRemoteDisconnected', { peerId: connection.peerId });\n this._context?.onConnectionClosed(connection);\n await connection.disable();\n this._connectionsPerPeer.delete(connection.peerId);\n this._connections.delete(connection);\n },\n shouldAdvertize: async (params: ShouldAdvertizeParams) => {\n log('shouldAdvertize', { peerId: connection.peerId, documentId: params.documentId });\n invariant(this._context);\n try {\n const spaceKey = await this._context.getContainingSpaceForDocument(params.documentId);\n if (!spaceKey) {\n log('space key not found for share policy check', {\n peerId: connection.peerId,\n documentId: params.documentId,\n });\n return false;\n }\n\n const authorizedDevices = this._authorizedDevices.get(spaceKey);\n\n if (!connection.remoteDeviceKey) {\n log('device key not found for share policy check', {\n peerId: connection.peerId,\n documentId: params.documentId,\n });\n return false;\n }\n\n const isAuthorized = authorizedDevices?.has(connection.remoteDeviceKey) ?? false;\n log('share policy check', {\n localPeer: this._context.peerId,\n remotePeer: connection.peerId,\n documentId: params.documentId,\n deviceKey: connection.remoteDeviceKey,\n spaceKey,\n isAuthorized,\n });\n return isAuthorized;\n } catch (err) {\n log.catch(err);\n return false;\n }\n },\n });\n this._connections.add(connection);\n\n return connection.replicatorExtension;\n }\n\n authorizeDevice(spaceKey: PublicKey, deviceKey: PublicKey) {\n log('authorizeDevice', { spaceKey, deviceKey });\n defaultMap(this._authorizedDevices, spaceKey, () => new ComplexSet(PublicKey.hash)).add(deviceKey);\n }\n}\n\ntype MeshReplicatorConnectionParams = {\n ownPeerId: string;\n onRemoteConnected: () => Promise<void>;\n onRemoteDisconnected: () => Promise<void>;\n shouldAdvertize: (params: ShouldAdvertizeParams) => Promise<boolean>;\n};\n\nclass MeshReplicatorConnection extends Resource implements ReplicatorConnection {\n public readable: ReadableStream<Message>;\n public writable: WritableStream<Message>;\n public remoteDeviceKey: PublicKey | null = null;\n\n public readonly replicatorExtension: AutomergeReplicator;\n\n private _remotePeerId: string | null = null;\n private _isEnabled = false;\n\n constructor(private readonly _params: MeshReplicatorConnectionParams) {\n super();\n\n let readableStreamController!: ReadableStreamDefaultController<Message>;\n this.readable = new ReadableStream<Message>({\n start: (controller) => {\n readableStreamController = controller;\n this._ctx.onDispose(() => controller.close());\n },\n });\n\n this.writable = new WritableStream<Message>({\n write: async (message: Message, controller) => {\n // TODO(dmaretskyi): Show we block on RPC completing here?\n this.replicatorExtension.sendSyncMessage({ payload: cbor.encode(message) }).catch((err) => {\n controller.error(err);\n });\n },\n });\n\n this.replicatorExtension = new AutomergeReplicator(\n {\n peerId: this._params.ownPeerId,\n },\n {\n onStartReplication: async (info, remotePeerId /** Teleport ID */) => {\n // Note: We store only one extension per peer.\n // There can be a case where two connected peers have more than one teleport connection between them\n // and each of them uses different teleport connections to send messages.\n // It works because we receive messages from all teleport connections and Automerge Repo dedup them.\n // TODO(mykola): Use only one teleport connection per peer.\n\n // TODO(dmaretskyi): Critical bug.\n // - two peers get connected via swarm 1\n // - they get connected via swarm 2\n // - swarm 1 gets disconnected\n // - automerge repo thinks that peer 2 got disconnected even though swarm 2 is still active\n\n this.remoteDeviceKey = remotePeerId;\n\n // Set automerge id.\n this._remotePeerId = info.id;\n\n log('onStartReplication', { id: info.id, thisPeerId: this.peerId, remotePeerId: remotePeerId.toHex() });\n\n await this._params.onRemoteConnected();\n },\n onSyncMessage: async ({ payload }) => {\n if (!this._isEnabled) {\n return;\n }\n const message = cbor.decode(payload) as Message;\n // Note: automerge Repo dedup messages.\n readableStreamController.enqueue(message);\n },\n onClose: async () => {\n if (!this._isEnabled) {\n return;\n }\n await this._params.onRemoteDisconnected();\n },\n },\n );\n }\n\n get peerId(): string {\n invariant(this._remotePeerId != null, 'Remote peer has not connected yet.');\n return this._remotePeerId;\n }\n\n async shouldAdvertize(params: ShouldAdvertizeParams): Promise<boolean> {\n return this._params.shouldAdvertize(params);\n }\n\n /**\n * Start exchanging messages with the remote peer.\n * Call after the remote peer has connected.\n */\n async enable() {\n invariant(this._remotePeerId != null, 'Remote peer has not connected yet.');\n this._isEnabled = true;\n }\n\n /**\n * Stop exchanging messages with the remote peer.\n */\n async disable() {\n this._isEnabled = false;\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["Event", "next", "automerge", "getBackend", "getHeads", "Repo", "Context", "invariant", "PublicKey", "log", "objectPointerCodec", "trace", "mapValues", "Trigger", "synchronized", "NetworkAdapter", "LifecycleState", "invariant", "log", "EchoNetworkAdapter", "constructor", "_params", "_replicators", "Set", "_connections", "Map", "_lifecycleState", "CLOSED", "_connected", "connect", "peerId", "peerMetadata", "wake", "send", "message", "connectionEntry", "get", "targetId", "Error", "writer", "write", "catch", "err", "isOpen", "disconnect", "open", "OPEN", "emit", "network", "close", "replicator", "clear", "whenConnected", "wait", "timeout", "addReplicator", "has", "add", "onConnectionOpen", "_onConnectionOpen", "bind", "onConnectionClosed", "_onConnectionClosed", "getContainingSpaceForDocument", "removeReplicator", "delete", "shouldAdvertize", "params", "connection", "reader", "readable", "getReader", "writable", "getWriter", "set", "queueMicrotask", "done", "value", "read", "dxos_peerSource", "entry", "cancel", "abort", "LifecycleState", "Resource", "LevelDBStorageAdapter", "Resource", "constructor", "_params", "load", "keyArray", "_lifecycleState", "LifecycleState", "OPEN", "undefined", "db", "get", "encodingOptions", "err", "isLevelDbNotFoundError", "save", "binary", "batch", "callbacks", "beforeSave", "path", "put", "Buffer", "from", "write", "afterSave", "remove", "del", "loadRange", "keyPrefix", "result", "key", "value", "iterator", "gte", "lte", "push", "data", "removeRange", "keyEncoder", "encode", "map", "k", "replaceAll", "join", "decode", "toString", "split", "format", "keyEncoding", "valueEncoding", "code", "Trigger", "NetworkAdapter", "cbor", "Stream", "invariant", "LocalHostNetworkAdapter", "_peers", "Map", "_connected", "_isConnected", "ready", "emit", "network", "connect", "peerId", "wake", "send", "message", "peer", "get", "targetId", "close", "forEach", "disconnect", "whenConnected", "wait", "timeout", "syncRepo", "id", "syncMessage", "_getPeerId", "next", "has", "set", "connected", "encode", "delete", "peerMetadata", "sendSyncMessage", "decode", "getHostInfo", "IndexedDBStorageAdapter", "log", "StorageType", "arrayToBuffer", "bufferToArray", "AutomergeStorageAdapter", "constructor", "_directory", "_state", "load", "key", "undefined", "filename", "_getFilename", "file", "getOrCreateFile", "size", "stat", "buffer", "read", "bufferToArray", "save", "data", "write", "arrayToBuffer", "truncate", "length", "flush", "remove", "destroy", "loadRange", "keyPrefix", "entries", "list", "Promise", "all", "filter", "entry", "startsWith", "map", "_getKeyFromFilename", "removeRange", "close", "k", "replaceAll", "join", "split", "levelMigration", "db", "directory", "isNewLevel", "iterator", "encodingOptions", "next", "oldStorageAdapter", "type", "StorageType", "IDB", "IndexedDBStorageAdapter", "path", "AutomergeStorageAdapter", "chunks", "loadRange", "length", "batch", "log", "info", "key", "data", "put", "write", "AutomergeHost", "constructor", "directory", "db", "indexMetadataStore", "_ctx", "Context", "_echoNetworkAdapter", "EchoNetworkAdapter", "getContainingSpaceForDocument", "_getContainingSpaceForDocument", "bind", "_requestedDocs", "Set", "_directory", "_db", "_indexMetadataStore", "open", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { Event } from '@dxos/async';\nimport { next as automerge, getBackend, getHeads, type Doc, type Heads } from '@dxos/automerge/automerge';\nimport {\n Repo,\n type DocHandle,\n type DocHandleChangePayload,\n type DocumentId,\n type PeerId,\n type StorageAdapterInterface,\n} from '@dxos/automerge/automerge-repo';\nimport { type Stream } from '@dxos/codec-protobuf';\nimport { Context, type Lifecycle } from '@dxos/context';\nimport { type SpaceDoc } from '@dxos/echo-protocol';\nimport { type IndexMetadataStore } from '@dxos/indexing';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { type SublevelDB } from '@dxos/kv-store';\nimport { log } from '@dxos/log';\nimport { objectPointerCodec } from '@dxos/protocols';\nimport {\n type FlushRequest,\n type HostInfo,\n type SyncRepoRequest,\n type SyncRepoResponse,\n} from '@dxos/protocols/proto/dxos/echo/service';\nimport { type Directory } from '@dxos/random-access-storage';\nimport { trace } from '@dxos/tracing';\nimport { mapValues } from '@dxos/util';\n\nimport { EchoNetworkAdapter } from './echo-network-adapter';\nimport { type EchoReplicator } from './echo-replicator';\nimport { LevelDBStorageAdapter, type BeforeSaveParams } from './leveldb-storage-adapter';\nimport { LocalHostNetworkAdapter } from './local-host-network-adapter';\nimport { levelMigration } from './migrations';\n\n// TODO: Remove\nexport type { DocumentId };\n\nexport type AutomergeHostParams = {\n db: SublevelDB;\n /**\n * For migration purposes.\n */\n directory?: Directory;\n\n indexMetadataStore: IndexMetadataStore;\n};\n\n@trace.resource()\nexport class AutomergeHost {\n private readonly _indexMetadataStore: IndexMetadataStore;\n private readonly _ctx = new Context();\n private readonly _directory?: Directory;\n private readonly _db: SublevelDB;\n private readonly _echoNetworkAdapter = new EchoNetworkAdapter({\n getContainingSpaceForDocument: this._getContainingSpaceForDocument.bind(this),\n });\n\n private _repo!: Repo;\n private _clientNetwork!: LocalHostNetworkAdapter;\n private _storage!: StorageAdapterInterface & Lifecycle;\n\n @trace.info()\n private _peerId!: string;\n\n public _requestedDocs = new Set<string>();\n\n constructor({ directory, db, indexMetadataStore }: AutomergeHostParams) {\n this._directory = directory;\n this._db = db;\n this._indexMetadataStore = indexMetadataStore;\n }\n\n async open() {\n // TODO(burdon): Should this be stable?\n this._peerId = `host-${PublicKey.random().toHex()}` as PeerId;\n\n // TODO(mykola): remove this before 0.6 release.\n this._directory && (await levelMigration({ db: this._db, directory: this._directory }));\n this._storage = new LevelDBStorageAdapter({\n db: this._db,\n callbacks: {\n beforeSave: async (params) => this._beforeSave(params),\n afterSave: async () => this._afterSave(),\n },\n });\n await this._storage.open?.();\n\n this._clientNetwork = new LocalHostNetworkAdapter();\n\n // Construct the automerge repo.\n this._repo = new Repo({\n peerId: this._peerId as PeerId,\n sharePolicy: this._sharePolicy.bind(this),\n storage: this._storage,\n network: [\n // Downstream client.\n this._clientNetwork,\n // Upstream swarm.\n this._echoNetworkAdapter,\n ],\n });\n\n this._clientNetwork.ready();\n await this._echoNetworkAdapter.open();\n await this._clientNetwork.whenConnected();\n await this._echoNetworkAdapter.whenConnected();\n }\n\n async close() {\n await this._storage.close?.();\n await this._clientNetwork.close();\n await this._echoNetworkAdapter.close();\n await this._ctx.dispose();\n }\n\n get repo(): Repo {\n return this._repo;\n }\n\n async addReplicator(replicator: EchoReplicator) {\n await this._echoNetworkAdapter.addReplicator(replicator);\n }\n\n async removeReplicator(replicator: EchoReplicator) {\n await this._echoNetworkAdapter.removeReplicator(replicator);\n }\n\n // TODO(dmaretskyi): Share based on HALO permissions and space affinity.\n // Hosts, running in the worker, don't share documents unless requested by other peers.\n // NOTE: If both peers return sharePolicy=false the replication will not happen\n // https://github.com/automerge/automerge-repo/pull/292\n private async _sharePolicy(\n peerId: PeerId /* device key */,\n documentId?: DocumentId /* space key */,\n ): Promise<boolean> {\n if (peerId.startsWith('client-')) {\n return false; // Only send docs to clients if they are requested.\n }\n\n if (!documentId) {\n return false;\n }\n\n // Workaround for https://github.com/automerge/automerge-repo/pull/292\n // NOTE: This must override the per-connection policy.\n const doc = this._repo.handles[documentId]?.docSync();\n if (!doc) {\n // TODO(dmaretskyi): Verify that this works as intended.\n // TODO(dmaretskyi): Move to MESH replicator?\n const isRequested = this._requestedDocs.has(`automerge:${documentId}`);\n log('doc share policy check', { peerId, documentId, isRequested });\n return isRequested;\n }\n\n const peerMetadata = this.repo.peerMetadataByPeerId[peerId];\n if ((peerMetadata as any)?.dxos_peerSource === 'EchoNetworkAdapter') {\n return this._echoNetworkAdapter.shouldAdvertize(peerId, { documentId });\n }\n\n return false;\n }\n\n private async _beforeSave({ path, batch }: BeforeSaveParams) {\n const handle = this._repo.handles[path[0] as DocumentId];\n if (!handle) {\n return;\n }\n const doc = handle.docSync();\n if (!doc) {\n return;\n }\n\n const spaceKey = getSpaceKeyFromDoc(doc) ?? undefined;\n\n const lastAvailableHash = getHeads(doc);\n\n const objectIds = Object.keys(doc.objects ?? {});\n const encodedIds = objectIds.map((objectId) =>\n objectPointerCodec.encode({ documentId: handle.documentId, objectId, spaceKey }),\n );\n const idToLastHash = new Map(encodedIds.map((id) => [id, lastAvailableHash]));\n this._indexMetadataStore.markDirty(idToLastHash, batch);\n }\n\n /**\n * Called by AutomergeStorageAdapter after levelDB batch commit.\n */\n private async _afterSave() {\n this._indexMetadataStore.notifyMarkedDirty();\n }\n\n @trace.info({ depth: null })\n private _automergeDocs() {\n return mapValues(this._repo.handles, (handle) => ({\n state: handle.state,\n hasDoc: !!handle.docSync(),\n heads: handle.docSync() ? automerge.getHeads(handle.docSync()) : null,\n data:\n handle.docSync() &&\n mapValues(handle.docSync(), (value, key) => {\n try {\n switch (key) {\n case 'access':\n case 'links':\n return value;\n case 'objects':\n return Object.keys(value as any);\n default:\n return `${value}`;\n }\n } catch (err) {\n return `${err}`;\n }\n }),\n }));\n }\n\n @trace.info({ depth: null })\n private _automergePeers() {\n return this._repo.peers;\n }\n\n private async _getContainingSpaceForDocument(documentId: string): Promise<PublicKey | null> {\n const doc = this._repo.handles[documentId as any]?.docSync();\n if (!doc) {\n return null;\n }\n\n const spaceKeyHex = getSpaceKeyFromDoc(doc);\n if (!spaceKeyHex) {\n return null;\n }\n\n return PublicKey.from(spaceKeyHex);\n }\n\n //\n // Methods for client-services.\n //\n @trace.span({ showInBrowserTimeline: true })\n async flush({ states }: FlushRequest): Promise<void> {\n // Note: Wait for all requested documents to be loaded/synced from thin-client.\n await Promise.all(\n states?.map(async ({ heads, documentId }) => {\n invariant(heads, 'heads are required for flush');\n const handle = this.repo.handles[documentId as DocumentId] ?? this._repo.find(documentId as DocumentId);\n await waitForHeads(handle, heads);\n }) ?? [],\n );\n\n await this._repo.flush(states?.map(({ documentId }) => documentId as DocumentId));\n }\n\n syncRepo(request: SyncRepoRequest): Stream<SyncRepoResponse> {\n return this._clientNetwork.syncRepo(request);\n }\n\n sendSyncMessage(request: SyncRepoRequest): Promise<void> {\n return this._clientNetwork.sendSyncMessage(request);\n }\n\n async getHostInfo(): Promise<HostInfo> {\n return this._clientNetwork.getHostInfo();\n }\n}\n\nexport const getSpaceKeyFromDoc = (doc: any): string | null => {\n // experimental_spaceKey is set on old documents, new ones are created with doc.access.spaceKey\n const rawSpaceKey = doc.access?.spaceKey ?? doc.experimental_spaceKey;\n if (rawSpaceKey == null) {\n return null;\n }\n\n return String(rawSpaceKey);\n};\n\nconst waitForHeads = async (handle: DocHandle<SpaceDoc>, heads: Heads) => {\n await handle.whenReady();\n const unavailableHeads = new Set(heads);\n\n await Event.wrap<DocHandleChangePayload<SpaceDoc>>(handle, 'change').waitForCondition(() => {\n // Check if unavailable heads became available.\n for (const changeHash of unavailableHeads.values()) {\n if (changeIsPresentInDoc(handle.docSync(), changeHash)) {\n unavailableHeads.delete(changeHash);\n }\n }\n\n if (unavailableHeads.size === 0) {\n return true;\n }\n return false;\n });\n};\n\nconst changeIsPresentInDoc = (doc: Doc<any>, changeHash: string): boolean => {\n return !!getBackend(doc).getChangeByHash(changeHash);\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { Trigger, synchronized } from '@dxos/async';\nimport { type Message, NetworkAdapter, type PeerId, type PeerMetadata } from '@dxos/automerge/automerge-repo';\nimport { LifecycleState } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\n\nimport { type EchoReplicator, type ReplicatorConnection, type ShouldAdvertizeParams } from './echo-replicator';\n\nexport type EchoNetworkAdapterParams = {\n getContainingSpaceForDocument: (documentId: string) => Promise<PublicKey | null>;\n};\n\n/**\n * Manages a set of {@link EchoReplicator} instances.\n */\nexport class EchoNetworkAdapter extends NetworkAdapter {\n private readonly _replicators = new Set<EchoReplicator>();\n /**\n * Remote peer id -> connection.\n */\n private readonly _connections = new Map<PeerId, ConnectionEntry>();\n private _lifecycleState: LifecycleState = LifecycleState.CLOSED;\n private readonly _connected = new Trigger();\n\n constructor(private readonly _params: EchoNetworkAdapterParams) {\n super();\n }\n\n override connect(peerId: PeerId, peerMetadata?: PeerMetadata | undefined): void {\n this.peerId = peerId;\n this.peerMetadata = peerMetadata;\n this._connected.wake();\n }\n\n override send(message: Message): void {\n const connectionEntry = this._connections.get(message.targetId);\n if (!connectionEntry) {\n throw new Error('Connection not found.');\n }\n\n // TODO(dmaretskyi): Find a way to enforce backpressure on AM-repo.\n connectionEntry.writer.write(message).catch((err) => {\n if (connectionEntry.isOpen) {\n log.catch(err);\n }\n });\n }\n\n override disconnect(): void {\n // No-op\n }\n\n @synchronized\n async open() {\n invariant(this._lifecycleState === LifecycleState.CLOSED);\n this._lifecycleState = LifecycleState.OPEN;\n\n log('emit ready');\n this.emit('ready', {\n network: this,\n });\n }\n\n @synchronized\n async close() {\n invariant(this._lifecycleState === LifecycleState.OPEN);\n\n for (const replicator of this._replicators) {\n await replicator.disconnect();\n }\n this._replicators.clear();\n\n this._lifecycleState = LifecycleState.CLOSED;\n }\n\n async whenConnected() {\n await this._connected.wait({ timeout: 10_000 });\n }\n\n @synchronized\n async addReplicator(replicator: EchoReplicator) {\n invariant(this._lifecycleState === LifecycleState.OPEN);\n invariant(this.peerId);\n invariant(!this._replicators.has(replicator));\n\n this._replicators.add(replicator);\n await replicator.connect({\n peerId: this.peerId,\n onConnectionOpen: this._onConnectionOpen.bind(this),\n onConnectionClosed: this._onConnectionClosed.bind(this),\n getContainingSpaceForDocument: this._params.getContainingSpaceForDocument,\n });\n }\n\n @synchronized\n async removeReplicator(replicator: EchoReplicator) {\n invariant(this._lifecycleState === LifecycleState.OPEN);\n invariant(this._replicators.has(replicator));\n ('');\n await replicator.disconnect();\n this._replicators.delete(replicator);\n }\n\n async shouldAdvertize(peerId: PeerId, params: ShouldAdvertizeParams): Promise<boolean> {\n const connection = this._connections.get(peerId);\n if (!connection) {\n return false;\n }\n\n return connection.connection.shouldAdvertize(params);\n }\n\n private _onConnectionOpen(connection: ReplicatorConnection) {\n log('Connection opened', { peerId: connection.peerId });\n invariant(!this._connections.has(connection.peerId as PeerId));\n const reader = connection.readable.getReader();\n const writer = connection.writable.getWriter();\n const connectionEntry: ConnectionEntry = { connection, reader, writer, isOpen: true };\n this._connections.set(connection.peerId as PeerId, connectionEntry);\n\n queueMicrotask(async () => {\n try {\n while (true) {\n // TODO(dmaretskyi): Find a way to enforce backpressure on AM-repo.\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n this.emit('message', value);\n }\n } catch (err) {\n if (connectionEntry.isOpen) {\n log.catch(err);\n }\n }\n });\n\n log('emit peer-candidate', { peerId: connection.peerId });\n this.emit('peer-candidate', {\n peerId: connection.peerId as PeerId,\n peerMetadata: {\n // TODO(dmaretskyi): Refactor this.\n dxos_peerSource: 'EchoNetworkAdapter',\n } as any,\n });\n }\n\n private _onConnectionClosed(connection: ReplicatorConnection) {\n log('Connection closed', { peerId: connection.peerId });\n const entry = this._connections.get(connection.peerId as PeerId);\n invariant(entry);\n\n entry.isOpen = false;\n this.emit('peer-disconnected', { peerId: connection.peerId as PeerId });\n\n void entry.reader.cancel().catch((err) => log.catch(err));\n void entry.writer.abort().catch((err) => log.catch(err));\n\n this._connections.delete(connection.peerId as PeerId);\n }\n}\n\ntype ConnectionEntry = {\n connection: ReplicatorConnection;\n reader: ReadableStreamDefaultReader<Message>;\n writer: WritableStreamDefaultWriter<Message>;\n isOpen: boolean;\n};\n", "//\n// Copyright 2024 DXOS.org\n// s\n\nimport { type MixedEncoding } from 'level-transcoder';\n\nimport { type StorageAdapterInterface, type Chunk, type StorageKey } from '@dxos/automerge/automerge-repo';\nimport { LifecycleState, Resource } from '@dxos/context';\nimport { type BatchLevel, type SublevelDB } from '@dxos/kv-store';\nimport { type MaybePromise } from '@dxos/util';\n\nexport type LevelDBStorageAdapterParams = {\n db: SublevelDB;\n callbacks?: StorageCallbacks;\n};\n\nexport type BeforeSaveParams = { path: StorageKey; batch: BatchLevel };\n\nexport interface StorageCallbacks {\n beforeSave(params: BeforeSaveParams): MaybePromise<void>;\n afterSave(path: StorageKey): MaybePromise<void>;\n}\n\nexport class LevelDBStorageAdapter extends Resource implements StorageAdapterInterface {\n constructor(private readonly _params: LevelDBStorageAdapterParams) {\n super();\n }\n\n async load(keyArray: StorageKey): Promise<Uint8Array | undefined> {\n try {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n // TODO(mykola): this should be an error.\n return undefined;\n }\n return await this._params.db.get<StorageKey, Uint8Array>(keyArray, { ...encodingOptions });\n } catch (err: any) {\n if (isLevelDbNotFoundError(err)) {\n return undefined;\n }\n throw err;\n }\n }\n\n async save(keyArray: StorageKey, binary: Uint8Array): Promise<void> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return undefined;\n }\n const batch = this._params.db.batch();\n\n await this._params.callbacks?.beforeSave?.({ path: keyArray, batch });\n batch.put<StorageKey, Uint8Array>(keyArray, Buffer.from(binary), {\n ...encodingOptions,\n });\n await batch.write();\n\n await this._params.callbacks?.afterSave?.(keyArray);\n }\n\n async remove(keyArray: StorageKey): Promise<void> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return undefined;\n }\n await this._params.db.del<StorageKey>(keyArray, { ...encodingOptions });\n }\n\n async loadRange(keyPrefix: StorageKey): Promise<Chunk[]> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return [];\n }\n const result: Chunk[] = [];\n for await (const [key, value] of this._params.db.iterator<StorageKey, Uint8Array>({\n gte: keyPrefix,\n lte: [...keyPrefix, '\\uffff'],\n ...encodingOptions,\n })) {\n result.push({\n key,\n data: value,\n });\n }\n return result;\n }\n\n async removeRange(keyPrefix: StorageKey): Promise<void> {\n if (this._lifecycleState !== LifecycleState.OPEN) {\n return undefined;\n }\n const batch = this._params.db.batch();\n\n for await (const [key] of this._params.db.iterator<StorageKey, Uint8Array>({\n gte: keyPrefix,\n lte: [...keyPrefix, '\\uffff'],\n ...encodingOptions,\n })) {\n batch.del<StorageKey>(key, { ...encodingOptions });\n }\n await batch.write();\n }\n}\n\nconst keyEncoder: MixedEncoding<StorageKey, Uint8Array, StorageKey> = {\n encode: (key: StorageKey): Uint8Array =>\n Buffer.from(key.map((k) => k.replaceAll('%', '%25').replaceAll('-', '%2D')).join('-')),\n decode: (key: Uint8Array): StorageKey =>\n Buffer.from(key)\n .toString()\n .split('-')\n .map((k) => k.replaceAll('%2D', '-').replaceAll('%25', '%')),\n format: 'buffer',\n};\n\nexport const encodingOptions = {\n keyEncoding: keyEncoder,\n valueEncoding: 'buffer',\n};\n\nconst isLevelDbNotFoundError = (err: any): boolean => err.code === 'LEVEL_NOT_FOUND';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { Trigger } from '@dxos/async';\nimport { NetworkAdapter, type Message, type PeerId, cbor } from '@dxos/automerge/automerge-repo';\nimport { Stream } from '@dxos/codec-protobuf';\nimport { invariant } from '@dxos/invariant';\nimport { type HostInfo, type SyncRepoRequest, type SyncRepoResponse } from '@dxos/protocols/proto/dxos/echo/service';\n\ntype ClientSyncState = {\n connected: boolean;\n send: (message: Message) => void;\n disconnect: () => void;\n};\n\n/**\n * Used to replicate with apps running on the same device.\n */\nexport class LocalHostNetworkAdapter extends NetworkAdapter {\n private readonly _peers: Map<PeerId, ClientSyncState> = new Map();\n\n /**\n * Emits `ready` event. That signals to `Repo` that it can start using the adapter.\n */\n ready() {\n // NOTE: Emitting `ready` event in NetworkAdapter`s constructor causes a race condition\n // because `Repo` waits for `ready` event (which it never receives) before it starts using the adapter.\n this.emit('ready', {\n network: this,\n });\n }\n\n private readonly _connected = new Trigger();\n private _isConnected: boolean = false;\n\n /**\n * Called by `Repo` to connect to the network.\n *\n * @param peerId Our peer Id.\n */\n override connect(peerId: PeerId): void {\n this.peerId = peerId;\n this._isConnected = true;\n this._connected.wake();\n // No-op. Client always connects first\n }\n\n override send(message: Message): void {\n const peer = this._peers.get(message.targetId);\n invariant(peer, 'Peer not found.');\n peer.send(message);\n }\n\n async close() {\n this._peers.forEach((peer) => peer.disconnect());\n this.emit('close');\n }\n\n override disconnect(): void {\n // TODO(mykola): `disconnect` is not used anywhere in `Repo` from `@automerge/automerge-repo`. Should we remove it?\n // No-op\n }\n\n async whenConnected(): Promise<void> {\n await this._connected.wait({ timeout: 10_000 });\n }\n\n syncRepo({ id, syncMessage }: SyncRepoRequest): Stream<SyncRepoResponse> {\n const peerId = this._getPeerId(id);\n\n return new Stream(({ next, close }) => {\n invariant(!this._peers.has(peerId), 'Peer already connected.');\n this._peers.set(peerId, {\n connected: true,\n send: (message) => {\n next({\n syncMessage: cbor.encode(message),\n });\n },\n disconnect: () => {\n this._peers.delete(peerId);\n close();\n this.emit('peer-disconnected', {\n peerId,\n });\n },\n });\n\n invariant(this._isConnected);\n this.emit('peer-candidate', {\n peerMetadata: {},\n peerId,\n });\n });\n }\n\n async sendSyncMessage({ id, syncMessage }: SyncRepoRequest): Promise<void> {\n invariant(this._isConnected);\n const message = cbor.decode(syncMessage!) as Message;\n this.emit('message', message);\n }\n\n async getHostInfo(): Promise<HostInfo> {\n invariant(this._isConnected);\n invariant(this.peerId, 'Peer id not set.');\n return {\n peerId: this.peerId,\n };\n }\n\n private _getPeerId(id: string): PeerId {\n return id as PeerId;\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type StorageKey } from '@dxos/automerge/automerge-repo';\nimport { IndexedDBStorageAdapter } from '@dxos/automerge/automerge-repo-storage-indexeddb';\nimport { type SublevelDB } from '@dxos/kv-store';\nimport { log } from '@dxos/log';\nimport { StorageType, type Directory } from '@dxos/random-access-storage';\n\nimport { AutomergeStorageAdapter } from './automerge-storage-adapter';\nimport { encodingOptions } from './leveldb-storage-adapter';\n\nexport const levelMigration = async ({ db, directory }: { db: SublevelDB; directory: Directory }) => {\n // Note: Make auto-migration from previous storage to leveldb here.\n const isNewLevel = !(await db\n .iterator<StorageKey, Uint8Array>({\n ...encodingOptions,\n })\n .next());\n\n if (!isNewLevel) {\n return;\n }\n\n const oldStorageAdapter =\n directory.type === StorageType.IDB\n ? new IndexedDBStorageAdapter(directory.path, 'data')\n : new AutomergeStorageAdapter(directory);\n\n const chunks = await oldStorageAdapter.loadRange([]);\n if (chunks.length === 0) {\n return;\n }\n\n const batch = db.batch();\n log.info('found chunks on old storage adapter', { chunks: chunks.length });\n for (const { key, data } of await oldStorageAdapter.loadRange([])) {\n data && batch.put<StorageKey, Uint8Array>(key, data, { ...encodingOptions });\n }\n await batch.write();\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Chunk, type StorageKey, type StorageAdapterInterface } from '@dxos/automerge/automerge-repo';\nimport { type Directory } from '@dxos/random-access-storage';\nimport { arrayToBuffer, bufferToArray } from '@dxos/util';\n\nexport class AutomergeStorageAdapter implements StorageAdapterInterface {\n // TODO(mykola): Hack for restricting automerge Repo to access storage if Host is `closed`.\n // Automerge Repo do not have any lifetime management.\n private _state: 'opened' | 'closed' = 'opened';\n\n constructor(private readonly _directory: Directory) {}\n\n async load(key: StorageKey): Promise<Uint8Array | undefined> {\n if (this._state !== 'opened') {\n return undefined;\n }\n const filename = this._getFilename(key);\n const file = this._directory.getOrCreateFile(filename);\n const { size } = await file.stat();\n if (!size || size === 0) {\n return undefined;\n }\n const buffer = await file.read(0, size);\n return bufferToArray(buffer);\n }\n\n async save(key: StorageKey, data: Uint8Array): Promise<void> {\n if (this._state !== 'opened') {\n return undefined;\n }\n const filename = this._getFilename(key);\n const file = this._directory.getOrCreateFile(filename);\n await file.write(0, arrayToBuffer(data));\n await file.truncate?.(data.length);\n\n await file.flush?.();\n }\n\n async remove(key: StorageKey): Promise<void> {\n if (this._state !== 'opened') {\n return undefined;\n }\n // TODO(dmaretskyi): Better deletion.\n const filename = this._getFilename(key);\n const file = this._directory.getOrCreateFile(filename);\n await file.destroy();\n }\n\n async loadRange(keyPrefix: StorageKey): Promise<Chunk[]> {\n if (this._state !== 'opened') {\n return [];\n }\n const filename = this._getFilename(keyPrefix);\n const entries = await this._directory.list();\n return Promise.all(\n entries\n .filter((entry) => entry.startsWith(filename))\n .map(async (entry): Promise<Chunk> => {\n const file = this._directory.getOrCreateFile(entry);\n const { size } = await file.stat();\n const buffer = await file.read(0, size);\n return {\n key: this._getKeyFromFilename(entry),\n data: bufferToArray(buffer),\n };\n }),\n );\n }\n\n async removeRange(keyPrefix: StorageKey): Promise<void> {\n if (this._state !== 'opened') {\n return undefined;\n }\n const filename = this._getFilename(keyPrefix);\n const entries = await this._directory.list();\n await Promise.all(\n entries\n .filter((entry) => entry.startsWith(filename))\n .map(async (entry): Promise<void> => {\n const file = this._directory.getOrCreateFile(entry);\n await file.destroy();\n }),\n );\n }\n\n async close(): Promise<void> {\n this._state = 'closed';\n }\n\n private _getFilename(key: StorageKey): string {\n return key.map((k) => k.replaceAll('%', '%25').replaceAll('-', '%2D')).join('-');\n }\n\n private _getKeyFromFilename(filename: string): StorageKey {\n return filename.split('-').map((k) => k.replaceAll('%2D', '-').replaceAll('%25', '%'));\n }\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { Event } from '@dxos/async';\nimport { type DocHandle, type AutomergeUrl, type DocumentId, type Repo } from '@dxos/automerge/automerge-repo';\nimport { cancelWithContext, type Context } from '@dxos/context';\nimport { warnAfterTimeout } from '@dxos/debug';\nimport { type SpaceState, type SpaceDoc } from '@dxos/echo-protocol';\nimport { invariant } from '@dxos/invariant';\nimport { type PublicKey, type SpaceId } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { trace } from '@dxos/tracing';\n\ntype SpaceDocumentLinks = SpaceDoc['links'];\n\nexport interface AutomergeDocumentLoader {\n onObjectDocumentLoaded: Event<ObjectDocumentLoaded>;\n\n getAllHandles(): DocHandle<SpaceDoc>[];\n\n loadSpaceRootDocHandle(ctx: Context, spaceState: SpaceState): Promise<void>;\n loadObjectDocument(objectId: string | string[]): void;\n getSpaceRootDocHandle(): DocHandle<SpaceDoc>;\n createDocumentForObject(objectId: string): DocHandle<SpaceDoc>;\n onObjectLinksUpdated(links: SpaceDocumentLinks): void;\n onObjectBoundToDocument(handle: DocHandle<SpaceDoc>, objectId: string): void;\n\n /**\n * @returns objectIds for which we had document handles or were loading one.\n */\n clearHandleReferences(): string[];\n}\n\n/**\n * Manages object <-> docHandle binding and automerge document loading.\n */\n@trace.resource()\nexport class AutomergeDocumentLoaderImpl implements AutomergeDocumentLoader {\n private _spaceRootDocHandle: DocHandle<SpaceDoc> | null = null;\n /**\n * An object id pointer to a handle of the document where the object is stored inline.\n */\n private readonly _objectDocumentHandles = new Map<string, DocHandle<SpaceDoc>>();\n /**\n * If object was requested via loadObjectDocument but root document links weren't updated yet\n * loading will be triggered in onObjectLinksUpdated callback.\n */\n private readonly _objectsPendingDocumentLoad = new Set<string>();\n\n public readonly onObjectDocumentLoaded = new Event<ObjectDocumentLoaded>();\n\n constructor(\n private readonly _spaceId: SpaceId,\n private readonly _repo: Repo,\n /** Legacy Id */\n private readonly _spaceKey: PublicKey,\n ) {}\n\n getAllHandles(): DocHandle<SpaceDoc>[] {\n return this._spaceRootDocHandle != null\n ? [this._spaceRootDocHandle, ...new Set(this._objectDocumentHandles.values())]\n : [];\n }\n\n @trace.span({ showInBrowserTimeline: true })\n public async loadSpaceRootDocHandle(ctx: Context, spaceState: SpaceState): Promise<void> {\n if (this._spaceRootDocHandle != null) {\n return;\n }\n if (!spaceState.rootUrl) {\n log.error('Database opened with no rootUrl', { spaceId: this._spaceId });\n this._createContextBoundSpaceRootDocument(ctx);\n } else {\n const existingDocHandle = await this._initDocHandle(ctx, spaceState.rootUrl);\n const doc = existingDocHandle.docSync();\n invariant(doc);\n if (doc.access == null) {\n this._initDocAccess(existingDocHandle);\n }\n this._spaceRootDocHandle = existingDocHandle;\n }\n }\n\n public loadObjectDocument(objectIdOrMany: string | string[]) {\n const objectIds = Array.isArray(objectIdOrMany) ? objectIdOrMany : [objectIdOrMany];\n let hasUrlsToLoad = false;\n const urlsToLoad: SpaceDoc['links'] = {};\n for (const objectId of objectIds) {\n invariant(this._spaceRootDocHandle);\n if (this._objectDocumentHandles.has(objectId) || this._objectsPendingDocumentLoad.has(objectId)) {\n continue;\n }\n const spaceRootDoc = this._spaceRootDocHandle.docSync();\n invariant(spaceRootDoc);\n const documentUrl = (spaceRootDoc.links ?? {})[objectId];\n if (documentUrl == null) {\n this._objectsPendingDocumentLoad.add(objectId);\n log.info('loading delayed until object links are initialized', { objectId });\n } else {\n urlsToLoad[objectId] = documentUrl;\n hasUrlsToLoad = true;\n }\n }\n if (hasUrlsToLoad) {\n this._loadLinkedObjects(urlsToLoad);\n }\n }\n\n public onObjectLinksUpdated(links: SpaceDocumentLinks) {\n if (!links) {\n return;\n }\n const linksAwaitingLoad = Object.entries(links).filter(([objectId]) =>\n this._objectsPendingDocumentLoad.has(objectId),\n );\n this._loadLinkedObjects(Object.fromEntries(linksAwaitingLoad));\n linksAwaitingLoad.forEach(([objectId]) => this._objectsPendingDocumentLoad.delete(objectId));\n }\n\n public getSpaceRootDocHandle(): DocHandle<SpaceDoc> {\n invariant(this._spaceRootDocHandle);\n return this._spaceRootDocHandle;\n }\n\n public createDocumentForObject(objectId: string): DocHandle<SpaceDoc> {\n invariant(this._spaceRootDocHandle);\n const spaceDocHandle = this._repo.create<SpaceDoc>();\n this._initDocAccess(spaceDocHandle);\n this.onObjectBoundToDocument(spaceDocHandle, objectId);\n this._spaceRootDocHandle.change((newDoc: SpaceDoc) => {\n newDoc.links ??= {};\n newDoc.links[objectId] = spaceDocHandle.url;\n });\n return spaceDocHandle;\n }\n\n public onObjectBoundToDocument(handle: DocHandle<SpaceDoc>, objectId: string) {\n this._objectDocumentHandles.set(objectId, handle);\n }\n\n public clearHandleReferences(): string[] {\n const objectsWithHandles = [...this._objectDocumentHandles.keys()];\n this._objectDocumentHandles.clear();\n this._spaceRootDocHandle = null;\n return objectsWithHandles;\n }\n\n private _loadLinkedObjects(links: SpaceDocumentLinks) {\n if (!links) {\n return;\n }\n for (const [objectId, automergeUrl] of Object.entries(links)) {\n const logMeta = { objectId, automergeUrl };\n const objectDocumentHandle = this._objectDocumentHandles.get(objectId);\n if (objectDocumentHandle != null && objectDocumentHandle.url !== automergeUrl) {\n log.warn('object already inlined in a different document, ignoring the link', {\n ...logMeta,\n actualDocumentUrl: objectDocumentHandle.url,\n });\n continue;\n }\n if (objectDocumentHandle?.url === automergeUrl) {\n log.warn('object document was already loaded', logMeta);\n continue;\n }\n const handle = this._repo.find<SpaceDoc>(automergeUrl as DocumentId);\n log.debug('document loading triggered', logMeta);\n this._objectDocumentHandles.set(objectId, handle);\n void this._createObjectOnDocumentLoad(handle, objectId);\n }\n }\n\n private async _initDocHandle(ctx: Context, url: string) {\n const docHandle = this._repo.find<SpaceDoc>(url as DocumentId);\n while (true) {\n try {\n await warnAfterTimeout(5_000, 'Automerge root doc load timeout (CoreDatabase)', async () => {\n await cancelWithContext(ctx, docHandle.whenReady()); // TODO(dmaretskyi): Temporary 5s timeout for debugging.\n });\n break;\n } catch (err) {\n if (`${err}`.includes('Timeout')) {\n log.info('wraparound', { id: docHandle.documentId, state: docHandle.state });\n continue;\n }\n\n throw err;\n }\n }\n\n if (docHandle.state === 'unavailable') {\n throw new Error('Automerge document is unavailable');\n }\n\n return docHandle;\n }\n\n private _createContextBoundSpaceRootDocument(ctx: Context) {\n const docHandle = this._repo.create<SpaceDoc>();\n this._spaceRootDocHandle = docHandle;\n ctx.onDispose(() => {\n docHandle.delete();\n this._spaceRootDocHandle = null;\n });\n }\n\n private _initDocAccess(handle: DocHandle<SpaceDoc>) {\n handle.change((newDoc: SpaceDoc) => {\n newDoc.access ??= { spaceKey: this._spaceKey.toHex() };\n newDoc.access.spaceKey = this._spaceKey.toHex();\n });\n }\n\n private async _createObjectOnDocumentLoad(handle: DocHandle<SpaceDoc>, objectId: string) {\n try {\n await handle.doc(['ready']);\n const logMeta = { objectId, docUrl: handle.url };\n if (this.onObjectDocumentLoaded.listenerCount() === 0) {\n log.info('document loaded after all listeners were removed', logMeta);\n return;\n }\n const objectDocHandle = this._objectDocumentHandles.get(objectId);\n if (objectDocHandle?.url !== handle.url) {\n log.warn('object was rebound while a document was loading, discarding handle', logMeta);\n return;\n }\n this.onObjectDocumentLoaded.emit({ handle, objectId });\n } catch (err) {\n const shouldRetryLoading = this.onObjectDocumentLoaded.listenerCount() > 0;\n log.warn('failed to load a document', {\n objectId,\n automergeUrl: handle.url,\n retryLoading: shouldRetryLoading,\n err,\n });\n if (shouldRetryLoading) {\n await this._createObjectOnDocumentLoad(handle, objectId);\n }\n }\n }\n}\n\nexport interface ObjectDocumentLoaded {\n handle: DocHandle<SpaceDoc>;\n objectId: string;\n}\n\nexport interface DocumentChanges {\n createdObjectIds: string[];\n updatedObjectIds: string[];\n objectsToRebind: string[];\n linkedDocuments: {\n [echoId: string]: AutomergeUrl;\n };\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Message, cbor } from '@dxos/automerge/automerge-repo';\nimport { Resource } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { PublicKey } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { AutomergeReplicator } from '@dxos/teleport-extension-automerge-replicator';\nimport { ComplexMap, ComplexSet, defaultMap } from '@dxos/util';\n\nimport {\n type EchoReplicator,\n type EchoReplicatorContext,\n type ReplicatorConnection,\n type ShouldAdvertizeParams,\n} from './echo-replicator';\n\n// TODO(dmaretskyi): Move out of @dxos/echo-pipeline.\n\n/**\n * Used to replicate with other peers over the network.\n */\nexport class MeshEchoReplicator implements EchoReplicator {\n private readonly _connections = new Set<MeshReplicatorConnection>();\n /**\n * Using automerge peerId as a key.\n */\n private readonly _connectionsPerPeer = new Map<string, MeshReplicatorConnection>();\n\n /**\n * spaceKey -> deviceKey[]\n */\n private readonly _authorizedDevices = new ComplexMap<PublicKey, ComplexSet<PublicKey>>(PublicKey.hash);\n\n private _context: EchoReplicatorContext | null = null;\n\n async connect(context: EchoReplicatorContext): Promise<void> {\n this._context = context;\n }\n\n async disconnect() {\n for (const connection of this._connections) {\n await connection.close();\n }\n this._connections.clear();\n this._connectionsPerPeer.clear();\n\n this._context = null;\n }\n\n createExtension(): AutomergeReplicator {\n invariant(this._context);\n\n const connection: MeshReplicatorConnection = new MeshReplicatorConnection({\n ownPeerId: this._context.peerId,\n onRemoteConnected: async () => {\n log('onRemoteConnected', { peerId: connection.peerId });\n invariant(this._context);\n\n if (!this._connectionsPerPeer.has(connection.peerId)) {\n this._connectionsPerPeer.set(connection.peerId, connection);\n await connection.enable();\n this._context.onConnectionOpen(connection);\n }\n },\n onRemoteDisconnected: async () => {\n log('onRemoteDisconnected', { peerId: connection.peerId });\n this._context?.onConnectionClosed(connection);\n await connection.disable();\n this._connectionsPerPeer.delete(connection.peerId);\n this._connections.delete(connection);\n },\n shouldAdvertize: async (params: ShouldAdvertizeParams) => {\n log('shouldAdvertize', { peerId: connection.peerId, documentId: params.documentId });\n invariant(this._context);\n try {\n const spaceKey = await this._context.getContainingSpaceForDocument(params.documentId);\n if (!spaceKey) {\n log('space key not found for share policy check', {\n peerId: connection.peerId,\n documentId: params.documentId,\n });\n return false;\n }\n\n const authorizedDevices = this._authorizedDevices.get(spaceKey);\n\n if (!connection.remoteDeviceKey) {\n log('device key not found for share policy check', {\n peerId: connection.peerId,\n documentId: params.documentId,\n });\n return false;\n }\n\n const isAuthorized = authorizedDevices?.has(connection.remoteDeviceKey) ?? false;\n log('share policy check', {\n localPeer: this._context.peerId,\n remotePeer: connection.peerId,\n documentId: params.documentId,\n deviceKey: connection.remoteDeviceKey,\n spaceKey,\n isAuthorized,\n });\n return isAuthorized;\n } catch (err) {\n log.catch(err);\n return false;\n }\n },\n });\n this._connections.add(connection);\n\n return connection.replicatorExtension;\n }\n\n authorizeDevice(spaceKey: PublicKey, deviceKey: PublicKey) {\n log('authorizeDevice', { spaceKey, deviceKey });\n defaultMap(this._authorizedDevices, spaceKey, () => new ComplexSet(PublicKey.hash)).add(deviceKey);\n }\n}\n\ntype MeshReplicatorConnectionParams = {\n ownPeerId: string;\n onRemoteConnected: () => Promise<void>;\n onRemoteDisconnected: () => Promise<void>;\n shouldAdvertize: (params: ShouldAdvertizeParams) => Promise<boolean>;\n};\n\nclass MeshReplicatorConnection extends Resource implements ReplicatorConnection {\n public readable: ReadableStream<Message>;\n public writable: WritableStream<Message>;\n public remoteDeviceKey: PublicKey | null = null;\n\n public readonly replicatorExtension: AutomergeReplicator;\n\n private _remotePeerId: string | null = null;\n private _isEnabled = false;\n\n constructor(private readonly _params: MeshReplicatorConnectionParams) {\n super();\n\n let readableStreamController!: ReadableStreamDefaultController<Message>;\n this.readable = new ReadableStream<Message>({\n start: (controller) => {\n readableStreamController = controller;\n this._ctx.onDispose(() => controller.close());\n },\n });\n\n this.writable = new WritableStream<Message>({\n write: async (message: Message, controller) => {\n // TODO(dmaretskyi): Show we block on RPC completing here?\n this.replicatorExtension.sendSyncMessage({ payload: cbor.encode(message) }).catch((err) => {\n controller.error(err);\n });\n },\n });\n\n this.replicatorExtension = new AutomergeReplicator(\n {\n peerId: this._params.ownPeerId,\n },\n {\n onStartReplication: async (info, remotePeerId /** Teleport ID */) => {\n // Note: We store only one extension per peer.\n // There can be a case where two connected peers have more than one teleport connection between them\n // and each of them uses different teleport connections to send messages.\n // It works because we receive messages from all teleport connections and Automerge Repo dedup them.\n // TODO(mykola): Use only one teleport connection per peer.\n\n // TODO(dmaretskyi): Critical bug.\n // - two peers get connected via swarm 1\n // - they get connected via swarm 2\n // - swarm 1 gets disconnected\n // - automerge repo thinks that peer 2 got disconnected even though swarm 2 is still active\n\n this.remoteDeviceKey = remotePeerId;\n\n // Set automerge id.\n this._remotePeerId = info.id;\n\n log('onStartReplication', { id: info.id, thisPeerId: this.peerId, remotePeerId: remotePeerId.toHex() });\n\n await this._params.onRemoteConnected();\n },\n onSyncMessage: async ({ payload }) => {\n if (!this._isEnabled) {\n return;\n }\n const message = cbor.decode(payload) as Message;\n // Note: automerge Repo dedup messages.\n readableStreamController.enqueue(message);\n },\n onClose: async () => {\n if (!this._isEnabled) {\n return;\n }\n await this._params.onRemoteDisconnected();\n },\n },\n );\n }\n\n get peerId(): string {\n invariant(this._remotePeerId != null, 'Remote peer has not connected yet.');\n return this._remotePeerId;\n }\n\n async shouldAdvertize(params: ShouldAdvertizeParams): Promise<boolean> {\n return this._params.shouldAdvertize(params);\n }\n\n /**\n * Start exchanging messages with the remote peer.\n * Call after the remote peer has connected.\n */\n async enable() {\n invariant(this._remotePeerId != null, 'Remote peer has not connected yet.');\n this._isEnabled = true;\n }\n\n /**\n * Stop exchanging messages with the remote peer.\n */\n async disable() {\n this._isEnabled = false;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,SAASA,aAAa;AACtB,SAASC,QAAQC,WAAWC,YAAYC,gBAAsC;AAC9E,SACEC,YAMK;AAEP,SAASC,eAA+B;AAGxC,SAASC,aAAAA,kBAAiB;AAC1B,SAASC,iBAAiB;AAE1B,SAASC,OAAAA,YAAW;AACpB,SAASC,0BAA0B;AAQnC,SAASC,aAAa;AACtB,SAASC,iBAAiB;;;AC3B1B,SAASC,SAASC,oBAAoB;AACtC,SAAuBC,sBAAsD;AAC7E,SAASC,sBAAsB;AAC/B,SAASC,iBAAiB;AAE1B,SAASC,WAAW;;;;;;;;;;;;AAWb,IAAMC,qBAAN,cAAiCJ,eAAAA;EAStCK,YAA6BC,SAAmC;AAC9D,UAAK;SADsBA,UAAAA;SARZC,eAAe,oBAAIC,IAAAA;SAInBC,eAAe,oBAAIC,IAAAA;SAC5BC,kBAAkCV,eAAeW;SACxCC,aAAa,IAAIf,QAAAA;EAIlC;EAESgB,QAAQC,QAAgBC,cAA+C;AAC9E,SAAKD,SAASA;AACd,SAAKC,eAAeA;AACpB,SAAKH,WAAWI,KAAI;EACtB;EAESC,KAAKC,SAAwB;AACpC,UAAMC,kBAAkB,KAAKX,aAAaY,IAAIF,QAAQG,QAAQ;AAC9D,QAAI,CAACF,iBAAiB;AACpB,YAAM,IAAIG,MAAM,uBAAA;IAClB;AAGAH,oBAAgBI,OAAOC,MAAMN,OAAAA,EAASO,MAAM,CAACC,QAAAA;AAC3C,UAAIP,gBAAgBQ,QAAQ;AAC1BzB,YAAIuB,MAAMC,KAAAA,QAAAA;;;;;;MACZ;IACF,CAAA;EACF;EAESE,aAAmB;EAE5B;EAEA,MACMC,OAAO;AACX5B,cAAU,KAAKS,oBAAoBV,eAAeW,QAAM,QAAA;;;;;;;;;AACxD,SAAKD,kBAAkBV,eAAe8B;AAEtC5B,QAAI,cAAA,QAAA;;;;;;AACJ,SAAK6B,KAAK,SAAS;MACjBC,SAAS;IACX,CAAA;EACF;EAEA,MACMC,QAAQ;AACZhC,cAAU,KAAKS,oBAAoBV,eAAe8B,MAAI,QAAA;;;;;;;;;AAEtD,eAAWI,cAAc,KAAK5B,cAAc;AAC1C,YAAM4B,WAAWN,WAAU;IAC7B;AACA,SAAKtB,aAAa6B,MAAK;AAEvB,SAAKzB,kBAAkBV,eAAeW;EACxC;EAEA,MAAMyB,gBAAgB;AACpB,UAAM,KAAKxB,WAAWyB,KAAK;MAAEC,SAAS;IAAO,CAAA;EAC/C;EAEA,MACMC,cAAcL,YAA4B;AAC9CjC,cAAU,KAAKS,oBAAoBV,eAAe8B,MAAI,QAAA;;;;;;;;;AACtD7B,cAAU,KAAKa,QAAM,QAAA;;;;;;;;;AACrBb,cAAU,CAAC,KAAKK,aAAakC,IAAIN,UAAAA,GAAAA,QAAAA;;;;;;;;;AAEjC,SAAK5B,aAAamC,IAAIP,UAAAA;AACtB,UAAMA,WAAWrB,QAAQ;MACvBC,QAAQ,KAAKA;MACb4B,kBAAkB,KAAKC,kBAAkBC,KAAK,IAAI;MAClDC,oBAAoB,KAAKC,oBAAoBF,KAAK,IAAI;MACtDG,+BAA+B,KAAK1C,QAAQ0C;IAC9C,CAAA;EACF;EAEA,MACMC,iBAAiBd,YAA4B;AACjDjC,cAAU,KAAKS,oBAAoBV,eAAe8B,MAAI,QAAA;;;;;;;;;AACtD7B,cAAU,KAAKK,aAAakC,IAAIN,UAAAA,GAAAA,QAAAA;;;;;;;;;AAC/B;AACD,UAAMA,WAAWN,WAAU;AAC3B,SAAKtB,aAAa2C,OAAOf,UAAAA;EAC3B;EAEA,MAAMgB,gBAAgBpC,QAAgBqC,QAAiD;AACrF,UAAMC,aAAa,KAAK5C,aAAaY,IAAIN,MAAAA;AACzC,QAAI,CAACsC,YAAY;AACf,aAAO;IACT;AAEA,WAAOA,WAAWA,WAAWF,gBAAgBC,MAAAA;EAC/C;EAEQR,kBAAkBS,YAAkC;AAC1DlD,QAAI,qBAAqB;MAAEY,QAAQsC,WAAWtC;IAAO,GAAA;;;;;;AACrDb,cAAU,CAAC,KAAKO,aAAagC,IAAIY,WAAWtC,MAAM,GAAA,QAAA;;;;;;;;;AAClD,UAAMuC,SAASD,WAAWE,SAASC,UAAS;AAC5C,UAAMhC,SAAS6B,WAAWI,SAASC,UAAS;AAC5C,UAAMtC,kBAAmC;MAAEiC;MAAYC;MAAQ9B;MAAQI,QAAQ;IAAK;AACpF,SAAKnB,aAAakD,IAAIN,WAAWtC,QAAkBK,eAAAA;AAEnDwC,mBAAe,YAAA;AACb,UAAI;AACF,eAAO,MAAM;AAEX,gBAAM,EAAEC,MAAMC,MAAK,IAAK,MAAMR,OAAOS,KAAI;AACzC,cAAIF,MAAM;AACR;UACF;AAEA,eAAK7B,KAAK,WAAW8B,KAAAA;QACvB;MACF,SAASnC,KAAK;AACZ,YAAIP,gBAAgBQ,QAAQ;AAC1BzB,cAAIuB,MAAMC,KAAAA,QAAAA;;;;;;QACZ;MACF;IACF,CAAA;AAEAxB,QAAI,uBAAuB;MAAEY,QAAQsC,WAAWtC;IAAO,GAAA;;;;;;AACvD,SAAKiB,KAAK,kBAAkB;MAC1BjB,QAAQsC,WAAWtC;MACnBC,cAAc;;QAEZgD,iBAAiB;MACnB;IACF,CAAA;EACF;EAEQjB,oBAAoBM,YAAkC;AAC5DlD,QAAI,qBAAqB;MAAEY,QAAQsC,WAAWtC;IAAO,GAAA;;;;;;AACrD,UAAMkD,QAAQ,KAAKxD,aAAaY,IAAIgC,WAAWtC,MAAM;AACrDb,cAAU+D,OAAAA,QAAAA;;;;;;;;;AAEVA,UAAMrC,SAAS;AACf,SAAKI,KAAK,qBAAqB;MAAEjB,QAAQsC,WAAWtC;IAAiB,CAAA;AAErE,SAAKkD,MAAMX,OAAOY,OAAM,EAAGxC,MAAM,CAACC,QAAQxB,IAAIuB,MAAMC,KAAAA,QAAAA;;;;;;AACpD,SAAKsC,MAAMzC,OAAO2C,MAAK,EAAGzC,MAAM,CAACC,QAAQxB,IAAIuB,MAAMC,KAAAA,QAAAA;;;;;;AAEnD,SAAKlB,aAAayC,OAAOG,WAAWtC,MAAM;EAC5C;AACF;;EA7GGhB;GArCUK,mBAAAA,WAAAA,QAAAA,IAAAA;;EAgDVL;GAhDUK,mBAAAA,WAAAA,SAAAA,IAAAA;;EAgEVL;GAhEUK,mBAAAA,WAAAA,iBAAAA,IAAAA;;EA+EVL;GA/EUK,mBAAAA,WAAAA,oBAAAA,IAAAA;;;ACbb,SAASgE,kBAAAA,iBAAgBC,gBAAgB;AAgBlC,IAAMC,wBAAN,cAAoCC,SAAAA;EACzCC,YAA6BC,SAAsC;AACjE,UAAK;SADsBA,UAAAA;EAE7B;EAEA,MAAMC,KAAKC,UAAuD;AAChE,QAAI;AACF,UAAI,KAAKC,oBAAoBC,gBAAeC,MAAM;AAEhD,eAAOC;MACT;AACA,aAAO,MAAM,KAAKN,QAAQO,GAAGC,IAA4BN,UAAU;QAAE,GAAGO;MAAgB,CAAA;IAC1F,SAASC,KAAU;AACjB,UAAIC,uBAAuBD,GAAAA,GAAM;AAC/B,eAAOJ;MACT;AACA,YAAMI;IACR;EACF;EAEA,MAAME,KAAKV,UAAsBW,QAAmC;AAClE,QAAI,KAAKV,oBAAoBC,gBAAeC,MAAM;AAChD,aAAOC;IACT;AACA,UAAMQ,QAAQ,KAAKd,QAAQO,GAAGO,MAAK;AAEnC,UAAM,KAAKd,QAAQe,WAAWC,aAAa;MAAEC,MAAMf;MAAUY;IAAM,CAAA;AACnEA,UAAMI,IAA4BhB,UAAUiB,OAAOC,KAAKP,MAAAA,GAAS;MAC/D,GAAGJ;IACL,CAAA;AACA,UAAMK,MAAMO,MAAK;AAEjB,UAAM,KAAKrB,QAAQe,WAAWO,YAAYpB,QAAAA;EAC5C;EAEA,MAAMqB,OAAOrB,UAAqC;AAChD,QAAI,KAAKC,oBAAoBC,gBAAeC,MAAM;AAChD,aAAOC;IACT;AACA,UAAM,KAAKN,QAAQO,GAAGiB,IAAgBtB,UAAU;MAAE,GAAGO;IAAgB,CAAA;EACvE;EAEA,MAAMgB,UAAUC,WAAyC;AACvD,QAAI,KAAKvB,oBAAoBC,gBAAeC,MAAM;AAChD,aAAO,CAAA;IACT;AACA,UAAMsB,SAAkB,CAAA;AACxB,qBAAiB,CAACC,KAAKC,KAAAA,KAAU,KAAK7B,QAAQO,GAAGuB,SAAiC;MAChFC,KAAKL;MACLM,KAAK;WAAIN;QAAW;;MACpB,GAAGjB;IACL,CAAA,GAAI;AACFkB,aAAOM,KAAK;QACVL;QACAM,MAAML;MACR,CAAA;IACF;AACA,WAAOF;EACT;EAEA,MAAMQ,YAAYT,WAAsC;AACtD,QAAI,KAAKvB,oBAAoBC,gBAAeC,MAAM;AAChD,aAAOC;IACT;AACA,UAAMQ,QAAQ,KAAKd,QAAQO,GAAGO,MAAK;AAEnC,qBAAiB,CAACc,GAAAA,KAAQ,KAAK5B,QAAQO,GAAGuB,SAAiC;MACzEC,KAAKL;MACLM,KAAK;WAAIN;QAAW;;MACpB,GAAGjB;IACL,CAAA,GAAI;AACFK,YAAMU,IAAgBI,KAAK;QAAE,GAAGnB;MAAgB,CAAA;IAClD;AACA,UAAMK,MAAMO,MAAK;EACnB;AACF;AAEA,IAAMe,aAAgE;EACpEC,QAAQ,CAACT,QACPT,OAAOC,KAAKQ,IAAIU,IAAI,CAACC,MAAMA,EAAEC,WAAW,KAAK,KAAA,EAAOA,WAAW,KAAK,KAAA,CAAA,EAAQC,KAAK,GAAA,CAAA;EACnFC,QAAQ,CAACd,QACPT,OAAOC,KAAKQ,GAAAA,EACTe,SAAQ,EACRC,MAAM,GAAA,EACNN,IAAI,CAACC,MAAMA,EAAEC,WAAW,OAAO,GAAA,EAAKA,WAAW,OAAO,GAAA,CAAA;EAC3DK,QAAQ;AACV;AAEO,IAAMpC,kBAAkB;EAC7BqC,aAAaV;EACbW,eAAe;AACjB;AAEA,IAAMpC,yBAAyB,CAACD,QAAsBA,IAAIsC,SAAS;;;AChHnE,SAASC,WAAAA,gBAAe;AACxB,SAASC,kBAAAA,iBAA2CC,YAAY;AAChE,SAASC,cAAc;AACvB,SAASC,aAAAA,kBAAiB;;AAYnB,IAAMC,0BAAN,cAAsCJ,gBAAAA;EAAtC;;AACYK,kBAAuC,oBAAIC,IAAAA;AAa3CC,sBAAa,IAAIR,SAAAA;AAC1BS,wBAAwB;;;;;EAThCC,QAAQ;AAGN,SAAKC,KAAK,SAAS;MACjBC,SAAS;IACX,CAAA;EACF;;;;;;EAUSC,QAAQC,QAAsB;AACrC,SAAKA,SAASA;AACd,SAAKL,eAAe;AACpB,SAAKD,WAAWO,KAAI;EAEtB;EAESC,KAAKC,SAAwB;AACpC,UAAMC,OAAO,KAAKZ,OAAOa,IAAIF,QAAQG,QAAQ;AAC7ChB,IAAAA,WAAUc,MAAM,mBAAA;;;;;;;;;AAChBA,SAAKF,KAAKC,OAAAA;EACZ;EAEA,MAAMI,QAAQ;AACZ,SAAKf,OAAOgB,QAAQ,CAACJ,SAASA,KAAKK,WAAU,CAAA;AAC7C,SAAKZ,KAAK,OAAA;EACZ;EAESY,aAAmB;EAG5B;EAEA,MAAMC,gBAA+B;AACnC,UAAM,KAAKhB,WAAWiB,KAAK;MAAEC,SAAS;IAAO,CAAA;EAC/C;EAEAC,SAAS,EAAEC,IAAIC,YAAW,GAA+C;AACvE,UAAMf,SAAS,KAAKgB,WAAWF,EAAAA;AAE/B,WAAO,IAAIzB,OAAO,CAAC,EAAE4B,MAAMV,MAAK,MAAE;AAChCjB,MAAAA,WAAU,CAAC,KAAKE,OAAO0B,IAAIlB,MAAAA,GAAS,2BAAA;;;;;;;;;AACpC,WAAKR,OAAO2B,IAAInB,QAAQ;QACtBoB,WAAW;QACXlB,MAAM,CAACC,YAAAA;AACLc,eAAK;YACHF,aAAa3B,KAAKiC,OAAOlB,OAAAA;UAC3B,CAAA;QACF;QACAM,YAAY,MAAA;AACV,eAAKjB,OAAO8B,OAAOtB,MAAAA;AACnBO,gBAAAA;AACA,eAAKV,KAAK,qBAAqB;YAC7BG;UACF,CAAA;QACF;MACF,CAAA;AAEAV,MAAAA,WAAU,KAAKK,cAAY,QAAA;;;;;;;;;AAC3B,WAAKE,KAAK,kBAAkB;QAC1B0B,cAAc,CAAC;QACfvB;MACF,CAAA;IACF,CAAA;EACF;EAEA,MAAMwB,gBAAgB,EAAEV,IAAIC,YAAW,GAAoC;AACzEzB,IAAAA,WAAU,KAAKK,cAAY,QAAA;;;;;;;;;AAC3B,UAAMQ,UAAUf,KAAKqC,OAAOV,WAAAA;AAC5B,SAAKlB,KAAK,WAAWM,OAAAA;EACvB;EAEA,MAAMuB,cAAiC;AACrCpC,IAAAA,WAAU,KAAKK,cAAY,QAAA;;;;;;;;;AAC3BL,IAAAA,WAAU,KAAKU,QAAQ,oBAAA;;;;;;;;;AACvB,WAAO;MACLA,QAAQ,KAAKA;IACf;EACF;EAEQgB,WAAWF,IAAoB;AACrC,WAAOA;EACT;AACF;;;AC7GA,SAASa,+BAA+B;AAExC,SAASC,OAAAA,YAAW;AACpB,SAASC,mBAAmC;;;ACC5C,SAASC,eAAeC,qBAAqB;AAEtC,IAAMC,0BAAN,MAAMA;EAKXC,YAA6BC,YAAuB;SAAvBA,aAAAA;SAFrBC,SAA8B;EAEe;EAErD,MAAMC,KAAKC,KAAkD;AAC3D,QAAI,KAAKF,WAAW,UAAU;AAC5B,aAAOG;IACT;AACA,UAAMC,WAAW,KAAKC,aAAaH,GAAAA;AACnC,UAAMI,OAAO,KAAKP,WAAWQ,gBAAgBH,QAAAA;AAC7C,UAAM,EAAEI,KAAI,IAAK,MAAMF,KAAKG,KAAI;AAChC,QAAI,CAACD,QAAQA,SAAS,GAAG;AACvB,aAAOL;IACT;AACA,UAAMO,SAAS,MAAMJ,KAAKK,KAAK,GAAGH,IAAAA;AAClC,WAAOI,cAAcF,MAAAA;EACvB;EAEA,MAAMG,KAAKX,KAAiBY,MAAiC;AAC3D,QAAI,KAAKd,WAAW,UAAU;AAC5B,aAAOG;IACT;AACA,UAAMC,WAAW,KAAKC,aAAaH,GAAAA;AACnC,UAAMI,OAAO,KAAKP,WAAWQ,gBAAgBH,QAAAA;AAC7C,UAAME,KAAKS,MAAM,GAAGC,cAAcF,IAAAA,CAAAA;AAClC,UAAMR,KAAKW,WAAWH,KAAKI,MAAM;AAEjC,UAAMZ,KAAKa,QAAK;EAClB;EAEA,MAAMC,OAAOlB,KAAgC;AAC3C,QAAI,KAAKF,WAAW,UAAU;AAC5B,aAAOG;IACT;AAEA,UAAMC,WAAW,KAAKC,aAAaH,GAAAA;AACnC,UAAMI,OAAO,KAAKP,WAAWQ,gBAAgBH,QAAAA;AAC7C,UAAME,KAAKe,QAAO;EACpB;EAEA,MAAMC,UAAUC,WAAyC;AACvD,QAAI,KAAKvB,WAAW,UAAU;AAC5B,aAAO,CAAA;IACT;AACA,UAAMI,WAAW,KAAKC,aAAakB,SAAAA;AACnC,UAAMC,UAAU,MAAM,KAAKzB,WAAW0B,KAAI;AAC1C,WAAOC,QAAQC,IACbH,QACGI,OAAO,CAACC,UAAUA,MAAMC,WAAW1B,QAAAA,CAAAA,EACnC2B,IAAI,OAAOF,UAAAA;AACV,YAAMvB,OAAO,KAAKP,WAAWQ,gBAAgBsB,KAAAA;AAC7C,YAAM,EAAErB,KAAI,IAAK,MAAMF,KAAKG,KAAI;AAChC,YAAMC,SAAS,MAAMJ,KAAKK,KAAK,GAAGH,IAAAA;AAClC,aAAO;QACLN,KAAK,KAAK8B,oBAAoBH,KAAAA;QAC9Bf,MAAMF,cAAcF,MAAAA;MACtB;IACF,CAAA,CAAA;EAEN;EAEA,MAAMuB,YAAYV,WAAsC;AACtD,QAAI,KAAKvB,WAAW,UAAU;AAC5B,aAAOG;IACT;AACA,UAAMC,WAAW,KAAKC,aAAakB,SAAAA;AACnC,UAAMC,UAAU,MAAM,KAAKzB,WAAW0B,KAAI;AAC1C,UAAMC,QAAQC,IACZH,QACGI,OAAO,CAACC,UAAUA,MAAMC,WAAW1B,QAAAA,CAAAA,EACnC2B,IAAI,OAAOF,UAAAA;AACV,YAAMvB,OAAO,KAAKP,WAAWQ,gBAAgBsB,KAAAA;AAC7C,YAAMvB,KAAKe,QAAO;IACpB,CAAA,CAAA;EAEN;EAEA,MAAMa,QAAuB;AAC3B,SAAKlC,SAAS;EAChB;EAEQK,aAAaH,KAAyB;AAC5C,WAAOA,IAAI6B,IAAI,CAACI,MAAMA,EAAEC,WAAW,KAAK,KAAA,EAAOA,WAAW,KAAK,KAAA,CAAA,EAAQC,KAAK,GAAA;EAC9E;EAEQL,oBAAoB5B,UAA8B;AACxD,WAAOA,SAASkC,MAAM,GAAA,EAAKP,IAAI,CAACI,MAAMA,EAAEC,WAAW,OAAO,GAAA,EAAKA,WAAW,OAAO,GAAA,CAAA;EACnF;AACF;;;;ADzFO,IAAMG,iBAAiB,OAAO,EAAEC,IAAIC,UAAS,MAA4C;AAE9F,QAAMC,aAAa,CAAE,MAAMF,GACxBG,SAAiC;IAChC,GAAGC;EACL,CAAA,EACCC,KAAI;AAEP,MAAI,CAACH,YAAY;AACf;EACF;AAEA,QAAMI,oBACJL,UAAUM,SAASC,YAAYC,MAC3B,IAAIC,wBAAwBT,UAAUU,MAAM,MAAA,IAC5C,IAAIC,wBAAwBX,SAAAA;AAElC,QAAMY,SAAS,MAAMP,kBAAkBQ,UAAU,CAAA,CAAE;AACnD,MAAID,OAAOE,WAAW,GAAG;AACvB;EACF;AAEA,QAAMC,QAAQhB,GAAGgB,MAAK;AACtBC,EAAAA,KAAIC,KAAK,uCAAuC;IAAEL,QAAQA,OAAOE;EAAO,GAAA;;;;;;AACxE,aAAW,EAAEI,KAAKC,KAAI,KAAM,MAAMd,kBAAkBQ,UAAU,CAAA,CAAE,GAAG;AACjEM,YAAQJ,MAAMK,IAA4BF,KAAKC,MAAM;MAAE,GAAGhB;IAAgB,CAAA;EAC5E;AACA,QAAMY,MAAMM,MAAK;AACnB;;;;;;;;;;;;;;AJYO,IAAMC,gBAAN,MAAMA;EAkBXC,YAAY,EAAEC,WAAWC,IAAIC,mBAAkB,GAAyB;AAhBvDC,gBAAO,IAAIC,QAAAA;AAGXC,+BAAsB,IAAIC,mBAAmB;MAC5DC,+BAA+B,KAAKC,+BAA+BC,KAAK,IAAI;IAC9E,CAAA;AASOC,0BAAiB,oBAAIC,IAAAA;AAG1B,SAAKC,aAAaZ;AAClB,SAAKa,MAAMZ;AACX,SAAKa,sBAAsBZ;EAC7B;EAEA,MAAMa,OAAO;AAEX,SAAKC,UAAU,QAAQC,UAAUC,OAAM,EAAGC,MAAK,CAAA;AAG/C,SAAKP,cAAe,MAAMQ,eAAe;MAAEnB,IAAI,KAAKY;MAAKb,WAAW,KAAKY;IAAW,CAAA;AACpF,SAAKS,WAAW,IAAIC,sBAAsB;MACxCrB,IAAI,KAAKY;MACTU,WAAW;QACTC,YAAY,OAAOC,WAAW,KAAKC,YAAYD,MAAAA;QAC/CE,WAAW,YAAY,KAAKC,WAAU;MACxC;IACF,CAAA;AACA,UAAM,KAAKP,SAASN,OAAI;AAExB,SAAKc,iBAAiB,IAAIC,wBAAAA;AAG1B,SAAKC,QAAQ,IAAIC,KAAK;MACpBC,QAAQ,KAAKjB;MACbkB,aAAa,KAAKC,aAAa1B,KAAK,IAAI;MACxC2B,SAAS,KAAKf;MACdgB,SAAS;;QAEP,KAAKR;;QAEL,KAAKxB;;IAET,CAAA;AAEA,SAAKwB,eAAeS,MAAK;AACzB,UAAM,KAAKjC,oBAAoBU,KAAI;AACnC,UAAM,KAAKc,eAAeU,cAAa;AACvC,UAAM,KAAKlC,oBAAoBkC,cAAa;EAC9C;EAEA,MAAMC,QAAQ;AACZ,UAAM,KAAKnB,SAASmB,QAAK;AACzB,UAAM,KAAKX,eAAeW,MAAK;AAC/B,UAAM,KAAKnC,oBAAoBmC,MAAK;AACpC,UAAM,KAAKrC,KAAKsC,QAAO;EACzB;EAEA,IAAIC,OAAa;AACf,WAAO,KAAKX;EACd;EAEA,MAAMY,cAAcC,YAA4B;AAC9C,UAAM,KAAKvC,oBAAoBsC,cAAcC,UAAAA;EAC/C;EAEA,MAAMC,iBAAiBD,YAA4B;AACjD,UAAM,KAAKvC,oBAAoBwC,iBAAiBD,UAAAA;EAClD;;;;;EAMA,MAAcT,aACZF,QACAa,YACkB;AAClB,QAAIb,OAAOc,WAAW,SAAA,GAAY;AAChC,aAAO;IACT;AAEA,QAAI,CAACD,YAAY;AACf,aAAO;IACT;AAIA,UAAME,MAAM,KAAKjB,MAAMkB,QAAQH,UAAAA,GAAaI,QAAAA;AAC5C,QAAI,CAACF,KAAK;AAGR,YAAMG,cAAc,KAAKzC,eAAe0C,IAAI,aAAaN,UAAAA,EAAY;AACrEO,MAAAA,KAAI,0BAA0B;QAAEpB;QAAQa;QAAYK;MAAY,GAAA;;;;;;AAChE,aAAOA;IACT;AAEA,UAAMG,eAAe,KAAKZ,KAAKa,qBAAqBtB,MAAAA;AACpD,QAAKqB,cAAsBE,oBAAoB,sBAAsB;AACnE,aAAO,KAAKnD,oBAAoBoD,gBAAgBxB,QAAQ;QAAEa;MAAW,CAAA;IACvE;AAEA,WAAO;EACT;EAEA,MAAcpB,YAAY,EAAEgC,MAAMC,MAAK,GAAsB;AAC3D,UAAMC,SAAS,KAAK7B,MAAMkB,QAAQS,KAAK,CAAA,CAAE;AACzC,QAAI,CAACE,QAAQ;AACX;IACF;AACA,UAAMZ,MAAMY,OAAOV,QAAO;AAC1B,QAAI,CAACF,KAAK;AACR;IACF;AAEA,UAAMa,WAAWC,mBAAmBd,GAAAA,KAAQe;AAE5C,UAAMC,oBAAoBC,SAASjB,GAAAA;AAEnC,UAAMkB,YAAYC,OAAOC,KAAKpB,IAAIqB,WAAW,CAAC,CAAA;AAC9C,UAAMC,aAAaJ,UAAUK,IAAI,CAACC,aAChCC,mBAAmBC,OAAO;MAAE5B,YAAYc,OAAOd;MAAY0B;MAAUX;IAAS,CAAA,CAAA;AAEhF,UAAMc,eAAe,IAAIC,IAAIN,WAAWC,IAAI,CAACM,OAAO;MAACA;MAAIb;KAAkB,CAAA;AAC3E,SAAKlD,oBAAoBgE,UAAUH,cAAchB,KAAAA;EACnD;;;;EAKA,MAAc/B,aAAa;AACzB,SAAKd,oBAAoBiE,kBAAiB;EAC5C;EAGQC,iBAAiB;AACvB,WAAOC,UAAU,KAAKlD,MAAMkB,SAAS,CAACW,YAAY;MAChDsB,OAAOtB,OAAOsB;MACdC,QAAQ,CAAC,CAACvB,OAAOV,QAAO;MACxBkC,OAAOxB,OAAOV,QAAO,IAAKmC,UAAUpB,SAASL,OAAOV,QAAO,CAAA,IAAM;MACjEoC,MACE1B,OAAOV,QAAO,KACd+B,UAAUrB,OAAOV,QAAO,GAAI,CAACqC,OAAOC,QAAAA;AAClC,YAAI;AACF,kBAAQA,KAAAA;YACN,KAAK;YACL,KAAK;AACH,qBAAOD;YACT,KAAK;AACH,qBAAOpB,OAAOC,KAAKmB,KAAAA;YACrB;AACE,qBAAO,GAAGA,KAAAA;UACd;QACF,SAASE,KAAK;AACZ,iBAAO,GAAGA,GAAAA;QACZ;MACF,CAAA;IACJ,EAAA;EACF;EAGQC,kBAAkB;AACxB,WAAO,KAAK3D,MAAM4D;EACpB;EAEA,MAAcnF,+BAA+BsC,YAA+C;AAC1F,UAAME,MAAM,KAAKjB,MAAMkB,QAAQH,UAAAA,GAAoBI,QAAAA;AACnD,QAAI,CAACF,KAAK;AACR,aAAO;IACT;AAEA,UAAM4C,cAAc9B,mBAAmBd,GAAAA;AACvC,QAAI,CAAC4C,aAAa;AAChB,aAAO;IACT;AAEA,WAAO3E,UAAU4E,KAAKD,WAAAA;EACxB;;;;EAKA,MACME,MAAM,EAAEC,OAAM,GAAiC;AAEnD,UAAMC,QAAQC,IACZF,QAAQxB,IAAI,OAAO,EAAEa,OAAOtC,WAAU,MAAE;AACtCoD,MAAAA,WAAUd,OAAO,gCAAA;;;;;;;;;AACjB,YAAMxB,SAAS,KAAKlB,KAAKO,QAAQH,UAAAA,KAA6B,KAAKf,MAAMoE,KAAKrD,UAAAA;AAC9E,YAAMsD,aAAaxC,QAAQwB,KAAAA;IAC7B,CAAA,KAAM,CAAA,CAAE;AAGV,UAAM,KAAKrD,MAAM+D,MAAMC,QAAQxB,IAAI,CAAC,EAAEzB,WAAU,MAAOA,UAAAA,CAAAA;EACzD;EAEAuD,SAASC,SAAoD;AAC3D,WAAO,KAAKzE,eAAewE,SAASC,OAAAA;EACtC;EAEAC,gBAAgBD,SAAyC;AACvD,WAAO,KAAKzE,eAAe0E,gBAAgBD,OAAAA;EAC7C;EAEA,MAAME,cAAiC;AACrC,WAAO,KAAK3E,eAAe2E,YAAW;EACxC;AACF;;EA3MGC,MAAMC,KAAI;GAbA5G,cAAAA,WAAAA,WAAAA,MAAAA;;EA+IV2G,MAAMC,KAAK;IAAEC,OAAO;EAAK,CAAA;GA/If7G,cAAAA,WAAAA,kBAAAA,IAAAA;;EAyKV2G,MAAMC,KAAK;IAAEC,OAAO;EAAK,CAAA;GAzKf7G,cAAAA,WAAAA,mBAAAA,IAAAA;;EA+LV2G,MAAMG,KAAK;IAAEC,uBAAuB;EAAK,CAAA;GA/L/B/G,cAAAA,WAAAA,SAAAA,IAAAA;AAAAA,gBAAAA,cAAAA;EADZ2G,MAAMK,SAAQ;GACFhH,aAAAA;AA0NN,IAAMgE,qBAAqB,CAACd,QAAAA;AAEjC,QAAM+D,cAAc/D,IAAIgE,QAAQnD,YAAYb,IAAIiE;AAChD,MAAIF,eAAe,MAAM;AACvB,WAAO;EACT;AAEA,SAAOG,OAAOH,WAAAA;AAChB;AAEA,IAAMX,eAAe,OAAOxC,QAA6BwB,UAAAA;AACvD,QAAMxB,OAAOuD,UAAS;AACtB,QAAMC,mBAAmB,IAAIzG,IAAIyE,KAAAA;AAEjC,QAAMiC,MAAMC,KAAuC1D,QAAQ,QAAA,EAAU2D,iBAAiB,MAAA;AAEpF,eAAWC,cAAcJ,iBAAiBK,OAAM,GAAI;AAClD,UAAIC,qBAAqB9D,OAAOV,QAAO,GAAIsE,UAAAA,GAAa;AACtDJ,yBAAiBO,OAAOH,UAAAA;MAC1B;IACF;AAEA,QAAIJ,iBAAiBQ,SAAS,GAAG;AAC/B,aAAO;IACT;AACA,WAAO;EACT,CAAA;AACF;AAEA,IAAMF,uBAAuB,CAAC1E,KAAewE,eAAAA;AAC3C,SAAO,CAAC,CAACK,WAAW7E,GAAAA,EAAK8E,gBAAgBN,UAAAA;AAC3C;;;AM1SA,SAASO,SAAAA,cAAa;AAEtB,SAASC,yBAAuC;AAChD,SAASC,wBAAwB;AAEjC,SAASC,aAAAA,kBAAiB;AAE1B,SAASC,OAAAA,YAAW;AACpB,SAASC,SAAAA,cAAa;;;;;;;;;;;;AA0Bf,IAAMC,8BAAN,MAAMA;EAcXC,YACmBC,UACAC,OAEAC,WACjB;SAJiBF,WAAAA;SACAC,QAAAA;SAEAC,YAAAA;SAjBXC,sBAAkD;SAIzCC,yBAAyB,oBAAIC,IAAAA;SAK7BC,8BAA8B,oBAAIC,IAAAA;SAEnCC,yBAAyB,IAAIhB,OAAAA;EAO1C;EAEHiB,gBAAuC;AACrC,WAAO,KAAKN,uBAAuB,OAC/B;MAAC,KAAKA;SAAwB,IAAII,IAAI,KAAKH,uBAAuBM,OAAM,CAAA;QACxE,CAAA;EACN;EAEA,MACaC,uBAAuBC,KAAcC,YAAuC;AACvF,QAAI,KAAKV,uBAAuB,MAAM;AACpC;IACF;AACA,QAAI,CAACU,WAAWC,SAAS;AACvBlB,MAAAA,KAAImB,MAAM,mCAAmC;QAAEC,SAAS,KAAKhB;MAAS,GAAA;;;;;;AACtE,WAAKiB,qCAAqCL,GAAAA;IAC5C,OAAO;AACL,YAAMM,oBAAoB,MAAM,KAAKC,eAAeP,KAAKC,WAAWC,OAAO;AAC3E,YAAMM,MAAMF,kBAAkBG,QAAO;AACrC1B,MAAAA,WAAUyB,KAAAA,QAAAA;;;;;;;;;AACV,UAAIA,IAAIE,UAAU,MAAM;AACtB,aAAKC,eAAeL,iBAAAA;MACtB;AACA,WAAKf,sBAAsBe;IAC7B;EACF;EAEOM,mBAAmBC,gBAAmC;AAC3D,UAAMC,YAAYC,MAAMC,QAAQH,cAAAA,IAAkBA,iBAAiB;MAACA;;AACpE,QAAII,gBAAgB;AACpB,UAAMC,aAAgC,CAAC;AACvC,eAAWC,YAAYL,WAAW;AAChC/B,MAAAA,WAAU,KAAKQ,qBAAmB,QAAA;;;;;;;;;AAClC,UAAI,KAAKC,uBAAuB4B,IAAID,QAAAA,KAAa,KAAKzB,4BAA4B0B,IAAID,QAAAA,GAAW;AAC/F;MACF;AACA,YAAME,eAAe,KAAK9B,oBAAoBkB,QAAO;AACrD1B,MAAAA,WAAUsC,cAAAA,QAAAA;;;;;;;;;AACV,YAAMC,eAAeD,aAAaE,SAAS,CAAC,GAAGJ,QAAAA;AAC/C,UAAIG,eAAe,MAAM;AACvB,aAAK5B,4BAA4B8B,IAAIL,QAAAA;AACrCnC,QAAAA,KAAIyC,KAAK,sDAAsD;UAAEN;QAAS,GAAA;;;;;;MAC5E,OAAO;AACLD,mBAAWC,QAAAA,IAAYG;AACvBL,wBAAgB;MAClB;IACF;AACA,QAAIA,eAAe;AACjB,WAAKS,mBAAmBR,UAAAA;IAC1B;EACF;EAEOS,qBAAqBJ,OAA2B;AACrD,QAAI,CAACA,OAAO;AACV;IACF;AACA,UAAMK,oBAAoBC,OAAOC,QAAQP,KAAAA,EAAOQ,OAAO,CAAC,CAACZ,QAAAA,MACvD,KAAKzB,4BAA4B0B,IAAID,QAAAA,CAAAA;AAEvC,SAAKO,mBAAmBG,OAAOG,YAAYJ,iBAAAA,CAAAA;AAC3CA,sBAAkBK,QAAQ,CAAC,CAACd,QAAAA,MAAc,KAAKzB,4BAA4BwC,OAAOf,QAAAA,CAAAA;EACpF;EAEOgB,wBAA6C;AAClDpD,IAAAA,WAAU,KAAKQ,qBAAmB,QAAA;;;;;;;;;AAClC,WAAO,KAAKA;EACd;EAEO6C,wBAAwBjB,UAAuC;AACpEpC,IAAAA,WAAU,KAAKQ,qBAAmB,QAAA;;;;;;;;;AAClC,UAAM8C,iBAAiB,KAAKhD,MAAMiD,OAAM;AACxC,SAAK3B,eAAe0B,cAAAA;AACpB,SAAKE,wBAAwBF,gBAAgBlB,QAAAA;AAC7C,SAAK5B,oBAAoBiD,OAAO,CAACC,WAAAA;AAC/BA,aAAOlB,UAAU,CAAC;AAClBkB,aAAOlB,MAAMJ,QAAAA,IAAYkB,eAAeK;IAC1C,CAAA;AACA,WAAOL;EACT;EAEOE,wBAAwBI,QAA6BxB,UAAkB;AAC5E,SAAK3B,uBAAuBoD,IAAIzB,UAAUwB,MAAAA;EAC5C;EAEOE,wBAAkC;AACvC,UAAMC,qBAAqB;SAAI,KAAKtD,uBAAuBuD,KAAI;;AAC/D,SAAKvD,uBAAuBwD,MAAK;AACjC,SAAKzD,sBAAsB;AAC3B,WAAOuD;EACT;EAEQpB,mBAAmBH,OAA2B;AACpD,QAAI,CAACA,OAAO;AACV;IACF;AACA,eAAW,CAACJ,UAAU8B,YAAAA,KAAiBpB,OAAOC,QAAQP,KAAAA,GAAQ;AAC5D,YAAM2B,UAAU;QAAE/B;QAAU8B;MAAa;AACzC,YAAME,uBAAuB,KAAK3D,uBAAuB4D,IAAIjC,QAAAA;AAC7D,UAAIgC,wBAAwB,QAAQA,qBAAqBT,QAAQO,cAAc;AAC7EjE,QAAAA,KAAIqE,KAAK,qEAAqE;UAC5E,GAAGH;UACHI,mBAAmBH,qBAAqBT;QAC1C,GAAA;;;;;;AACA;MACF;AACA,UAAIS,sBAAsBT,QAAQO,cAAc;AAC9CjE,QAAAA,KAAIqE,KAAK,sCAAsCH,SAAAA;;;;;;AAC/C;MACF;AACA,YAAMP,SAAS,KAAKtD,MAAMkE,KAAeN,YAAAA;AACzCjE,MAAAA,KAAIwE,MAAM,8BAA8BN,SAAAA;;;;;;AACxC,WAAK1D,uBAAuBoD,IAAIzB,UAAUwB,MAAAA;AAC1C,WAAK,KAAKc,4BAA4Bd,QAAQxB,QAAAA;IAChD;EACF;EAEA,MAAcZ,eAAeP,KAAc0C,KAAa;AACtD,UAAMgB,YAAY,KAAKrE,MAAMkE,KAAeb,GAAAA;AAC5C,WAAO,MAAM;AACX,UAAI;AACF,cAAM5D,iBAAiB,KAAO,kDAAkD,YAAA;AAC9E,gBAAMD,kBAAkBmB,KAAK0D,UAAUC,UAAS,CAAA;QAClD,CAAA;AACA;MACF,SAASC,KAAK;AACZ,YAAI,GAAGA,GAAAA,GAAMC,SAAS,SAAA,GAAY;AAChC7E,UAAAA,KAAIyC,KAAK,cAAc;YAAEqC,IAAIJ,UAAUK;YAAYC,OAAON,UAAUM;UAAM,GAAA;;;;;;AAC1E;QACF;AAEA,cAAMJ;MACR;IACF;AAEA,QAAIF,UAAUM,UAAU,eAAe;AACrC,YAAM,IAAIC,MAAM,mCAAA;IAClB;AAEA,WAAOP;EACT;EAEQrD,qCAAqCL,KAAc;AACzD,UAAM0D,YAAY,KAAKrE,MAAMiD,OAAM;AACnC,SAAK/C,sBAAsBmE;AAC3B1D,QAAIkE,UAAU,MAAA;AACZR,gBAAUxB,OAAM;AAChB,WAAK3C,sBAAsB;IAC7B,CAAA;EACF;EAEQoB,eAAegC,QAA6B;AAClDA,WAAOH,OAAO,CAACC,WAAAA;AACbA,aAAO/B,WAAW;QAAEyD,UAAU,KAAK7E,UAAU8E,MAAK;MAAG;AACrD3B,aAAO/B,OAAOyD,WAAW,KAAK7E,UAAU8E,MAAK;IAC/C,CAAA;EACF;EAEA,MAAcX,4BAA4Bd,QAA6BxB,UAAkB;AACvF,QAAI;AACF,YAAMwB,OAAOnC,IAAI;QAAC;OAAQ;AAC1B,YAAM0C,UAAU;QAAE/B;QAAUkD,QAAQ1B,OAAOD;MAAI;AAC/C,UAAI,KAAK9C,uBAAuB0E,cAAa,MAAO,GAAG;AACrDtF,QAAAA,KAAIyC,KAAK,oDAAoDyB,SAAAA;;;;;;AAC7D;MACF;AACA,YAAMqB,kBAAkB,KAAK/E,uBAAuB4D,IAAIjC,QAAAA;AACxD,UAAIoD,iBAAiB7B,QAAQC,OAAOD,KAAK;AACvC1D,QAAAA,KAAIqE,KAAK,sEAAsEH,SAAAA;;;;;;AAC/E;MACF;AACA,WAAKtD,uBAAuB4E,KAAK;QAAE7B;QAAQxB;MAAS,CAAA;IACtD,SAASyC,KAAK;AACZ,YAAMa,qBAAqB,KAAK7E,uBAAuB0E,cAAa,IAAK;AACzEtF,MAAAA,KAAIqE,KAAK,6BAA6B;QACpClC;QACA8B,cAAcN,OAAOD;QACrBgC,cAAcD;QACdb;MACF,GAAA;;;;;;AACA,UAAIa,oBAAoB;AACtB,cAAM,KAAKhB,4BAA4Bd,QAAQxB,QAAAA;MACjD;IACF;EACF;AACF;;EAhLGlC,OAAM0F,KAAK;IAAEC,uBAAuB;EAAK,CAAA;GA3B/B1F,4BAAAA,WAAAA,0BAAAA,IAAAA;AAAAA,8BAAAA,cAAAA;EADZD,OAAM4F,SAAQ;GACF3F,2BAAAA;;;AClCb,SAAuB4F,QAAAA,aAAY;AACnC,SAASC,YAAAA,iBAAgB;AACzB,SAASC,aAAAA,kBAAiB;AAC1B,SAASC,aAAAA,kBAAiB;AAC1B,SAASC,OAAAA,YAAW;AACpB,SAASC,2BAA2B;AACpC,SAASC,YAAYC,YAAYC,kBAAkB;;AAc5C,IAAMC,qBAAN,MAAMA;EAAN;AACYC,wBAAe,oBAAIC,IAAAA;AAInBC;;;+BAAsB,oBAAIC,IAAAA;AAK1BC;;;8BAAqB,IAAIR,WAA6CH,WAAUY,IAAI;AAE7FC,oBAAyC;;EAEjD,MAAMC,QAAQC,SAA+C;AAC3D,SAAKF,WAAWE;EAClB;EAEA,MAAMC,aAAa;AACjB,eAAWC,cAAc,KAAKV,cAAc;AAC1C,YAAMU,WAAWC,MAAK;IACxB;AACA,SAAKX,aAAaY,MAAK;AACvB,SAAKV,oBAAoBU,MAAK;AAE9B,SAAKN,WAAW;EAClB;EAEAO,kBAAuC;AACrCrB,IAAAA,WAAU,KAAKc,UAAQ,QAAA;;;;;;;;;AAEvB,UAAMI,aAAuC,IAAII,yBAAyB;MACxEC,WAAW,KAAKT,SAASU;MACzBC,mBAAmB,YAAA;AACjBvB,QAAAA,KAAI,qBAAqB;UAAEsB,QAAQN,WAAWM;QAAO,GAAA;;;;;;AACrDxB,QAAAA,WAAU,KAAKc,UAAQ,QAAA;;;;;;;;;AAEvB,YAAI,CAAC,KAAKJ,oBAAoBgB,IAAIR,WAAWM,MAAM,GAAG;AACpD,eAAKd,oBAAoBiB,IAAIT,WAAWM,QAAQN,UAAAA;AAChD,gBAAMA,WAAWU,OAAM;AACvB,eAAKd,SAASe,iBAAiBX,UAAAA;QACjC;MACF;MACAY,sBAAsB,YAAA;AACpB5B,QAAAA,KAAI,wBAAwB;UAAEsB,QAAQN,WAAWM;QAAO,GAAA;;;;;;AACxD,aAAKV,UAAUiB,mBAAmBb,UAAAA;AAClC,cAAMA,WAAWc,QAAO;AACxB,aAAKtB,oBAAoBuB,OAAOf,WAAWM,MAAM;AACjD,aAAKhB,aAAayB,OAAOf,UAAAA;MAC3B;MACAgB,iBAAiB,OAAOC,WAAAA;AACtBjC,QAAAA,KAAI,mBAAmB;UAAEsB,QAAQN,WAAWM;UAAQY,YAAYD,OAAOC;QAAW,GAAA;;;;;;AAClFpC,QAAAA,WAAU,KAAKc,UAAQ,QAAA;;;;;;;;;AACvB,YAAI;AACF,gBAAMuB,WAAW,MAAM,KAAKvB,SAASwB,8BAA8BH,OAAOC,UAAU;AACpF,cAAI,CAACC,UAAU;AACbnC,YAAAA,KAAI,8CAA8C;cAChDsB,QAAQN,WAAWM;cACnBY,YAAYD,OAAOC;YACrB,GAAA;;;;;;AACA,mBAAO;UACT;AAEA,gBAAMG,oBAAoB,KAAK3B,mBAAmB4B,IAAIH,QAAAA;AAEtD,cAAI,CAACnB,WAAWuB,iBAAiB;AAC/BvC,YAAAA,KAAI,+CAA+C;cACjDsB,QAAQN,WAAWM;cACnBY,YAAYD,OAAOC;YACrB,GAAA;;;;;;AACA,mBAAO;UACT;AAEA,gBAAMM,eAAeH,mBAAmBb,IAAIR,WAAWuB,eAAe,KAAK;AAC3EvC,UAAAA,KAAI,sBAAsB;YACxByC,WAAW,KAAK7B,SAASU;YACzBoB,YAAY1B,WAAWM;YACvBY,YAAYD,OAAOC;YACnBS,WAAW3B,WAAWuB;YACtBJ;YACAK;UACF,GAAA;;;;;;AACA,iBAAOA;QACT,SAASI,KAAK;AACZ5C,UAAAA,KAAI6C,MAAMD,KAAAA,QAAAA;;;;;;AACV,iBAAO;QACT;MACF;IACF,CAAA;AACA,SAAKtC,aAAawC,IAAI9B,UAAAA;AAEtB,WAAOA,WAAW+B;EACpB;EAEAC,gBAAgBb,UAAqBQ,WAAsB;AACzD3C,IAAAA,KAAI,mBAAmB;MAAEmC;MAAUQ;IAAU,GAAA;;;;;;AAC7CvC,eAAW,KAAKM,oBAAoByB,UAAU,MAAM,IAAIhC,WAAWJ,WAAUY,IAAI,CAAA,EAAGmC,IAAIH,SAAAA;EAC1F;AACF;AASA,IAAMvB,2BAAN,cAAuCvB,UAAAA;EAUrCoD,YAA6BC,SAAyC;AACpE,UAAK;SADsBA,UAAAA;SAPtBX,kBAAoC;SAInCY,gBAA+B;SAC/BC,aAAa;AAKnB,QAAIC;AACJ,SAAKC,WAAW,IAAIC,eAAwB;MAC1CC,OAAO,CAACC,eAAAA;AACNJ,mCAA2BI;AAC3B,aAAKC,KAAKC,UAAU,MAAMF,WAAWxC,MAAK,CAAA;MAC5C;IACF,CAAA;AAEA,SAAK2C,WAAW,IAAIC,eAAwB;MAC1CC,OAAO,OAAOC,SAAkBN,eAAAA;AAE9B,aAAKV,oBAAoBiB,gBAAgB;UAAEC,SAASrE,MAAKsE,OAAOH,OAAAA;QAAS,CAAA,EAAGlB,MAAM,CAACD,QAAAA;AACjFa,qBAAWU,MAAMvB,GAAAA;QACnB,CAAA;MACF;IACF,CAAA;AAEA,SAAKG,sBAAsB,IAAI9C,oBAC7B;MACEqB,QAAQ,KAAK4B,QAAQ7B;IACvB,GACA;MACE+C,oBAAoB,OAAOC,MAAMC,iBAA6B;AAa5D,aAAK/B,kBAAkB+B;AAGvB,aAAKnB,gBAAgBkB,KAAKE;AAE1BvE,QAAAA,KAAI,sBAAsB;UAAEuE,IAAIF,KAAKE;UAAIC,YAAY,KAAKlD;UAAQgD,cAAcA,aAAaG,MAAK;QAAG,GAAA;;;;;;AAErG,cAAM,KAAKvB,QAAQ3B,kBAAiB;MACtC;MACAmD,eAAe,OAAO,EAAET,QAAO,MAAE;AAC/B,YAAI,CAAC,KAAKb,YAAY;AACpB;QACF;AACA,cAAMW,UAAUnE,MAAK+E,OAAOV,OAAAA;AAE5BZ,iCAAyBuB,QAAQb,OAAAA;MACnC;MACAc,SAAS,YAAA;AACP,YAAI,CAAC,KAAKzB,YAAY;AACpB;QACF;AACA,cAAM,KAAKF,QAAQtB,qBAAoB;MACzC;IACF,CAAA;EAEJ;EAEA,IAAIN,SAAiB;AACnBxB,IAAAA,WAAU,KAAKqD,iBAAiB,MAAM,sCAAA;;;;;;;;;AACtC,WAAO,KAAKA;EACd;EAEA,MAAMnB,gBAAgBC,QAAiD;AACrE,WAAO,KAAKiB,QAAQlB,gBAAgBC,MAAAA;EACtC;;;;;EAMA,MAAMP,SAAS;AACb5B,IAAAA,WAAU,KAAKqD,iBAAiB,MAAM,sCAAA;;;;;;;;;AACtC,SAAKC,aAAa;EACpB;;;;EAKA,MAAMtB,UAAU;AACd,SAAKsB,aAAa;EACpB;AACF;",
|
|
6
|
+
"names": ["Event", "next", "automerge", "getBackend", "getHeads", "Repo", "Context", "invariant", "PublicKey", "log", "objectPointerCodec", "trace", "mapValues", "Trigger", "synchronized", "NetworkAdapter", "LifecycleState", "invariant", "log", "EchoNetworkAdapter", "constructor", "_params", "_replicators", "Set", "_connections", "Map", "_lifecycleState", "CLOSED", "_connected", "connect", "peerId", "peerMetadata", "wake", "send", "message", "connectionEntry", "get", "targetId", "Error", "writer", "write", "catch", "err", "isOpen", "disconnect", "open", "OPEN", "emit", "network", "close", "replicator", "clear", "whenConnected", "wait", "timeout", "addReplicator", "has", "add", "onConnectionOpen", "_onConnectionOpen", "bind", "onConnectionClosed", "_onConnectionClosed", "getContainingSpaceForDocument", "removeReplicator", "delete", "shouldAdvertize", "params", "connection", "reader", "readable", "getReader", "writable", "getWriter", "set", "queueMicrotask", "done", "value", "read", "dxos_peerSource", "entry", "cancel", "abort", "LifecycleState", "Resource", "LevelDBStorageAdapter", "Resource", "constructor", "_params", "load", "keyArray", "_lifecycleState", "LifecycleState", "OPEN", "undefined", "db", "get", "encodingOptions", "err", "isLevelDbNotFoundError", "save", "binary", "batch", "callbacks", "beforeSave", "path", "put", "Buffer", "from", "write", "afterSave", "remove", "del", "loadRange", "keyPrefix", "result", "key", "value", "iterator", "gte", "lte", "push", "data", "removeRange", "keyEncoder", "encode", "map", "k", "replaceAll", "join", "decode", "toString", "split", "format", "keyEncoding", "valueEncoding", "code", "Trigger", "NetworkAdapter", "cbor", "Stream", "invariant", "LocalHostNetworkAdapter", "_peers", "Map", "_connected", "_isConnected", "ready", "emit", "network", "connect", "peerId", "wake", "send", "message", "peer", "get", "targetId", "close", "forEach", "disconnect", "whenConnected", "wait", "timeout", "syncRepo", "id", "syncMessage", "_getPeerId", "next", "has", "set", "connected", "encode", "delete", "peerMetadata", "sendSyncMessage", "decode", "getHostInfo", "IndexedDBStorageAdapter", "log", "StorageType", "arrayToBuffer", "bufferToArray", "AutomergeStorageAdapter", "constructor", "_directory", "_state", "load", "key", "undefined", "filename", "_getFilename", "file", "getOrCreateFile", "size", "stat", "buffer", "read", "bufferToArray", "save", "data", "write", "arrayToBuffer", "truncate", "length", "flush", "remove", "destroy", "loadRange", "keyPrefix", "entries", "list", "Promise", "all", "filter", "entry", "startsWith", "map", "_getKeyFromFilename", "removeRange", "close", "k", "replaceAll", "join", "split", "levelMigration", "db", "directory", "isNewLevel", "iterator", "encodingOptions", "next", "oldStorageAdapter", "type", "StorageType", "IDB", "IndexedDBStorageAdapter", "path", "AutomergeStorageAdapter", "chunks", "loadRange", "length", "batch", "log", "info", "key", "data", "put", "write", "AutomergeHost", "constructor", "directory", "db", "indexMetadataStore", "_ctx", "Context", "_echoNetworkAdapter", "EchoNetworkAdapter", "getContainingSpaceForDocument", "_getContainingSpaceForDocument", "bind", "_requestedDocs", "Set", "_directory", "_db", "_indexMetadataStore", "open", "_peerId", "PublicKey", "random", "toHex", "levelMigration", "_storage", "LevelDBStorageAdapter", "callbacks", "beforeSave", "params", "_beforeSave", "afterSave", "_afterSave", "_clientNetwork", "LocalHostNetworkAdapter", "_repo", "Repo", "peerId", "sharePolicy", "_sharePolicy", "storage", "network", "ready", "whenConnected", "close", "dispose", "repo", "addReplicator", "replicator", "removeReplicator", "documentId", "startsWith", "doc", "handles", "docSync", "isRequested", "has", "log", "peerMetadata", "peerMetadataByPeerId", "dxos_peerSource", "shouldAdvertize", "path", "batch", "handle", "spaceKey", "getSpaceKeyFromDoc", "undefined", "lastAvailableHash", "getHeads", "objectIds", "Object", "keys", "objects", "encodedIds", "map", "objectId", "objectPointerCodec", "encode", "idToLastHash", "Map", "id", "markDirty", "notifyMarkedDirty", "_automergeDocs", "mapValues", "state", "hasDoc", "heads", "automerge", "data", "value", "key", "err", "_automergePeers", "peers", "spaceKeyHex", "from", "flush", "states", "Promise", "all", "invariant", "find", "waitForHeads", "syncRepo", "request", "sendSyncMessage", "getHostInfo", "trace", "info", "depth", "span", "showInBrowserTimeline", "resource", "rawSpaceKey", "access", "experimental_spaceKey", "String", "whenReady", "unavailableHeads", "Event", "wrap", "waitForCondition", "changeHash", "values", "changeIsPresentInDoc", "delete", "size", "getBackend", "getChangeByHash", "Event", "cancelWithContext", "warnAfterTimeout", "invariant", "log", "trace", "AutomergeDocumentLoaderImpl", "constructor", "_spaceId", "_repo", "_spaceKey", "_spaceRootDocHandle", "_objectDocumentHandles", "Map", "_objectsPendingDocumentLoad", "Set", "onObjectDocumentLoaded", "getAllHandles", "values", "loadSpaceRootDocHandle", "ctx", "spaceState", "rootUrl", "error", "spaceId", "_createContextBoundSpaceRootDocument", "existingDocHandle", "_initDocHandle", "doc", "docSync", "access", "_initDocAccess", "loadObjectDocument", "objectIdOrMany", "objectIds", "Array", "isArray", "hasUrlsToLoad", "urlsToLoad", "objectId", "has", "spaceRootDoc", "documentUrl", "links", "add", "info", "_loadLinkedObjects", "onObjectLinksUpdated", "linksAwaitingLoad", "Object", "entries", "filter", "fromEntries", "forEach", "delete", "getSpaceRootDocHandle", "createDocumentForObject", "spaceDocHandle", "create", "onObjectBoundToDocument", "change", "newDoc", "url", "handle", "set", "clearHandleReferences", "objectsWithHandles", "keys", "clear", "automergeUrl", "logMeta", "objectDocumentHandle", "get", "warn", "actualDocumentUrl", "find", "debug", "_createObjectOnDocumentLoad", "docHandle", "whenReady", "err", "includes", "id", "documentId", "state", "Error", "onDispose", "spaceKey", "toHex", "docUrl", "listenerCount", "objectDocHandle", "emit", "shouldRetryLoading", "retryLoading", "span", "showInBrowserTimeline", "resource", "cbor", "Resource", "invariant", "PublicKey", "log", "AutomergeReplicator", "ComplexMap", "ComplexSet", "defaultMap", "MeshEchoReplicator", "_connections", "Set", "_connectionsPerPeer", "Map", "_authorizedDevices", "hash", "_context", "connect", "context", "disconnect", "connection", "close", "clear", "createExtension", "MeshReplicatorConnection", "ownPeerId", "peerId", "onRemoteConnected", "has", "set", "enable", "onConnectionOpen", "onRemoteDisconnected", "onConnectionClosed", "disable", "delete", "shouldAdvertize", "params", "documentId", "spaceKey", "getContainingSpaceForDocument", "authorizedDevices", "get", "remoteDeviceKey", "isAuthorized", "localPeer", "remotePeer", "deviceKey", "err", "catch", "add", "replicatorExtension", "authorizeDevice", "constructor", "_params", "_remotePeerId", "_isEnabled", "readableStreamController", "readable", "ReadableStream", "start", "controller", "_ctx", "onDispose", "writable", "WritableStream", "write", "message", "sendSyncMessage", "payload", "encode", "error", "onStartReplication", "info", "remotePeerId", "id", "thisPeerId", "toHex", "onSyncMessage", "decode", "enqueue", "onClose"]
|
|
7
7
|
}
|