@graffiti-garden/implementation-local 0.6.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +0 -1
  2. package/dist/browser/ajv-IY2ZY7VT.js +9 -0
  3. package/dist/browser/ajv-IY2ZY7VT.js.map +7 -0
  4. package/dist/browser/{chunk-KNUPPOQC.js → chunk-GE6AZATH.js} +2 -2
  5. package/dist/browser/{chunk-KNUPPOQC.js.map → chunk-GE6AZATH.js.map} +1 -1
  6. package/dist/browser/{index-browser.es-G37SKL53.js → index-browser.es-UXYPGJ2M.js} +2 -2
  7. package/dist/browser/{index-browser.es-G37SKL53.js.map → index-browser.es-UXYPGJ2M.js.map} +1 -1
  8. package/dist/browser/index.js +11 -2
  9. package/dist/browser/index.js.map +4 -4
  10. package/dist/cjs/identity.js +112 -0
  11. package/dist/cjs/identity.js.map +7 -0
  12. package/dist/cjs/index.js +43 -22
  13. package/dist/cjs/index.js.map +2 -2
  14. package/dist/cjs/media.js +111 -0
  15. package/dist/cjs/media.js.map +7 -0
  16. package/dist/cjs/objects.js +307 -0
  17. package/dist/cjs/objects.js.map +7 -0
  18. package/dist/cjs/tests.spec.js +1 -2
  19. package/dist/cjs/tests.spec.js.map +2 -2
  20. package/dist/cjs/utilities.js +68 -43
  21. package/dist/cjs/utilities.js.map +2 -2
  22. package/dist/esm/identity.js +92 -0
  23. package/dist/esm/identity.js.map +7 -0
  24. package/dist/esm/index.js +43 -24
  25. package/dist/esm/index.js.map +2 -2
  26. package/dist/esm/media.js +91 -0
  27. package/dist/esm/media.js.map +7 -0
  28. package/dist/esm/objects.js +285 -0
  29. package/dist/esm/objects.js.map +7 -0
  30. package/dist/esm/tests.spec.js +2 -4
  31. package/dist/esm/tests.spec.js.map +2 -2
  32. package/dist/esm/utilities.js +69 -48
  33. package/dist/esm/utilities.js.map +2 -2
  34. package/dist/{session-manager.d.ts → identity.d.ts} +7 -5
  35. package/dist/identity.d.ts.map +1 -0
  36. package/dist/index.d.ts +15 -13
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/media.d.ts +9 -0
  39. package/dist/media.d.ts.map +1 -0
  40. package/dist/objects.d.ts +63 -0
  41. package/dist/objects.d.ts.map +1 -0
  42. package/dist/utilities.d.ts +19 -8
  43. package/dist/utilities.d.ts.map +1 -1
  44. package/package.json +31 -19
  45. package/src/identity.ts +131 -0
  46. package/src/index.ts +44 -29
  47. package/src/media.ts +106 -0
  48. package/src/objects.ts +431 -0
  49. package/src/tests.spec.ts +2 -4
  50. package/src/utilities.ts +67 -87
  51. package/dist/browser/ajv-6AI3HK2A.js +0 -9
  52. package/dist/browser/ajv-6AI3HK2A.js.map +0 -7
  53. package/dist/browser/fast-json-patch-ZE7SZEYK.js +0 -19
  54. package/dist/browser/fast-json-patch-ZE7SZEYK.js.map +0 -7
  55. package/dist/cjs/database.js +0 -621
  56. package/dist/cjs/database.js.map +0 -7
  57. package/dist/cjs/session-manager.js +0 -107
  58. package/dist/cjs/session-manager.js.map +0 -7
  59. package/dist/database.d.ts +0 -105
  60. package/dist/database.d.ts.map +0 -1
  61. package/dist/esm/database.js +0 -603
  62. package/dist/esm/database.js.map +0 -7
  63. package/dist/esm/session-manager.js +0 -87
  64. package/dist/esm/session-manager.js.map +0 -7
  65. package/dist/session-manager.d.ts.map +0 -1
  66. package/src/database.ts +0 -911
  67. package/src/session-manager.ts +0 -123
