@graffiti-garden/implementation-decentralized 0.1.3 → 0.1.5
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/1-services/4-inboxes/cache.d.ts +34 -0
- package/dist/1-services/4-inboxes/cache.d.ts.map +1 -0
- package/dist/1-services/4-inboxes/messages.d.ts +70 -0
- package/dist/1-services/4-inboxes/messages.d.ts.map +1 -0
- package/dist/1-services/4-inboxes.d.ts +28 -67
- package/dist/1-services/4-inboxes.d.ts.map +1 -1
- package/dist/3-protocol/4-graffiti.d.ts +1 -0
- package/dist/3-protocol/4-graffiti.d.ts.map +1 -1
- package/dist/browser/index.js +7 -7
- package/dist/browser/index.js.map +4 -4
- package/dist/cjs/1-services/1-authorization.js +1 -1
- package/dist/cjs/1-services/1-authorization.js.map +2 -2
- package/dist/cjs/1-services/4-inboxes/cache.js +186 -0
- package/dist/cjs/1-services/4-inboxes/cache.js.map +7 -0
- package/dist/cjs/1-services/4-inboxes/messages.js +69 -0
- package/dist/cjs/1-services/4-inboxes/messages.js.map +7 -0
- package/dist/cjs/1-services/4-inboxes-tests.js +339 -9
- package/dist/cjs/1-services/4-inboxes-tests.js.map +3 -3
- package/dist/cjs/1-services/4-inboxes.js +210 -399
- package/dist/cjs/1-services/4-inboxes.js.map +3 -3
- package/dist/cjs/3-protocol/4-graffiti.js +19 -10
- package/dist/cjs/3-protocol/4-graffiti.js.map +2 -2
- package/dist/cjs/index.spec.js +1 -0
- package/dist/cjs/index.spec.js.map +2 -2
- package/dist/esm/1-services/1-authorization.js +1 -1
- package/dist/esm/1-services/1-authorization.js.map +2 -2
- package/dist/esm/1-services/4-inboxes/cache.js +156 -0
- package/dist/esm/1-services/4-inboxes/cache.js.map +7 -0
- package/dist/esm/1-services/4-inboxes/messages.js +60 -0
- package/dist/esm/1-services/4-inboxes/messages.js.map +7 -0
- package/dist/esm/1-services/4-inboxes-tests.js +340 -10
- package/dist/esm/1-services/4-inboxes-tests.js.map +3 -3
- package/dist/esm/1-services/4-inboxes.js +222 -383
- package/dist/esm/1-services/4-inboxes.js.map +3 -3
- package/dist/esm/3-protocol/4-graffiti.js +19 -10
- package/dist/esm/3-protocol/4-graffiti.js.map +2 -2
- package/dist/esm/index.spec.js +2 -1
- package/dist/esm/index.spec.js.map +2 -2
- package/package.json +1 -1
- package/src/1-services/1-authorization.ts +1 -1
- package/src/1-services/4-inboxes/cache.ts +227 -0
- package/src/1-services/4-inboxes/messages.ts +63 -0
- package/src/1-services/4-inboxes-tests.ts +387 -2
- package/src/1-services/4-inboxes.ts +297 -512
- package/src/3-protocol/4-graffiti.ts +26 -10
- package/src/index.spec.ts +3 -1
|
@@ -18,13 +18,15 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var inboxes_tests_exports = {};
|
|
20
20
|
__export(inboxes_tests_exports, {
|
|
21
|
-
inboxTests: () => inboxTests
|
|
21
|
+
inboxTests: () => inboxTests,
|
|
22
|
+
inboxUnitTests: () => inboxUnitTests
|
|
22
23
|
});
|
|
23
24
|
module.exports = __toCommonJS(inboxes_tests_exports);
|
|
24
25
|
var import_vitest = require("vitest");
|
|
25
26
|
var import_inboxes = require("./4-inboxes");
|
|
26
27
|
var import_utilities = require("./utilities");
|
|
27
28
|
var import_utils = require("@noble/hashes/utils.js");
|
|
29
|
+
var import_api = require("@graffiti-garden/api");
|
|
28
30
|
var import_dag_cbor = require("@ipld/dag-cbor");
|
|
29
31
|
function inboxTests(inboxEndpoint, inboxToken) {
|
|
30
32
|
(0, import_vitest.describe)("Inboxes", async () => {
|
|
@@ -49,10 +51,10 @@ function inboxTests(inboxEndpoint, inboxToken) {
|
|
|
49
51
|
t: tags
|
|
50
52
|
};
|
|
51
53
|
const messageId = await inboxes.send(inboxEndpoint, sending);
|
|
52
|
-
const
|
|
53
|
-
(0, import_vitest.assert)(
|
|
54
|
-
(0, import_vitest.expect)(
|
|
55
|
-
(0, import_vitest.expect)(
|
|
54
|
+
const message2 = await inboxes.get(inboxEndpoint, messageId, inboxToken);
|
|
55
|
+
(0, import_vitest.assert)(message2 !== null);
|
|
56
|
+
(0, import_vitest.expect)(message2.m).toEqual(sending);
|
|
57
|
+
(0, import_vitest.expect)(message2.l).toEqual(0);
|
|
56
58
|
const iterator = inboxes.query(inboxEndpoint, tags, {}, inboxToken);
|
|
57
59
|
const result = await iterator.next();
|
|
58
60
|
(0, import_vitest.assert)(!result.done);
|
|
@@ -69,10 +71,10 @@ function inboxTests(inboxEndpoint, inboxToken) {
|
|
|
69
71
|
(0, import_vitest.expect)(result2.value.l).toEqual(42);
|
|
70
72
|
const endResult2 = await iterator2.next();
|
|
71
73
|
(0, import_vitest.expect)(endResult2.done).toBe(true);
|
|
72
|
-
const
|
|
73
|
-
(0, import_vitest.assert)(
|
|
74
|
-
(0, import_vitest.expect)(
|
|
75
|
-
(0, import_vitest.expect)(
|
|
74
|
+
const message22 = await inboxes.get(inboxEndpoint, messageId, inboxToken);
|
|
75
|
+
(0, import_vitest.assert)(message22 !== null);
|
|
76
|
+
(0, import_vitest.expect)(message22.m).toEqual(sending);
|
|
77
|
+
(0, import_vitest.expect)(message22.l).toEqual(42);
|
|
76
78
|
});
|
|
77
79
|
(0, import_vitest.test)("query with continue", async () => {
|
|
78
80
|
const tags = [(0, import_utils.randomBytes)(), (0, import_utils.randomBytes)()];
|
|
@@ -164,4 +166,332 @@ function inboxTests(inboxEndpoint, inboxToken) {
|
|
|
164
166
|
}, 1e5);
|
|
165
167
|
});
|
|
166
168
|
}
|
|
169
|
+
const inboxUrl = "https://example.test/inbox";
|
|
170
|
+
const message = {
|
|
171
|
+
id: "message-1",
|
|
172
|
+
m: {
|
|
173
|
+
t: [new Uint8Array([1])],
|
|
174
|
+
o: {
|
|
175
|
+
url: "https://example.test/object",
|
|
176
|
+
actor: "did:example:author",
|
|
177
|
+
channels: ["test"],
|
|
178
|
+
value: {}
|
|
179
|
+
},
|
|
180
|
+
m: new Uint8Array([2])
|
|
181
|
+
},
|
|
182
|
+
l: 0
|
|
183
|
+
};
|
|
184
|
+
function cborResponse(value) {
|
|
185
|
+
return new Response(new Uint8Array((0, import_dag_cbor.encode)(value)).slice(), {
|
|
186
|
+
headers: { "Content-Type": "application/cbor" }
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function queryPage(results, cursor, hasMore = false) {
|
|
190
|
+
return cborResponse({ results, hasMore, cursor });
|
|
191
|
+
}
|
|
192
|
+
class TestInboxes extends import_inboxes.Inboxes {
|
|
193
|
+
async prepareCache() {
|
|
194
|
+
await this.cache;
|
|
195
|
+
}
|
|
196
|
+
async deleteCachedQuery(key) {
|
|
197
|
+
await (await this.cache).messageIds.del(key);
|
|
198
|
+
}
|
|
199
|
+
async fetchQueryBatch() {
|
|
200
|
+
const batch = await this.fetchMessageBatch(
|
|
201
|
+
"https://example.test/inbox",
|
|
202
|
+
"query",
|
|
203
|
+
void 0
|
|
204
|
+
);
|
|
205
|
+
await batch.response.arrayBuffer();
|
|
206
|
+
return batch;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function enableLockPath(request) {
|
|
210
|
+
import_vitest.vi.stubGlobal("indexedDB", {
|
|
211
|
+
open: () => {
|
|
212
|
+
const probe = {};
|
|
213
|
+
queueMicrotask(() => {
|
|
214
|
+
probe.result = { close() {
|
|
215
|
+
} };
|
|
216
|
+
probe.onsuccess?.();
|
|
217
|
+
});
|
|
218
|
+
return probe;
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
import_vitest.vi.stubGlobal("window", { navigator: { locks: { request } } });
|
|
222
|
+
}
|
|
223
|
+
function inboxUnitTests() {
|
|
224
|
+
(0, import_vitest.describe)("Inboxes unit", () => {
|
|
225
|
+
(0, import_vitest.afterEach)(() => {
|
|
226
|
+
import_vitest.vi.unstubAllGlobals();
|
|
227
|
+
import_vitest.vi.restoreAllMocks();
|
|
228
|
+
});
|
|
229
|
+
(0, import_vitest.describe)("inbox stream lock and network failures", () => {
|
|
230
|
+
(0, import_vitest.test)("backs off for five seconds after an initial request failure", async () => {
|
|
231
|
+
const failure = new Error("offline");
|
|
232
|
+
const fetch2 = import_vitest.vi.fn(() => Promise.reject(failure));
|
|
233
|
+
import_vitest.vi.stubGlobal("fetch", fetch2);
|
|
234
|
+
import_vitest.vi.spyOn(console, "error").mockImplementation(() => {
|
|
235
|
+
});
|
|
236
|
+
const realSetTimeout = globalThis.setTimeout;
|
|
237
|
+
const timer = import_vitest.vi.spyOn(globalThis, "setTimeout").mockImplementation(
|
|
238
|
+
((handler, delay, ...args) => realSetTimeout(
|
|
239
|
+
handler,
|
|
240
|
+
delay === 5e3 ? 0 : delay,
|
|
241
|
+
...args
|
|
242
|
+
))
|
|
243
|
+
);
|
|
244
|
+
await (0, import_vitest.expect)(new import_inboxes.Inboxes().query(inboxUrl, [], {}).next()).rejects.toBe(
|
|
245
|
+
failure
|
|
246
|
+
);
|
|
247
|
+
(0, import_vitest.expect)(fetch2).toHaveBeenCalledOnce();
|
|
248
|
+
(0, import_vitest.expect)(timer).toHaveBeenCalledWith(import_vitest.expect.any(Function), 5e3);
|
|
249
|
+
});
|
|
250
|
+
(0, import_vitest.test)("a rejected lock request rejects the stream", async () => {
|
|
251
|
+
const inboxes = new TestInboxes();
|
|
252
|
+
await inboxes.prepareCache();
|
|
253
|
+
const error = new Error("lock request failed");
|
|
254
|
+
enableLockPath(import_vitest.vi.fn(() => Promise.reject(error)));
|
|
255
|
+
await (0, import_vitest.expect)(
|
|
256
|
+
inboxes.query("https://example.test/inbox", [], {}).next()
|
|
257
|
+
).rejects.toBe(error);
|
|
258
|
+
});
|
|
259
|
+
(0, import_vitest.test)("waiting for another tab's lock has a deadline", async () => {
|
|
260
|
+
const inboxes = new TestInboxes();
|
|
261
|
+
await inboxes.prepareCache();
|
|
262
|
+
const timeoutError = new DOMException("timed out", "TimeoutError");
|
|
263
|
+
import_vitest.vi.spyOn(AbortSignal, "timeout").mockReturnValue(
|
|
264
|
+
AbortSignal.abort(timeoutError)
|
|
265
|
+
);
|
|
266
|
+
const request = import_vitest.vi.fn(
|
|
267
|
+
(_key, _options) => Promise.reject(timeoutError)
|
|
268
|
+
);
|
|
269
|
+
enableLockPath(request);
|
|
270
|
+
await (0, import_vitest.expect)(
|
|
271
|
+
inboxes.query("https://example.test/inbox", [], {}).next()
|
|
272
|
+
).rejects.toThrow("Timed out waiting for another tab's inbox query");
|
|
273
|
+
(0, import_vitest.expect)(request).toHaveBeenCalledOnce();
|
|
274
|
+
});
|
|
275
|
+
(0, import_vitest.test)("a stalled request is aborted", async () => {
|
|
276
|
+
const realTimeout = AbortSignal.timeout;
|
|
277
|
+
import_vitest.vi.spyOn(AbortSignal, "timeout").mockImplementation(() => realTimeout(5));
|
|
278
|
+
import_vitest.vi.stubGlobal(
|
|
279
|
+
"fetch",
|
|
280
|
+
import_vitest.vi.fn(
|
|
281
|
+
(_url, options) => new Promise((_resolve, reject) => {
|
|
282
|
+
const signal = options.signal;
|
|
283
|
+
signal.addEventListener("abort", () => reject(signal.reason), {
|
|
284
|
+
once: true
|
|
285
|
+
});
|
|
286
|
+
})
|
|
287
|
+
)
|
|
288
|
+
);
|
|
289
|
+
await (0, import_vitest.expect)(new TestInboxes().fetchQueryBatch()).rejects.toMatchObject({
|
|
290
|
+
name: "TimeoutError"
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
(0, import_vitest.test)("the deadline remains active while reading a response body", async () => {
|
|
294
|
+
const realTimeout = AbortSignal.timeout;
|
|
295
|
+
import_vitest.vi.spyOn(AbortSignal, "timeout").mockImplementation(() => realTimeout(5));
|
|
296
|
+
import_vitest.vi.stubGlobal(
|
|
297
|
+
"fetch",
|
|
298
|
+
import_vitest.vi.fn((_url, options) => {
|
|
299
|
+
const signal = options.signal;
|
|
300
|
+
const body = new ReadableStream({
|
|
301
|
+
start(controller) {
|
|
302
|
+
signal.addEventListener("abort", () => controller.error(signal.reason), {
|
|
303
|
+
once: true
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
return Promise.resolve(new Response(body));
|
|
308
|
+
})
|
|
309
|
+
);
|
|
310
|
+
await (0, import_vitest.expect)(new TestInboxes().fetchQueryBatch()).rejects.toMatchObject({
|
|
311
|
+
name: "TimeoutError"
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
(0, import_vitest.describe)("inbox query cache", () => {
|
|
316
|
+
(0, import_vitest.test)("fetches the next page while the current message is yielded", async () => {
|
|
317
|
+
const inboxes = new TestInboxes();
|
|
318
|
+
await inboxes.prepareCache();
|
|
319
|
+
let held = 0;
|
|
320
|
+
enableLockPath(import_vitest.vi.fn(async (key, _options, callback) => {
|
|
321
|
+
held++;
|
|
322
|
+
try {
|
|
323
|
+
return await callback({ name: key, mode: "exclusive" });
|
|
324
|
+
} finally {
|
|
325
|
+
held--;
|
|
326
|
+
}
|
|
327
|
+
}));
|
|
328
|
+
let prefetchAborted = false;
|
|
329
|
+
const fetch2 = import_vitest.vi.fn((_url, options) => {
|
|
330
|
+
if (fetch2.mock.calls.length === 1) {
|
|
331
|
+
return Promise.resolve(queryPage([message], "cursor-1", true));
|
|
332
|
+
}
|
|
333
|
+
return new Promise((_resolve, reject) => {
|
|
334
|
+
const signal = options.signal;
|
|
335
|
+
signal.addEventListener("abort", () => {
|
|
336
|
+
prefetchAborted = true;
|
|
337
|
+
reject(signal.reason);
|
|
338
|
+
}, { once: true });
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
import_vitest.vi.stubGlobal("fetch", fetch2);
|
|
342
|
+
const iterator = inboxes.query(inboxUrl, [new Uint8Array([1])], {});
|
|
343
|
+
(0, import_vitest.expect)((await iterator.next()).value).toEqual(message);
|
|
344
|
+
await import_vitest.vi.waitFor(() => (0, import_vitest.expect)(fetch2).toHaveBeenCalledTimes(2));
|
|
345
|
+
(0, import_vitest.expect)(fetch2.mock.calls[1][0]).toBe(`${inboxUrl}/query?cursor=cursor-1`);
|
|
346
|
+
await iterator.return("");
|
|
347
|
+
(0, import_vitest.expect)(prefetchAborted).toBe(true);
|
|
348
|
+
await import_vitest.vi.waitFor(() => (0, import_vitest.expect)(held).toBe(0));
|
|
349
|
+
});
|
|
350
|
+
(0, import_vitest.test)("reports a cursor that expires after the first page", async () => {
|
|
351
|
+
const fetch2 = import_vitest.vi.fn().mockResolvedValueOnce(queryPage([message], "cursor-1", true)).mockResolvedValueOnce(new Response("stale", { status: 410 }));
|
|
352
|
+
import_vitest.vi.stubGlobal("fetch", fetch2);
|
|
353
|
+
const iterator = new import_inboxes.Inboxes().query(inboxUrl, [new Uint8Array([1])], {});
|
|
354
|
+
(0, import_vitest.expect)((await iterator.next()).value).toEqual(message);
|
|
355
|
+
await (0, import_vitest.expect)(iterator.next()).rejects.toBeInstanceOf(
|
|
356
|
+
import_api.GraffitiErrorCursorExpired
|
|
357
|
+
);
|
|
358
|
+
(0, import_vitest.expect)(fetch2).toHaveBeenCalledTimes(2);
|
|
359
|
+
});
|
|
360
|
+
(0, import_vitest.test)("does not replay messages after another tab resets the cache", async () => {
|
|
361
|
+
const inboxes = new TestInboxes();
|
|
362
|
+
await inboxes.prepareCache();
|
|
363
|
+
let markPrefetchStarted;
|
|
364
|
+
const prefetchStarted = new Promise((resolve) => {
|
|
365
|
+
markPrefetchStarted = resolve;
|
|
366
|
+
});
|
|
367
|
+
let releasePrefetch;
|
|
368
|
+
const pause = new Promise((resolve) => {
|
|
369
|
+
releasePrefetch = resolve;
|
|
370
|
+
});
|
|
371
|
+
let lockCalls = 0;
|
|
372
|
+
let cacheKey = "";
|
|
373
|
+
enableLockPath(import_vitest.vi.fn(async (name, _options, work) => {
|
|
374
|
+
cacheKey = name.slice("graffiti:inbox:".length);
|
|
375
|
+
if (++lockCalls === 2) {
|
|
376
|
+
markPrefetchStarted();
|
|
377
|
+
await pause;
|
|
378
|
+
}
|
|
379
|
+
return work({ name, mode: "exclusive" });
|
|
380
|
+
}));
|
|
381
|
+
import_vitest.vi.stubGlobal("fetch", import_vitest.vi.fn(async () => queryPage([message], "cursor-1", true)));
|
|
382
|
+
const iterator = inboxes.query(inboxUrl, [new Uint8Array([1])], {});
|
|
383
|
+
(0, import_vitest.expect)((await iterator.next()).value).toEqual(message);
|
|
384
|
+
await prefetchStarted;
|
|
385
|
+
await inboxes.deleteCachedQuery(cacheKey);
|
|
386
|
+
releasePrefetch();
|
|
387
|
+
await (0, import_vitest.expect)(iterator.next()).rejects.toBeInstanceOf(
|
|
388
|
+
import_api.GraffitiErrorCursorExpired
|
|
389
|
+
);
|
|
390
|
+
});
|
|
391
|
+
(0, import_vitest.test)("a later query reads messages from the cached server cursor", async () => {
|
|
392
|
+
const fetch2 = import_vitest.vi.fn().mockResolvedValueOnce(queryPage([message], "cursor-1")).mockResolvedValueOnce(queryPage([], "cursor-2"));
|
|
393
|
+
import_vitest.vi.stubGlobal("fetch", fetch2);
|
|
394
|
+
const inboxes = new import_inboxes.Inboxes();
|
|
395
|
+
const tags = [new Uint8Array([1])];
|
|
396
|
+
const first = inboxes.query(inboxUrl, tags, {});
|
|
397
|
+
(0, import_vitest.expect)((await first.next()).value).toEqual(message);
|
|
398
|
+
(0, import_vitest.expect)((await first.next()).done).toBe(true);
|
|
399
|
+
const second = inboxes.query(inboxUrl, tags, {});
|
|
400
|
+
(0, import_vitest.expect)((await second.next()).value).toEqual(message);
|
|
401
|
+
(0, import_vitest.expect)((await second.next()).done).toBe(true);
|
|
402
|
+
(0, import_vitest.expect)(fetch2).toHaveBeenCalledTimes(2);
|
|
403
|
+
(0, import_vitest.expect)(fetch2.mock.calls[1][0]).toBe(`${inboxUrl}/query?cursor=cursor-1`);
|
|
404
|
+
});
|
|
405
|
+
(0, import_vitest.test)("does not hold the query lock while a message is yielded", async () => {
|
|
406
|
+
const inboxes = new TestInboxes();
|
|
407
|
+
await inboxes.prepareCache();
|
|
408
|
+
let held = false;
|
|
409
|
+
enableLockPath(import_vitest.vi.fn(async (key, _options, callback) => {
|
|
410
|
+
held = true;
|
|
411
|
+
try {
|
|
412
|
+
return await callback({ name: key, mode: "exclusive" });
|
|
413
|
+
} finally {
|
|
414
|
+
held = false;
|
|
415
|
+
}
|
|
416
|
+
}));
|
|
417
|
+
import_vitest.vi.stubGlobal("fetch", import_vitest.vi.fn(async () => queryPage([message], "cursor-1")));
|
|
418
|
+
const iterator = inboxes.query(inboxUrl, [new Uint8Array([1])], {});
|
|
419
|
+
try {
|
|
420
|
+
(0, import_vitest.expect)((await iterator.next()).value).toEqual(message);
|
|
421
|
+
(0, import_vitest.expect)(held).toBe(false);
|
|
422
|
+
} finally {
|
|
423
|
+
await iterator.return("");
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
(0, import_vitest.test)("closing a yielded query leaves no lock held", async () => {
|
|
427
|
+
const inboxes = new TestInboxes();
|
|
428
|
+
await inboxes.prepareCache();
|
|
429
|
+
let held = false;
|
|
430
|
+
enableLockPath(import_vitest.vi.fn(async (key, _options, callback) => {
|
|
431
|
+
held = true;
|
|
432
|
+
try {
|
|
433
|
+
return await callback({ name: key, mode: "exclusive" });
|
|
434
|
+
} finally {
|
|
435
|
+
held = false;
|
|
436
|
+
}
|
|
437
|
+
}));
|
|
438
|
+
import_vitest.vi.stubGlobal("fetch", import_vitest.vi.fn(async () => queryPage([message], "cursor-1")));
|
|
439
|
+
const iterator = inboxes.query(inboxUrl, [new Uint8Array([1])], {});
|
|
440
|
+
(0, import_vitest.expect)((await iterator.next()).value).toEqual(message);
|
|
441
|
+
(0, import_vitest.expect)(held).toBe(false);
|
|
442
|
+
await iterator.return("");
|
|
443
|
+
(0, import_vitest.expect)(held).toBe(false);
|
|
444
|
+
});
|
|
445
|
+
(0, import_vitest.test)("concurrent queries reuse a page fetched under the lock", async () => {
|
|
446
|
+
const inboxes = new TestInboxes();
|
|
447
|
+
await inboxes.prepareCache();
|
|
448
|
+
let releasePrevious = Promise.resolve();
|
|
449
|
+
let requests = 0;
|
|
450
|
+
let bothRequested;
|
|
451
|
+
const ready = new Promise((resolve) => {
|
|
452
|
+
bothRequested = resolve;
|
|
453
|
+
});
|
|
454
|
+
enableLockPath(import_vitest.vi.fn(async (key, _options, callback) => {
|
|
455
|
+
requests++;
|
|
456
|
+
if (requests === 2) bothRequested();
|
|
457
|
+
const previous = releasePrevious;
|
|
458
|
+
let release;
|
|
459
|
+
releasePrevious = new Promise((resolve) => {
|
|
460
|
+
release = resolve;
|
|
461
|
+
});
|
|
462
|
+
await previous;
|
|
463
|
+
try {
|
|
464
|
+
return await callback({ name: key, mode: "exclusive" });
|
|
465
|
+
} finally {
|
|
466
|
+
release();
|
|
467
|
+
}
|
|
468
|
+
}));
|
|
469
|
+
const nextMessage = { ...message, id: "message-2" };
|
|
470
|
+
const fetch2 = import_vitest.vi.fn(async () => {
|
|
471
|
+
await ready;
|
|
472
|
+
return fetch2.mock.calls.length === 1 ? queryPage([message], "cursor-1", true) : queryPage([nextMessage], "cursor-2");
|
|
473
|
+
});
|
|
474
|
+
import_vitest.vi.stubGlobal("fetch", fetch2);
|
|
475
|
+
const tags = [new Uint8Array([1])];
|
|
476
|
+
const first = inboxes.query(inboxUrl, tags, {});
|
|
477
|
+
const second = inboxes.query(inboxUrl, tags, {});
|
|
478
|
+
const [firstResult, secondResult] = await Promise.all([
|
|
479
|
+
first.next(),
|
|
480
|
+
second.next()
|
|
481
|
+
]);
|
|
482
|
+
(0, import_vitest.expect)(firstResult.value).toEqual(message);
|
|
483
|
+
(0, import_vitest.expect)(secondResult.value).toEqual(message);
|
|
484
|
+
const [firstNext, secondNext] = await Promise.all([
|
|
485
|
+
first.next(),
|
|
486
|
+
second.next()
|
|
487
|
+
]);
|
|
488
|
+
(0, import_vitest.expect)(firstNext.value).toEqual(nextMessage);
|
|
489
|
+
(0, import_vitest.expect)(secondNext.value).toEqual(nextMessage);
|
|
490
|
+
(0, import_vitest.expect)(fetch2).toHaveBeenCalledTimes(2);
|
|
491
|
+
(0, import_vitest.expect)((await first.next()).done).toBe(true);
|
|
492
|
+
(0, import_vitest.expect)((await second.next()).done).toBe(true);
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
}
|
|
167
497
|
//# sourceMappingURL=4-inboxes-tests.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/1-services/4-inboxes-tests.ts"],
|
|
4
|
-
"sourcesContent": ["import { assert, describe, expect, test } from \"vitest\";\nimport { Inboxes, LABELED_MESSAGE_LABEL_KEY } from \"./4-inboxes\";\nimport { GraffitiErrorUnauthorized } from \"./utilities\";\nimport { randomBytes } from \"@noble/hashes/utils.js\";\nimport type { GraffitiObjectBase } from \"@graffiti-garden/api\";\nimport { encode as dagCborEncode, decode as dagCborDecode } from \"@ipld/dag-cbor\";\n\nexport function inboxTests(inboxEndpoint: string, inboxToken: string) {\n describe(\"Inboxes\", async () => {\n const inboxes = new Inboxes();\n\n test(\"send, get\", async () => {\n const tags = [randomBytes(), randomBytes()];\n const metadata = randomBytes();\n const object: GraffitiObjectBase = {\n url: \"url:example\",\n actor: \"did:example\",\n channels: [\"example\", \"something\"],\n value: {\n nested: {\n property: [1, \"askdfj\", null],\n },\n },\n allowed: [\"did:example2\"],\n };\n\n const sending = {\n m: metadata,\n o: object,\n t: tags,\n };\n const messageId = await inboxes.send(inboxEndpoint, sending);\n\n // Get the message back\n const message = await inboxes.get(inboxEndpoint, messageId, inboxToken);\n assert(message !== null);\n expect(message.m).toEqual(sending);\n expect(message.l).toEqual(0);\n\n const iterator = inboxes.query<{}>(inboxEndpoint, tags, {}, inboxToken);\n\n const result = await iterator.next();\n assert(!result.done);\n\n // No label yet so it must be zero\n expect(result.value.l).toEqual(0);\n\n expect(result.value.m.t).toEqual(tags);\n expect(result.value.m.o).toEqual(object);\n expect(result.value.id).toEqual(messageId);\n\n const endResult = await iterator.next();\n expect(endResult.done).toBe(true);\n\n // Label the message\n await inboxes.label(inboxEndpoint, messageId, 42, inboxToken);\n\n const iterator2 = inboxes.query<{}>(inboxEndpoint, tags, {}, inboxToken);\n\n const result2 = await iterator2.next();\n assert(!result2.done);\n expect(result2.value.l).toEqual(42);\n const endResult2 = await iterator2.next();\n expect(endResult2.done).toBe(true);\n\n const message2 = await inboxes.get(inboxEndpoint, messageId, inboxToken);\n assert(message2 !== null);\n expect(message2.m).toEqual(sending);\n expect(message2.l).toEqual(42);\n });\n\n test(\"query with continue\", async () => {\n const tags = [randomBytes(), randomBytes()];\n\n const nullResult = await inboxes\n .query<{}>(inboxEndpoint, tags, {}, inboxToken)\n .next();\n assert(nullResult.done);\n const cursor = nullResult.value;\n\n const metadata = randomBytes();\n\n const messageId = await inboxes.send(inboxEndpoint, {\n o: {\n url: \"url:example\",\n actor: \"did:example\",\n channels: [\"example\", \"something\"],\n value: {\n nested: {\n property: [1, \"askdfj\", null],\n },\n },\n allowed: [\"did:example2\"],\n },\n t: [randomBytes(), tags[0]],\n m: metadata,\n });\n\n const result = await inboxes\n .continueQuery(inboxEndpoint, cursor, inboxToken)\n .next();\n assert(!result.done);\n expect(result.value.id).toEqual(messageId);\n });\n\n test(\"unauthorized access\", async () => {\n const tags = [randomBytes()];\n\n await expect(\n inboxes.query(inboxEndpoint, tags, {}, \"invalid-token\").next(),\n ).rejects.toThrowError(GraffitiErrorUnauthorized);\n await expect(\n inboxes.label(inboxEndpoint, \"1\", 1, \"invalid-token\"),\n ).rejects.toThrowError(GraffitiErrorUnauthorized);\n await expect(\n inboxes.export(inboxEndpoint, \"invalid-token\").next(),\n ).rejects.toThrowError(GraffitiErrorUnauthorized);\n }, 30000);\n\n test(\"query paged\", async () => {\n const tags = [randomBytes(), randomBytes()];\n\n const numSends = 211;\n for (let i = 0; i < numSends; i++) {\n await inboxes.send(inboxEndpoint, {\n t: tags,\n m: randomBytes(),\n o: {\n url: \"url:example\",\n actor: \"did:example\",\n channels: [\"example\", \"something\"],\n value: {\n nested: {\n property: [1, \"askdfj\", null],\n },\n },\n allowed: [\"did:example2\"],\n },\n });\n }\n\n let cursor: string | undefined;\n for (const [page, expectedCount] of [10, 100, 101].entries()) {\n const response = await fetch(\n `${inboxEndpoint}/query${cursor ? `?cursor=${encodeURIComponent(cursor)}` : \"\"}`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/cbor\",\n Authorization: `Bearer ${inboxToken}`,\n },\n body: cursor ? undefined : dagCborEncode({ tags: [tags[1]], schema: {} }).slice(),\n },\n );\n expect(response.status).toBe(200);\n const pageResult = dagCborDecode(new Uint8Array(await response.arrayBuffer())) as {\n results: unknown[];\n hasMore: boolean;\n cursor: string;\n };\n expect(pageResult.results).toHaveLength(expectedCount);\n expect(pageResult.hasMore).toBe(page < 2);\n cursor = pageResult.cursor;\n }\n\n const iterator = inboxes.query(\n inboxEndpoint,\n [randomBytes(), tags[1], randomBytes()],\n {},\n inboxToken,\n );\n\n let count = 0;\n for await (const _ of iterator) {\n count++;\n }\n\n expect(count).toBe(numSends);\n }, 100000);\n });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["dagCborEncode", "dagCborDecode"]
|
|
4
|
+
"sourcesContent": ["import { afterEach, assert, describe, expect, test, vi } from \"vitest\";\nimport { Inboxes, LABELED_MESSAGE_LABEL_KEY } from \"./4-inboxes\";\nimport { GraffitiErrorUnauthorized } from \"./utilities\";\nimport { randomBytes } from \"@noble/hashes/utils.js\";\nimport { GraffitiErrorCursorExpired, type GraffitiObjectBase } from \"@graffiti-garden/api\";\nimport { encode as dagCborEncode, decode as dagCborDecode } from \"@ipld/dag-cbor\";\n\nexport function inboxTests(inboxEndpoint: string, inboxToken: string) {\n describe(\"Inboxes\", async () => {\n const inboxes = new Inboxes();\n\n test(\"send, get\", async () => {\n const tags = [randomBytes(), randomBytes()];\n const metadata = randomBytes();\n const object: GraffitiObjectBase = {\n url: \"url:example\",\n actor: \"did:example\",\n channels: [\"example\", \"something\"],\n value: {\n nested: {\n property: [1, \"askdfj\", null],\n },\n },\n allowed: [\"did:example2\"],\n };\n\n const sending = {\n m: metadata,\n o: object,\n t: tags,\n };\n const messageId = await inboxes.send(inboxEndpoint, sending);\n\n // Get the message back\n const message = await inboxes.get(inboxEndpoint, messageId, inboxToken);\n assert(message !== null);\n expect(message.m).toEqual(sending);\n expect(message.l).toEqual(0);\n\n const iterator = inboxes.query<{}>(inboxEndpoint, tags, {}, inboxToken);\n\n const result = await iterator.next();\n assert(!result.done);\n\n // No label yet so it must be zero\n expect(result.value.l).toEqual(0);\n\n expect(result.value.m.t).toEqual(tags);\n expect(result.value.m.o).toEqual(object);\n expect(result.value.id).toEqual(messageId);\n\n const endResult = await iterator.next();\n expect(endResult.done).toBe(true);\n\n // Label the message\n await inboxes.label(inboxEndpoint, messageId, 42, inboxToken);\n\n const iterator2 = inboxes.query<{}>(inboxEndpoint, tags, {}, inboxToken);\n\n const result2 = await iterator2.next();\n assert(!result2.done);\n expect(result2.value.l).toEqual(42);\n const endResult2 = await iterator2.next();\n expect(endResult2.done).toBe(true);\n\n const message2 = await inboxes.get(inboxEndpoint, messageId, inboxToken);\n assert(message2 !== null);\n expect(message2.m).toEqual(sending);\n expect(message2.l).toEqual(42);\n });\n\n test(\"query with continue\", async () => {\n const tags = [randomBytes(), randomBytes()];\n\n const nullResult = await inboxes\n .query<{}>(inboxEndpoint, tags, {}, inboxToken)\n .next();\n assert(nullResult.done);\n const cursor = nullResult.value;\n\n const metadata = randomBytes();\n\n const messageId = await inboxes.send(inboxEndpoint, {\n o: {\n url: \"url:example\",\n actor: \"did:example\",\n channels: [\"example\", \"something\"],\n value: {\n nested: {\n property: [1, \"askdfj\", null],\n },\n },\n allowed: [\"did:example2\"],\n },\n t: [randomBytes(), tags[0]],\n m: metadata,\n });\n\n const result = await inboxes\n .continueQuery(inboxEndpoint, cursor, inboxToken)\n .next();\n assert(!result.done);\n expect(result.value.id).toEqual(messageId);\n });\n\n test(\"unauthorized access\", async () => {\n const tags = [randomBytes()];\n\n await expect(\n inboxes.query(inboxEndpoint, tags, {}, \"invalid-token\").next(),\n ).rejects.toThrowError(GraffitiErrorUnauthorized);\n await expect(\n inboxes.label(inboxEndpoint, \"1\", 1, \"invalid-token\"),\n ).rejects.toThrowError(GraffitiErrorUnauthorized);\n await expect(\n inboxes.export(inboxEndpoint, \"invalid-token\").next(),\n ).rejects.toThrowError(GraffitiErrorUnauthorized);\n }, 30000);\n\n test(\"query paged\", async () => {\n const tags = [randomBytes(), randomBytes()];\n\n const numSends = 211;\n for (let i = 0; i < numSends; i++) {\n await inboxes.send(inboxEndpoint, {\n t: tags,\n m: randomBytes(),\n o: {\n url: \"url:example\",\n actor: \"did:example\",\n channels: [\"example\", \"something\"],\n value: {\n nested: {\n property: [1, \"askdfj\", null],\n },\n },\n allowed: [\"did:example2\"],\n },\n });\n }\n\n let cursor: string | undefined;\n for (const [page, expectedCount] of [10, 100, 101].entries()) {\n const response = await fetch(\n `${inboxEndpoint}/query${cursor ? `?cursor=${encodeURIComponent(cursor)}` : \"\"}`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/cbor\",\n Authorization: `Bearer ${inboxToken}`,\n },\n body: cursor ? undefined : dagCborEncode({ tags: [tags[1]], schema: {} }).slice(),\n },\n );\n expect(response.status).toBe(200);\n const pageResult = dagCborDecode(new Uint8Array(await response.arrayBuffer())) as {\n results: unknown[];\n hasMore: boolean;\n cursor: string;\n };\n expect(pageResult.results).toHaveLength(expectedCount);\n expect(pageResult.hasMore).toBe(page < 2);\n cursor = pageResult.cursor;\n }\n\n const iterator = inboxes.query(\n inboxEndpoint,\n [randomBytes(), tags[1], randomBytes()],\n {},\n inboxToken,\n );\n\n let count = 0;\n for await (const _ of iterator) {\n count++;\n }\n\n expect(count).toBe(numSends);\n }, 100000);\n });\n}\n\n// Focused client behavior tests use mocked network and browser locks.\nconst inboxUrl = \"https://example.test/inbox\";\nconst message = {\n id: \"message-1\",\n m: {\n t: [new Uint8Array([1])],\n o: {\n url: \"https://example.test/object\",\n actor: \"did:example:author\",\n channels: [\"test\"],\n value: {},\n },\n m: new Uint8Array([2]),\n },\n l: 0,\n};\n\nfunction cborResponse(value: unknown) {\n return new Response(new Uint8Array(dagCborEncode(value)).slice(), {\n headers: { \"Content-Type\": \"application/cbor\" },\n });\n}\n\nfunction queryPage(results: (typeof message)[], cursor: string, hasMore = false) {\n return cborResponse({ results, hasMore, cursor });\n}\n\nclass TestInboxes extends Inboxes {\n async prepareCache() {\n await this.cache;\n }\n\n async deleteCachedQuery(key: string) {\n await (await this.cache).messageIds.del(key);\n }\n\n async fetchQueryBatch() {\n const batch = await this.fetchMessageBatch(\n \"https://example.test/inbox\",\n \"query\",\n undefined,\n );\n await batch.response.arrayBuffer();\n return batch;\n }\n}\n\nfunction enableLockPath(request: unknown) {\n vi.stubGlobal(\"indexedDB\", {\n open: () => {\n const probe: { result?: { close: () => void }; onsuccess?: () => void } = {};\n queueMicrotask(() => {\n probe.result = { close() {} };\n probe.onsuccess?.();\n });\n return probe;\n },\n });\n vi.stubGlobal(\"window\", { navigator: { locks: { request } } });\n}\n\nexport function inboxUnitTests() {\n describe(\"Inboxes unit\", () => {\n afterEach(() => {\n vi.unstubAllGlobals();\n vi.restoreAllMocks();\n });\n\n describe(\"inbox stream lock and network failures\", () => {\n test(\"backs off for five seconds after an initial request failure\", async () => {\n const failure = new Error(\"offline\");\n const fetch = vi.fn(() => Promise.reject(failure));\n vi.stubGlobal(\"fetch\", fetch);\n vi.spyOn(console, \"error\").mockImplementation(() => {});\n const realSetTimeout = globalThis.setTimeout;\n const timer = vi.spyOn(globalThis, \"setTimeout\").mockImplementation(\n ((handler: TimerHandler, delay?: number, ...args: unknown[]) =>\n realSetTimeout(\n handler,\n delay === 5000 ? 0 : delay,\n ...args,\n )) as typeof setTimeout,\n );\n\n await expect(new Inboxes().query(inboxUrl, [], {}).next()).rejects.toBe(\n failure,\n );\n expect(fetch).toHaveBeenCalledOnce();\n expect(timer).toHaveBeenCalledWith(expect.any(Function), 5000);\n });\n\n test(\"a rejected lock request rejects the stream\", async () => {\n const inboxes = new TestInboxes();\n await inboxes.prepareCache();\n const error = new Error(\"lock request failed\");\n enableLockPath(vi.fn(() => Promise.reject(error)));\n\n await expect(\n inboxes.query(\"https://example.test/inbox\", [], {}).next(),\n ).rejects.toBe(error);\n });\n\n test(\"waiting for another tab's lock has a deadline\", async () => {\n const inboxes = new TestInboxes();\n await inboxes.prepareCache();\n const timeoutError = new DOMException(\"timed out\", \"TimeoutError\");\n vi.spyOn(AbortSignal, \"timeout\").mockReturnValue(\n AbortSignal.abort(timeoutError),\n );\n const request = vi.fn(\n (\n _key: string,\n _options: { signal?: AbortSignal },\n ) => Promise.reject(timeoutError),\n );\n enableLockPath(request);\n\n await expect(\n inboxes.query(\"https://example.test/inbox\", [], {}).next(),\n ).rejects.toThrow(\"Timed out waiting for another tab's inbox query\");\n expect(request).toHaveBeenCalledOnce();\n });\n\n test(\"a stalled request is aborted\", async () => {\n const realTimeout = AbortSignal.timeout;\n vi.spyOn(AbortSignal, \"timeout\").mockImplementation(() => realTimeout(5));\n vi.stubGlobal(\n \"fetch\",\n vi.fn((_url: string, options: RequestInit) =>\n new Promise<Response>((_resolve, reject) => {\n const signal = options.signal as AbortSignal;\n signal.addEventListener(\"abort\", () => reject(signal.reason), {\n once: true,\n });\n }),\n ),\n );\n\n await expect(new TestInboxes().fetchQueryBatch()).rejects.toMatchObject({\n name: \"TimeoutError\",\n });\n });\n\n test(\"the deadline remains active while reading a response body\", async () => {\n const realTimeout = AbortSignal.timeout;\n vi.spyOn(AbortSignal, \"timeout\").mockImplementation(() => realTimeout(5));\n vi.stubGlobal(\n \"fetch\",\n vi.fn((_url: string, options: RequestInit) => {\n const signal = options.signal as AbortSignal;\n const body = new ReadableStream({\n start(controller) {\n signal.addEventListener(\"abort\", () => controller.error(signal.reason), {\n once: true,\n });\n },\n });\n return Promise.resolve(new Response(body));\n }),\n );\n\n await expect(new TestInboxes().fetchQueryBatch()).rejects.toMatchObject({\n name: \"TimeoutError\",\n });\n });\n });\n\n describe(\"inbox query cache\", () => {\n test(\"fetches the next page while the current message is yielded\", async () => {\n const inboxes = new TestInboxes();\n await inboxes.prepareCache();\n let held = 0;\n enableLockPath(vi.fn(async (\n key: string,\n _options: { signal?: AbortSignal },\n callback: (lock: Lock) => Promise<unknown>,\n ) => {\n held++;\n try {\n return await callback({ name: key, mode: \"exclusive\" });\n } finally {\n held--;\n }\n }));\n let prefetchAborted = false;\n const fetch = vi.fn((_url: string, options: RequestInit) => {\n if (fetch.mock.calls.length === 1) {\n return Promise.resolve(queryPage([message], \"cursor-1\", true));\n }\n return new Promise<Response>((_resolve, reject) => {\n const signal = options.signal as AbortSignal;\n signal.addEventListener(\"abort\", () => {\n prefetchAborted = true;\n reject(signal.reason);\n }, { once: true });\n });\n });\n vi.stubGlobal(\"fetch\", fetch);\n\n const iterator = inboxes.query(inboxUrl, [new Uint8Array([1])], {});\n expect((await iterator.next()).value).toEqual(message);\n await vi.waitFor(() => expect(fetch).toHaveBeenCalledTimes(2));\n expect(fetch.mock.calls[1][0]).toBe(`${inboxUrl}/query?cursor=cursor-1`);\n await iterator.return(\"\");\n expect(prefetchAborted).toBe(true);\n await vi.waitFor(() => expect(held).toBe(0));\n });\n\n test(\"reports a cursor that expires after the first page\", async () => {\n const fetch = vi.fn()\n .mockResolvedValueOnce(queryPage([message], \"cursor-1\", true))\n .mockResolvedValueOnce(new Response(\"stale\", { status: 410 }));\n vi.stubGlobal(\"fetch\", fetch);\n\n const iterator = new Inboxes().query(inboxUrl, [new Uint8Array([1])], {});\n expect((await iterator.next()).value).toEqual(message);\n await expect(iterator.next()).rejects.toBeInstanceOf(\n GraffitiErrorCursorExpired,\n );\n expect(fetch).toHaveBeenCalledTimes(2);\n });\n\n test(\"does not replay messages after another tab resets the cache\", async () => {\n const inboxes = new TestInboxes();\n await inboxes.prepareCache();\n let markPrefetchStarted!: () => void;\n const prefetchStarted = new Promise<void>((resolve) => {\n markPrefetchStarted = resolve;\n });\n let releasePrefetch!: () => void;\n const pause = new Promise<void>((resolve) => {\n releasePrefetch = resolve;\n });\n let lockCalls = 0;\n let cacheKey = \"\";\n enableLockPath(vi.fn(async (\n name: string,\n _options: { signal?: AbortSignal },\n work: (lock: Lock) => Promise<unknown>,\n ) => {\n cacheKey = name.slice(\"graffiti:inbox:\".length);\n if (++lockCalls === 2) {\n markPrefetchStarted();\n await pause;\n }\n return work({ name, mode: \"exclusive\" });\n }));\n vi.stubGlobal(\"fetch\", vi.fn(async () => queryPage([message], \"cursor-1\", true)));\n\n const iterator = inboxes.query(inboxUrl, [new Uint8Array([1])], {});\n expect((await iterator.next()).value).toEqual(message);\n await prefetchStarted;\n await inboxes.deleteCachedQuery(cacheKey);\n releasePrefetch();\n await expect(iterator.next()).rejects.toBeInstanceOf(\n GraffitiErrorCursorExpired,\n );\n });\n\n test(\"a later query reads messages from the cached server cursor\", async () => {\n const fetch = vi.fn()\n .mockResolvedValueOnce(queryPage([message], \"cursor-1\"))\n .mockResolvedValueOnce(queryPage([], \"cursor-2\"));\n vi.stubGlobal(\"fetch\", fetch);\n const inboxes = new Inboxes();\n const tags = [new Uint8Array([1])];\n\n const first = inboxes.query(inboxUrl, tags, {});\n expect((await first.next()).value).toEqual(message);\n expect((await first.next()).done).toBe(true);\n\n const second = inboxes.query(inboxUrl, tags, {});\n expect((await second.next()).value).toEqual(message);\n expect((await second.next()).done).toBe(true);\n expect(fetch).toHaveBeenCalledTimes(2);\n expect(fetch.mock.calls[1][0]).toBe(`${inboxUrl}/query?cursor=cursor-1`);\n });\n\n test(\"does not hold the query lock while a message is yielded\", async () => {\n const inboxes = new TestInboxes();\n await inboxes.prepareCache();\n let held = false;\n enableLockPath(vi.fn(async (\n key: string,\n _options: { ifAvailable?: boolean },\n callback: (lock: Lock) => Promise<unknown>,\n ) => {\n held = true;\n try {\n return await callback({ name: key, mode: \"exclusive\" });\n } finally {\n held = false;\n }\n }));\n vi.stubGlobal(\"fetch\", vi.fn(async () => queryPage([message], \"cursor-1\")));\n\n const iterator = inboxes.query(inboxUrl, [new Uint8Array([1])], {});\n try {\n expect((await iterator.next()).value).toEqual(message);\n expect(held).toBe(false);\n } finally {\n await iterator.return(\"\");\n }\n });\n\n test(\"closing a yielded query leaves no lock held\", async () => {\n const inboxes = new TestInboxes();\n await inboxes.prepareCache();\n let held = false;\n enableLockPath(vi.fn(async (\n key: string,\n _options: { ifAvailable?: boolean },\n callback: (lock: Lock) => Promise<unknown>,\n ) => {\n held = true;\n try {\n return await callback({ name: key, mode: \"exclusive\" });\n } finally {\n held = false;\n }\n }));\n vi.stubGlobal(\"fetch\", vi.fn(async () => queryPage([message], \"cursor-1\")));\n\n const iterator = inboxes.query(inboxUrl, [new Uint8Array([1])], {});\n expect((await iterator.next()).value).toEqual(message);\n expect(held).toBe(false);\n await iterator.return(\"\");\n expect(held).toBe(false);\n });\n\n test(\"concurrent queries reuse a page fetched under the lock\", async () => {\n const inboxes = new TestInboxes();\n await inboxes.prepareCache();\n let releasePrevious = Promise.resolve();\n let requests = 0;\n let bothRequested!: () => void;\n const ready = new Promise<void>((resolve) => { bothRequested = resolve; });\n enableLockPath(vi.fn(async (\n key: string,\n _options: { signal?: AbortSignal },\n callback: (lock: Lock) => Promise<unknown>,\n ) => {\n requests++;\n if (requests === 2) bothRequested();\n const previous = releasePrevious;\n let release!: () => void;\n releasePrevious = new Promise<void>((resolve) => { release = resolve; });\n await previous;\n try {\n return await callback({ name: key, mode: \"exclusive\" });\n } finally {\n release();\n }\n }));\n const nextMessage = { ...message, id: \"message-2\" };\n const fetch = vi.fn(async () => {\n await ready;\n return fetch.mock.calls.length === 1\n ? queryPage([message], \"cursor-1\", true)\n : queryPage([nextMessage], \"cursor-2\");\n });\n vi.stubGlobal(\"fetch\", fetch);\n\n const tags = [new Uint8Array([1])];\n const first = inboxes.query(inboxUrl, tags, {});\n const second = inboxes.query(inboxUrl, tags, {});\n const [firstResult, secondResult] = await Promise.all([\n first.next(), second.next(),\n ]);\n expect(firstResult.value).toEqual(message);\n expect(secondResult.value).toEqual(message);\n const [firstNext, secondNext] = await Promise.all([\n first.next(), second.next(),\n ]);\n expect(firstNext.value).toEqual(nextMessage);\n expect(secondNext.value).toEqual(nextMessage);\n expect(fetch).toHaveBeenCalledTimes(2);\n expect((await first.next()).done).toBe(true);\n expect((await second.next()).done).toBe(true);\n });\n\n });\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["message", "message2", "dagCborEncode", "dagCborDecode", "fetch"]
|
|
7
7
|
}
|