@peerbit/document-proxy 0.0.0-e209d2e
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/LICENSE +202 -0
- package/dist/src/auto.d.ts +14 -0
- package/dist/src/auto.d.ts.map +1 -0
- package/dist/src/auto.js +65 -0
- package/dist/src/auto.js.map +1 -0
- package/dist/src/client.d.ts +28 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +748 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/host.d.ts +19 -0
- package/dist/src/host.d.ts.map +1 -0
- package/dist/src/host.js +412 -0
- package/dist/src/host.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/protocol.d.ts +182 -0
- package/dist/src/protocol.d.ts.map +1 -0
- package/dist/src/protocol.js +800 -0
- package/dist/src/protocol.js.map +1 -0
- package/package.json +104 -0
- package/src/auto.ts +74 -0
- package/src/client.ts +997 -0
- package/src/host.ts +517 -0
- package/src/index.ts +1 -0
- package/src/protocol.ts +481 -0
package/src/host.ts
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AbstractType,
|
|
3
|
+
deserialize,
|
|
4
|
+
getSchema,
|
|
5
|
+
serialize,
|
|
6
|
+
} from "@dao-xyz/borsh";
|
|
7
|
+
import { type RpcTransport, bindService } from "@dao-xyz/borsh-rpc";
|
|
8
|
+
import {
|
|
9
|
+
type CanonicalChannel,
|
|
10
|
+
type CanonicalContext,
|
|
11
|
+
type CanonicalModule,
|
|
12
|
+
createMessagePortTransport,
|
|
13
|
+
} from "@peerbit/canonical-host";
|
|
14
|
+
import { Documents } from "@peerbit/document";
|
|
15
|
+
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
16
|
+
import type { SharedLogService } from "@peerbit/shared-log-proxy";
|
|
17
|
+
import { createSharedLogService } from "@peerbit/shared-log-proxy/host";
|
|
18
|
+
import {
|
|
19
|
+
DocumentsChange,
|
|
20
|
+
DocumentsCountRequest,
|
|
21
|
+
DocumentsGetRequest,
|
|
22
|
+
DocumentsIndexPutRequest,
|
|
23
|
+
DocumentsPutWithContextRequest,
|
|
24
|
+
DocumentsRemoteOptions,
|
|
25
|
+
DocumentsService,
|
|
26
|
+
DocumentsWaitForRequest,
|
|
27
|
+
OpenDocumentsRequest,
|
|
28
|
+
} from "./protocol.js";
|
|
29
|
+
import {
|
|
30
|
+
DocumentsIndexResult,
|
|
31
|
+
DocumentsIterateRequest,
|
|
32
|
+
DocumentsIteratorBatch,
|
|
33
|
+
DocumentsIteratorService,
|
|
34
|
+
DocumentsIteratorUpdate,
|
|
35
|
+
} from "./protocol.js";
|
|
36
|
+
|
|
37
|
+
const ensureCustomEvent = () => {
|
|
38
|
+
if (typeof (globalThis as any).CustomEvent === "function") {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
class CustomEventPolyfill<T = any> extends Event {
|
|
43
|
+
detail: T;
|
|
44
|
+
constructor(type: string, params?: CustomEventInit<T>) {
|
|
45
|
+
super(type, params);
|
|
46
|
+
this.detail = params?.detail as T;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
(globalThis as any).CustomEvent = CustomEventPolyfill;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const toHex = (bytes: Uint8Array): string => {
|
|
54
|
+
let out = "";
|
|
55
|
+
for (const b of bytes) out += b.toString(16).padStart(2, "0");
|
|
56
|
+
return out;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const toRemoteOptions = (options?: DocumentsRemoteOptions) => {
|
|
60
|
+
if (!options) return undefined;
|
|
61
|
+
const remote: Record<string, any> = {};
|
|
62
|
+
if (options.strategy) remote.strategy = options.strategy;
|
|
63
|
+
if (options.timeoutMs != null) remote.timeout = options.timeoutMs;
|
|
64
|
+
if (options.from?.length) remote.from = options.from;
|
|
65
|
+
if (options.reachEager != null) {
|
|
66
|
+
remote.reach = { eager: options.reachEager };
|
|
67
|
+
}
|
|
68
|
+
if (options.waitTimeoutMs != null) {
|
|
69
|
+
remote.wait = { timeout: options.waitTimeoutMs };
|
|
70
|
+
}
|
|
71
|
+
return remote;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const asInstanceOf = <T>(value: any, type: AbstractType<T>): T => {
|
|
75
|
+
if (!value || typeof value !== "object") {
|
|
76
|
+
return value as T;
|
|
77
|
+
}
|
|
78
|
+
if (value instanceof (type as any)) {
|
|
79
|
+
return value as T;
|
|
80
|
+
}
|
|
81
|
+
return Object.assign(Object.create((type as any).prototype), value) as T;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const registeredDocumentTypes: Map<string, AbstractType<any>> = new Map();
|
|
85
|
+
|
|
86
|
+
export function registerDocumentType<T>(type: AbstractType<T>): void;
|
|
87
|
+
export function registerDocumentType<T>(
|
|
88
|
+
name: string,
|
|
89
|
+
type: AbstractType<T>,
|
|
90
|
+
): void;
|
|
91
|
+
export function registerDocumentType<T>(
|
|
92
|
+
nameOrType: string | AbstractType<T>,
|
|
93
|
+
type?: AbstractType<T>,
|
|
94
|
+
): void {
|
|
95
|
+
if (typeof nameOrType === "string") {
|
|
96
|
+
if (!type) {
|
|
97
|
+
throw new Error("registerDocumentType(name, type) requires a type");
|
|
98
|
+
}
|
|
99
|
+
registeredDocumentTypes.set(nameOrType, type);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const schema = getSchema(nameOrType);
|
|
104
|
+
const variant = schema?.variant;
|
|
105
|
+
if (!variant) {
|
|
106
|
+
throw new Error("Document type is missing @variant() metadata");
|
|
107
|
+
}
|
|
108
|
+
registeredDocumentTypes.set(String(variant), nameOrType);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const registerDocumentTypes = (
|
|
112
|
+
entries:
|
|
113
|
+
| Record<string, AbstractType<any>>
|
|
114
|
+
| Iterable<readonly [string, AbstractType<any>]>,
|
|
115
|
+
): void => {
|
|
116
|
+
if (!entries) return;
|
|
117
|
+
if (Symbol.iterator in Object(entries)) {
|
|
118
|
+
for (const [name, type] of entries as Iterable<
|
|
119
|
+
readonly [string, AbstractType<any>]
|
|
120
|
+
>) {
|
|
121
|
+
registerDocumentType(name, type);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const [name, type] of Object.entries(entries)) {
|
|
127
|
+
registerDocumentType(name, type);
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const getRegisteredDocumentType = (
|
|
132
|
+
name: string,
|
|
133
|
+
): AbstractType<any> | undefined => {
|
|
134
|
+
return registeredDocumentTypes.get(name);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const openDocuments: Map<string, { program: Documents<any>; refs: number }> =
|
|
138
|
+
new Map();
|
|
139
|
+
|
|
140
|
+
export type DocumentModuleStats = {
|
|
141
|
+
total: number;
|
|
142
|
+
entries: Array<{ key: string; refs: number }>;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export const getDocumentModuleStats = (): DocumentModuleStats => {
|
|
146
|
+
return {
|
|
147
|
+
total: openDocuments.size,
|
|
148
|
+
entries: [...openDocuments.entries()].map(([key, value]) => ({
|
|
149
|
+
key,
|
|
150
|
+
refs: value.refs,
|
|
151
|
+
})),
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const acquireDocuments = async <T>(properties: {
|
|
156
|
+
ctx: CanonicalContext;
|
|
157
|
+
typeName: string;
|
|
158
|
+
type: AbstractType<T>;
|
|
159
|
+
id: Uint8Array;
|
|
160
|
+
}): Promise<{
|
|
161
|
+
program: Documents<T>;
|
|
162
|
+
release: () => Promise<void>;
|
|
163
|
+
}> => {
|
|
164
|
+
const key = `${properties.typeName}:${toHex(properties.id)}`;
|
|
165
|
+
const existing = openDocuments.get(key);
|
|
166
|
+
if (existing) {
|
|
167
|
+
existing.refs += 1;
|
|
168
|
+
return {
|
|
169
|
+
program: existing.program,
|
|
170
|
+
release: async () => releaseDocuments(key),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const peer = await properties.ctx.peer();
|
|
175
|
+
const program = await peer.open(new Documents<T>({ id: properties.id }), {
|
|
176
|
+
existing: "reuse",
|
|
177
|
+
args: {
|
|
178
|
+
type: properties.type,
|
|
179
|
+
replicate: { factor: 1 },
|
|
180
|
+
} as any,
|
|
181
|
+
});
|
|
182
|
+
openDocuments.set(key, { program, refs: 1 });
|
|
183
|
+
return { program, release: async () => releaseDocuments(key) };
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const releaseDocuments = async (key: string): Promise<void> => {
|
|
187
|
+
const existing = openDocuments.get(key);
|
|
188
|
+
if (!existing) return;
|
|
189
|
+
existing.refs -= 1;
|
|
190
|
+
if (existing.refs > 0) return;
|
|
191
|
+
openDocuments.delete(key);
|
|
192
|
+
await existing.program.close();
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const documentModule: CanonicalModule = {
|
|
196
|
+
name: "@peerbit/document",
|
|
197
|
+
open: async (
|
|
198
|
+
ctx: CanonicalContext,
|
|
199
|
+
port: CanonicalChannel,
|
|
200
|
+
payload: Uint8Array,
|
|
201
|
+
) => {
|
|
202
|
+
ensureCustomEvent();
|
|
203
|
+
|
|
204
|
+
const request = deserialize(payload, OpenDocumentsRequest);
|
|
205
|
+
const type = getRegisteredDocumentType(request.type);
|
|
206
|
+
if (!type) {
|
|
207
|
+
throw new Error(
|
|
208
|
+
`Unknown document type '${request.type}'. Register it in the worker with registerDocumentType(...)`,
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const acquired = await acquireDocuments({
|
|
213
|
+
ctx,
|
|
214
|
+
typeName: request.type,
|
|
215
|
+
type,
|
|
216
|
+
id: request.id,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
let closed = false;
|
|
220
|
+
let unbind: (() => void) | undefined;
|
|
221
|
+
const iteratorClosers = new Set<() => Promise<void>>();
|
|
222
|
+
const logServices = new Set<SharedLogService>();
|
|
223
|
+
const waitControllers = new Map<string, AbortController>();
|
|
224
|
+
const indexedType = (acquired.program.index as any).indexedType as
|
|
225
|
+
| AbstractType<any>
|
|
226
|
+
| undefined;
|
|
227
|
+
|
|
228
|
+
const encodeResult = (
|
|
229
|
+
value: any,
|
|
230
|
+
resolve: boolean,
|
|
231
|
+
): DocumentsIndexResult => {
|
|
232
|
+
const context = value?.__context;
|
|
233
|
+
let valueBytes: Uint8Array | undefined;
|
|
234
|
+
let indexedBytes: Uint8Array | undefined;
|
|
235
|
+
|
|
236
|
+
if (resolve) {
|
|
237
|
+
const docInstance = asInstanceOf(value, type);
|
|
238
|
+
valueBytes = serialize(docInstance as any);
|
|
239
|
+
if (value?.__indexed && indexedType) {
|
|
240
|
+
const indexedInstance = asInstanceOf(value.__indexed, indexedType);
|
|
241
|
+
indexedBytes = serialize(indexedInstance as any);
|
|
242
|
+
}
|
|
243
|
+
} else if (indexedType) {
|
|
244
|
+
const indexedInstance = asInstanceOf(value, indexedType);
|
|
245
|
+
indexedBytes = serialize(indexedInstance as any);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return new DocumentsIndexResult({
|
|
249
|
+
context,
|
|
250
|
+
value: valueBytes,
|
|
251
|
+
indexed: indexedBytes,
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const transport: RpcTransport = createMessagePortTransport(port);
|
|
256
|
+
const service = new DocumentsService({
|
|
257
|
+
put: async (doc) => {
|
|
258
|
+
const decoded = deserialize(doc.value, type);
|
|
259
|
+
await acquired.program.put(decoded);
|
|
260
|
+
},
|
|
261
|
+
get: async (request: DocumentsGetRequest) => {
|
|
262
|
+
const key =
|
|
263
|
+
request.id instanceof indexerTypes.IdKey
|
|
264
|
+
? request.id
|
|
265
|
+
: indexerTypes.toId(request.id as any);
|
|
266
|
+
const remoteOptions = toRemoteOptions(request.remoteOptions);
|
|
267
|
+
const options: any = {
|
|
268
|
+
resolve: request.resolve !== false,
|
|
269
|
+
};
|
|
270
|
+
if (request.local !== undefined) {
|
|
271
|
+
options.local = request.local;
|
|
272
|
+
}
|
|
273
|
+
if (remoteOptions) {
|
|
274
|
+
options.remote = remoteOptions;
|
|
275
|
+
} else if (request.remote !== undefined) {
|
|
276
|
+
options.remote = request.remote;
|
|
277
|
+
}
|
|
278
|
+
if (request.waitForMs != null) {
|
|
279
|
+
options.waitFor = request.waitForMs;
|
|
280
|
+
}
|
|
281
|
+
const value = await acquired.program.index.get(key, options);
|
|
282
|
+
return value
|
|
283
|
+
? encodeResult(value, options.resolve !== false)
|
|
284
|
+
: undefined;
|
|
285
|
+
},
|
|
286
|
+
del: async (id) => {
|
|
287
|
+
const ideable =
|
|
288
|
+
id instanceof indexerTypes.IdKey
|
|
289
|
+
? indexerTypes.toIdeable(id)
|
|
290
|
+
: (id as any);
|
|
291
|
+
await acquired.program.del(ideable);
|
|
292
|
+
},
|
|
293
|
+
iterate: async (iterateRequest: DocumentsIterateRequest) => {
|
|
294
|
+
const resolve = iterateRequest.request.resolve !== false;
|
|
295
|
+
const toResult = (value: any) => encodeResult(value, resolve);
|
|
296
|
+
|
|
297
|
+
let iterator: any;
|
|
298
|
+
let done = false;
|
|
299
|
+
const closeIterator = async () => {
|
|
300
|
+
if (done) return;
|
|
301
|
+
done = true;
|
|
302
|
+
iteratorClosers.delete(closeIterator);
|
|
303
|
+
if (iterator) {
|
|
304
|
+
await iterator.close();
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const updates = new DocumentsIteratorService({
|
|
309
|
+
next: async (amount) => {
|
|
310
|
+
if (!iterator) {
|
|
311
|
+
throw new Error("Documents iterator not ready");
|
|
312
|
+
}
|
|
313
|
+
const items = await iterator.next(amount);
|
|
314
|
+
return new DocumentsIteratorBatch({
|
|
315
|
+
results: items.map(toResult),
|
|
316
|
+
done: iterator.done(),
|
|
317
|
+
});
|
|
318
|
+
},
|
|
319
|
+
pending: async () => {
|
|
320
|
+
if (!iterator) {
|
|
321
|
+
throw new Error("Documents iterator not ready");
|
|
322
|
+
}
|
|
323
|
+
const pending = await iterator.pending();
|
|
324
|
+
return pending != null ? BigInt(pending) : undefined;
|
|
325
|
+
},
|
|
326
|
+
done: async () => {
|
|
327
|
+
if (!iterator) return false;
|
|
328
|
+
return iterator.done();
|
|
329
|
+
},
|
|
330
|
+
close: async () => {
|
|
331
|
+
await closeIterator();
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
const emitUpdate = (reason: string, items?: any[]) => {
|
|
336
|
+
const results = (items ?? []).map(toResult);
|
|
337
|
+
updates.updates.dispatchEvent(
|
|
338
|
+
new CustomEvent("update", {
|
|
339
|
+
detail: new DocumentsIteratorUpdate({ reason, results }),
|
|
340
|
+
}),
|
|
341
|
+
);
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const remoteOptions = toRemoteOptions(iterateRequest.remoteOptions);
|
|
345
|
+
const iterateOptions: any = {
|
|
346
|
+
closePolicy: iterateRequest.closePolicy,
|
|
347
|
+
updates: iterateRequest.emitUpdates
|
|
348
|
+
? {
|
|
349
|
+
push: iterateRequest.request.pushUpdates,
|
|
350
|
+
merge: iterateRequest.request.mergeUpdates ? true : undefined,
|
|
351
|
+
notify: (reason: string) => emitUpdate(reason),
|
|
352
|
+
onBatch: (batch: any[], meta: { reason: string }) =>
|
|
353
|
+
emitUpdate(meta.reason, batch),
|
|
354
|
+
}
|
|
355
|
+
: undefined,
|
|
356
|
+
};
|
|
357
|
+
if (iterateRequest.local !== undefined) {
|
|
358
|
+
iterateOptions.local = iterateRequest.local;
|
|
359
|
+
}
|
|
360
|
+
if (remoteOptions) {
|
|
361
|
+
iterateOptions.remote = remoteOptions;
|
|
362
|
+
} else if (iterateRequest.remote !== undefined) {
|
|
363
|
+
iterateOptions.remote = iterateRequest.remote;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
iterator = acquired.program.index.iterate(
|
|
367
|
+
iterateRequest.request,
|
|
368
|
+
iterateOptions,
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
iteratorClosers.add(closeIterator);
|
|
372
|
+
return updates;
|
|
373
|
+
},
|
|
374
|
+
putWithContext: async (request: DocumentsPutWithContextRequest) => {
|
|
375
|
+
const decoded = deserialize(request.value.value, type);
|
|
376
|
+
await acquired.program.index.putWithContext(
|
|
377
|
+
asInstanceOf(decoded, type),
|
|
378
|
+
request.id,
|
|
379
|
+
request.context,
|
|
380
|
+
);
|
|
381
|
+
},
|
|
382
|
+
indexPut: async (request: DocumentsIndexPutRequest) => {
|
|
383
|
+
if (!indexedType) {
|
|
384
|
+
throw new Error("Index type is missing");
|
|
385
|
+
}
|
|
386
|
+
const decoded = deserialize(request.indexed, indexedType);
|
|
387
|
+
const wrapped = new (acquired.program.index as any).wrappedIndexedType(
|
|
388
|
+
asInstanceOf(decoded, indexedType),
|
|
389
|
+
request.context,
|
|
390
|
+
);
|
|
391
|
+
await (acquired.program.index as any).index.put(wrapped);
|
|
392
|
+
},
|
|
393
|
+
count: async (request: DocumentsCountRequest) => {
|
|
394
|
+
const approximate = request?.approximate !== false;
|
|
395
|
+
if (approximate) {
|
|
396
|
+
const { estimate } = await acquired.program.count({ approximate: true });
|
|
397
|
+
return BigInt(estimate);
|
|
398
|
+
}
|
|
399
|
+
const count = await acquired.program.index.getSize();
|
|
400
|
+
return BigInt(count);
|
|
401
|
+
},
|
|
402
|
+
indexSize: async () => {
|
|
403
|
+
const size = await acquired.program.index.getSize();
|
|
404
|
+
return BigInt(size);
|
|
405
|
+
},
|
|
406
|
+
waitFor: async (request: DocumentsWaitForRequest) => {
|
|
407
|
+
const requestId = request.requestId;
|
|
408
|
+
const controller = requestId ? new AbortController() : undefined;
|
|
409
|
+
if (requestId && controller) {
|
|
410
|
+
waitControllers.set(requestId, controller);
|
|
411
|
+
}
|
|
412
|
+
try {
|
|
413
|
+
return await acquired.program.waitFor(request.peers, {
|
|
414
|
+
seek: request.seek,
|
|
415
|
+
timeout: request.timeoutMs,
|
|
416
|
+
signal: controller?.signal,
|
|
417
|
+
});
|
|
418
|
+
} finally {
|
|
419
|
+
if (requestId) waitControllers.delete(requestId);
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
indexWaitFor: async (request: DocumentsWaitForRequest) => {
|
|
423
|
+
const requestId = request.requestId;
|
|
424
|
+
const controller = requestId ? new AbortController() : undefined;
|
|
425
|
+
if (requestId && controller) {
|
|
426
|
+
waitControllers.set(requestId, controller);
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
return await acquired.program.index.waitFor(request.peers, {
|
|
430
|
+
seek: request.seek,
|
|
431
|
+
timeout: request.timeoutMs,
|
|
432
|
+
signal: controller?.signal,
|
|
433
|
+
});
|
|
434
|
+
} finally {
|
|
435
|
+
if (requestId) waitControllers.delete(requestId);
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
cancelWait: async (requestId: string) => {
|
|
439
|
+
const controller = waitControllers.get(requestId);
|
|
440
|
+
if (!controller) return;
|
|
441
|
+
waitControllers.delete(requestId);
|
|
442
|
+
try {
|
|
443
|
+
controller.abort(new Error("AbortError"));
|
|
444
|
+
} catch {
|
|
445
|
+
controller.abort();
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
recover: async () => {
|
|
449
|
+
await acquired.program.recover();
|
|
450
|
+
},
|
|
451
|
+
openLog: async () => {
|
|
452
|
+
let service: SharedLogService;
|
|
453
|
+
service = createSharedLogService(acquired.program.log, {
|
|
454
|
+
onClose: async () => {
|
|
455
|
+
logServices.delete(service);
|
|
456
|
+
},
|
|
457
|
+
});
|
|
458
|
+
logServices.add(service);
|
|
459
|
+
return service;
|
|
460
|
+
},
|
|
461
|
+
close: async () => {
|
|
462
|
+
if (closed) return;
|
|
463
|
+
closed = true;
|
|
464
|
+
for (const controller of waitControllers.values()) {
|
|
465
|
+
try {
|
|
466
|
+
controller.abort(new Error("DocumentsService closed"));
|
|
467
|
+
} catch {
|
|
468
|
+
controller.abort();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
waitControllers.clear();
|
|
472
|
+
acquired.program.events.removeEventListener("change", onChange as any);
|
|
473
|
+
unbind?.();
|
|
474
|
+
for (const service of logServices) {
|
|
475
|
+
await service.close();
|
|
476
|
+
}
|
|
477
|
+
for (const closeIterator of iteratorClosers) {
|
|
478
|
+
await closeIterator();
|
|
479
|
+
}
|
|
480
|
+
await acquired.release();
|
|
481
|
+
},
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
const onChange = (evt: CustomEvent<any>) => {
|
|
485
|
+
const change = evt.detail as {
|
|
486
|
+
added?: Array<any>;
|
|
487
|
+
removed?: Array<any>;
|
|
488
|
+
};
|
|
489
|
+
const added = (change.added ?? []).map((x) => encodeResult(x, true));
|
|
490
|
+
const removed = (change.removed ?? []).map((x) => encodeResult(x, true));
|
|
491
|
+
service.changes.dispatchEvent(
|
|
492
|
+
new CustomEvent("change", {
|
|
493
|
+
detail: new DocumentsChange({ added, removed }),
|
|
494
|
+
}),
|
|
495
|
+
);
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
acquired.program.events.addEventListener("change", onChange as any);
|
|
499
|
+
unbind = bindService(DocumentsService, transport, service);
|
|
500
|
+
port.onClose?.(() => {
|
|
501
|
+
void service.close();
|
|
502
|
+
});
|
|
503
|
+
},
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
export const installDocumentModule = (
|
|
507
|
+
host: { registerModule: (module: CanonicalModule) => void },
|
|
508
|
+
entries?:
|
|
509
|
+
| Record<string, AbstractType<any>>
|
|
510
|
+
| Iterable<readonly [string, AbstractType<any>]>,
|
|
511
|
+
): CanonicalModule => {
|
|
512
|
+
if (entries) {
|
|
513
|
+
registerDocumentTypes(entries);
|
|
514
|
+
}
|
|
515
|
+
host.registerModule(documentModule);
|
|
516
|
+
return documentModule;
|
|
517
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./protocol.js";
|