@@ -1,603 +0,0 @@
1
- import {
2
- GraffitiErrorNotFound,
3
- GraffitiErrorSchemaMismatch,
4
- GraffitiErrorForbidden,
5
- GraffitiErrorPatchError
6
- } from "@graffiti-garden/api";
7
- import {
8
- randomBase64,
9
- applyGraffitiPatch,
10
- maskGraffitiObject,
11
- isActorAllowedGraffitiObject,
12
- compileGraffitiObjectSchema,
13
- unpackObjectUrl
14
- } from "./utilities.js";
15
- const DEFAULT_ORIGIN = "graffiti:local:";
16
- const LAST_MODIFIED_BUFFER = 6e4;
17
- class GraffitiLocalDatabase {
18
- db_;
19
- applyPatch_;
20
- ajv_;
21
- options;
22
- origin;
23
- get db() {
24
- if (!this.db_) {
25
- this.db_ = (async () => {
26
- const { default: PouchDB } = await import("pouchdb");
27
- const pouchDbOptions = {
28
- name: "graffitiDb",
29
- ...this.options.pouchDBOptions
30
- };
31
- const db = new PouchDB(
32
- pouchDbOptions.name,
33
- pouchDbOptions
34
- );
35
- await db.put({
36
- _id: "_design/indexes",
37
- views: {
38
- objectsPerChannelAndLastModified: {
39
- map: function(object) {
40
- const paddedLastModified = object.lastModified.toString().padStart(15, "0");
41
- object.channels.forEach(function(channel) {
42
- const id = encodeURIComponent(channel) + "/" + paddedLastModified;
43
- emit(id);
44
- });
45
- }.toString()
46
- },
47
- orphansPerActorAndLastModified: {
48
- map: function(object) {
49
- if (object.channels.length === 0) {
50
- const paddedLastModified = object.lastModified.toString().padStart(15, "0");
51
- const id = encodeURIComponent(object.actor) + "/" + paddedLastModified;
52
- emit(id);
53
- }
54
- }.toString()
55
- },
56
- channelStatsPerActor: {
57
- map: function(object) {
58
- if (object.tombstone) return;
59
- object.channels.forEach(function(channel) {
60
- const id = encodeURIComponent(object.actor) + "/" + encodeURIComponent(channel);
61
- emit(id, object.lastModified);
62
- });
63
- }.toString(),
64
- reduce: "_stats"
65
- }
66
- }
67
- }).catch((error) => {
68
- if (error && typeof error === "object" && "name" in error && error.name === "conflict") {
69
- return;
70
- } else {
71
- throw error;
72
- }
73
- });
74
- return db;
75
- })();
76
- }
77
- return this.db_;
78
- }
79
- get applyPatch() {
80
- if (!this.applyPatch_) {
81
- this.applyPatch_ = (async () => {
82
- const imported = await import("fast-json-patch");
83
- return imported.applyPatch || imported.default.applyPatch;
84
- })();
85
- }
86
- return this.applyPatch_;
87
- }
88
- get ajv() {
89
- if (!this.ajv_) {
90
- this.ajv_ = this.options.ajv ? Promise.resolve(this.options.ajv) : (async () => {
91
- const { default: Ajv } = await import("ajv");
92
- return new Ajv({ strict: false });
93
- })();
94
- }
95
- return this.ajv_;
96
- }
97
- extractGraffitiObject(object) {
98
- const { value, channels, allowed, url, actor, lastModified } = object;
99
- return {
100
- value,
101
- channels,
102
- allowed,
103
- url,
104
- actor,
105
- lastModified
106
- };
107
- }
108
- constructor(options) {
109
- this.options = options ?? {};
110
- this.origin = this.options.origin ?? DEFAULT_ORIGIN;
111
- if (!this.origin.endsWith(":") && !this.origin.endsWith("/")) {
112
- this.origin += "/";
113
- }
114
- }
115
- async allDocsAtLocation(objectUrl) {
116
- const url = unpackObjectUrl(objectUrl) + "/";
117
- const results = await (await this.db).allDocs({
118
- startkey: url,
119
- endkey: url + "\uFFFF",
120
- // \uffff is the last unicode character
121
- include_docs: true
122
- });
123
- const docs = results.rows.map((row) => row.doc).reduce((acc, doc) => {
124
- if (doc) acc.push(doc);
125
- return acc;
126
- }, []);
127
- return docs;
128
- }
129
- docId(objectUrl) {
130
- return objectUrl.url + "/" + randomBase64();
131
- }
132
- get = async (...args) => {
133
- const [urlObject, schema, session] = args;
134
- const docsAll = await this.allDocsAtLocation(urlObject);
135
- const docs = docsAll.filter(
136
- (doc2) => isActorAllowedGraffitiObject(doc2, session)
137
- );
138
- if (!docs.length)
139
- throw new GraffitiErrorNotFound(
140
- "The object you are trying to get either does not exist or you are not allowed to see it"
141
- );
142
- const doc = docs.reduce(
143
- (a, b) => a.lastModified > b.lastModified || a.lastModified === b.lastModified && !a.tombstone && b.tombstone ? a : b
144
- );
145
- if (doc.tombstone) {
146
- throw new GraffitiErrorNotFound(
147
- "The object you are trying to get either does not exist or you are not allowed to see it"
148
- );
149
- }
150
- const object = this.extractGraffitiObject(doc);
151
- maskGraffitiObject(object, [], session);
152
- const validate = compileGraffitiObjectSchema(await this.ajv, schema);
153
- if (!validate(object)) {
154
- throw new GraffitiErrorSchemaMismatch();
155
- }
156
- return object;
157
- };
158
- /**
159
- * Deletes all docs at a particular location.
160
- * If the `keepLatest` flag is set to true,
161
- * the doc with the most recent timestamp will be
162
- * spared. If there are multiple docs with the same
163
- * timestamp, the one with the highest `_id` will be
164
- * spared.
165
- */
166
- async deleteAtLocation(url, options = {
167
- keepLatest: false
168
- }) {
169
- const docsAtLocationAll = await this.allDocsAtLocation(url);
170
- const docsAtLocationAllowed = options.session ? docsAtLocationAll.filter(
171
- (doc) => isActorAllowedGraffitiObject(doc, options.session)
172
- ) : docsAtLocationAll;
173
- if (!docsAtLocationAllowed.length) {
174
- throw new GraffitiErrorNotFound(
175
- "The object you are trying to delete either does not exist or you are not allowed to see it"
176
- );
177
- } else if (options.session && docsAtLocationAllowed.some((doc) => doc.actor !== options.session?.actor)) {
178
- throw new GraffitiErrorForbidden(
179
- "You cannot delete an object owned by another actor"
180
- );
181
- }
182
- const docsAtLocation = docsAtLocationAllowed.filter(
183
- (doc) => !doc.tombstone
184
- );
185
- if (!docsAtLocation.length) return void 0;
186
- const latestModified = docsAtLocation.map((doc) => doc.lastModified).reduce((a, b) => a > b ? a : b);
187
- const docsToDelete = docsAtLocation.filter(
188
- (doc) => !options.keepLatest || doc.lastModified < latestModified
189
- );
190
- const concurrentDocsAll = docsAtLocation.filter(
191
- (doc) => options.keepLatest && doc.lastModified === latestModified
192
- );
193
- if (concurrentDocsAll.length) {
194
- const keepDocId = concurrentDocsAll.map((doc) => doc._id).reduce((a, b) => a > b ? a : b);
195
- const concurrentDocsToDelete = concurrentDocsAll.filter(
196
- (doc) => doc._id !== keepDocId
197
- );
198
- docsToDelete.push(...concurrentDocsToDelete);
199
- }
200
- const lastModified = options.keepLatest ? latestModified : (/* @__PURE__ */ new Date()).getTime();
201
- const deleteResults = await (await this.db).bulkDocs(
202
- docsToDelete.map((doc) => ({
203
- ...doc,
204
- tombstone: true,
205
- lastModified
206
- }))
207
- );
208
- let deletedObject = void 0;
209
- for (const resultOrError of deleteResults) {
210
- if ("ok" in resultOrError) {
211
- const { id } = resultOrError;
212
- const deletedDoc = docsToDelete.find((doc) => doc._id === id);
213
- if (deletedDoc) {
214
- deletedObject = {
215
- ...this.extractGraffitiObject(deletedDoc),
216
- lastModified
217
- };
218
- break;
219
- }
220
- }
221
- }
222
- return deletedObject;
223
- }
224
- delete = async (...args) => {
225
- const [url, session] = args;
226
- const deletedObject = await this.deleteAtLocation(url, {
227
- session
228
- });
229
- if (!deletedObject) {
230
- throw new GraffitiErrorNotFound("The object has already been deleted");
231
- }
232
- return deletedObject;
233
- };
234
- put = async (...args) => {
235
- const [objectPartial, session] = args;
236
- if (objectPartial.actor && objectPartial.actor !== session.actor) {
237
- throw new GraffitiErrorForbidden(
238
- "Cannot put an object with a different actor than the session actor"
239
- );
240
- }
241
- if (objectPartial.url) {
242
- let oldObject;
243
- try {
244
- oldObject = await this.get(objectPartial.url, {}, session);
245
- } catch (e) {
246
- if (e instanceof GraffitiErrorNotFound) {
247
- if (!this.options.allowSettingArbitraryUrls) {
248
- throw new GraffitiErrorNotFound(
249
- "The object you are trying to replace does not exist or you are not allowed to see it"
250
- );
251
- }
252
- } else {
253
- throw e;
254
- }
255
- }
256
- if (oldObject?.actor !== session.actor) {
257
- throw new GraffitiErrorForbidden(
258
- "The object you are trying to replace is owned by another actor"
259
- );
260
- }
261
- }
262
- const lastModified = (this.options.allowSettinngLastModified ?? false) && objectPartial.lastModified || (/* @__PURE__ */ new Date()).getTime();
263
- const object = {
264
- value: objectPartial.value,
265
- channels: objectPartial.channels,
266
- allowed: objectPartial.allowed,
267
- url: objectPartial.url ?? this.origin + randomBase64(),
268
- actor: session.actor,
269
- tombstone: false,
270
- lastModified
271
- };
272
- await (await this.db).put({
273
- _id: this.docId(object),
274
- ...object
275
- });
276
- const previousObject = await this.deleteAtLocation(object, {
277
- keepLatest: true
278
- });
279
- if (previousObject) {
280
- return previousObject;
281
- } else {
282
- return {
283
- ...object,
284
- value: {},
285
- channels: [],
286
- allowed: [],
287
- tombstone: true
288
- };
289
- }
290
- };
291
- patch = async (...args) => {
292
- const [patch, url, session] = args;
293
- let originalObject;
294
- try {
295
- originalObject = await this.get(url, {}, session);
296
- } catch (e) {
297
- if (e instanceof GraffitiErrorNotFound) {
298
- throw new GraffitiErrorNotFound(
299
- "The object you are trying to patch does not exist or you are not allowed to see it"
300
- );
301
- } else {
302
- throw e;
303
- }
304
- }
305
- if (originalObject.actor !== session.actor) {
306
- throw new GraffitiErrorForbidden(
307
- "The object you are trying to patch is owned by another actor"
308
- );
309
- }
310
- const patchObject = { ...originalObject };
311
- for (const prop of ["value", "channels", "allowed"]) {
312
- applyGraffitiPatch(await this.applyPatch, prop, patch, patchObject);
313
- }
314
- if (typeof patchObject.value !== "object" || Array.isArray(patchObject.value) || !patchObject.value) {
315
- throw new GraffitiErrorPatchError("value is no longer an object");
316
- }
317
- if (!Array.isArray(patchObject.channels) || !patchObject.channels.every((channel) => typeof channel === "string")) {
318
- throw new GraffitiErrorPatchError(
319
- "channels are no longer an array of strings"
320
- );
321
- }
322
- if (patchObject.allowed && (!Array.isArray(patchObject.allowed) || !patchObject.allowed.every((allowed) => typeof allowed === "string"))) {
323
- throw new GraffitiErrorPatchError(
324
- "allowed list is not an array of strings"
325
- );
326
- }
327
- patchObject.lastModified = (/* @__PURE__ */ new Date()).getTime();
328
- await (await this.db).put({
329
- ...patchObject,
330
- tombstone: false,
331
- _id: this.docId(patchObject)
332
- });
333
- await this.deleteAtLocation(patchObject, {
334
- keepLatest: true
335
- });
336
- return {
337
- ...originalObject,
338
- lastModified: patchObject.lastModified
339
- };
340
- };
341
- queryLastModifiedSuffixes(schema, lastModified) {
342
- let startKeySuffix = "";
343
- let endKeySuffix = "\uFFFF";
344
- if (typeof schema === "object" && schema.properties?.lastModified && typeof schema.properties.lastModified === "object") {
345
- const lastModifiedSchema = schema.properties.lastModified;
346
- const minimum = lastModified && lastModifiedSchema.minimum ? Math.max(lastModified, lastModifiedSchema.minimum) : lastModified ?? lastModifiedSchema.minimum;
347
- const exclusiveMinimum = lastModifiedSchema.exclusiveMinimum;
348
- let intMinimum;
349
- if (exclusiveMinimum !== void 0) {
350
- intMinimum = Math.ceil(exclusiveMinimum);
351
- intMinimum === exclusiveMinimum && intMinimum++;
352
- } else if (minimum !== void 0) {
353
- intMinimum = Math.ceil(minimum);
354
- }
355
- if (intMinimum !== void 0) {
356
- startKeySuffix = intMinimum.toString().padStart(15, "0");
357
- }
358
- const maximum = lastModifiedSchema.maximum;
359
- const exclusiveMaximum = lastModifiedSchema.exclusiveMaximum;
360
- let intMaximum;
361
- if (exclusiveMaximum !== void 0) {
362
- intMaximum = Math.floor(exclusiveMaximum);
363
- intMaximum === exclusiveMaximum && intMaximum--;
364
- } else if (maximum !== void 0) {
365
- intMaximum = Math.floor(maximum);
366
- }
367
- if (intMaximum !== void 0) {
368
- endKeySuffix = intMaximum.toString().padStart(15, "0");
369
- }
370
- }
371
- return {
372
- startKeySuffix,
373
- endKeySuffix
374
- };
375
- }
376
- async *streamObjects(index, startkey, endkey, validate, session, ifModifiedSince, channels, processedIds) {
377
- if (ifModifiedSince !== void 0) {
378
- const continueBuffer = this.options.continueBuffer ?? 1e3;
379
- const timeElapsedSinceContinue = Date.now() - ifModifiedSince;
380
- if (timeElapsedSinceContinue < continueBuffer) {
381
- await new Promise(
382
- (resolve) => setTimeout(resolve, continueBuffer - timeElapsedSinceContinue)
383
- );
384
- }
385
- ifModifiedSince -= LAST_MODIFIED_BUFFER;
386
- }
387
- const result = await (await this.db).query(index, {
388
- startkey,
389
- endkey,
390
- include_docs: true
391
- });
392
- for (const row of result.rows) {
393
- const doc = row.doc;
394
- if (!doc) continue;
395
- if (processedIds?.has(doc._id)) continue;
396
- processedIds?.add(doc._id);
397
- if (ifModifiedSince === void 0 && doc.tombstone) continue;
398
- const object = this.extractGraffitiObject(doc);
399
- if (channels) {
400
- if (!isActorAllowedGraffitiObject(object, session)) continue;
401
- maskGraffitiObject(object, channels, session);
402
- }
403
- if (!validate(object)) continue;
404
- yield doc.tombstone ? {
405
- tombstone: true,
406
- object: {
407
- url: object.url,
408
- lastModified: object.lastModified
409
- }
410
- } : { object };
411
- }
412
- }
413
- async *discoverMeta(args, ifModifiedSince) {
414
- const [channels, schema, session] = args;
415
- const validate = compileGraffitiObjectSchema(await this.ajv, schema);
416
- const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(
417
- schema,
418
- ifModifiedSince
419
- );
420
- const processedIds = /* @__PURE__ */ new Set();
421
- const startTime = (/* @__PURE__ */ new Date()).getTime();
422
- for (const channel of channels) {
423
- const keyPrefix = encodeURIComponent(channel) + "/";
424
- const startkey = keyPrefix + startKeySuffix;
425
- const endkey = keyPrefix + endKeySuffix;
426
- const iterator = this.streamObjects(
427
- "indexes/objectsPerChannelAndLastModified",
428
- startkey,
429
- endkey,
430
- validate,
431
- session,
432
- ifModifiedSince,
433
- channels,
434
- processedIds
435
- );
436
- for await (const result of iterator) yield result;
437
- }
438
- return startTime;
439
- }
440
- async *recoverOrphansMeta(args, ifModifiedSince) {
441
- const [schema, session] = args;
442
- const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(
443
- schema,
444
- ifModifiedSince
445
- );
446
- const keyPrefix = encodeURIComponent(session.actor) + "/";
447
- const startkey = keyPrefix + startKeySuffix;
448
- const endkey = keyPrefix + endKeySuffix;
449
- const validate = compileGraffitiObjectSchema(await this.ajv, schema);
450
- const startTime = (/* @__PURE__ */ new Date()).getTime();
451
- const iterator = this.streamObjects(
452
- "indexes/orphansPerActorAndLastModified",
453
- startkey,
454
- endkey,
455
- validate,
456
- session,
457
- ifModifiedSince
458
- );
459
- for await (const result of iterator) yield result;
460
- return startTime;
461
- }
462
- discoverCursor(args, ifModifiedSince) {
463
- return "discover:" + JSON.stringify({
464
- channels: args[0],
465
- schema: args[1],
466
- actor: args[2]?.actor,
467
- ifModifiedSince
468
- });
469
- }
470
- async *discoverContinue(args, ifModifiedSince) {
471
- const iterator = this.discoverMeta(args, ifModifiedSince);
472
- while (true) {
473
- const result = await iterator.next();
474
- if (result.done) {
475
- const ifModifiedSince2 = result.value;
476
- return {
477
- continue: () => this.discoverContinue(args, ifModifiedSince2),
478
- cursor: this.discoverCursor(args, ifModifiedSince2)
479
- };
480
- }
481
- yield result.value;
482
- }
483
- }
484
- discover = (...args) => {
485
- const iterator = this.discoverMeta(args);
486
- const this_ = this;
487
- return async function* () {
488
- while (true) {
489
- const result = await iterator.next();
490
- if (result.done) {
491
- return {
492
- continue: () => this_.discoverContinue(args, result.value),
493
- cursor: this_.discoverCursor(args, result.value)
494
- };
495
- }
496
- if (result.value.tombstone) continue;
497
- yield result.value;
498
- }
499
- }();
500
- };
501
- recoverOrphansCursor(args, ifModifiedSince) {
502
- return "orphans:" + JSON.stringify({
503
- schema: args[0],
504
- actor: args[1]?.actor,
505
- ifModifiedSince
506
- });
507
- }
508
- async *recoverOrphansContinue(args, ifModifiedSince) {
509
- const iterator = this.recoverOrphansMeta(args, ifModifiedSince);
510
- while (true) {
511
- const result = await iterator.next();
512
- if (result.done) {
513
- const ifModifiedSince2 = result.value;
514
- return {
515
- continue: () => this.recoverOrphansContinue(args, ifModifiedSince2),
516
- cursor: this.recoverOrphansCursor(args, ifModifiedSince2)
517
- };
518
- }
519
- yield result.value;
520
- }
521
- }
522
- recoverOrphans = (...args) => {
523
- const iterator = this.recoverOrphansMeta(args);
524
- const this_ = this;
525
- return async function* () {
526
- while (true) {
527
- const result = await iterator.next();
528
- if (result.done) {
529
- return {
530
- continue: () => this_.recoverOrphansContinue(
531
- args,
532
- result.value
533
- ),
534
- cursor: this_.recoverOrphansCursor(args, result.value)
535
- };
536
- }
537
- if (result.value.tombstone) continue;
538
- yield result.value;
539
- }
540
- }();
541
- };
542
- channelStats = (session) => {
543
- const this_ = this;
544
- return async function* () {
545
- const keyPrefix = encodeURIComponent(session.actor) + "/";
546
- const result = await (await this_.db).query("indexes/channelStatsPerActor", {
547
- startkey: keyPrefix,
548
- endkey: keyPrefix + "\uFFFF",
549
- reduce: true,
550
- group: true
551
- });
552
- for (const row of result.rows) {
553
- const channelEncoded = row.key.split("/")[1];
554
- if (typeof channelEncoded !== "string") continue;
555
- const { count, max: lastModified } = row.value;
556
- if (typeof count !== "number" || typeof lastModified !== "number")
557
- continue;
558
- yield {
559
- value: {
560
- channel: decodeURIComponent(channelEncoded),
561
- count,
562
- lastModified
563
- }
564
- };
565
- }
566
- }();
567
- };
568
- continueObjectStream = (cursor, session) => {
569
- if (cursor.startsWith("discover:")) {
570
- const { channels, schema, actor, ifModifiedSince } = JSON.parse(
571
- cursor.slice("discover:".length)
572
- );
573
- if (actor && actor !== session?.actor) {
574
- throw new GraffitiErrorForbidden(
575
- "Cannot continue a cursor for another actor"
576
- );
577
- }
578
- return this.discoverContinue(
579
- [channels, schema, session],
580
- ifModifiedSince
581
- );
582
- } else if (cursor.startsWith("orphans:")) {
583
- const { schema, actor, ifModifiedSince } = JSON.parse(
584
- cursor.slice("orphans:".length)
585
- );
586
- if (!session || actor !== session?.actor) {
587
- throw new GraffitiErrorForbidden(
588
- "Cannot continue a cursor for another actor"
589
- );
590
- }
591
- return this.recoverOrphansContinue(
592
- [schema, session],
593
- ifModifiedSince
594
- );
595
- } else {
596
- throw new GraffitiErrorNotFound("Cursor not found");
597
- }
598
- };
599
- }
600
- export {
601
- GraffitiLocalDatabase
602
- };
603
- //# sourceMappingURL=database.js.map