@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/client.ts
ADDED
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
import { type AbstractType, deserialize, serialize } from "@dao-xyz/borsh";
|
|
2
|
+
import { createProxyFromService } from "@dao-xyz/borsh-rpc";
|
|
3
|
+
import {
|
|
4
|
+
type CanonicalClient,
|
|
5
|
+
createMessagePortTransport,
|
|
6
|
+
} from "@peerbit/canonical-client";
|
|
7
|
+
import type {
|
|
8
|
+
CountEstimate,
|
|
9
|
+
DocumentsLike,
|
|
10
|
+
DocumentsLikeCountOptions,
|
|
11
|
+
DocumentsLikeIndex,
|
|
12
|
+
DocumentsLikeQuery,
|
|
13
|
+
DocumentsLikeWaitForOptions,
|
|
14
|
+
GetOptions,
|
|
15
|
+
QueryOptions,
|
|
16
|
+
ReachScope,
|
|
17
|
+
ResultsIterator,
|
|
18
|
+
SearchOptions,
|
|
19
|
+
UpdateOptions,
|
|
20
|
+
UpdateReason,
|
|
21
|
+
ValueTypeFromRequest,
|
|
22
|
+
WithContext,
|
|
23
|
+
} from "@peerbit/document";
|
|
24
|
+
import {
|
|
25
|
+
Context,
|
|
26
|
+
IterationRequest,
|
|
27
|
+
PushUpdatesMode,
|
|
28
|
+
ResultIndexedValue,
|
|
29
|
+
ResultValue,
|
|
30
|
+
Results,
|
|
31
|
+
} from "@peerbit/document-interface";
|
|
32
|
+
import * as indexerTypes from "@peerbit/indexer-interface";
|
|
33
|
+
import {
|
|
34
|
+
type SharedLogProxy,
|
|
35
|
+
createSharedLogProxyFromService,
|
|
36
|
+
} from "@peerbit/shared-log-proxy/client";
|
|
37
|
+
import {
|
|
38
|
+
type PeerRefs,
|
|
39
|
+
coercePeerRefsToHashes,
|
|
40
|
+
} from "@peerbit/stream-interface";
|
|
41
|
+
import {
|
|
42
|
+
Bytes,
|
|
43
|
+
DocumentsChange,
|
|
44
|
+
DocumentsCountRequest,
|
|
45
|
+
DocumentsGetRequest,
|
|
46
|
+
DocumentsIndexPutRequest,
|
|
47
|
+
DocumentsIndexResult,
|
|
48
|
+
DocumentsIterateRequest,
|
|
49
|
+
DocumentsIteratorBatch,
|
|
50
|
+
DocumentsIteratorService,
|
|
51
|
+
DocumentsIteratorUpdate,
|
|
52
|
+
DocumentsPutWithContextRequest,
|
|
53
|
+
DocumentsRemoteOptions,
|
|
54
|
+
DocumentsService,
|
|
55
|
+
DocumentsWaitForRequest,
|
|
56
|
+
OpenDocumentsRequest,
|
|
57
|
+
} from "./protocol.js";
|
|
58
|
+
|
|
59
|
+
const ensureCustomEvent = () => {
|
|
60
|
+
if (typeof (globalThis as any).CustomEvent === "function") {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
class CustomEventPolyfill<T = any> extends Event {
|
|
65
|
+
detail: T;
|
|
66
|
+
constructor(type: string, params?: CustomEventInit<T>) {
|
|
67
|
+
super(type, params);
|
|
68
|
+
this.detail = params?.detail as T;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
(globalThis as any).CustomEvent = CustomEventPolyfill;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const asInstanceOf = <T>(value: any, type: AbstractType<T>): T => {
|
|
76
|
+
if (!value || typeof value !== "object") {
|
|
77
|
+
return value as T;
|
|
78
|
+
}
|
|
79
|
+
if (value instanceof (type as any)) {
|
|
80
|
+
return value as T;
|
|
81
|
+
}
|
|
82
|
+
return Object.assign(Object.create((type as any).prototype), value) as T;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
export type DocumentsProxyChange<T> = {
|
|
86
|
+
added: T[];
|
|
87
|
+
removed: T[];
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type DocumentsProxyWaitForOptions = DocumentsLikeWaitForOptions;
|
|
91
|
+
|
|
92
|
+
export type DocumentsProxyCountOptions = DocumentsLikeCountOptions;
|
|
93
|
+
|
|
94
|
+
export type DocumentsProxyIndex<T, I = any> = DocumentsLikeIndex<T, I> & {
|
|
95
|
+
putWithContext?: (
|
|
96
|
+
value: T,
|
|
97
|
+
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
98
|
+
context: Context,
|
|
99
|
+
) => Promise<void>;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export type DocumentsProxy<T, I = any> = DocumentsLike<T, I> & {
|
|
103
|
+
raw: DocumentsService;
|
|
104
|
+
log: SharedLogProxy;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const coerceWithContext = <T>(value: T, context: any): T => {
|
|
108
|
+
if (value && typeof value === "object") {
|
|
109
|
+
(value as any).__context = context;
|
|
110
|
+
}
|
|
111
|
+
return value;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const coerceWithIndexed = <T>(value: T, indexed: any): T => {
|
|
115
|
+
if (value && typeof value === "object") {
|
|
116
|
+
(value as any).__indexed = indexed;
|
|
117
|
+
}
|
|
118
|
+
return value;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const normalizeUpdates = <Resolve extends boolean | undefined>(
|
|
122
|
+
updates?: UpdateOptions<any, any, Resolve>,
|
|
123
|
+
): { push?: PushUpdatesMode; merge?: boolean; emitUpdates: boolean } => {
|
|
124
|
+
if (!updates) {
|
|
125
|
+
return { emitUpdates: false };
|
|
126
|
+
}
|
|
127
|
+
if (updates === true) {
|
|
128
|
+
return { merge: true, emitUpdates: true };
|
|
129
|
+
}
|
|
130
|
+
if (typeof updates === "string") {
|
|
131
|
+
if (updates === "local") {
|
|
132
|
+
return { merge: true, emitUpdates: true };
|
|
133
|
+
}
|
|
134
|
+
if (updates === "remote") {
|
|
135
|
+
return { push: PushUpdatesMode.STREAM, emitUpdates: true };
|
|
136
|
+
}
|
|
137
|
+
if (updates === "all") {
|
|
138
|
+
return { merge: true, push: PushUpdatesMode.STREAM, emitUpdates: true };
|
|
139
|
+
}
|
|
140
|
+
return { emitUpdates: false };
|
|
141
|
+
}
|
|
142
|
+
if (typeof updates === "object") {
|
|
143
|
+
const hasMerge = Object.prototype.hasOwnProperty.call(updates, "merge");
|
|
144
|
+
const merge = hasMerge
|
|
145
|
+
? updates.merge === false
|
|
146
|
+
? undefined
|
|
147
|
+
: true
|
|
148
|
+
: true;
|
|
149
|
+
const push =
|
|
150
|
+
typeof updates.push === "number"
|
|
151
|
+
? updates.push
|
|
152
|
+
: updates.push
|
|
153
|
+
? PushUpdatesMode.STREAM
|
|
154
|
+
: undefined;
|
|
155
|
+
const emitUpdates = !!(updates.notify || updates.onBatch || merge || push);
|
|
156
|
+
return { push, merge, emitUpdates };
|
|
157
|
+
}
|
|
158
|
+
return { emitUpdates: false };
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const toRemoteOptions = (remote: any): DocumentsRemoteOptions | undefined => {
|
|
162
|
+
if (!remote || typeof remote === "boolean") return undefined;
|
|
163
|
+
const waitTimeoutMs =
|
|
164
|
+
typeof remote.wait === "object" ? remote.wait?.timeout : undefined;
|
|
165
|
+
return new DocumentsRemoteOptions({
|
|
166
|
+
strategy: remote.strategy,
|
|
167
|
+
timeoutMs: remote.timeout,
|
|
168
|
+
from: remote.from,
|
|
169
|
+
reachEager: remote.reach?.eager,
|
|
170
|
+
waitTimeoutMs,
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const openDocuments = async <T, I = T>(properties: {
|
|
175
|
+
client: CanonicalClient;
|
|
176
|
+
id: Uint8Array;
|
|
177
|
+
typeName: string;
|
|
178
|
+
type: AbstractType<T>;
|
|
179
|
+
indexType?: AbstractType<I>;
|
|
180
|
+
}): Promise<DocumentsProxy<T, I>> => {
|
|
181
|
+
ensureCustomEvent();
|
|
182
|
+
|
|
183
|
+
const channel = await properties.client.openPort(
|
|
184
|
+
"@peerbit/document",
|
|
185
|
+
serialize(
|
|
186
|
+
new OpenDocumentsRequest({
|
|
187
|
+
id: properties.id,
|
|
188
|
+
type: properties.typeName,
|
|
189
|
+
}),
|
|
190
|
+
),
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
const transport = createMessagePortTransport(channel, {
|
|
194
|
+
requestTimeoutMs: (method) => {
|
|
195
|
+
if (method === "waitFor" || method === "indexWaitFor") return undefined;
|
|
196
|
+
return 30_000;
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
const raw = createProxyFromService(
|
|
200
|
+
DocumentsService,
|
|
201
|
+
transport,
|
|
202
|
+
) as unknown as DocumentsService;
|
|
203
|
+
const logService = await raw.openLog();
|
|
204
|
+
const log = await createSharedLogProxyFromService(logService);
|
|
205
|
+
let closed = false;
|
|
206
|
+
|
|
207
|
+
const decodeChangeValue = (result: DocumentsIndexResult): T | undefined => {
|
|
208
|
+
if (!result.value) return undefined;
|
|
209
|
+
const value = deserialize(result.value, properties.type);
|
|
210
|
+
coerceWithContext(value as any, result.context);
|
|
211
|
+
const indexType = properties.indexType ?? properties.type;
|
|
212
|
+
if (result.indexed && indexType) {
|
|
213
|
+
const indexed = deserialize(result.indexed, indexType);
|
|
214
|
+
coerceWithIndexed(value as any, indexed);
|
|
215
|
+
}
|
|
216
|
+
return value as T;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const decodeChange = (change: DocumentsChange): DocumentsProxyChange<T> => {
|
|
220
|
+
return {
|
|
221
|
+
added: (change.added ?? []).map(decodeChangeValue).filter(Boolean) as T[],
|
|
222
|
+
removed: (change.removed ?? [])
|
|
223
|
+
.map(decodeChangeValue)
|
|
224
|
+
.filter(Boolean) as T[],
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const changes = new EventTarget();
|
|
229
|
+
const onChange = (e: any) => {
|
|
230
|
+
const detail = decodeChange(e.detail as DocumentsChange);
|
|
231
|
+
changes.dispatchEvent(new CustomEvent("change", { detail }));
|
|
232
|
+
};
|
|
233
|
+
raw.changes.addEventListener("change", onChange);
|
|
234
|
+
|
|
235
|
+
const coerceIdKey = (
|
|
236
|
+
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
237
|
+
): indexerTypes.IdKey => {
|
|
238
|
+
return id instanceof indexerTypes.IdKey ? id : indexerTypes.toId(id);
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const createGetRequest = <Resolve extends boolean | undefined>(
|
|
242
|
+
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
243
|
+
options?: GetOptions<T, I, any, Resolve>,
|
|
244
|
+
resolveOverride?: Resolve,
|
|
245
|
+
) => {
|
|
246
|
+
if (options?.signal?.aborted) {
|
|
247
|
+
throw new Error("AbortError");
|
|
248
|
+
}
|
|
249
|
+
const resolve =
|
|
250
|
+
resolveOverride !== undefined
|
|
251
|
+
? resolveOverride !== false
|
|
252
|
+
: options?.resolve !== false;
|
|
253
|
+
const remoteOption = options?.remote;
|
|
254
|
+
const remoteOptions = toRemoteOptions(remoteOption);
|
|
255
|
+
const remote =
|
|
256
|
+
typeof remoteOption === "boolean"
|
|
257
|
+
? remoteOption
|
|
258
|
+
: remoteOption
|
|
259
|
+
? true
|
|
260
|
+
: undefined;
|
|
261
|
+
return {
|
|
262
|
+
resolve: resolve as Resolve,
|
|
263
|
+
request: new DocumentsGetRequest({
|
|
264
|
+
id: coerceIdKey(id),
|
|
265
|
+
resolve,
|
|
266
|
+
local: options?.local,
|
|
267
|
+
remote,
|
|
268
|
+
remoteOptions,
|
|
269
|
+
waitForMs: options?.waitFor,
|
|
270
|
+
}),
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const fetchValue = async <Resolve extends boolean | undefined>(
|
|
275
|
+
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
276
|
+
options?: GetOptions<T, I, any, Resolve>,
|
|
277
|
+
resolveOverride?: Resolve,
|
|
278
|
+
): Promise<ValueTypeFromRequest<Resolve, T, I> | undefined> => {
|
|
279
|
+
const { request, resolve } = createGetRequest(id, options, resolveOverride);
|
|
280
|
+
const result = await raw.get(request);
|
|
281
|
+
if (!result) return undefined;
|
|
282
|
+
return decodeIndexResult(result, resolve) as ValueTypeFromRequest<
|
|
283
|
+
Resolve,
|
|
284
|
+
T,
|
|
285
|
+
I
|
|
286
|
+
>;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const get = async (
|
|
290
|
+
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
291
|
+
options?: GetOptions<T, I, any, true | undefined>,
|
|
292
|
+
) => {
|
|
293
|
+
return fetchValue(id, options, true) as Promise<T | undefined>;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const idPath =
|
|
297
|
+
indexerTypes.getIdProperty(properties.indexType ?? properties.type) ??
|
|
298
|
+
(["id"] as string[]);
|
|
299
|
+
const resolveId = (value: any): indexerTypes.IdKey => {
|
|
300
|
+
let candidate = value;
|
|
301
|
+
if (candidate && typeof candidate === "object") {
|
|
302
|
+
if ("__indexed" in candidate && candidate.__indexed) {
|
|
303
|
+
candidate = candidate.__indexed;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const resolved = indexerTypes.extractFieldValue(
|
|
307
|
+
candidate,
|
|
308
|
+
idPath as string[],
|
|
309
|
+
);
|
|
310
|
+
return indexerTypes.toId(resolved as indexerTypes.Ideable);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const decodeIndexResult = <Resolve extends boolean | undefined>(
|
|
314
|
+
result: DocumentsIndexResult,
|
|
315
|
+
resolve: Resolve,
|
|
316
|
+
): ValueTypeFromRequest<Resolve, T, I> | undefined => {
|
|
317
|
+
const context = result.context;
|
|
318
|
+
const indexType = properties.indexType ?? properties.type;
|
|
319
|
+
if (resolve !== false) {
|
|
320
|
+
if (!result.value) return undefined;
|
|
321
|
+
const value = deserialize(result.value, properties.type);
|
|
322
|
+
coerceWithContext(value as any, context);
|
|
323
|
+
if (result.indexed && indexType) {
|
|
324
|
+
const indexed = deserialize(result.indexed, indexType);
|
|
325
|
+
coerceWithIndexed(value as any, indexed);
|
|
326
|
+
}
|
|
327
|
+
return value as ValueTypeFromRequest<Resolve, T, I>;
|
|
328
|
+
}
|
|
329
|
+
if (result.indexed && indexType) {
|
|
330
|
+
const indexed = deserialize(result.indexed, indexType);
|
|
331
|
+
coerceWithContext(indexed as any, context);
|
|
332
|
+
return indexed as ValueTypeFromRequest<Resolve, T, I>;
|
|
333
|
+
}
|
|
334
|
+
return undefined;
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const decodeIteratorBatch = <Resolve extends boolean | undefined>(
|
|
338
|
+
batch: DocumentsIteratorBatch,
|
|
339
|
+
resolve: Resolve,
|
|
340
|
+
): {
|
|
341
|
+
items: ValueTypeFromRequest<Resolve, T, I>[];
|
|
342
|
+
done: boolean;
|
|
343
|
+
} => {
|
|
344
|
+
const items = (batch.results ?? [])
|
|
345
|
+
.map((result) => decodeIndexResult(result, resolve))
|
|
346
|
+
.filter(Boolean) as ValueTypeFromRequest<Resolve, T, I>[];
|
|
347
|
+
return { items, done: batch.done };
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const decodeUpdateResults = <Resolve extends boolean | undefined>(
|
|
351
|
+
update: DocumentsIteratorUpdate,
|
|
352
|
+
resolve: Resolve,
|
|
353
|
+
): ValueTypeFromRequest<Resolve, T, I>[] => {
|
|
354
|
+
return (update.results ?? [])
|
|
355
|
+
.map((result) => decodeIndexResult(result, resolve))
|
|
356
|
+
.filter(Boolean) as ValueTypeFromRequest<Resolve, T, I>[];
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const toNumber = (value: bigint | number): number => {
|
|
360
|
+
return typeof value === "bigint" ? Number(value) : value;
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
const randomId = (): string => {
|
|
364
|
+
if (
|
|
365
|
+
typeof crypto !== "undefined" &&
|
|
366
|
+
typeof crypto.randomUUID === "function"
|
|
367
|
+
) {
|
|
368
|
+
return crypto.randomUUID();
|
|
369
|
+
}
|
|
370
|
+
return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
const abortError = () => new Error("AbortError");
|
|
374
|
+
|
|
375
|
+
const createWaitForRequest = (
|
|
376
|
+
peers: PeerRefs,
|
|
377
|
+
options?: DocumentsProxyWaitForOptions,
|
|
378
|
+
requestId?: string,
|
|
379
|
+
) => {
|
|
380
|
+
if (options?.signal?.aborted) {
|
|
381
|
+
throw new Error("AbortError");
|
|
382
|
+
}
|
|
383
|
+
const hashes = coercePeerRefsToHashes(peers);
|
|
384
|
+
return new DocumentsWaitForRequest({
|
|
385
|
+
peers: hashes,
|
|
386
|
+
seek: options?.seek,
|
|
387
|
+
timeoutMs: options?.timeout,
|
|
388
|
+
requestId,
|
|
389
|
+
});
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const waitFor = async (
|
|
393
|
+
peers: PeerRefs,
|
|
394
|
+
options?: DocumentsProxyWaitForOptions,
|
|
395
|
+
): Promise<string[]> => {
|
|
396
|
+
const signal = options?.signal;
|
|
397
|
+
const requestId = signal ? randomId() : undefined;
|
|
398
|
+
const request = createWaitForRequest(peers, options, requestId);
|
|
399
|
+
const call = raw.waitFor(request);
|
|
400
|
+
if (!signal || !requestId) {
|
|
401
|
+
return call;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return new Promise<string[]>((resolve, reject) => {
|
|
405
|
+
const cleanup = () => {
|
|
406
|
+
signal.removeEventListener("abort", onAbort);
|
|
407
|
+
};
|
|
408
|
+
const onAbort = () => {
|
|
409
|
+
cleanup();
|
|
410
|
+
void raw.cancelWait(requestId).catch(() => {});
|
|
411
|
+
reject(abortError());
|
|
412
|
+
};
|
|
413
|
+
if (signal.aborted) {
|
|
414
|
+
onAbort();
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
418
|
+
call.then(
|
|
419
|
+
(value) => {
|
|
420
|
+
cleanup();
|
|
421
|
+
resolve(value);
|
|
422
|
+
},
|
|
423
|
+
(error) => {
|
|
424
|
+
cleanup();
|
|
425
|
+
reject(error);
|
|
426
|
+
},
|
|
427
|
+
);
|
|
428
|
+
});
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
const indexWaitFor = async (
|
|
432
|
+
peers: PeerRefs,
|
|
433
|
+
options?: DocumentsProxyWaitForOptions,
|
|
434
|
+
): Promise<string[]> => {
|
|
435
|
+
const signal = options?.signal;
|
|
436
|
+
const requestId = signal ? randomId() : undefined;
|
|
437
|
+
const request = createWaitForRequest(peers, options, requestId);
|
|
438
|
+
const call = raw.indexWaitFor(request);
|
|
439
|
+
if (!signal || !requestId) {
|
|
440
|
+
return call;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return new Promise<string[]>((resolve, reject) => {
|
|
444
|
+
const cleanup = () => {
|
|
445
|
+
signal.removeEventListener("abort", onAbort);
|
|
446
|
+
};
|
|
447
|
+
const onAbort = () => {
|
|
448
|
+
cleanup();
|
|
449
|
+
void raw.cancelWait(requestId).catch(() => {});
|
|
450
|
+
reject(abortError());
|
|
451
|
+
};
|
|
452
|
+
if (signal.aborted) {
|
|
453
|
+
onAbort();
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
457
|
+
call.then(
|
|
458
|
+
(value) => {
|
|
459
|
+
cleanup();
|
|
460
|
+
resolve(value);
|
|
461
|
+
},
|
|
462
|
+
(error) => {
|
|
463
|
+
cleanup();
|
|
464
|
+
reject(error);
|
|
465
|
+
},
|
|
466
|
+
);
|
|
467
|
+
});
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
const indexSize = async (): Promise<number> => {
|
|
471
|
+
const size = await raw.indexSize();
|
|
472
|
+
return toNumber(size);
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
const index: DocumentsProxyIndex<T, I> = {
|
|
476
|
+
get: async <Resolve extends boolean | undefined = true>(
|
|
477
|
+
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
478
|
+
options?: GetOptions<T, I, any, Resolve>,
|
|
479
|
+
) => {
|
|
480
|
+
return fetchValue(id, options);
|
|
481
|
+
},
|
|
482
|
+
getDetailed: async <Resolve extends boolean | undefined = true>(
|
|
483
|
+
id: indexerTypes.IdKey | indexerTypes.IdPrimitive,
|
|
484
|
+
options?: QueryOptions<T, I, any, Resolve>,
|
|
485
|
+
) => {
|
|
486
|
+
const resolve =
|
|
487
|
+
options?.resolve !== undefined ? options.resolve !== false : true;
|
|
488
|
+
|
|
489
|
+
const remoteOption = options?.remote;
|
|
490
|
+
const remoteOptions = toRemoteOptions(remoteOption);
|
|
491
|
+
const remote =
|
|
492
|
+
typeof remoteOption === "boolean"
|
|
493
|
+
? remoteOption
|
|
494
|
+
: remoteOption
|
|
495
|
+
? true
|
|
496
|
+
: undefined;
|
|
497
|
+
|
|
498
|
+
const result = await raw.get(
|
|
499
|
+
new DocumentsGetRequest({
|
|
500
|
+
id: coerceIdKey(id as any),
|
|
501
|
+
resolve,
|
|
502
|
+
local: options?.local,
|
|
503
|
+
remote,
|
|
504
|
+
remoteOptions,
|
|
505
|
+
}),
|
|
506
|
+
);
|
|
507
|
+
|
|
508
|
+
if (!result) return undefined;
|
|
509
|
+
|
|
510
|
+
if (resolve) {
|
|
511
|
+
const value = decodeIndexResult(result, true as Resolve);
|
|
512
|
+
if (!value) return undefined;
|
|
513
|
+
const entry = new ResultValue({
|
|
514
|
+
source: result.value,
|
|
515
|
+
context: result.context,
|
|
516
|
+
value,
|
|
517
|
+
});
|
|
518
|
+
return [new Results({ results: [entry], kept: 0n })] as any;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const indexed = decodeIndexResult(result, false as Resolve);
|
|
522
|
+
if (!indexed) return undefined;
|
|
523
|
+
const entry = new ResultIndexedValue({
|
|
524
|
+
source: result.indexed ?? new Uint8Array(),
|
|
525
|
+
indexed,
|
|
526
|
+
entries: [],
|
|
527
|
+
context: result.context,
|
|
528
|
+
});
|
|
529
|
+
return [new Results({ results: [entry], kept: 0n })] as any;
|
|
530
|
+
},
|
|
531
|
+
resolveId,
|
|
532
|
+
iterate: <Resolve extends boolean | undefined = true>(
|
|
533
|
+
query?: DocumentsLikeQuery,
|
|
534
|
+
options?: QueryOptions<T, I, any, Resolve>,
|
|
535
|
+
): ResultsIterator<ValueTypeFromRequest<Resolve, T, I>> => {
|
|
536
|
+
const updates = normalizeUpdates(options?.updates);
|
|
537
|
+
const remoteOption = options?.remote;
|
|
538
|
+
const remoteOptions = toRemoteOptions(remoteOption);
|
|
539
|
+
let remote =
|
|
540
|
+
typeof remoteOption === "boolean"
|
|
541
|
+
? remoteOption
|
|
542
|
+
: remoteOption
|
|
543
|
+
? true
|
|
544
|
+
: undefined;
|
|
545
|
+
let replicate =
|
|
546
|
+
typeof remoteOption === "object" && remoteOption?.replicate
|
|
547
|
+
? true
|
|
548
|
+
: false;
|
|
549
|
+
if (updates.push && remote !== false) {
|
|
550
|
+
remote = true;
|
|
551
|
+
replicate = true;
|
|
552
|
+
}
|
|
553
|
+
const queryObject = query as any;
|
|
554
|
+
const isQueryWrapper =
|
|
555
|
+
!!queryObject &&
|
|
556
|
+
typeof queryObject === "object" &&
|
|
557
|
+
!Array.isArray(queryObject) &&
|
|
558
|
+
("query" in queryObject ||
|
|
559
|
+
("sort" in queryObject &&
|
|
560
|
+
Object.keys(queryObject).every(
|
|
561
|
+
(k) => k === "sort" || k === "query",
|
|
562
|
+
)));
|
|
563
|
+
const queryValue = isQueryWrapper ? queryObject.query : queryObject;
|
|
564
|
+
const sortValue = isQueryWrapper ? queryObject.sort : undefined;
|
|
565
|
+
const request =
|
|
566
|
+
query instanceof IterationRequest
|
|
567
|
+
? query
|
|
568
|
+
: new IterationRequest({
|
|
569
|
+
query: queryValue,
|
|
570
|
+
sort: sortValue,
|
|
571
|
+
fetch: (options as any)?.fetch ?? 10,
|
|
572
|
+
resolve: options?.resolve !== false,
|
|
573
|
+
replicate: options?.resolve !== false ? false : replicate,
|
|
574
|
+
});
|
|
575
|
+
const resolveBool =
|
|
576
|
+
options?.resolve !== undefined
|
|
577
|
+
? options.resolve !== false
|
|
578
|
+
: request.resolve !== false;
|
|
579
|
+
const resolve = resolveBool as Resolve;
|
|
580
|
+
if (options?.resolve !== undefined) {
|
|
581
|
+
request.resolve = resolveBool;
|
|
582
|
+
}
|
|
583
|
+
if (!resolve && replicate && request.replicate !== true) {
|
|
584
|
+
request.replicate = true;
|
|
585
|
+
}
|
|
586
|
+
if (updates.emitUpdates) {
|
|
587
|
+
request.pushUpdates = updates.push;
|
|
588
|
+
request.mergeUpdates = updates.merge;
|
|
589
|
+
}
|
|
590
|
+
const emitUpdates =
|
|
591
|
+
updates.emitUpdates ||
|
|
592
|
+
request.pushUpdates != null ||
|
|
593
|
+
request.mergeUpdates != null;
|
|
594
|
+
const iterateRequest = new DocumentsIterateRequest({
|
|
595
|
+
request,
|
|
596
|
+
local: options?.local,
|
|
597
|
+
remote,
|
|
598
|
+
remoteOptions,
|
|
599
|
+
closePolicy: (options as any)?.closePolicy,
|
|
600
|
+
emitUpdates,
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
let done = false;
|
|
604
|
+
let updatesListener: ((event: any) => void) | undefined;
|
|
605
|
+
const abortSignal = options?.signal;
|
|
606
|
+
let abortListener: (() => void) | undefined;
|
|
607
|
+
|
|
608
|
+
const proxyPromise = raw.iterate(iterateRequest);
|
|
609
|
+
|
|
610
|
+
const createIterator = (
|
|
611
|
+
service: DocumentsIteratorService,
|
|
612
|
+
): ResultsIterator<ValueTypeFromRequest<Resolve, T, I>> => {
|
|
613
|
+
if (
|
|
614
|
+
updates.emitUpdates &&
|
|
615
|
+
options?.updates &&
|
|
616
|
+
typeof options.updates === "object"
|
|
617
|
+
) {
|
|
618
|
+
const updateConfig = options.updates;
|
|
619
|
+
updatesListener = (event: any) => {
|
|
620
|
+
const detail = event?.detail as DocumentsIteratorUpdate;
|
|
621
|
+
if (!detail) return;
|
|
622
|
+
const reason = detail.reason as UpdateReason;
|
|
623
|
+
if (updateConfig.notify) {
|
|
624
|
+
updateConfig.notify(reason);
|
|
625
|
+
}
|
|
626
|
+
if (updateConfig.onBatch && detail.results?.length) {
|
|
627
|
+
const items = decodeUpdateResults(detail, resolve);
|
|
628
|
+
if (items.length) {
|
|
629
|
+
updateConfig.onBatch(items as any, { reason });
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
service.updates.addEventListener("update", updatesListener);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
const iterator: ResultsIterator<ValueTypeFromRequest<Resolve, T, I>> = {
|
|
637
|
+
next: async (amount: number) => {
|
|
638
|
+
if (abortSignal?.aborted) {
|
|
639
|
+
throw abortError();
|
|
640
|
+
}
|
|
641
|
+
const batch = await service.next(amount);
|
|
642
|
+
const decoded = decodeIteratorBatch(batch, resolve);
|
|
643
|
+
done = decoded.done;
|
|
644
|
+
return decoded.items;
|
|
645
|
+
},
|
|
646
|
+
pending: async () => {
|
|
647
|
+
if (abortSignal?.aborted) {
|
|
648
|
+
throw abortError();
|
|
649
|
+
}
|
|
650
|
+
const pending = await service.pending();
|
|
651
|
+
return pending != null ? Number(pending) : undefined;
|
|
652
|
+
},
|
|
653
|
+
done: () => done,
|
|
654
|
+
all: async () => {
|
|
655
|
+
if (abortSignal?.aborted) {
|
|
656
|
+
throw abortError();
|
|
657
|
+
}
|
|
658
|
+
const out: ValueTypeFromRequest<Resolve, T, I>[] = [];
|
|
659
|
+
while (!done) {
|
|
660
|
+
const next = await iterator.next((options as any)?.fetch ?? 10);
|
|
661
|
+
out.push(...next);
|
|
662
|
+
}
|
|
663
|
+
return out;
|
|
664
|
+
},
|
|
665
|
+
first: async () => {
|
|
666
|
+
if (abortSignal?.aborted) {
|
|
667
|
+
throw abortError();
|
|
668
|
+
}
|
|
669
|
+
const next = await iterator.next(1);
|
|
670
|
+
return next[0];
|
|
671
|
+
},
|
|
672
|
+
close: async () => {
|
|
673
|
+
done = true;
|
|
674
|
+
if (abortSignal && abortListener) {
|
|
675
|
+
abortSignal.removeEventListener("abort", abortListener);
|
|
676
|
+
}
|
|
677
|
+
if (updatesListener) {
|
|
678
|
+
service.updates.removeEventListener("update", updatesListener);
|
|
679
|
+
}
|
|
680
|
+
await service.close();
|
|
681
|
+
},
|
|
682
|
+
[Symbol.asyncIterator]: () => {
|
|
683
|
+
return {
|
|
684
|
+
next: async () => {
|
|
685
|
+
const items = await iterator.next(1);
|
|
686
|
+
if (items.length === 0) {
|
|
687
|
+
return { done: true, value: undefined };
|
|
688
|
+
}
|
|
689
|
+
return { done: false, value: items[0] };
|
|
690
|
+
},
|
|
691
|
+
return: async () => {
|
|
692
|
+
await iterator.close();
|
|
693
|
+
return { done: true, value: undefined };
|
|
694
|
+
},
|
|
695
|
+
};
|
|
696
|
+
},
|
|
697
|
+
};
|
|
698
|
+
return iterator;
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
let iterator: ResultsIterator<ValueTypeFromRequest<Resolve, T, I>>;
|
|
702
|
+
abortListener = () => {
|
|
703
|
+
void iterator.close();
|
|
704
|
+
};
|
|
705
|
+
iterator = {
|
|
706
|
+
next: async (amount: number) => {
|
|
707
|
+
if (abortSignal?.aborted) {
|
|
708
|
+
throw abortError();
|
|
709
|
+
}
|
|
710
|
+
const service = await proxyPromise;
|
|
711
|
+
Object.assign(iterator, createIterator(service));
|
|
712
|
+
return iterator.next(amount);
|
|
713
|
+
},
|
|
714
|
+
pending: async () => {
|
|
715
|
+
if (abortSignal?.aborted) {
|
|
716
|
+
throw abortError();
|
|
717
|
+
}
|
|
718
|
+
const service = await proxyPromise;
|
|
719
|
+
Object.assign(iterator, createIterator(service));
|
|
720
|
+
return iterator.pending();
|
|
721
|
+
},
|
|
722
|
+
done: () => done,
|
|
723
|
+
all: async () => {
|
|
724
|
+
if (abortSignal?.aborted) {
|
|
725
|
+
throw abortError();
|
|
726
|
+
}
|
|
727
|
+
const service = await proxyPromise;
|
|
728
|
+
Object.assign(iterator, createIterator(service));
|
|
729
|
+
return iterator.all();
|
|
730
|
+
},
|
|
731
|
+
first: async () => {
|
|
732
|
+
if (abortSignal?.aborted) {
|
|
733
|
+
throw abortError();
|
|
734
|
+
}
|
|
735
|
+
const service = await proxyPromise;
|
|
736
|
+
Object.assign(iterator, createIterator(service));
|
|
737
|
+
return iterator.first();
|
|
738
|
+
},
|
|
739
|
+
close: async () => {
|
|
740
|
+
const service = await proxyPromise;
|
|
741
|
+
Object.assign(iterator, createIterator(service));
|
|
742
|
+
return iterator.close();
|
|
743
|
+
},
|
|
744
|
+
[Symbol.asyncIterator]: () => {
|
|
745
|
+
return {
|
|
746
|
+
next: async () => {
|
|
747
|
+
if (abortSignal?.aborted) {
|
|
748
|
+
throw abortError();
|
|
749
|
+
}
|
|
750
|
+
const service = await proxyPromise;
|
|
751
|
+
Object.assign(iterator, createIterator(service));
|
|
752
|
+
const iter = iterator[Symbol.asyncIterator]();
|
|
753
|
+
return iter.next();
|
|
754
|
+
},
|
|
755
|
+
return: async () => {
|
|
756
|
+
if (abortSignal?.aborted) {
|
|
757
|
+
return { done: true, value: undefined };
|
|
758
|
+
}
|
|
759
|
+
const service = await proxyPromise;
|
|
760
|
+
Object.assign(iterator, createIterator(service));
|
|
761
|
+
const iter = iterator[Symbol.asyncIterator]();
|
|
762
|
+
return iter.return
|
|
763
|
+
? iter.return()
|
|
764
|
+
: { done: true, value: undefined };
|
|
765
|
+
},
|
|
766
|
+
};
|
|
767
|
+
},
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
if (abortSignal) {
|
|
771
|
+
if (abortSignal.aborted) {
|
|
772
|
+
throw abortError();
|
|
773
|
+
}
|
|
774
|
+
abortSignal.addEventListener("abort", abortListener, { once: true });
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
return iterator;
|
|
778
|
+
},
|
|
779
|
+
search: async <Resolve extends boolean | undefined = true>(
|
|
780
|
+
query: DocumentsLikeQuery,
|
|
781
|
+
options?: SearchOptions<T, I, any, Resolve>,
|
|
782
|
+
) => {
|
|
783
|
+
const iterator = index.iterate<Resolve>(query, {
|
|
784
|
+
resolve: options?.resolve,
|
|
785
|
+
local: options?.local,
|
|
786
|
+
remote: options?.remote,
|
|
787
|
+
fetch: (options as any)?.fetch ?? 0xffffffff,
|
|
788
|
+
} as any);
|
|
789
|
+
const out = await iterator.all();
|
|
790
|
+
await iterator.close();
|
|
791
|
+
const seen = new Set<string>();
|
|
792
|
+
return out.filter((item) => {
|
|
793
|
+
const id = resolveId(item).primitive;
|
|
794
|
+
if (seen.has(String(id))) return false;
|
|
795
|
+
seen.add(String(id));
|
|
796
|
+
return true;
|
|
797
|
+
}) as ValueTypeFromRequest<Resolve, T, I>[];
|
|
798
|
+
},
|
|
799
|
+
getSize: indexSize,
|
|
800
|
+
waitFor: indexWaitFor,
|
|
801
|
+
};
|
|
802
|
+
|
|
803
|
+
const countByIterate = async (
|
|
804
|
+
query?: indexerTypes.QueryLike | indexerTypes.Query[],
|
|
805
|
+
): Promise<number> => {
|
|
806
|
+
const iterator = index.iterate(query ? { query } : undefined, {
|
|
807
|
+
resolve: false,
|
|
808
|
+
fetch: 100,
|
|
809
|
+
local: true,
|
|
810
|
+
remote: false,
|
|
811
|
+
} as any);
|
|
812
|
+
let total = 0;
|
|
813
|
+
while (!iterator.done()) {
|
|
814
|
+
const batch = await iterator.next(100);
|
|
815
|
+
total += batch.length;
|
|
816
|
+
}
|
|
817
|
+
await iterator.close();
|
|
818
|
+
return total;
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
const toCountEstimate = (estimate: number): CountEstimate => ({
|
|
822
|
+
estimate,
|
|
823
|
+
errorMargin: undefined,
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
async function count(options?: {
|
|
827
|
+
query?: indexerTypes.Query | indexerTypes.QueryLike;
|
|
828
|
+
approximate?: false | undefined;
|
|
829
|
+
}): Promise<number>;
|
|
830
|
+
async function count(options: {
|
|
831
|
+
query?: indexerTypes.Query | indexerTypes.QueryLike;
|
|
832
|
+
approximate: true | { scope?: ReachScope };
|
|
833
|
+
}): Promise<CountEstimate>;
|
|
834
|
+
async function count(
|
|
835
|
+
options?: DocumentsProxyCountOptions,
|
|
836
|
+
): Promise<number | CountEstimate> {
|
|
837
|
+
const approximate =
|
|
838
|
+
options?.approximate === true || typeof options?.approximate === "object";
|
|
839
|
+
if (options?.query) {
|
|
840
|
+
const total = await countByIterate(options.query as any);
|
|
841
|
+
return approximate ? toCountEstimate(total) : total;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
const total = await raw.count(new DocumentsCountRequest({ approximate }));
|
|
845
|
+
const estimate = toNumber(total);
|
|
846
|
+
return approximate ? toCountEstimate(estimate) : estimate;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
class WrappedIndexedType {
|
|
850
|
+
__context: Context;
|
|
851
|
+
constructor(value: I, context: Context) {
|
|
852
|
+
Object.assign(this, value);
|
|
853
|
+
this.__context = context;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const putWithContext = async (
|
|
858
|
+
value: T,
|
|
859
|
+
id: indexerTypes.Ideable | indexerTypes.IdKey,
|
|
860
|
+
context: Context,
|
|
861
|
+
) => {
|
|
862
|
+
const ctx =
|
|
863
|
+
context instanceof Context ? context : new Context(context as any);
|
|
864
|
+
const request = new DocumentsPutWithContextRequest({
|
|
865
|
+
value: new Bytes({ value: serialize(value as any) }),
|
|
866
|
+
id: coerceIdKey(id),
|
|
867
|
+
context: ctx,
|
|
868
|
+
});
|
|
869
|
+
await raw.putWithContext(request);
|
|
870
|
+
};
|
|
871
|
+
|
|
872
|
+
const indexPut = async (value: any) => {
|
|
873
|
+
const ctx = value?.__context;
|
|
874
|
+
if (!ctx) {
|
|
875
|
+
throw new Error("Missing __context for index.put");
|
|
876
|
+
}
|
|
877
|
+
const context = ctx instanceof Context ? ctx : new Context(ctx as any);
|
|
878
|
+
const indexType = properties.indexType ?? properties.type;
|
|
879
|
+
const stripped = { ...(value as any) };
|
|
880
|
+
delete (stripped as any).__context;
|
|
881
|
+
const indexed = asInstanceOf(stripped, indexType);
|
|
882
|
+
const request = new DocumentsIndexPutRequest({
|
|
883
|
+
indexed: serialize(indexed as any),
|
|
884
|
+
context,
|
|
885
|
+
});
|
|
886
|
+
await raw.indexPut(request);
|
|
887
|
+
};
|
|
888
|
+
|
|
889
|
+
const createIndexIterator = (
|
|
890
|
+
iterator: ResultsIterator<WithContext<I>>,
|
|
891
|
+
): indexerTypes.IndexIterator<
|
|
892
|
+
WithContext<I>,
|
|
893
|
+
indexerTypes.Shape | undefined
|
|
894
|
+
> => {
|
|
895
|
+
const toIndexedResult = (value: WithContext<I>) => ({
|
|
896
|
+
id: resolveId(value),
|
|
897
|
+
value,
|
|
898
|
+
});
|
|
899
|
+
return {
|
|
900
|
+
next: async (amount: number) => {
|
|
901
|
+
const batch = await iterator.next(amount);
|
|
902
|
+
return batch.map(toIndexedResult);
|
|
903
|
+
},
|
|
904
|
+
all: async () => {
|
|
905
|
+
const batch = await iterator.all();
|
|
906
|
+
return batch.map(toIndexedResult);
|
|
907
|
+
},
|
|
908
|
+
done: () => iterator.done(),
|
|
909
|
+
pending: async () => {
|
|
910
|
+
const pending = await iterator.pending();
|
|
911
|
+
return pending ?? 0;
|
|
912
|
+
},
|
|
913
|
+
close: async () => {
|
|
914
|
+
await iterator.close();
|
|
915
|
+
},
|
|
916
|
+
};
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
index.putWithContext = putWithContext;
|
|
920
|
+
index.wrappedIndexedType = WrappedIndexedType as unknown as new (
|
|
921
|
+
value: I,
|
|
922
|
+
context: Context,
|
|
923
|
+
) => WithContext<I>;
|
|
924
|
+
index.index = {
|
|
925
|
+
count: async (options?: indexerTypes.CountOptions) => {
|
|
926
|
+
return countByIterate(options?.query as any);
|
|
927
|
+
},
|
|
928
|
+
getSize: indexSize,
|
|
929
|
+
get: async (
|
|
930
|
+
id: indexerTypes.IdKey,
|
|
931
|
+
_options?: { shape?: indexerTypes.Shape },
|
|
932
|
+
) => {
|
|
933
|
+
const value = await fetchValue(id, {
|
|
934
|
+
resolve: false,
|
|
935
|
+
local: true,
|
|
936
|
+
remote: false,
|
|
937
|
+
} as any);
|
|
938
|
+
return value
|
|
939
|
+
? { id: coerceIdKey(id), value: value as WithContext<I> }
|
|
940
|
+
: undefined;
|
|
941
|
+
},
|
|
942
|
+
iterate: (
|
|
943
|
+
request?: indexerTypes.IterateOptions,
|
|
944
|
+
_options?: { shape?: indexerTypes.Shape; reference?: boolean },
|
|
945
|
+
) => {
|
|
946
|
+
const iterator = index.iterate(
|
|
947
|
+
request as any,
|
|
948
|
+
{
|
|
949
|
+
resolve: false,
|
|
950
|
+
local: true,
|
|
951
|
+
remote: false,
|
|
952
|
+
} as any,
|
|
953
|
+
) as unknown as ResultsIterator<WithContext<I>>;
|
|
954
|
+
return createIndexIterator(iterator);
|
|
955
|
+
},
|
|
956
|
+
put: indexPut,
|
|
957
|
+
};
|
|
958
|
+
|
|
959
|
+
const close = async () => {
|
|
960
|
+
if (closed) return;
|
|
961
|
+
closed = true;
|
|
962
|
+
raw.changes.removeEventListener("change", onChange);
|
|
963
|
+
try {
|
|
964
|
+
await log.close();
|
|
965
|
+
await raw.close();
|
|
966
|
+
} finally {
|
|
967
|
+
channel.close?.();
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
const proxy = {
|
|
972
|
+
raw,
|
|
973
|
+
log,
|
|
974
|
+
events: changes,
|
|
975
|
+
changes,
|
|
976
|
+
index,
|
|
977
|
+
put: async (doc) => raw.put(new Bytes({ value: serialize(doc as any) })),
|
|
978
|
+
get,
|
|
979
|
+
del: async (id) => raw.del(coerceIdKey(id)),
|
|
980
|
+
count,
|
|
981
|
+
waitFor,
|
|
982
|
+
recover: async () => {
|
|
983
|
+
await raw.recover();
|
|
984
|
+
},
|
|
985
|
+
close,
|
|
986
|
+
} as DocumentsProxy<T, I>;
|
|
987
|
+
|
|
988
|
+
Object.defineProperty(proxy, "closed", {
|
|
989
|
+
get: () => closed,
|
|
990
|
+
set: (value: boolean) => {
|
|
991
|
+
closed = value;
|
|
992
|
+
},
|
|
993
|
+
enumerable: true,
|
|
994
|
+
});
|
|
995
|
+
|
|
996
|
+
return proxy;
|
|
997
|
+
};
|