@graffiti-garden/implementation-local 0.6.1 → 0.6.2
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/README.md +4 -1
- package/dist/browser/index.js +2 -2
- package/dist/browser/index.js.map +3 -3
- package/dist/cjs/database.js +56 -10
- package/dist/cjs/database.js.map +2 -2
- package/dist/cjs/index.js +0 -9
- package/dist/cjs/index.js.map +2 -2
- package/dist/cjs/utilities.js.map +2 -2
- package/dist/database.d.ts +3 -1
- package/dist/database.d.ts.map +1 -1
- package/dist/esm/database.js +56 -10
- package/dist/esm/database.js.map +2 -2
- package/dist/esm/index.js +0 -9
- package/dist/esm/index.js.map +2 -2
- package/dist/esm/utilities.js +0 -1
- package/dist/esm/utilities.js.map +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/utilities.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/database.ts +71 -11
- package/src/index.ts +0 -13
- package/src/utilities.ts +0 -1
package/dist/cjs/database.js
CHANGED
|
@@ -100,8 +100,8 @@ class GraffitiLocalDatabase {
|
|
|
100
100
|
get applyPatch() {
|
|
101
101
|
if (!this.applyPatch_) {
|
|
102
102
|
this.applyPatch_ = (async () => {
|
|
103
|
-
const
|
|
104
|
-
return applyPatch;
|
|
103
|
+
const imported = await import("fast-json-patch");
|
|
104
|
+
return imported.applyPatch || imported.default.applyPatch;
|
|
105
105
|
})();
|
|
106
106
|
}
|
|
107
107
|
return this.applyPatch_;
|
|
@@ -471,6 +471,14 @@ class GraffitiLocalDatabase {
|
|
|
471
471
|
for await (const result of iterator) yield result;
|
|
472
472
|
return startTime - LAST_MODIFIED_BUFFER;
|
|
473
473
|
}
|
|
474
|
+
discoverCursor(args, ifModifiedSince) {
|
|
475
|
+
return "discover:" + JSON.stringify({
|
|
476
|
+
channels: args[0],
|
|
477
|
+
schema: args[1],
|
|
478
|
+
actor: args[2]?.actor,
|
|
479
|
+
ifModifiedSince
|
|
480
|
+
});
|
|
481
|
+
}
|
|
474
482
|
async *discoverContinue(args, ifModifiedSince) {
|
|
475
483
|
const iterator = this.discoverMeta(args, ifModifiedSince);
|
|
476
484
|
while (true) {
|
|
@@ -479,7 +487,7 @@ class GraffitiLocalDatabase {
|
|
|
479
487
|
const ifModifiedSince2 = result.value;
|
|
480
488
|
return {
|
|
481
489
|
continue: () => this.discoverContinue(args, ifModifiedSince2),
|
|
482
|
-
cursor:
|
|
490
|
+
cursor: this.discoverCursor(args, ifModifiedSince2)
|
|
483
491
|
};
|
|
484
492
|
}
|
|
485
493
|
yield result.value;
|
|
@@ -494,7 +502,7 @@ class GraffitiLocalDatabase {
|
|
|
494
502
|
if (result.done) {
|
|
495
503
|
return {
|
|
496
504
|
continue: () => this_.discoverContinue(args, result.value),
|
|
497
|
-
cursor:
|
|
505
|
+
cursor: this_.discoverCursor(args, result.value)
|
|
498
506
|
};
|
|
499
507
|
}
|
|
500
508
|
if (result.value.tombstone) continue;
|
|
@@ -502,15 +510,22 @@ class GraffitiLocalDatabase {
|
|
|
502
510
|
}
|
|
503
511
|
}();
|
|
504
512
|
};
|
|
505
|
-
|
|
513
|
+
recoverOrphansCursor(args, ifModifiedSince) {
|
|
514
|
+
return "orphans:" + JSON.stringify({
|
|
515
|
+
schema: args[0],
|
|
516
|
+
actor: args[1]?.actor,
|
|
517
|
+
ifModifiedSince
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
async *recoverOrphansContinue(args, ifModifiedSince) {
|
|
506
521
|
const iterator = this.recoverOrphansMeta(args, ifModifiedSince);
|
|
507
522
|
while (true) {
|
|
508
523
|
const result = await iterator.next();
|
|
509
524
|
if (result.done) {
|
|
510
525
|
const ifModifiedSince2 = result.value;
|
|
511
526
|
return {
|
|
512
|
-
continue: () => this.
|
|
513
|
-
cursor:
|
|
527
|
+
continue: () => this.recoverOrphansContinue(args, ifModifiedSince2),
|
|
528
|
+
cursor: this.recoverOrphansCursor(args, ifModifiedSince2)
|
|
514
529
|
};
|
|
515
530
|
}
|
|
516
531
|
yield result.value;
|
|
@@ -524,8 +539,11 @@ class GraffitiLocalDatabase {
|
|
|
524
539
|
const result = await iterator.next();
|
|
525
540
|
if (result.done) {
|
|
526
541
|
return {
|
|
527
|
-
continue: () => this_.
|
|
528
|
-
|
|
542
|
+
continue: () => this_.recoverOrphansContinue(
|
|
543
|
+
args,
|
|
544
|
+
result.value
|
|
545
|
+
),
|
|
546
|
+
cursor: this_.recoverOrphansCursor(args, result.value)
|
|
529
547
|
};
|
|
530
548
|
}
|
|
531
549
|
if (result.value.tombstone) continue;
|
|
@@ -560,7 +578,35 @@ class GraffitiLocalDatabase {
|
|
|
560
578
|
}();
|
|
561
579
|
};
|
|
562
580
|
continueObjectStream = (cursor, session) => {
|
|
563
|
-
|
|
581
|
+
if (cursor.startsWith("discover:")) {
|
|
582
|
+
const { channels, schema, actor, ifModifiedSince } = JSON.parse(
|
|
583
|
+
cursor.slice("discover:".length)
|
|
584
|
+
);
|
|
585
|
+
if (actor && actor !== session?.actor) {
|
|
586
|
+
throw new import_api.GraffitiErrorForbidden(
|
|
587
|
+
"Cannot continue a cursor for another actor"
|
|
588
|
+
);
|
|
589
|
+
}
|
|
590
|
+
return this.discoverContinue(
|
|
591
|
+
[channels, schema, session],
|
|
592
|
+
ifModifiedSince
|
|
593
|
+
);
|
|
594
|
+
} else if (cursor.startsWith("orphans:")) {
|
|
595
|
+
const { schema, actor, ifModifiedSince } = JSON.parse(
|
|
596
|
+
cursor.slice("orphans:".length)
|
|
597
|
+
);
|
|
598
|
+
if (!session || actor !== session?.actor) {
|
|
599
|
+
throw new import_api.GraffitiErrorForbidden(
|
|
600
|
+
"Cannot continue a cursor for another actor"
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
return this.recoverOrphansContinue(
|
|
604
|
+
[schema, session],
|
|
605
|
+
ifModifiedSince
|
|
606
|
+
);
|
|
607
|
+
} else {
|
|
608
|
+
throw new import_api.GraffitiErrorNotFound("Cursor not found");
|
|
609
|
+
}
|
|
564
610
|
};
|
|
565
611
|
}
|
|
566
612
|
//# sourceMappingURL=database.js.map
|
package/dist/cjs/database.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/database.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n Graffiti,\n GraffitiObjectBase,\n GraffitiObjectUrl,\n JSONSchema,\n GraffitiSession,\n GraffitiObjectStreamContinue,\n GraffitiObjectStreamContinueEntry,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorPatchError,\n} from \"@graffiti-garden/api\";\nimport {\n randomBase64,\n applyGraffitiPatch,\n maskGraffitiObject,\n isActorAllowedGraffitiObject,\n compileGraffitiObjectSchema,\n unpackObjectUrl,\n} from \"./utilities.js\";\nimport type Ajv from \"ajv\";\nimport type { applyPatch } from \"fast-json-patch\";\n\n/**\n * Constructor options for the GraffitiPoubchDB class.\n */\nexport interface GraffitiLocalOptions {\n /**\n * Options to pass to the PouchDB constructor.\n * Defaults to `{ name: \"graffitiDb\" }`.\n *\n * See the [PouchDB documentation](https://pouchdb.com/api.html#create_database)\n * for available options.\n */\n pouchDBOptions?: PouchDB.Configuration.DatabaseConfiguration;\n /**\n * Includes the scheme and other information (possibly domain name)\n * to prefix prefixes all URLs put in the system. Defaults to `graffiti:local`.\n */\n origin?: string;\n /**\n * Whether to allow putting objects at arbtirary URLs, i.e.\n * URLs that are *not* prefixed with the origin or not generated\n * by the system. Defaults to `false`.\n *\n * Allows this implementation to be used as a client-side cache\n * for remote sources.\n */\n allowSettingArbitraryUrls?: boolean;\n /**\n * Whether to allow the user to set the lastModified field\n * when putting objects. Defaults to `false`.\n *\n * Allows this implementation to be used as a client-side cache\n * for remote sources.\n */\n allowSettinngLastModified?: boolean;\n /**\n * An optional Ajv instance to use for schema validation.\n * If not provided, an internal instance will be created.\n */\n ajv?: Ajv;\n}\n\nconst DEFAULT_ORIGIN = \"graffiti:local:\";\nconst LAST_MODIFIED_BUFFER = 60000;\n\ntype GraffitiObjectWithTombstone = GraffitiObjectBase & { tombstone: boolean };\n\n/**\n * An implementation of only the database operations of the\n * GraffitiAPI without synchronization or session management.\n */\nexport class GraffitiLocalDatabase\n implements Omit<Graffiti, \"login\" | \"logout\" | \"sessionEvents\">\n{\n protected db_:\n | Promise<PouchDB.Database<GraffitiObjectWithTombstone>>\n | undefined;\n protected applyPatch_: Promise<typeof applyPatch> | undefined;\n protected ajv_: Promise<Ajv> | undefined;\n protected readonly options: GraffitiLocalOptions;\n protected readonly origin: string;\n\n get db() {\n if (!this.db_) {\n this.db_ = (async () => {\n const { default: PouchDB } = await import(\"pouchdb\");\n const pouchDbOptions = {\n name: \"graffitiDb\",\n ...this.options.pouchDBOptions,\n };\n const db = new PouchDB<GraffitiObjectWithTombstone>(\n pouchDbOptions.name,\n pouchDbOptions,\n );\n await db\n //@ts-ignore\n .put({\n _id: \"_design/indexes\",\n views: {\n objectsPerChannelAndLastModified: {\n map: function (object: GraffitiObjectWithTombstone) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n object.channels.forEach(function (channel) {\n const id =\n encodeURIComponent(channel) + \"/\" + paddedLastModified;\n //@ts-ignore\n emit(id);\n });\n }.toString(),\n },\n orphansPerActorAndLastModified: {\n map: function (object: GraffitiObjectWithTombstone) {\n if (object.channels.length === 0) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n const id =\n encodeURIComponent(object.actor) +\n \"/\" +\n paddedLastModified;\n //@ts-ignore\n emit(id);\n }\n }.toString(),\n },\n channelStatsPerActor: {\n map: function (object: GraffitiObjectWithTombstone) {\n if (object.tombstone) return;\n object.channels.forEach(function (channel) {\n const id =\n encodeURIComponent(object.actor) +\n \"/\" +\n encodeURIComponent(channel);\n //@ts-ignore\n emit(id, object.lastModified);\n });\n }.toString(),\n reduce: \"_stats\",\n },\n },\n })\n //@ts-ignore\n .catch((error) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n error.name === \"conflict\"\n ) {\n // Design document already exists\n return;\n } else {\n throw error;\n }\n });\n return db;\n })();\n }\n return this.db_;\n }\n\n protected get applyPatch() {\n if (!this.applyPatch_) {\n this.applyPatch_ = (async () => {\n const { applyPatch } = await import(\"fast-json-patch\");\n return applyPatch;\n })();\n }\n return this.applyPatch_;\n }\n\n protected get ajv() {\n if (!this.ajv_) {\n this.ajv_ = this.options.ajv\n ? Promise.resolve(this.options.ajv)\n : (async () => {\n const { default: Ajv } = await import(\"ajv\");\n return new Ajv({ strict: false });\n })();\n }\n return this.ajv_;\n }\n\n protected extractGraffitiObject(\n object: GraffitiObjectWithTombstone,\n ): GraffitiObjectBase {\n const { value, channels, allowed, url, actor, lastModified } = object;\n return {\n value,\n channels,\n allowed,\n url,\n actor,\n lastModified,\n };\n }\n\n constructor(options?: GraffitiLocalOptions) {\n this.options = options ?? {};\n this.origin = this.options.origin ?? DEFAULT_ORIGIN;\n if (!this.origin.endsWith(\":\") && !this.origin.endsWith(\"/\")) {\n this.origin += \"/\";\n }\n }\n\n protected async allDocsAtLocation(objectUrl: string | GraffitiObjectUrl) {\n const url = unpackObjectUrl(objectUrl) + \"/\";\n const results = await (\n await this.db\n ).allDocs({\n startkey: url,\n endkey: url + \"\\uffff\", // \\uffff is the last unicode character\n include_docs: true,\n });\n const docs = results.rows\n .map((row) => row.doc)\n // Remove undefined docs\n .reduce<\n PouchDB.Core.ExistingDocument<\n GraffitiObjectWithTombstone & PouchDB.Core.AllDocsMeta\n >[]\n >((acc, doc) => {\n if (doc) acc.push(doc);\n return acc;\n }, []);\n return docs;\n }\n\n protected docId(objectUrl: GraffitiObjectUrl) {\n return objectUrl.url + \"/\" + randomBase64();\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [urlObject, schema, session] = args;\n\n const docsAll = await this.allDocsAtLocation(urlObject);\n\n // Filter out ones not allowed\n const docs = docsAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, session),\n );\n if (!docs.length)\n throw new GraffitiErrorNotFound(\n \"The object you are trying to get either does not exist or you are not allowed to see it\",\n );\n\n // Get the most recent document\n const doc = docs.reduce((a, b) =>\n a.lastModified > b.lastModified ||\n (a.lastModified === b.lastModified && !a.tombstone && b.tombstone)\n ? a\n : b,\n );\n\n if (doc.tombstone) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to get either does not exist or you are not allowed to see it\",\n );\n }\n\n const object = this.extractGraffitiObject(doc);\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, [], session);\n\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n if (!validate(object)) {\n throw new GraffitiErrorSchemaMismatch();\n }\n return object;\n };\n\n /**\n * Deletes all docs at a particular location.\n * If the `keepLatest` flag is set to true,\n * the doc with the most recent timestamp will be\n * spared. If there are multiple docs with the same\n * timestamp, the one with the highest `_id` will be\n * spared.\n */\n protected async deleteAtLocation(\n url: GraffitiObjectUrl | string,\n options: {\n keepLatest?: boolean;\n session?: GraffitiSession;\n } = {\n keepLatest: false,\n },\n ) {\n const docsAtLocationAll = await this.allDocsAtLocation(url);\n const docsAtLocationAllowed = options.session\n ? docsAtLocationAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, options.session),\n )\n : docsAtLocationAll;\n if (!docsAtLocationAllowed.length) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to delete either does not exist or you are not allowed to see it\",\n );\n } else if (\n options.session &&\n docsAtLocationAllowed.some((doc) => doc.actor !== options.session?.actor)\n ) {\n throw new GraffitiErrorForbidden(\n \"You cannot delete an object owned by another actor\",\n );\n }\n const docsAtLocation = docsAtLocationAllowed.filter(\n (doc) => !doc.tombstone,\n );\n if (!docsAtLocation.length) return undefined;\n\n // Get the most recent lastModified timestamp.\n const latestModified = docsAtLocation\n .map((doc) => doc.lastModified)\n .reduce((a, b) => (a > b ? a : b));\n\n // Delete all old docs\n const docsToDelete = docsAtLocation.filter(\n (doc) => !options.keepLatest || doc.lastModified < latestModified,\n );\n\n // For docs with the same timestamp,\n // keep the one with the highest _id\n // to break concurrency ties\n const concurrentDocsAll = docsAtLocation.filter(\n (doc) => options.keepLatest && doc.lastModified === latestModified,\n );\n if (concurrentDocsAll.length) {\n const keepDocId = concurrentDocsAll\n .map((doc) => doc._id)\n .reduce((a, b) => (a > b ? a : b));\n const concurrentDocsToDelete = concurrentDocsAll.filter(\n (doc) => doc._id !== keepDocId,\n );\n docsToDelete.push(...concurrentDocsToDelete);\n }\n\n const lastModified = options.keepLatest\n ? latestModified\n : new Date().getTime();\n\n const deleteResults = await (\n await this.db\n ).bulkDocs<GraffitiObjectBase>(\n docsToDelete.map((doc) => ({\n ...doc,\n tombstone: true,\n lastModified,\n })),\n );\n\n // Get one of the docs that was deleted\n let deletedObject: GraffitiObjectBase | undefined = undefined;\n for (const resultOrError of deleteResults) {\n if (\"ok\" in resultOrError) {\n const { id } = resultOrError;\n const deletedDoc = docsToDelete.find((doc) => doc._id === id);\n if (deletedDoc) {\n deletedObject = {\n ...this.extractGraffitiObject(deletedDoc),\n lastModified,\n };\n break;\n }\n }\n }\n\n return deletedObject;\n }\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const [url, session] = args;\n const deletedObject = await this.deleteAtLocation(url, {\n session,\n });\n if (!deletedObject) {\n throw new GraffitiErrorNotFound(\"The object has already been deleted\");\n }\n return deletedObject;\n };\n\n put: Graffiti[\"put\"] = async (...args) => {\n const [objectPartial, session] = args;\n if (objectPartial.actor && objectPartial.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"Cannot put an object with a different actor than the session actor\",\n );\n }\n\n if (objectPartial.url) {\n let oldObject: GraffitiObjectBase | undefined;\n try {\n oldObject = await this.get(objectPartial.url, {}, session);\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n if (!this.options.allowSettingArbitraryUrls) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to replace does not exist or you are not allowed to see it\",\n );\n }\n } else {\n throw e;\n }\n }\n if (oldObject?.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"The object you are trying to replace is owned by another actor\",\n );\n }\n }\n\n const lastModified =\n ((this.options.allowSettinngLastModified ?? false) &&\n objectPartial.lastModified) ||\n new Date().getTime();\n\n const object: GraffitiObjectWithTombstone = {\n value: objectPartial.value,\n channels: objectPartial.channels,\n allowed: objectPartial.allowed,\n url: objectPartial.url ?? this.origin + randomBase64(),\n actor: session.actor,\n tombstone: false,\n lastModified,\n };\n\n await (\n await this.db\n ).put({\n _id: this.docId(object),\n ...object,\n });\n\n // Delete the old object\n const previousObject = await this.deleteAtLocation(object, {\n keepLatest: true,\n });\n if (previousObject) {\n return previousObject;\n } else {\n return {\n ...object,\n value: {},\n channels: [],\n allowed: [],\n tombstone: true,\n };\n }\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const [patch, url, session] = args;\n let originalObject: GraffitiObjectBase;\n try {\n originalObject = await this.get(url, {}, session);\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch does not exist or you are not allowed to see it\",\n );\n } else {\n throw e;\n }\n }\n if (originalObject.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"The object you are trying to patch is owned by another actor\",\n );\n }\n\n // Patch it outside of the database\n const patchObject: GraffitiObjectBase = { ...originalObject };\n for (const prop of [\"value\", \"channels\", \"allowed\"] as const) {\n applyGraffitiPatch(await this.applyPatch, prop, patch, patchObject);\n }\n\n // Make sure the value is an object\n if (\n typeof patchObject.value !== \"object\" ||\n Array.isArray(patchObject.value) ||\n !patchObject.value\n ) {\n throw new GraffitiErrorPatchError(\"value is no longer an object\");\n }\n\n // Make sure the channels are an array of strings\n if (\n !Array.isArray(patchObject.channels) ||\n !patchObject.channels.every((channel) => typeof channel === \"string\")\n ) {\n throw new GraffitiErrorPatchError(\n \"channels are no longer an array of strings\",\n );\n }\n\n // Make sure the allowed list is an array of strings or undefined\n if (\n patchObject.allowed &&\n (!Array.isArray(patchObject.allowed) ||\n !patchObject.allowed.every((allowed) => typeof allowed === \"string\"))\n ) {\n throw new GraffitiErrorPatchError(\n \"allowed list is not an array of strings\",\n );\n }\n\n patchObject.lastModified = new Date().getTime();\n await (\n await this.db\n ).put({\n ...patchObject,\n tombstone: false,\n _id: this.docId(patchObject),\n });\n\n // Delete the old object\n await this.deleteAtLocation(patchObject, {\n keepLatest: true,\n });\n\n return {\n ...originalObject,\n lastModified: patchObject.lastModified,\n };\n };\n\n protected queryLastModifiedSuffixes(\n schema: JSONSchema,\n lastModified?: number,\n ) {\n // Use the index for queries over ranges of lastModified\n let startKeySuffix = \"\";\n let endKeySuffix = \"\\uffff\";\n if (\n typeof schema === \"object\" &&\n schema.properties?.lastModified &&\n typeof schema.properties.lastModified === \"object\"\n ) {\n const lastModifiedSchema = schema.properties.lastModified;\n\n const minimum =\n lastModified && lastModifiedSchema.minimum\n ? Math.max(lastModified, lastModifiedSchema.minimum)\n : (lastModified ?? lastModifiedSchema.minimum);\n const exclusiveMinimum = lastModifiedSchema.exclusiveMinimum;\n\n let intMinimum: number | undefined;\n if (exclusiveMinimum !== undefined) {\n intMinimum = Math.ceil(exclusiveMinimum);\n intMinimum === exclusiveMinimum && intMinimum++;\n } else if (minimum !== undefined) {\n intMinimum = Math.ceil(minimum);\n }\n\n if (intMinimum !== undefined) {\n startKeySuffix = intMinimum.toString().padStart(15, \"0\");\n }\n\n const maximum = lastModifiedSchema.maximum;\n const exclusiveMaximum = lastModifiedSchema.exclusiveMaximum;\n\n let intMaximum: number | undefined;\n if (exclusiveMaximum !== undefined) {\n intMaximum = Math.floor(exclusiveMaximum);\n intMaximum === exclusiveMaximum && intMaximum--;\n } else if (maximum !== undefined) {\n intMaximum = Math.floor(maximum);\n }\n\n if (intMaximum !== undefined) {\n endKeySuffix = intMaximum.toString().padStart(15, \"0\");\n }\n }\n return {\n startKeySuffix,\n endKeySuffix,\n };\n }\n\n protected async *streamObjects<Schema extends JSONSchema>(\n index: string,\n startkey: string,\n endkey: string,\n validate: ReturnType<typeof compileGraffitiObjectSchema<Schema>>,\n session: GraffitiSession | undefined | null,\n ifModifiedSince: number | undefined,\n channels?: string[],\n processedIds?: Set<string>,\n ): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>> {\n const showTombstones = ifModifiedSince !== undefined;\n\n const result = await (\n await this.db\n ).query<GraffitiObjectWithTombstone>(index, {\n startkey,\n endkey,\n include_docs: true,\n });\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n if (processedIds?.has(doc._id)) continue;\n processedIds?.add(doc._id);\n\n if (!showTombstones && doc.tombstone) continue;\n\n const object = this.extractGraffitiObject(doc);\n\n if (channels) {\n if (!isActorAllowedGraffitiObject(object, session)) continue;\n maskGraffitiObject(object, channels, session);\n }\n\n if (!validate(object)) continue;\n\n yield doc.tombstone\n ? {\n tombstone: true,\n object: {\n url: object.url,\n lastModified: object.lastModified,\n },\n }\n : { object };\n }\n }\n\n protected async *discoverMeta<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.discover<Schema>>,\n ifModifiedSince?: number,\n ): AsyncGenerator<\n GraffitiObjectStreamContinueEntry<Schema>,\n number | undefined\n > {\n const [channels, schema, session] = args;\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(\n schema,\n ifModifiedSince,\n );\n\n const processedIds = new Set<string>();\n\n const startTime = new Date().getTime();\n\n for (const channel of channels) {\n const keyPrefix = encodeURIComponent(channel) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const iterator = this.streamObjects<Schema>(\n \"indexes/objectsPerChannelAndLastModified\",\n startkey,\n endkey,\n validate,\n session,\n ifModifiedSince,\n channels,\n processedIds,\n );\n\n for await (const result of iterator) yield result;\n }\n\n // Subtract a minute to make sure we don't miss any objects\n return startTime - LAST_MODIFIED_BUFFER;\n }\n\n protected async *recoverOrphansMeta<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>,\n ifModifiedSince?: number,\n ): AsyncGenerator<\n GraffitiObjectStreamContinueEntry<Schema>,\n number | undefined\n > {\n const [schema, session] = args;\n const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(\n schema,\n ifModifiedSince,\n );\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n\n const startTime = new Date().getTime();\n\n const iterator = this.streamObjects<Schema>(\n \"indexes/orphansPerActorAndLastModified\",\n startkey,\n endkey,\n validate,\n session,\n ifModifiedSince,\n );\n\n for await (const result of iterator) yield result;\n\n return startTime - LAST_MODIFIED_BUFFER;\n }\n\n protected async *discoverContinue<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.discover<Schema>>,\n ifModifiedSince?: number,\n ): GraffitiObjectStreamContinue<Schema> {\n const iterator = this.discoverMeta(args, ifModifiedSince);\n\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n const ifModifiedSince = result.value;\n return {\n continue: () => this.discoverContinue<Schema>(args, ifModifiedSince),\n cursor: \"\",\n };\n }\n yield result.value;\n }\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const iterator = this.discoverMeta(args);\n\n const this_ = this;\n return (async function* () {\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n return {\n continue: () =>\n this_.discoverContinue<(typeof args)[1]>(args, result.value),\n cursor: \"\",\n };\n }\n // Make sure to filter out tombstones\n if (result.value.tombstone) continue;\n yield result.value;\n }\n })();\n };\n\n protected async *recoverContinue<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>,\n ifModifiedSince?: number,\n ): GraffitiObjectStreamContinue<Schema> {\n const iterator = this.recoverOrphansMeta(args, ifModifiedSince);\n\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n const ifModifiedSince = result.value;\n return {\n continue: () => this.recoverContinue<Schema>(args, ifModifiedSince),\n cursor: \"\",\n };\n }\n yield result.value;\n }\n }\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (...args) => {\n const iterator = this.recoverOrphansMeta(args);\n\n const this_ = this;\n return (async function* () {\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n return {\n continue: () =>\n this_.recoverContinue<(typeof args)[0]>(args, result.value),\n cursor: \"\",\n };\n }\n // Make sure to filter out tombstones\n if (result.value.tombstone) continue;\n yield result.value;\n }\n })();\n };\n\n channelStats: Graffiti[\"channelStats\"] = (session) => {\n const this_ = this;\n return (async function* () {\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const result = await (\n await this_.db\n ).query(\"indexes/channelStatsPerActor\", {\n startkey: keyPrefix,\n endkey: keyPrefix + \"\\uffff\",\n reduce: true,\n group: true,\n });\n for (const row of result.rows) {\n const channelEncoded = row.key.split(\"/\")[1];\n if (typeof channelEncoded !== \"string\") continue;\n const { count, max: lastModified } = row.value;\n if (typeof count !== \"number\" || typeof lastModified !== \"number\")\n continue;\n yield {\n value: {\n channel: decodeURIComponent(channelEncoded),\n count,\n lastModified,\n },\n };\n }\n })();\n };\n\n continueObjectStream: Graffiti[\"continueObjectStream\"] = (\n cursor,\n session,\n ) => {\n // TODO: Implement this\n throw new GraffitiErrorNotFound(\"Cursor not found\");\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type {\n Graffiti,\n GraffitiObjectBase,\n GraffitiObjectUrl,\n JSONSchema,\n GraffitiSession,\n GraffitiObjectStreamContinue,\n GraffitiObjectStreamContinueEntry,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorPatchError,\n} from \"@graffiti-garden/api\";\nimport {\n randomBase64,\n applyGraffitiPatch,\n maskGraffitiObject,\n isActorAllowedGraffitiObject,\n compileGraffitiObjectSchema,\n unpackObjectUrl,\n} from \"./utilities.js\";\nimport type Ajv from \"ajv\";\nimport type { applyPatch } from \"fast-json-patch\";\n\n/**\n * Constructor options for the GraffitiPoubchDB class.\n */\nexport interface GraffitiLocalOptions {\n /**\n * Options to pass to the PouchDB constructor.\n * Defaults to `{ name: \"graffitiDb\" }`.\n *\n * See the [PouchDB documentation](https://pouchdb.com/api.html#create_database)\n * for available options.\n */\n pouchDBOptions?: PouchDB.Configuration.DatabaseConfiguration;\n /**\n * Includes the scheme and other information (possibly domain name)\n * to prefix prefixes all URLs put in the system. Defaults to `graffiti:local`.\n */\n origin?: string;\n /**\n * Whether to allow putting objects at arbtirary URLs, i.e.\n * URLs that are *not* prefixed with the origin or not generated\n * by the system. Defaults to `false`.\n *\n * Allows this implementation to be used as a client-side cache\n * for remote sources.\n */\n allowSettingArbitraryUrls?: boolean;\n /**\n * Whether to allow the user to set the lastModified field\n * when putting objects. Defaults to `false`.\n *\n * Allows this implementation to be used as a client-side cache\n * for remote sources.\n */\n allowSettinngLastModified?: boolean;\n /**\n * An optional Ajv instance to use for schema validation.\n * If not provided, an internal instance will be created.\n */\n ajv?: Ajv;\n}\n\nconst DEFAULT_ORIGIN = \"graffiti:local:\";\nconst LAST_MODIFIED_BUFFER = 60000;\n\ntype GraffitiObjectWithTombstone = GraffitiObjectBase & { tombstone: boolean };\n\n/**\n * An implementation of only the database operations of the\n * GraffitiAPI without synchronization or session management.\n */\nexport class GraffitiLocalDatabase\n implements Omit<Graffiti, \"login\" | \"logout\" | \"sessionEvents\">\n{\n protected db_:\n | Promise<PouchDB.Database<GraffitiObjectWithTombstone>>\n | undefined;\n protected applyPatch_: Promise<typeof applyPatch> | undefined;\n protected ajv_: Promise<Ajv> | undefined;\n protected readonly options: GraffitiLocalOptions;\n protected readonly origin: string;\n\n get db() {\n if (!this.db_) {\n this.db_ = (async () => {\n const { default: PouchDB } = await import(\"pouchdb\");\n const pouchDbOptions = {\n name: \"graffitiDb\",\n ...this.options.pouchDBOptions,\n };\n const db = new PouchDB<GraffitiObjectWithTombstone>(\n pouchDbOptions.name,\n pouchDbOptions,\n );\n await db\n //@ts-ignore\n .put({\n _id: \"_design/indexes\",\n views: {\n objectsPerChannelAndLastModified: {\n map: function (object: GraffitiObjectWithTombstone) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n object.channels.forEach(function (channel) {\n const id =\n encodeURIComponent(channel) + \"/\" + paddedLastModified;\n //@ts-ignore\n emit(id);\n });\n }.toString(),\n },\n orphansPerActorAndLastModified: {\n map: function (object: GraffitiObjectWithTombstone) {\n if (object.channels.length === 0) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n const id =\n encodeURIComponent(object.actor) +\n \"/\" +\n paddedLastModified;\n //@ts-ignore\n emit(id);\n }\n }.toString(),\n },\n channelStatsPerActor: {\n map: function (object: GraffitiObjectWithTombstone) {\n if (object.tombstone) return;\n object.channels.forEach(function (channel) {\n const id =\n encodeURIComponent(object.actor) +\n \"/\" +\n encodeURIComponent(channel);\n //@ts-ignore\n emit(id, object.lastModified);\n });\n }.toString(),\n reduce: \"_stats\",\n },\n },\n })\n //@ts-ignore\n .catch((error) => {\n if (\n error &&\n typeof error === \"object\" &&\n \"name\" in error &&\n error.name === \"conflict\"\n ) {\n // Design document already exists\n return;\n } else {\n throw error;\n }\n });\n return db;\n })();\n }\n return this.db_;\n }\n\n protected get applyPatch() {\n if (!this.applyPatch_) {\n this.applyPatch_ = (async () => {\n const imported = await import(\"fast-json-patch\");\n return imported.applyPatch || imported.default.applyPatch;\n })();\n }\n return this.applyPatch_;\n }\n\n protected get ajv() {\n if (!this.ajv_) {\n this.ajv_ = this.options.ajv\n ? Promise.resolve(this.options.ajv)\n : (async () => {\n const { default: Ajv } = await import(\"ajv\");\n return new Ajv({ strict: false });\n })();\n }\n return this.ajv_;\n }\n\n protected extractGraffitiObject(\n object: GraffitiObjectWithTombstone,\n ): GraffitiObjectBase {\n const { value, channels, allowed, url, actor, lastModified } = object;\n return {\n value,\n channels,\n allowed,\n url,\n actor,\n lastModified,\n };\n }\n\n constructor(options?: GraffitiLocalOptions) {\n this.options = options ?? {};\n this.origin = this.options.origin ?? DEFAULT_ORIGIN;\n if (!this.origin.endsWith(\":\") && !this.origin.endsWith(\"/\")) {\n this.origin += \"/\";\n }\n }\n\n protected async allDocsAtLocation(objectUrl: string | GraffitiObjectUrl) {\n const url = unpackObjectUrl(objectUrl) + \"/\";\n const results = await (\n await this.db\n ).allDocs({\n startkey: url,\n endkey: url + \"\\uffff\", // \\uffff is the last unicode character\n include_docs: true,\n });\n const docs = results.rows\n .map((row) => row.doc)\n // Remove undefined docs\n .reduce<\n PouchDB.Core.ExistingDocument<\n GraffitiObjectWithTombstone & PouchDB.Core.AllDocsMeta\n >[]\n >((acc, doc) => {\n if (doc) acc.push(doc);\n return acc;\n }, []);\n return docs;\n }\n\n protected docId(objectUrl: GraffitiObjectUrl) {\n return objectUrl.url + \"/\" + randomBase64();\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [urlObject, schema, session] = args;\n\n const docsAll = await this.allDocsAtLocation(urlObject);\n\n // Filter out ones not allowed\n const docs = docsAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, session),\n );\n if (!docs.length)\n throw new GraffitiErrorNotFound(\n \"The object you are trying to get either does not exist or you are not allowed to see it\",\n );\n\n // Get the most recent document\n const doc = docs.reduce((a, b) =>\n a.lastModified > b.lastModified ||\n (a.lastModified === b.lastModified && !a.tombstone && b.tombstone)\n ? a\n : b,\n );\n\n if (doc.tombstone) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to get either does not exist or you are not allowed to see it\",\n );\n }\n\n const object = this.extractGraffitiObject(doc);\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, [], session);\n\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n if (!validate(object)) {\n throw new GraffitiErrorSchemaMismatch();\n }\n return object;\n };\n\n /**\n * Deletes all docs at a particular location.\n * If the `keepLatest` flag is set to true,\n * the doc with the most recent timestamp will be\n * spared. If there are multiple docs with the same\n * timestamp, the one with the highest `_id` will be\n * spared.\n */\n protected async deleteAtLocation(\n url: GraffitiObjectUrl | string,\n options: {\n keepLatest?: boolean;\n session?: GraffitiSession;\n } = {\n keepLatest: false,\n },\n ) {\n const docsAtLocationAll = await this.allDocsAtLocation(url);\n const docsAtLocationAllowed = options.session\n ? docsAtLocationAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, options.session),\n )\n : docsAtLocationAll;\n if (!docsAtLocationAllowed.length) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to delete either does not exist or you are not allowed to see it\",\n );\n } else if (\n options.session &&\n docsAtLocationAllowed.some((doc) => doc.actor !== options.session?.actor)\n ) {\n throw new GraffitiErrorForbidden(\n \"You cannot delete an object owned by another actor\",\n );\n }\n const docsAtLocation = docsAtLocationAllowed.filter(\n (doc) => !doc.tombstone,\n );\n if (!docsAtLocation.length) return undefined;\n\n // Get the most recent lastModified timestamp.\n const latestModified = docsAtLocation\n .map((doc) => doc.lastModified)\n .reduce((a, b) => (a > b ? a : b));\n\n // Delete all old docs\n const docsToDelete = docsAtLocation.filter(\n (doc) => !options.keepLatest || doc.lastModified < latestModified,\n );\n\n // For docs with the same timestamp,\n // keep the one with the highest _id\n // to break concurrency ties\n const concurrentDocsAll = docsAtLocation.filter(\n (doc) => options.keepLatest && doc.lastModified === latestModified,\n );\n if (concurrentDocsAll.length) {\n const keepDocId = concurrentDocsAll\n .map((doc) => doc._id)\n .reduce((a, b) => (a > b ? a : b));\n const concurrentDocsToDelete = concurrentDocsAll.filter(\n (doc) => doc._id !== keepDocId,\n );\n docsToDelete.push(...concurrentDocsToDelete);\n }\n\n const lastModified = options.keepLatest\n ? latestModified\n : new Date().getTime();\n\n const deleteResults = await (\n await this.db\n ).bulkDocs<GraffitiObjectBase>(\n docsToDelete.map((doc) => ({\n ...doc,\n tombstone: true,\n lastModified,\n })),\n );\n\n // Get one of the docs that was deleted\n let deletedObject: GraffitiObjectBase | undefined = undefined;\n for (const resultOrError of deleteResults) {\n if (\"ok\" in resultOrError) {\n const { id } = resultOrError;\n const deletedDoc = docsToDelete.find((doc) => doc._id === id);\n if (deletedDoc) {\n deletedObject = {\n ...this.extractGraffitiObject(deletedDoc),\n lastModified,\n };\n break;\n }\n }\n }\n\n return deletedObject;\n }\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const [url, session] = args;\n const deletedObject = await this.deleteAtLocation(url, {\n session,\n });\n if (!deletedObject) {\n throw new GraffitiErrorNotFound(\"The object has already been deleted\");\n }\n return deletedObject;\n };\n\n put: Graffiti[\"put\"] = async (...args) => {\n const [objectPartial, session] = args;\n if (objectPartial.actor && objectPartial.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"Cannot put an object with a different actor than the session actor\",\n );\n }\n\n if (objectPartial.url) {\n let oldObject: GraffitiObjectBase | undefined;\n try {\n oldObject = await this.get(objectPartial.url, {}, session);\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n if (!this.options.allowSettingArbitraryUrls) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to replace does not exist or you are not allowed to see it\",\n );\n }\n } else {\n throw e;\n }\n }\n if (oldObject?.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"The object you are trying to replace is owned by another actor\",\n );\n }\n }\n\n const lastModified =\n ((this.options.allowSettinngLastModified ?? false) &&\n objectPartial.lastModified) ||\n new Date().getTime();\n\n const object: GraffitiObjectWithTombstone = {\n value: objectPartial.value,\n channels: objectPartial.channels,\n allowed: objectPartial.allowed,\n url: objectPartial.url ?? this.origin + randomBase64(),\n actor: session.actor,\n tombstone: false,\n lastModified,\n };\n\n await (\n await this.db\n ).put({\n _id: this.docId(object),\n ...object,\n });\n\n // Delete the old object\n const previousObject = await this.deleteAtLocation(object, {\n keepLatest: true,\n });\n if (previousObject) {\n return previousObject;\n } else {\n return {\n ...object,\n value: {},\n channels: [],\n allowed: [],\n tombstone: true,\n };\n }\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const [patch, url, session] = args;\n let originalObject: GraffitiObjectBase;\n try {\n originalObject = await this.get(url, {}, session);\n } catch (e) {\n if (e instanceof GraffitiErrorNotFound) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch does not exist or you are not allowed to see it\",\n );\n } else {\n throw e;\n }\n }\n if (originalObject.actor !== session.actor) {\n throw new GraffitiErrorForbidden(\n \"The object you are trying to patch is owned by another actor\",\n );\n }\n\n // Patch it outside of the database\n const patchObject: GraffitiObjectBase = { ...originalObject };\n for (const prop of [\"value\", \"channels\", \"allowed\"] as const) {\n applyGraffitiPatch(await this.applyPatch, prop, patch, patchObject);\n }\n\n // Make sure the value is an object\n if (\n typeof patchObject.value !== \"object\" ||\n Array.isArray(patchObject.value) ||\n !patchObject.value\n ) {\n throw new GraffitiErrorPatchError(\"value is no longer an object\");\n }\n\n // Make sure the channels are an array of strings\n if (\n !Array.isArray(patchObject.channels) ||\n !patchObject.channels.every((channel) => typeof channel === \"string\")\n ) {\n throw new GraffitiErrorPatchError(\n \"channels are no longer an array of strings\",\n );\n }\n\n // Make sure the allowed list is an array of strings or undefined\n if (\n patchObject.allowed &&\n (!Array.isArray(patchObject.allowed) ||\n !patchObject.allowed.every((allowed) => typeof allowed === \"string\"))\n ) {\n throw new GraffitiErrorPatchError(\n \"allowed list is not an array of strings\",\n );\n }\n\n patchObject.lastModified = new Date().getTime();\n await (\n await this.db\n ).put({\n ...patchObject,\n tombstone: false,\n _id: this.docId(patchObject),\n });\n\n // Delete the old object\n await this.deleteAtLocation(patchObject, {\n keepLatest: true,\n });\n\n return {\n ...originalObject,\n lastModified: patchObject.lastModified,\n };\n };\n\n protected queryLastModifiedSuffixes(\n schema: JSONSchema,\n lastModified?: number,\n ) {\n // Use the index for queries over ranges of lastModified\n let startKeySuffix = \"\";\n let endKeySuffix = \"\\uffff\";\n if (\n typeof schema === \"object\" &&\n schema.properties?.lastModified &&\n typeof schema.properties.lastModified === \"object\"\n ) {\n const lastModifiedSchema = schema.properties.lastModified;\n\n const minimum =\n lastModified && lastModifiedSchema.minimum\n ? Math.max(lastModified, lastModifiedSchema.minimum)\n : (lastModified ?? lastModifiedSchema.minimum);\n const exclusiveMinimum = lastModifiedSchema.exclusiveMinimum;\n\n let intMinimum: number | undefined;\n if (exclusiveMinimum !== undefined) {\n intMinimum = Math.ceil(exclusiveMinimum);\n intMinimum === exclusiveMinimum && intMinimum++;\n } else if (minimum !== undefined) {\n intMinimum = Math.ceil(minimum);\n }\n\n if (intMinimum !== undefined) {\n startKeySuffix = intMinimum.toString().padStart(15, \"0\");\n }\n\n const maximum = lastModifiedSchema.maximum;\n const exclusiveMaximum = lastModifiedSchema.exclusiveMaximum;\n\n let intMaximum: number | undefined;\n if (exclusiveMaximum !== undefined) {\n intMaximum = Math.floor(exclusiveMaximum);\n intMaximum === exclusiveMaximum && intMaximum--;\n } else if (maximum !== undefined) {\n intMaximum = Math.floor(maximum);\n }\n\n if (intMaximum !== undefined) {\n endKeySuffix = intMaximum.toString().padStart(15, \"0\");\n }\n }\n return {\n startKeySuffix,\n endKeySuffix,\n };\n }\n\n protected async *streamObjects<Schema extends JSONSchema>(\n index: string,\n startkey: string,\n endkey: string,\n validate: ReturnType<typeof compileGraffitiObjectSchema<Schema>>,\n session: GraffitiSession | undefined | null,\n ifModifiedSince: number | undefined,\n channels?: string[],\n processedIds?: Set<string>,\n ): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>> {\n const showTombstones = ifModifiedSince !== undefined;\n\n const result = await (\n await this.db\n ).query<GraffitiObjectWithTombstone>(index, {\n startkey,\n endkey,\n include_docs: true,\n });\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n if (processedIds?.has(doc._id)) continue;\n processedIds?.add(doc._id);\n\n if (!showTombstones && doc.tombstone) continue;\n\n const object = this.extractGraffitiObject(doc);\n\n if (channels) {\n if (!isActorAllowedGraffitiObject(object, session)) continue;\n maskGraffitiObject(object, channels, session);\n }\n\n if (!validate(object)) continue;\n\n yield doc.tombstone\n ? {\n tombstone: true,\n object: {\n url: object.url,\n lastModified: object.lastModified,\n },\n }\n : { object };\n }\n }\n\n protected async *discoverMeta<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.discover<Schema>>,\n ifModifiedSince?: number,\n ): AsyncGenerator<\n GraffitiObjectStreamContinueEntry<Schema>,\n number | undefined\n > {\n const [channels, schema, session] = args;\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(\n schema,\n ifModifiedSince,\n );\n\n const processedIds = new Set<string>();\n\n const startTime = new Date().getTime();\n\n for (const channel of channels) {\n const keyPrefix = encodeURIComponent(channel) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const iterator = this.streamObjects<Schema>(\n \"indexes/objectsPerChannelAndLastModified\",\n startkey,\n endkey,\n validate,\n session,\n ifModifiedSince,\n channels,\n processedIds,\n );\n\n for await (const result of iterator) yield result;\n }\n\n // Subtract a minute to make sure we don't miss any objects\n return startTime - LAST_MODIFIED_BUFFER;\n }\n\n protected async *recoverOrphansMeta<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>,\n ifModifiedSince?: number,\n ): AsyncGenerator<\n GraffitiObjectStreamContinueEntry<Schema>,\n number | undefined\n > {\n const [schema, session] = args;\n const { startKeySuffix, endKeySuffix } = this.queryLastModifiedSuffixes(\n schema,\n ifModifiedSince,\n );\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const validate = compileGraffitiObjectSchema(await this.ajv, schema);\n\n const startTime = new Date().getTime();\n\n const iterator = this.streamObjects<Schema>(\n \"indexes/orphansPerActorAndLastModified\",\n startkey,\n endkey,\n validate,\n session,\n ifModifiedSince,\n );\n\n for await (const result of iterator) yield result;\n\n return startTime - LAST_MODIFIED_BUFFER;\n }\n\n protected discoverCursor(\n args: Parameters<typeof Graffiti.prototype.discover<{}>>,\n ifModifiedSince?: number,\n ): string {\n return (\n \"discover:\" +\n JSON.stringify({\n channels: args[0],\n schema: args[1],\n actor: args[2]?.actor,\n ifModifiedSince: ifModifiedSince,\n })\n );\n }\n\n protected async *discoverContinue<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.discover<Schema>>,\n ifModifiedSince?: number,\n ): GraffitiObjectStreamContinue<Schema> {\n const iterator = this.discoverMeta(args, ifModifiedSince);\n\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n const ifModifiedSince = result.value;\n return {\n continue: () => this.discoverContinue<Schema>(args, ifModifiedSince),\n cursor: this.discoverCursor(args, ifModifiedSince),\n };\n }\n yield result.value;\n }\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const iterator = this.discoverMeta(args);\n\n const this_ = this;\n return (async function* () {\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n return {\n continue: () =>\n this_.discoverContinue<(typeof args)[1]>(args, result.value),\n cursor: this_.discoverCursor(args, result.value),\n };\n }\n // Make sure to filter out tombstones\n if (result.value.tombstone) continue;\n yield result.value;\n }\n })();\n };\n\n protected recoverOrphansCursor(\n args: Parameters<typeof Graffiti.prototype.recoverOrphans<{}>>,\n ifModifiedSince?: number,\n ): string {\n return (\n \"orphans:\" +\n JSON.stringify({\n schema: args[0],\n actor: args[1]?.actor,\n ifModifiedSince,\n })\n );\n }\n\n protected async *recoverOrphansContinue<Schema extends JSONSchema>(\n args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>,\n ifModifiedSince?: number,\n ): GraffitiObjectStreamContinue<Schema> {\n const iterator = this.recoverOrphansMeta(args, ifModifiedSince);\n\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n const ifModifiedSince = result.value;\n return {\n continue: () =>\n this.recoverOrphansContinue<Schema>(args, ifModifiedSince),\n cursor: this.recoverOrphansCursor(args, ifModifiedSince),\n };\n }\n yield result.value;\n }\n }\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (...args) => {\n const iterator = this.recoverOrphansMeta(args);\n\n const this_ = this;\n return (async function* () {\n while (true) {\n const result = await iterator.next();\n if (result.done) {\n return {\n continue: () =>\n this_.recoverOrphansContinue<(typeof args)[0]>(\n args,\n result.value,\n ),\n cursor: this_.recoverOrphansCursor(args, result.value),\n };\n }\n // Make sure to filter out tombstones\n if (result.value.tombstone) continue;\n yield result.value;\n }\n })();\n };\n\n channelStats: Graffiti[\"channelStats\"] = (session) => {\n const this_ = this;\n return (async function* () {\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const result = await (\n await this_.db\n ).query(\"indexes/channelStatsPerActor\", {\n startkey: keyPrefix,\n endkey: keyPrefix + \"\\uffff\",\n reduce: true,\n group: true,\n });\n for (const row of result.rows) {\n const channelEncoded = row.key.split(\"/\")[1];\n if (typeof channelEncoded !== \"string\") continue;\n const { count, max: lastModified } = row.value;\n if (typeof count !== \"number\" || typeof lastModified !== \"number\")\n continue;\n yield {\n value: {\n channel: decodeURIComponent(channelEncoded),\n count,\n lastModified,\n },\n };\n }\n })();\n };\n\n continueObjectStream: Graffiti[\"continueObjectStream\"] = (\n cursor,\n session,\n ) => {\n if (cursor.startsWith(\"discover:\")) {\n const { channels, schema, actor, ifModifiedSince } = JSON.parse(\n cursor.slice(\"discover:\".length),\n );\n if (actor && actor !== session?.actor) {\n throw new GraffitiErrorForbidden(\n \"Cannot continue a cursor for another actor\",\n );\n }\n return this.discoverContinue<{}>(\n [channels, schema, session],\n ifModifiedSince,\n );\n } else if (cursor.startsWith(\"orphans:\")) {\n const { schema, actor, ifModifiedSince } = JSON.parse(\n cursor.slice(\"orphans:\".length),\n );\n if (!session || actor !== session?.actor) {\n throw new GraffitiErrorForbidden(\n \"Cannot continue a cursor for another actor\",\n );\n }\n return this.recoverOrphansContinue<{}>(\n [schema, session],\n ifModifiedSince,\n );\n } else {\n throw new GraffitiErrorNotFound(\"Cursor not found\");\n }\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["doc", "ifModifiedSince"]
|
|
7
7
|
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -50,13 +50,4 @@ class GraffitiLocal extends import_api.Graffiti {
|
|
|
50
50
|
this.continueObjectStream = graffitiPouchDbBase.continueObjectStream.bind(graffitiPouchDbBase);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
function myFunction(flag) {
|
|
54
|
-
if (!flag) {
|
|
55
|
-
return "Hello";
|
|
56
|
-
} else {
|
|
57
|
-
return 42;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
const a = myFunction(false);
|
|
61
|
-
const b = myFunction(true);
|
|
62
53
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import { Graffiti, type GraffitiSession } from \"@graffiti-garden/api\";\nimport { GraffitiLocalSessionManager } from \"./session-manager.js\";\nimport {\n GraffitiLocalDatabase,\n type GraffitiLocalOptions,\n} from \"./database.js\";\n\nexport type { GraffitiLocalOptions };\n\n/**\n * A local implementation of the [Graffiti API](https://api.graffiti.garden/classes/Graffiti.html)\n * based on [PouchDB](https://pouchdb.com/). PouchDb will automatically persist data in a local\n * database, either in the browser or in Node.js.\n * It can also be configured to work with an external [CouchDB](https://couchdb.apache.org/) server,\n * although using it with a remote server will not be secure.\n */\nexport class GraffitiLocal extends Graffiti {\n protected sessionManagerLocal = new GraffitiLocalSessionManager();\n login = this.sessionManagerLocal.login.bind(this.sessionManagerLocal);\n logout = this.sessionManagerLocal.logout.bind(this.sessionManagerLocal);\n sessionEvents = this.sessionManagerLocal.sessionEvents;\n\n put: Graffiti[\"put\"];\n get: Graffiti[\"get\"];\n patch: Graffiti[\"patch\"];\n delete: Graffiti[\"delete\"];\n discover: Graffiti[\"discover\"];\n recoverOrphans: Graffiti[\"recoverOrphans\"];\n channelStats: Graffiti[\"channelStats\"];\n continueObjectStream: Graffiti[\"continueObjectStream\"];\n\n constructor(options?: GraffitiLocalOptions) {\n super();\n\n const graffitiPouchDbBase = new GraffitiLocalDatabase(options);\n\n this.put = graffitiPouchDbBase.put.bind(graffitiPouchDbBase);\n this.get = graffitiPouchDbBase.get.bind(graffitiPouchDbBase);\n this.patch = graffitiPouchDbBase.patch.bind(graffitiPouchDbBase);\n this.delete = graffitiPouchDbBase.delete.bind(graffitiPouchDbBase);\n this.discover = graffitiPouchDbBase.discover.bind(graffitiPouchDbBase);\n this.recoverOrphans =\n graffitiPouchDbBase.recoverOrphans.bind(graffitiPouchDbBase);\n this.channelStats =\n graffitiPouchDbBase.channelStats.bind(graffitiPouchDbBase);\n this.continueObjectStream =\n graffitiPouchDbBase.continueObjectStream.bind(graffitiPouchDbBase);\n }\n}\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAA+C;AAC/C,6BAA4C;AAC5C,sBAGO;AAWA,MAAM,sBAAsB,oBAAS;AAAA,EAChC,sBAAsB,IAAI,mDAA4B;AAAA,EAChE,QAAQ,KAAK,oBAAoB,MAAM,KAAK,KAAK,mBAAmB;AAAA,EACpE,SAAS,KAAK,oBAAoB,OAAO,KAAK,KAAK,mBAAmB;AAAA,EACtE,gBAAgB,KAAK,oBAAoB;AAAA,EAEzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,SAAgC;AAC1C,UAAM;AAEN,UAAM,sBAAsB,IAAI,sCAAsB,OAAO;AAE7D,SAAK,MAAM,oBAAoB,IAAI,KAAK,mBAAmB;AAC3D,SAAK,MAAM,oBAAoB,IAAI,KAAK,mBAAmB;AAC3D,SAAK,QAAQ,oBAAoB,MAAM,KAAK,mBAAmB;AAC/D,SAAK,SAAS,oBAAoB,OAAO,KAAK,mBAAmB;AACjE,SAAK,WAAW,oBAAoB,SAAS,KAAK,mBAAmB;AACrE,SAAK,iBACH,oBAAoB,eAAe,KAAK,mBAAmB;AAC7D,SAAK,eACH,oBAAoB,aAAa,KAAK,mBAAmB;AAC3D,SAAK,uBACH,oBAAoB,qBAAqB,KAAK,mBAAmB;AAAA,EACrE;AACF;
|
|
4
|
+
"sourcesContent": ["import { Graffiti, type GraffitiSession } from \"@graffiti-garden/api\";\nimport { GraffitiLocalSessionManager } from \"./session-manager.js\";\nimport {\n GraffitiLocalDatabase,\n type GraffitiLocalOptions,\n} from \"./database.js\";\n\nexport type { GraffitiLocalOptions };\n\n/**\n * A local implementation of the [Graffiti API](https://api.graffiti.garden/classes/Graffiti.html)\n * based on [PouchDB](https://pouchdb.com/). PouchDb will automatically persist data in a local\n * database, either in the browser or in Node.js.\n * It can also be configured to work with an external [CouchDB](https://couchdb.apache.org/) server,\n * although using it with a remote server will not be secure.\n */\nexport class GraffitiLocal extends Graffiti {\n protected sessionManagerLocal = new GraffitiLocalSessionManager();\n login = this.sessionManagerLocal.login.bind(this.sessionManagerLocal);\n logout = this.sessionManagerLocal.logout.bind(this.sessionManagerLocal);\n sessionEvents = this.sessionManagerLocal.sessionEvents;\n\n put: Graffiti[\"put\"];\n get: Graffiti[\"get\"];\n patch: Graffiti[\"patch\"];\n delete: Graffiti[\"delete\"];\n discover: Graffiti[\"discover\"];\n recoverOrphans: Graffiti[\"recoverOrphans\"];\n channelStats: Graffiti[\"channelStats\"];\n continueObjectStream: Graffiti[\"continueObjectStream\"];\n\n constructor(options?: GraffitiLocalOptions) {\n super();\n\n const graffitiPouchDbBase = new GraffitiLocalDatabase(options);\n\n this.put = graffitiPouchDbBase.put.bind(graffitiPouchDbBase);\n this.get = graffitiPouchDbBase.get.bind(graffitiPouchDbBase);\n this.patch = graffitiPouchDbBase.patch.bind(graffitiPouchDbBase);\n this.delete = graffitiPouchDbBase.delete.bind(graffitiPouchDbBase);\n this.discover = graffitiPouchDbBase.discover.bind(graffitiPouchDbBase);\n this.recoverOrphans =\n graffitiPouchDbBase.recoverOrphans.bind(graffitiPouchDbBase);\n this.channelStats =\n graffitiPouchDbBase.channelStats.bind(graffitiPouchDbBase);\n this.continueObjectStream =\n graffitiPouchDbBase.continueObjectStream.bind(graffitiPouchDbBase);\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAA+C;AAC/C,6BAA4C;AAC5C,sBAGO;AAWA,MAAM,sBAAsB,oBAAS;AAAA,EAChC,sBAAsB,IAAI,mDAA4B;AAAA,EAChE,QAAQ,KAAK,oBAAoB,MAAM,KAAK,KAAK,mBAAmB;AAAA,EACpE,SAAS,KAAK,oBAAoB,OAAO,KAAK,KAAK,mBAAmB;AAAA,EACtE,gBAAgB,KAAK,oBAAoB;AAAA,EAEzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,SAAgC;AAC1C,UAAM;AAEN,UAAM,sBAAsB,IAAI,sCAAsB,OAAO;AAE7D,SAAK,MAAM,oBAAoB,IAAI,KAAK,mBAAmB;AAC3D,SAAK,MAAM,oBAAoB,IAAI,KAAK,mBAAmB;AAC3D,SAAK,QAAQ,oBAAoB,MAAM,KAAK,mBAAmB;AAC/D,SAAK,SAAS,oBAAoB,OAAO,KAAK,mBAAmB;AACjE,SAAK,WAAW,oBAAoB,SAAS,KAAK,mBAAmB;AACrE,SAAK,iBACH,oBAAoB,eAAe,KAAK,mBAAmB;AAC7D,SAAK,eACH,oBAAoB,aAAa,KAAK,mBAAmB;AAC3D,SAAK,uBACH,oBAAoB,qBAAqB,KAAK,mBAAmB;AAAA,EACrE;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utilities.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n GraffitiErrorInvalidSchema,\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,
|
|
4
|
+
"sourcesContent": ["import {\n GraffitiErrorInvalidSchema,\n GraffitiErrorPatchError,\n GraffitiErrorPatchTestFailed,\n} from \"@graffiti-garden/api\";\nimport type {\n GraffitiObject,\n GraffitiObjectBase,\n GraffitiPatch,\n JSONSchema,\n GraffitiSession,\n GraffitiObjectUrl,\n} from \"@graffiti-garden/api\";\nimport type { Ajv } from \"ajv\";\nimport type { applyPatch } from \"fast-json-patch\";\n\nexport function unpackObjectUrl(url: string | GraffitiObjectUrl) {\n return typeof url === \"string\" ? url : url.url;\n}\n\nexport function randomBase64(numBytes: number = 24) {\n const bytes = new Uint8Array(numBytes);\n crypto.getRandomValues(bytes);\n // Convert it to base64\n const base64 = btoa(String.fromCodePoint(...bytes));\n // Make sure it is url safe\n return base64.replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/\\=+$/, \"\");\n}\n\nexport function applyGraffitiPatch<Prop extends keyof GraffitiPatch>(\n apply: typeof applyPatch,\n prop: Prop,\n patch: GraffitiPatch,\n object: GraffitiObjectBase,\n): void {\n const ops = patch[prop];\n if (!ops || !ops.length) return;\n try {\n object[prop] = apply(object[prop], ops, true, false).newDocument;\n } catch (e) {\n if (\n typeof e === \"object\" &&\n e &&\n \"name\" in e &&\n typeof e.name === \"string\" &&\n \"message\" in e &&\n typeof e.message === \"string\"\n ) {\n if (e.name === \"TEST_OPERATION_FAILED\") {\n throw new GraffitiErrorPatchTestFailed(e.message);\n } else {\n throw new GraffitiErrorPatchError(e.name + \": \" + e.message);\n }\n } else {\n throw e;\n }\n }\n}\n\nexport function compileGraffitiObjectSchema<Schema extends JSONSchema>(\n ajv: Ajv,\n schema: Schema,\n) {\n try {\n // Force the validation guard because\n // it is too big for the type checker.\n // Fortunately json-schema-to-ts is\n // well tested against ajv.\n return ajv.compile(schema) as (\n data: GraffitiObjectBase,\n ) => data is GraffitiObject<Schema>;\n } catch (error) {\n throw new GraffitiErrorInvalidSchema(\n error instanceof Error ? error.message : undefined,\n );\n }\n}\n\nexport function maskGraffitiObject(\n object: GraffitiObjectBase,\n channels: string[],\n session?: GraffitiSession | null,\n): void {\n if (object.actor !== session?.actor) {\n object.allowed = object.allowed && session ? [session.actor] : undefined;\n object.channels = object.channels.filter((channel) =>\n channels.includes(channel),\n );\n }\n}\nexport function isActorAllowedGraffitiObject(\n object: GraffitiObjectBase,\n session?: GraffitiSession | null,\n) {\n return (\n object.allowed === undefined ||\n object.allowed === null ||\n (!!session?.actor &&\n (object.actor === session.actor ||\n object.allowed.includes(session.actor)))\n );\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAIO;AAYA,SAAS,gBAAgB,KAAiC;AAC/D,SAAO,OAAO,QAAQ,WAAW,MAAM,IAAI;AAC7C;AAEO,SAAS,aAAa,WAAmB,IAAI;AAClD,QAAM,QAAQ,IAAI,WAAW,QAAQ;AACrC,SAAO,gBAAgB,KAAK;AAE5B,QAAM,SAAS,KAAK,OAAO,cAAc,GAAG,KAAK,CAAC;AAElD,SAAO,OAAO,QAAQ,OAAO,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,QAAQ,EAAE;AAC1E;AAEO,SAAS,mBACd,OACA,MACA,OACA,QACM;AACN,QAAM,MAAM,MAAM,IAAI;AACtB,MAAI,CAAC,OAAO,CAAC,IAAI,OAAQ;AACzB,MAAI;AACF,WAAO,IAAI,IAAI,MAAM,OAAO,IAAI,GAAG,KAAK,MAAM,KAAK,EAAE;AAAA,EACvD,SAAS,GAAG;AACV,QACE,OAAO,MAAM,YACb,KACA,UAAU,KACV,OAAO,EAAE,SAAS,YAClB,aAAa,KACb,OAAO,EAAE,YAAY,UACrB;AACA,UAAI,EAAE,SAAS,yBAAyB;AACtC,cAAM,IAAI,wCAA6B,EAAE,OAAO;AAAA,MAClD,OAAO;AACL,cAAM,IAAI,mCAAwB,EAAE,OAAO,OAAO,EAAE,OAAO;AAAA,MAC7D;AAAA,IACF,OAAO;AACL,YAAM;AAAA,IACR;AAAA,EACF;AACF;AAEO,SAAS,4BACd,KACA,QACA;AACA,MAAI;AAKF,WAAO,IAAI,QAAQ,MAAM;AAAA,EAG3B,SAAS,OAAO;AACd,UAAM,IAAI;AAAA,MACR,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAC3C;AAAA,EACF;AACF;AAEO,SAAS,mBACd,QACA,UACA,SACM;AACN,MAAI,OAAO,UAAU,SAAS,OAAO;AACnC,WAAO,UAAU,OAAO,WAAW,UAAU,CAAC,QAAQ,KAAK,IAAI;AAC/D,WAAO,WAAW,OAAO,SAAS;AAAA,MAAO,CAAC,YACxC,SAAS,SAAS,OAAO;AAAA,IAC3B;AAAA,EACF;AACF;AACO,SAAS,6BACd,QACA,SACA;AACA,SACE,OAAO,YAAY,UACnB,OAAO,YAAY,QAClB,CAAC,CAAC,SAAS,UACT,OAAO,UAAU,QAAQ,SACxB,OAAO,QAAQ,SAAS,QAAQ,KAAK;AAE7C;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/database.d.ts
CHANGED
|
@@ -87,9 +87,11 @@ export declare class GraffitiLocalDatabase implements Omit<Graffiti, "login" | "
|
|
|
87
87
|
protected streamObjects<Schema extends JSONSchema>(index: string, startkey: string, endkey: string, validate: ReturnType<typeof compileGraffitiObjectSchema<Schema>>, session: GraffitiSession | undefined | null, ifModifiedSince: number | undefined, channels?: string[], processedIds?: Set<string>): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>>;
|
|
88
88
|
protected discoverMeta<Schema extends JSONSchema>(args: Parameters<typeof Graffiti.prototype.discover<Schema>>, ifModifiedSince?: number): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>, number | undefined>;
|
|
89
89
|
protected recoverOrphansMeta<Schema extends JSONSchema>(args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>, ifModifiedSince?: number): AsyncGenerator<GraffitiObjectStreamContinueEntry<Schema>, number | undefined>;
|
|
90
|
+
protected discoverCursor(args: Parameters<typeof Graffiti.prototype.discover<{}>>, ifModifiedSince?: number): string;
|
|
90
91
|
protected discoverContinue<Schema extends JSONSchema>(args: Parameters<typeof Graffiti.prototype.discover<Schema>>, ifModifiedSince?: number): GraffitiObjectStreamContinue<Schema>;
|
|
91
92
|
discover: Graffiti["discover"];
|
|
92
|
-
protected
|
|
93
|
+
protected recoverOrphansCursor(args: Parameters<typeof Graffiti.prototype.recoverOrphans<{}>>, ifModifiedSince?: number): string;
|
|
94
|
+
protected recoverOrphansContinue<Schema extends JSONSchema>(args: Parameters<typeof Graffiti.prototype.recoverOrphans<Schema>>, ifModifiedSince?: number): GraffitiObjectStreamContinue<Schema>;
|
|
93
95
|
recoverOrphans: Graffiti["recoverOrphans"];
|
|
94
96
|
channelStats: Graffiti["channelStats"];
|
|
95
97
|
continueObjectStream: Graffiti["continueObjectStream"];
|
package/dist/database.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/database.js
CHANGED
|
@@ -79,8 +79,8 @@ class GraffitiLocalDatabase {
|
|
|
79
79
|
get applyPatch() {
|
|
80
80
|
if (!this.applyPatch_) {
|
|
81
81
|
this.applyPatch_ = (async () => {
|
|
82
|
-
const
|
|
83
|
-
return applyPatch;
|
|
82
|
+
const imported = await import("fast-json-patch");
|
|
83
|
+
return imported.applyPatch || imported.default.applyPatch;
|
|
84
84
|
})();
|
|
85
85
|
}
|
|
86
86
|
return this.applyPatch_;
|
|
@@ -450,6 +450,14 @@ class GraffitiLocalDatabase {
|
|
|
450
450
|
for await (const result of iterator) yield result;
|
|
451
451
|
return startTime - LAST_MODIFIED_BUFFER;
|
|
452
452
|
}
|
|
453
|
+
discoverCursor(args, ifModifiedSince) {
|
|
454
|
+
return "discover:" + JSON.stringify({
|
|
455
|
+
channels: args[0],
|
|
456
|
+
schema: args[1],
|
|
457
|
+
actor: args[2]?.actor,
|
|
458
|
+
ifModifiedSince
|
|
459
|
+
});
|
|
460
|
+
}
|
|
453
461
|
async *discoverContinue(args, ifModifiedSince) {
|
|
454
462
|
const iterator = this.discoverMeta(args, ifModifiedSince);
|
|
455
463
|
while (true) {
|
|
@@ -458,7 +466,7 @@ class GraffitiLocalDatabase {
|
|
|
458
466
|
const ifModifiedSince2 = result.value;
|
|
459
467
|
return {
|
|
460
468
|
continue: () => this.discoverContinue(args, ifModifiedSince2),
|
|
461
|
-
cursor:
|
|
469
|
+
cursor: this.discoverCursor(args, ifModifiedSince2)
|
|
462
470
|
};
|
|
463
471
|
}
|
|
464
472
|
yield result.value;
|
|
@@ -473,7 +481,7 @@ class GraffitiLocalDatabase {
|
|
|
473
481
|
if (result.done) {
|
|
474
482
|
return {
|
|
475
483
|
continue: () => this_.discoverContinue(args, result.value),
|
|
476
|
-
cursor:
|
|
484
|
+
cursor: this_.discoverCursor(args, result.value)
|
|
477
485
|
};
|
|
478
486
|
}
|
|
479
487
|
if (result.value.tombstone) continue;
|
|
@@ -481,15 +489,22 @@ class GraffitiLocalDatabase {
|
|
|
481
489
|
}
|
|
482
490
|
}();
|
|
483
491
|
};
|
|
484
|
-
|
|
492
|
+
recoverOrphansCursor(args, ifModifiedSince) {
|
|
493
|
+
return "orphans:" + JSON.stringify({
|
|
494
|
+
schema: args[0],
|
|
495
|
+
actor: args[1]?.actor,
|
|
496
|
+
ifModifiedSince
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
async *recoverOrphansContinue(args, ifModifiedSince) {
|
|
485
500
|
const iterator = this.recoverOrphansMeta(args, ifModifiedSince);
|
|
486
501
|
while (true) {
|
|
487
502
|
const result = await iterator.next();
|
|
488
503
|
if (result.done) {
|
|
489
504
|
const ifModifiedSince2 = result.value;
|
|
490
505
|
return {
|
|
491
|
-
continue: () => this.
|
|
492
|
-
cursor:
|
|
506
|
+
continue: () => this.recoverOrphansContinue(args, ifModifiedSince2),
|
|
507
|
+
cursor: this.recoverOrphansCursor(args, ifModifiedSince2)
|
|
493
508
|
};
|
|
494
509
|
}
|
|
495
510
|
yield result.value;
|
|
@@ -503,8 +518,11 @@ class GraffitiLocalDatabase {
|
|
|
503
518
|
const result = await iterator.next();
|
|
504
519
|
if (result.done) {
|
|
505
520
|
return {
|
|
506
|
-
continue: () => this_.
|
|
507
|
-
|
|
521
|
+
continue: () => this_.recoverOrphansContinue(
|
|
522
|
+
args,
|
|
523
|
+
result.value
|
|
524
|
+
),
|
|
525
|
+
cursor: this_.recoverOrphansCursor(args, result.value)
|
|
508
526
|
};
|
|
509
527
|
}
|
|
510
528
|
if (result.value.tombstone) continue;
|
|
@@ -539,7 +557,35 @@ class GraffitiLocalDatabase {
|
|
|
539
557
|
}();
|
|
540
558
|
};
|
|
541
559
|
continueObjectStream = (cursor, session) => {
|
|
542
|
-
|
|
560
|
+
if (cursor.startsWith("discover:")) {
|
|
561
|
+
const { channels, schema, actor, ifModifiedSince } = JSON.parse(
|
|
562
|
+
cursor.slice("discover:".length)
|
|
563
|
+
);
|
|
564
|
+
if (actor && actor !== session?.actor) {
|
|
565
|
+
throw new GraffitiErrorForbidden(
|
|
566
|
+
"Cannot continue a cursor for another actor"
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
return this.discoverContinue(
|
|
570
|
+
[channels, schema, session],
|
|
571
|
+
ifModifiedSince
|
|
572
|
+
);
|
|
573
|
+
} else if (cursor.startsWith("orphans:")) {
|
|
574
|
+
const { schema, actor, ifModifiedSince } = JSON.parse(
|
|
575
|
+
cursor.slice("orphans:".length)
|
|
576
|
+
);
|
|
577
|
+
if (!session || actor !== session?.actor) {
|
|
578
|
+
throw new GraffitiErrorForbidden(
|
|
579
|
+
"Cannot continue a cursor for another actor"
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
return this.recoverOrphansContinue(
|
|
583
|
+
[schema, session],
|
|
584
|
+
ifModifiedSince
|
|
585
|
+
);
|
|
586
|
+
} else {
|
|
587
|
+
throw new GraffitiErrorNotFound("Cursor not found");
|
|
588
|
+
}
|
|
543
589
|
};
|
|
544
590
|
}
|
|
545
591
|
export {
|