@graffiti-garden/implementation-local 0.2.10 → 0.2.12

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.
@@ -1,2 +1,2 @@
1
- "use strict";var G=Object.create;var h=Object.defineProperty;var z=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var g=Object.getPrototypeOf,S=Object.prototype.hasOwnProperty;var E=(n,t)=>{for(var e in t)h(n,e,{get:t[e],enumerable:!0})},y=(n,t,e,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of w(t))!S.call(n,i)&&i!==e&&h(n,i,{get:()=>t[i],enumerable:!(r=z(t,i))||r.enumerable});return n};var D=(n,t,e)=>(e=n!=null?G(g(n)):{},y(t||!n||!n.__esModule?h(e,"default",{value:n,enumerable:!0}):e,n)),B=n=>y(h({},"__esModule",{value:!0}),n);var k={};E(k,{GraffitiSynchronize:()=>R});module.exports=B(k);var d=D(require("ajv-draft-04")),b=require("@repeaterjs/repeater"),u=require("fast-json-patch"),a=require("./utilities.js");class R{synchronizeEvents=new EventTarget;ajv;graffiti;constructor(t,e){this.ajv=e??new d.default({strict:!1}),this.graffiti=t}synchronizeDispatch(t,e){const r=new CustomEvent("change",{detail:{oldObject:t,newObject:e}});this.synchronizeEvents.dispatchEvent(r)}get=async(...t)=>{const e=await this.graffiti.get(...t);return this.synchronizeDispatch(e),e};put=async(...t)=>{const e=await this.graffiti.put(...t),r=t[0],i={...e,value:r.value,channels:r.channels,allowed:r.allowed,tombstone:!1};return this.synchronizeDispatch(e,i),e};patch=async(...t)=>{const e=await this.graffiti.patch(...t),r={...e};r.tombstone=!1;for(const i of["value","channels","allowed"])(0,a.applyGraffitiPatch)(u.applyPatch,i,t[0],r);return this.synchronizeDispatch(e,r),e};delete=async(...t)=>{const e=await this.graffiti.delete(...t);return this.synchronizeDispatch(e),e};objectStream(t){const e=this.synchronizeDispatch.bind(this);return async function*(){let i=await t.next();for(;!i.done;)i.value.error||e(i.value.value),yield i.value,i=await t.next();return i.value}()}discover=(...t)=>{const e=this.graffiti.discover(...t);return this.objectStream(e)};recoverOrphans=(...t)=>{const e=this.graffiti.recoverOrphans(...t);return this.objectStream(e)};synchronize(t,e,r,i){const c=(0,a.attemptAjvCompile)(this.ajv,r);return new b.Repeater(async(s,p)=>{const v=j=>{const{oldObject:O,newObject:m}=j.detail;for(const f of[m,O])if(f&&t(f)&&(0,a.isActorAllowedGraffitiObject)(f,i)){const l={...f};if((0,a.maskGraffitiObject)(l,e,i),c(l)){s({value:l});break}}};this.synchronizeEvents.addEventListener("change",v),await p,this.synchronizeEvents.removeEventListener("change",v)})}synchronizeDiscover=(...t)=>{const[e,r,i]=t;function c(o){return o.channels.some(s=>e.includes(s))}return this.synchronize(c,e,r,i)};synchronizeGet=(...t)=>{const[e,r,i]=t;function c(o){const s=(0,a.locationToUri)(o),{uri:p}=(0,a.unpackLocationOrUri)(e);return s===p}return this.synchronize(c,[],r,i)};synchronizeRecoverOrphans=(...t)=>{const[e,r]=t;function i(c){return c.actor===r.actor&&c.channels.length===0}return this.synchronize(i,[],e,r)}}
1
+ "use strict";var O=Object.create;var h=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var z=Object.getPrototypeOf,g=Object.prototype.hasOwnProperty;var S=(r,e)=>{for(var t in e)h(r,t,{get:e[t],enumerable:!0})},d=(r,e,t,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of w(e))!g.call(r,a)&&a!==t&&h(r,a,{get:()=>e[a],enumerable:!(i=v(e,a))||i.enumerable});return r};var k=(r,e,t)=>(t=r!=null?O(z(r)):{},d(e||!r||!r.__esModule?h(t,"default",{value:r,enumerable:!0}):t,r)),D=r=>d(h({},"__esModule",{value:!0}),r);var R={};S(R,{GraffitiSynchronize:()=>B});module.exports=D(R);var u=k(require("ajv-draft-04")),y=require("@repeaterjs/repeater"),m=require("fast-json-patch"),c=require("./utilities.js");class B{ajv;graffiti;callbacks=new Set;constructor(e,t){this.ajv=t??new u.default({strict:!1}),this.graffiti=e}async synchronizeDispatch(e,t,i=!1){for(const a of this.callbacks)a(e,t);i&&await new Promise(a=>setTimeout(a,0))}get=async(...e)=>{const t=await this.graffiti.get(...e);return this.synchronizeDispatch(t),t};put=async(...e)=>{const t=await this.graffiti.put(...e),i=e[0],a={...t,value:i.value,channels:i.channels,allowed:i.allowed,tombstone:!1};return await this.synchronizeDispatch(t,a,!0),t};patch=async(...e)=>{const t=await this.graffiti.patch(...e),i={...t};i.tombstone=!1;for(const a of["value","channels","allowed"])(0,c.applyGraffitiPatch)(m.applyPatch,a,e[0],i);return await this.synchronizeDispatch(t,i,!0),t};delete=async(...e)=>{const t=await this.graffiti.delete(...e);return await this.synchronizeDispatch(t,void 0,!0),t};objectStream(e){const t=this.synchronizeDispatch.bind(this);return async function*(){let a=await e.next();for(;!a.done;)a.value.error||t(a.value.value),yield a.value,a=await e.next();return a.value}()}discover=(...e)=>{const t=this.graffiti.discover(...e);return this.objectStream(t)};recoverOrphans=(...e)=>{const t=this.graffiti.recoverOrphans(...e);return this.objectStream(t)};synchronize(e,t,i,a){const s=(0,c.attemptAjvCompile)(this.ajv,i);return new y.Repeater(async(n,l)=>{const b=(j,G)=>{for(const f of[G,j])if(f&&e(f)&&(0,c.isActorAllowedGraffitiObject)(f,a)){const p={...f};if((0,c.maskGraffitiObject)(p,t,a),s(p)){n({value:p});break}}};this.callbacks.add(b),await l,this.callbacks.delete(b)})}synchronizeDiscover=(...e)=>{const[t,i,a]=e;function s(o){return o.channels.some(n=>t.includes(n))}return this.synchronize(s,t,i,a)};synchronizeGet=(...e)=>{const[t,i,a]=e;function s(o){const n=(0,c.locationToUri)(o),{uri:l}=(0,c.unpackLocationOrUri)(t);return n===l}return this.synchronize(s,[],i,a)};synchronizeRecoverOrphans=(...e)=>{const[t,i]=e;function a(s){return s.actor===i.actor&&s.channels.length===0}return this.synchronize(a,[],t,i)}}
2
2
  //# sourceMappingURL=synchronize.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/synchronize.ts"],
4
- "sourcesContent": ["import Ajv from \"ajv-draft-04\";\nimport type {\n Graffiti,\n GraffitiSession,\n JSONSchema4,\n} from \"@graffiti-garden/api\";\nimport type { GraffitiObjectBase } from \"@graffiti-garden/api\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport { applyPatch } from \"fast-json-patch\";\nimport {\n applyGraffitiPatch,\n attemptAjvCompile,\n isActorAllowedGraffitiObject,\n locationToUri,\n maskGraffitiObject,\n unpackLocationOrUri,\n} from \"./utilities.js\";\n\ntype SynchronizeEvent = CustomEvent<{\n oldObject: GraffitiObjectBase;\n newObject?: GraffitiObjectBase;\n}>;\n\ntype GraffitiDatabaseMethods = Pick<\n Graffiti,\n \"get\" | \"put\" | \"patch\" | \"delete\" | \"discover\" | \"recoverOrphans\"\n>;\n\n/**\n * Wraps a partial implementation of the [Graffiti API](https://api.graffiti.garden/classes/Graffiti.html)\n * to provide the [`synchronize`](https://api.graffiti.garden/classes/Graffiti.html#synchronize) method.\n * The partial implementation must include the primary database methods:\n * `get`, `put`, `patch`, `delete`, and `discover`.\n */\nexport class GraffitiSynchronize\n implements\n Pick<\n Graffiti,\n | \"put\"\n | \"get\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"synchronizeDiscover\"\n | \"synchronizeGet\"\n | \"synchronizeRecoverOrphans\"\n >\n{\n protected readonly synchronizeEvents = new EventTarget();\n protected readonly ajv: Ajv;\n protected readonly graffiti: GraffitiDatabaseMethods;\n\n // Pass in the ajv instance\n // and database methods to wrap\n constructor(graffiti: GraffitiDatabaseMethods, ajv?: Ajv) {\n this.ajv = ajv ?? new Ajv({ strict: false });\n this.graffiti = graffiti;\n }\n\n protected synchronizeDispatch(\n oldObject: GraffitiObjectBase,\n newObject?: GraffitiObjectBase,\n ) {\n const event: SynchronizeEvent = new CustomEvent(\"change\", {\n detail: {\n oldObject,\n newObject,\n },\n });\n this.synchronizeEvents.dispatchEvent(event);\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const object = await this.graffiti.get(...args);\n this.synchronizeDispatch(object);\n return object;\n };\n\n put: Graffiti[\"put\"] = async (...args) => {\n const oldObject = await this.graffiti.put(...args);\n const partialObject = args[0];\n const newObject: GraffitiObjectBase = {\n ...oldObject,\n value: partialObject.value,\n channels: partialObject.channels,\n allowed: partialObject.allowed,\n tombstone: false,\n };\n this.synchronizeDispatch(oldObject, newObject);\n return oldObject;\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const oldObject = await this.graffiti.patch(...args);\n const newObject: GraffitiObjectBase = { ...oldObject };\n newObject.tombstone = false;\n for (const prop of [\"value\", \"channels\", \"allowed\"] as const) {\n applyGraffitiPatch(applyPatch, prop, args[0], newObject);\n }\n this.synchronizeDispatch(oldObject, newObject);\n return oldObject;\n };\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const oldObject = await this.graffiti.delete(...args);\n this.synchronizeDispatch(oldObject);\n return oldObject;\n };\n\n protected objectStream<Schema extends JSONSchema4>(\n iterator: ReturnType<typeof Graffiti.prototype.discover<Schema>>,\n ) {\n const dispatch = this.synchronizeDispatch.bind(this);\n const wrapper = async function* () {\n let result = await iterator.next();\n while (!result.done) {\n if (!result.value.error) {\n dispatch(result.value.value);\n }\n yield result.value;\n result = await iterator.next();\n }\n return result.value;\n };\n return wrapper();\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const iterator = this.graffiti.discover(...args);\n return this.objectStream(iterator);\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (...args) => {\n const iterator = this.graffiti.recoverOrphans(...args);\n return this.objectStream(iterator);\n };\n\n protected synchronize<Schema extends JSONSchema4>(\n matchObject: (object: GraffitiObjectBase) => boolean,\n channels: string[],\n schema: Schema,\n session?: GraffitiSession | null,\n ) {\n const validate = attemptAjvCompile(this.ajv, schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.synchronizeDiscover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const callback = (event: SynchronizeEvent) => {\n const { oldObject: oldObjectRaw, newObject: newObjectRaw } =\n event.detail;\n\n for (const objectRaw of [newObjectRaw, oldObjectRaw]) {\n if (\n objectRaw &&\n matchObject(objectRaw) &&\n isActorAllowedGraffitiObject(objectRaw, session)\n ) {\n const object = { ...objectRaw };\n maskGraffitiObject(object, channels, session);\n if (validate(object)) {\n push({ value: object });\n break;\n }\n }\n }\n };\n\n this.synchronizeEvents.addEventListener(\n \"change\",\n callback as EventListener,\n );\n await stop;\n this.synchronizeEvents.removeEventListener(\n \"change\",\n callback as EventListener,\n );\n });\n\n return repeater;\n }\n\n synchronizeDiscover: Graffiti[\"synchronizeDiscover\"] = (...args) => {\n const [channels, schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n return object.channels.some((channel) => channels.includes(channel));\n }\n return this.synchronize(matchObject, channels, schema, session);\n };\n\n synchronizeGet: Graffiti[\"synchronizeGet\"] = (...args) => {\n const [locationOrUri, schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n const objectUri = locationToUri(object);\n const { uri } = unpackLocationOrUri(locationOrUri);\n return objectUri === uri;\n }\n return this.synchronize(matchObject, [], schema, session);\n };\n\n synchronizeRecoverOrphans: Graffiti[\"synchronizeRecoverOrphans\"] = (\n ...args\n ) => {\n const [schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n return object.actor === session.actor && object.channels.length === 0;\n }\n return this.synchronize(matchObject, [], schema, session);\n };\n}\n"],
5
- "mappings": "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",
6
- "names": ["synchronize_exports", "__export", "GraffitiSynchronize", "__toCommonJS", "import_ajv_draft_04", "import_repeater", "import_fast_json_patch", "import_utilities", "graffiti", "ajv", "Ajv", "oldObject", "newObject", "event", "args", "object", "partialObject", "prop", "iterator", "dispatch", "result", "matchObject", "channels", "schema", "session", "validate", "push", "stop", "callback", "oldObjectRaw", "newObjectRaw", "objectRaw", "channel", "locationOrUri", "objectUri", "uri"]
4
+ "sourcesContent": ["import Ajv from \"ajv-draft-04\";\nimport type {\n Graffiti,\n GraffitiSession,\n JSONSchema4,\n} from \"@graffiti-garden/api\";\nimport type { GraffitiObjectBase } from \"@graffiti-garden/api\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport { applyPatch } from \"fast-json-patch\";\nimport {\n applyGraffitiPatch,\n attemptAjvCompile,\n isActorAllowedGraffitiObject,\n locationToUri,\n maskGraffitiObject,\n unpackLocationOrUri,\n} from \"./utilities.js\";\n\ntype GraffitiDatabaseMethods = Pick<\n Graffiti,\n \"get\" | \"put\" | \"patch\" | \"delete\" | \"discover\" | \"recoverOrphans\"\n>;\n\ntype Callback = (\n oldObject: GraffitiObjectBase,\n newObject?: GraffitiObjectBase,\n) => void;\n\n/**\n * Wraps a partial implementation of the [Graffiti API](https://api.graffiti.garden/classes/Graffiti.html)\n * to provide the [`synchronize`](https://api.graffiti.garden/classes/Graffiti.html#synchronize) method.\n * The partial implementation must include the primary database methods:\n * `get`, `put`, `patch`, `delete`, and `discover`.\n */\nexport class GraffitiSynchronize\n implements\n Pick<\n Graffiti,\n | \"put\"\n | \"get\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"synchronizeDiscover\"\n | \"synchronizeGet\"\n | \"synchronizeRecoverOrphans\"\n >\n{\n protected readonly ajv: Ajv;\n protected readonly graffiti: GraffitiDatabaseMethods;\n protected readonly callbacks = new Set<Callback>();\n\n // Pass in the ajv instance\n // and database methods to wrap\n constructor(graffiti: GraffitiDatabaseMethods, ajv?: Ajv) {\n this.ajv = ajv ?? new Ajv({ strict: false });\n this.graffiti = graffiti;\n }\n\n protected async synchronizeDispatch(\n oldObject: GraffitiObjectBase,\n newObject?: GraffitiObjectBase,\n macroTask = false,\n ) {\n for (const callback of this.callbacks) {\n callback(oldObject, newObject);\n }\n if (macroTask) {\n // Wait for one macro task cycle...\n // This way the yields, triggered by the callbacks,\n // will resolve first. Unfortunately, if we try to\n // use @repeaterjs's `await push` in the callback,\n // the promise won't resolve until the next\n // .next() call of the iterator, so if only\n // one .next() is called, this dispatch will hang.\n //\n // Only mutators (put, patch, delete) should bother\n // using this, so that they can ensure the application\n // state has been updated everywhere before returning,\n // for proper feedback.\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const object = await this.graffiti.get(...args);\n this.synchronizeDispatch(object);\n return object;\n };\n\n put: Graffiti[\"put\"] = async (...args) => {\n const oldObject = await this.graffiti.put(...args);\n const partialObject = args[0];\n const newObject: GraffitiObjectBase = {\n ...oldObject,\n value: partialObject.value,\n channels: partialObject.channels,\n allowed: partialObject.allowed,\n tombstone: false,\n };\n await this.synchronizeDispatch(oldObject, newObject, true);\n return oldObject;\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const oldObject = await this.graffiti.patch(...args);\n const newObject: GraffitiObjectBase = { ...oldObject };\n newObject.tombstone = false;\n for (const prop of [\"value\", \"channels\", \"allowed\"] as const) {\n applyGraffitiPatch(applyPatch, prop, args[0], newObject);\n }\n await this.synchronizeDispatch(oldObject, newObject, true);\n return oldObject;\n };\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const oldObject = await this.graffiti.delete(...args);\n await this.synchronizeDispatch(oldObject, undefined, true);\n return oldObject;\n };\n\n protected objectStream<Schema extends JSONSchema4>(\n iterator: ReturnType<typeof Graffiti.prototype.discover<Schema>>,\n ) {\n const dispatch = this.synchronizeDispatch.bind(this);\n const wrapper = async function* () {\n let result = await iterator.next();\n while (!result.done) {\n if (!result.value.error) {\n dispatch(result.value.value);\n }\n yield result.value;\n result = await iterator.next();\n }\n return result.value;\n };\n return wrapper();\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const iterator = this.graffiti.discover(...args);\n return this.objectStream(iterator);\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (...args) => {\n const iterator = this.graffiti.recoverOrphans(...args);\n return this.objectStream(iterator);\n };\n\n protected synchronize<Schema extends JSONSchema4>(\n matchObject: (object: GraffitiObjectBase) => boolean,\n channels: string[],\n schema: Schema,\n session?: GraffitiSession | null,\n ) {\n const validate = attemptAjvCompile(this.ajv, schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.synchronizeDiscover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const callback: Callback = (oldObjectRaw, newObjectRaw) => {\n for (const objectRaw of [newObjectRaw, oldObjectRaw]) {\n if (\n objectRaw &&\n matchObject(objectRaw) &&\n isActorAllowedGraffitiObject(objectRaw, session)\n ) {\n const object = { ...objectRaw };\n maskGraffitiObject(object, channels, session);\n if (validate(object)) {\n push({ value: object });\n break;\n }\n }\n }\n };\n\n this.callbacks.add(callback);\n await stop;\n this.callbacks.delete(callback);\n });\n\n return repeater;\n }\n\n synchronizeDiscover: Graffiti[\"synchronizeDiscover\"] = (...args) => {\n const [channels, schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n return object.channels.some((channel) => channels.includes(channel));\n }\n return this.synchronize(matchObject, channels, schema, session);\n };\n\n synchronizeGet: Graffiti[\"synchronizeGet\"] = (...args) => {\n const [locationOrUri, schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n const objectUri = locationToUri(object);\n const { uri } = unpackLocationOrUri(locationOrUri);\n return objectUri === uri;\n }\n return this.synchronize(matchObject, [], schema, session);\n };\n\n synchronizeRecoverOrphans: Graffiti[\"synchronizeRecoverOrphans\"] = (\n ...args\n ) => {\n const [schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n return object.actor === session.actor && object.channels.length === 0;\n }\n return this.synchronize(matchObject, [], schema, session);\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["synchronize_exports", "__export", "GraffitiSynchronize", "__toCommonJS", "import_ajv_draft_04", "import_repeater", "import_fast_json_patch", "import_utilities", "graffiti", "ajv", "Ajv", "oldObject", "newObject", "macroTask", "callback", "resolve", "args", "object", "partialObject", "prop", "iterator", "dispatch", "result", "matchObject", "channels", "schema", "session", "validate", "push", "stop", "oldObjectRaw", "newObjectRaw", "objectRaw", "channel", "locationOrUri", "objectUri", "uri"]
7
7
  }
@@ -1,2 +1,2 @@
1
- import y from"ajv-draft-04";import{Repeater as d}from"@repeaterjs/repeater";import{applyPatch as b}from"fast-json-patch";import{applyGraffitiPatch as u,attemptAjvCompile as j,isActorAllowedGraffitiObject as O,locationToUri as m,maskGraffitiObject as G,unpackLocationOrUri as z}from"./utilities.js";class B{synchronizeEvents=new EventTarget;ajv;graffiti;constructor(t,e){this.ajv=e??new y({strict:!1}),this.graffiti=t}synchronizeDispatch(t,e){const i=new CustomEvent("change",{detail:{oldObject:t,newObject:e}});this.synchronizeEvents.dispatchEvent(i)}get=async(...t)=>{const e=await this.graffiti.get(...t);return this.synchronizeDispatch(e),e};put=async(...t)=>{const e=await this.graffiti.put(...t),i=t[0],r={...e,value:i.value,channels:i.channels,allowed:i.allowed,tombstone:!1};return this.synchronizeDispatch(e,r),e};patch=async(...t)=>{const e=await this.graffiti.patch(...t),i={...e};i.tombstone=!1;for(const r of["value","channels","allowed"])u(b,r,t[0],i);return this.synchronizeDispatch(e,i),e};delete=async(...t)=>{const e=await this.graffiti.delete(...t);return this.synchronizeDispatch(e),e};objectStream(t){const e=this.synchronizeDispatch.bind(this);return async function*(){let r=await t.next();for(;!r.done;)r.value.error||e(r.value.value),yield r.value,r=await t.next();return r.value}()}discover=(...t)=>{const e=this.graffiti.discover(...t);return this.objectStream(e)};recoverOrphans=(...t)=>{const e=this.graffiti.recoverOrphans(...t);return this.objectStream(e)};synchronize(t,e,i,r){const n=j(this.ajv,i);return new d(async(a,o)=>{const h=p=>{const{oldObject:l,newObject:v}=p.detail;for(const s of[v,l])if(s&&t(s)&&O(s,r)){const f={...s};if(G(f,e,r),n(f)){a({value:f});break}}};this.synchronizeEvents.addEventListener("change",h),await o,this.synchronizeEvents.removeEventListener("change",h)})}synchronizeDiscover=(...t)=>{const[e,i,r]=t;function n(c){return c.channels.some(a=>e.includes(a))}return this.synchronize(n,e,i,r)};synchronizeGet=(...t)=>{const[e,i,r]=t;function n(c){const a=m(c),{uri:o}=z(e);return a===o}return this.synchronize(n,[],i,r)};synchronizeRecoverOrphans=(...t)=>{const[e,i]=t;function r(n){return n.actor===i.actor&&n.channels.length===0}return this.synchronize(r,[],e,i)}}export{B as GraffitiSynchronize};
1
+ import b from"ajv-draft-04";import{Repeater as d}from"@repeaterjs/repeater";import{applyPatch as u}from"fast-json-patch";import{applyGraffitiPatch as y,attemptAjvCompile as m,isActorAllowedGraffitiObject as j,locationToUri as G,maskGraffitiObject as O,unpackLocationOrUri as v}from"./utilities.js";class D{ajv;graffiti;callbacks=new Set;constructor(e,t){this.ajv=t??new b({strict:!1}),this.graffiti=e}async synchronizeDispatch(e,t,i=!1){for(const a of this.callbacks)a(e,t);i&&await new Promise(a=>setTimeout(a,0))}get=async(...e)=>{const t=await this.graffiti.get(...e);return this.synchronizeDispatch(t),t};put=async(...e)=>{const t=await this.graffiti.put(...e),i=e[0],a={...t,value:i.value,channels:i.channels,allowed:i.allowed,tombstone:!1};return await this.synchronizeDispatch(t,a,!0),t};patch=async(...e)=>{const t=await this.graffiti.patch(...e),i={...t};i.tombstone=!1;for(const a of["value","channels","allowed"])y(u,a,e[0],i);return await this.synchronizeDispatch(t,i,!0),t};delete=async(...e)=>{const t=await this.graffiti.delete(...e);return await this.synchronizeDispatch(t,void 0,!0),t};objectStream(e){const t=this.synchronizeDispatch.bind(this);return async function*(){let a=await e.next();for(;!a.done;)a.value.error||t(a.value.value),yield a.value,a=await e.next();return a.value}()}discover=(...e)=>{const t=this.graffiti.discover(...e);return this.objectStream(t)};recoverOrphans=(...e)=>{const t=this.graffiti.recoverOrphans(...e);return this.objectStream(t)};synchronize(e,t,i,a){const r=m(this.ajv,i);return new d(async(c,o)=>{const h=(l,p)=>{for(const n of[p,l])if(n&&e(n)&&j(n,a)){const f={...n};if(O(f,t,a),r(f)){c({value:f});break}}};this.callbacks.add(h),await o,this.callbacks.delete(h)})}synchronizeDiscover=(...e)=>{const[t,i,a]=e;function r(s){return s.channels.some(c=>t.includes(c))}return this.synchronize(r,t,i,a)};synchronizeGet=(...e)=>{const[t,i,a]=e;function r(s){const c=G(s),{uri:o}=v(t);return c===o}return this.synchronize(r,[],i,a)};synchronizeRecoverOrphans=(...e)=>{const[t,i]=e;function a(r){return r.actor===i.actor&&r.channels.length===0}return this.synchronize(a,[],t,i)}}export{D as GraffitiSynchronize};
2
2
  //# sourceMappingURL=synchronize.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/synchronize.ts"],
4
- "sourcesContent": ["import Ajv from \"ajv-draft-04\";\nimport type {\n Graffiti,\n GraffitiSession,\n JSONSchema4,\n} from \"@graffiti-garden/api\";\nimport type { GraffitiObjectBase } from \"@graffiti-garden/api\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport { applyPatch } from \"fast-json-patch\";\nimport {\n applyGraffitiPatch,\n attemptAjvCompile,\n isActorAllowedGraffitiObject,\n locationToUri,\n maskGraffitiObject,\n unpackLocationOrUri,\n} from \"./utilities.js\";\n\ntype SynchronizeEvent = CustomEvent<{\n oldObject: GraffitiObjectBase;\n newObject?: GraffitiObjectBase;\n}>;\n\ntype GraffitiDatabaseMethods = Pick<\n Graffiti,\n \"get\" | \"put\" | \"patch\" | \"delete\" | \"discover\" | \"recoverOrphans\"\n>;\n\n/**\n * Wraps a partial implementation of the [Graffiti API](https://api.graffiti.garden/classes/Graffiti.html)\n * to provide the [`synchronize`](https://api.graffiti.garden/classes/Graffiti.html#synchronize) method.\n * The partial implementation must include the primary database methods:\n * `get`, `put`, `patch`, `delete`, and `discover`.\n */\nexport class GraffitiSynchronize\n implements\n Pick<\n Graffiti,\n | \"put\"\n | \"get\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"synchronizeDiscover\"\n | \"synchronizeGet\"\n | \"synchronizeRecoverOrphans\"\n >\n{\n protected readonly synchronizeEvents = new EventTarget();\n protected readonly ajv: Ajv;\n protected readonly graffiti: GraffitiDatabaseMethods;\n\n // Pass in the ajv instance\n // and database methods to wrap\n constructor(graffiti: GraffitiDatabaseMethods, ajv?: Ajv) {\n this.ajv = ajv ?? new Ajv({ strict: false });\n this.graffiti = graffiti;\n }\n\n protected synchronizeDispatch(\n oldObject: GraffitiObjectBase,\n newObject?: GraffitiObjectBase,\n ) {\n const event: SynchronizeEvent = new CustomEvent(\"change\", {\n detail: {\n oldObject,\n newObject,\n },\n });\n this.synchronizeEvents.dispatchEvent(event);\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const object = await this.graffiti.get(...args);\n this.synchronizeDispatch(object);\n return object;\n };\n\n put: Graffiti[\"put\"] = async (...args) => {\n const oldObject = await this.graffiti.put(...args);\n const partialObject = args[0];\n const newObject: GraffitiObjectBase = {\n ...oldObject,\n value: partialObject.value,\n channels: partialObject.channels,\n allowed: partialObject.allowed,\n tombstone: false,\n };\n this.synchronizeDispatch(oldObject, newObject);\n return oldObject;\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const oldObject = await this.graffiti.patch(...args);\n const newObject: GraffitiObjectBase = { ...oldObject };\n newObject.tombstone = false;\n for (const prop of [\"value\", \"channels\", \"allowed\"] as const) {\n applyGraffitiPatch(applyPatch, prop, args[0], newObject);\n }\n this.synchronizeDispatch(oldObject, newObject);\n return oldObject;\n };\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const oldObject = await this.graffiti.delete(...args);\n this.synchronizeDispatch(oldObject);\n return oldObject;\n };\n\n protected objectStream<Schema extends JSONSchema4>(\n iterator: ReturnType<typeof Graffiti.prototype.discover<Schema>>,\n ) {\n const dispatch = this.synchronizeDispatch.bind(this);\n const wrapper = async function* () {\n let result = await iterator.next();\n while (!result.done) {\n if (!result.value.error) {\n dispatch(result.value.value);\n }\n yield result.value;\n result = await iterator.next();\n }\n return result.value;\n };\n return wrapper();\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const iterator = this.graffiti.discover(...args);\n return this.objectStream(iterator);\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (...args) => {\n const iterator = this.graffiti.recoverOrphans(...args);\n return this.objectStream(iterator);\n };\n\n protected synchronize<Schema extends JSONSchema4>(\n matchObject: (object: GraffitiObjectBase) => boolean,\n channels: string[],\n schema: Schema,\n session?: GraffitiSession | null,\n ) {\n const validate = attemptAjvCompile(this.ajv, schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.synchronizeDiscover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const callback = (event: SynchronizeEvent) => {\n const { oldObject: oldObjectRaw, newObject: newObjectRaw } =\n event.detail;\n\n for (const objectRaw of [newObjectRaw, oldObjectRaw]) {\n if (\n objectRaw &&\n matchObject(objectRaw) &&\n isActorAllowedGraffitiObject(objectRaw, session)\n ) {\n const object = { ...objectRaw };\n maskGraffitiObject(object, channels, session);\n if (validate(object)) {\n push({ value: object });\n break;\n }\n }\n }\n };\n\n this.synchronizeEvents.addEventListener(\n \"change\",\n callback as EventListener,\n );\n await stop;\n this.synchronizeEvents.removeEventListener(\n \"change\",\n callback as EventListener,\n );\n });\n\n return repeater;\n }\n\n synchronizeDiscover: Graffiti[\"synchronizeDiscover\"] = (...args) => {\n const [channels, schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n return object.channels.some((channel) => channels.includes(channel));\n }\n return this.synchronize(matchObject, channels, schema, session);\n };\n\n synchronizeGet: Graffiti[\"synchronizeGet\"] = (...args) => {\n const [locationOrUri, schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n const objectUri = locationToUri(object);\n const { uri } = unpackLocationOrUri(locationOrUri);\n return objectUri === uri;\n }\n return this.synchronize(matchObject, [], schema, session);\n };\n\n synchronizeRecoverOrphans: Graffiti[\"synchronizeRecoverOrphans\"] = (\n ...args\n ) => {\n const [schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n return object.actor === session.actor && object.channels.length === 0;\n }\n return this.synchronize(matchObject, [], schema, session);\n };\n}\n"],
5
- "mappings": "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",
6
- "names": ["Ajv", "Repeater", "applyPatch", "applyGraffitiPatch", "attemptAjvCompile", "isActorAllowedGraffitiObject", "locationToUri", "maskGraffitiObject", "unpackLocationOrUri", "GraffitiSynchronize", "graffiti", "ajv", "oldObject", "newObject", "event", "args", "object", "partialObject", "prop", "iterator", "dispatch", "result", "matchObject", "channels", "schema", "session", "validate", "push", "stop", "callback", "oldObjectRaw", "newObjectRaw", "objectRaw", "channel", "locationOrUri", "objectUri", "uri"]
4
+ "sourcesContent": ["import Ajv from \"ajv-draft-04\";\nimport type {\n Graffiti,\n GraffitiSession,\n JSONSchema4,\n} from \"@graffiti-garden/api\";\nimport type { GraffitiObjectBase } from \"@graffiti-garden/api\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport { applyPatch } from \"fast-json-patch\";\nimport {\n applyGraffitiPatch,\n attemptAjvCompile,\n isActorAllowedGraffitiObject,\n locationToUri,\n maskGraffitiObject,\n unpackLocationOrUri,\n} from \"./utilities.js\";\n\ntype GraffitiDatabaseMethods = Pick<\n Graffiti,\n \"get\" | \"put\" | \"patch\" | \"delete\" | \"discover\" | \"recoverOrphans\"\n>;\n\ntype Callback = (\n oldObject: GraffitiObjectBase,\n newObject?: GraffitiObjectBase,\n) => void;\n\n/**\n * Wraps a partial implementation of the [Graffiti API](https://api.graffiti.garden/classes/Graffiti.html)\n * to provide the [`synchronize`](https://api.graffiti.garden/classes/Graffiti.html#synchronize) method.\n * The partial implementation must include the primary database methods:\n * `get`, `put`, `patch`, `delete`, and `discover`.\n */\nexport class GraffitiSynchronize\n implements\n Pick<\n Graffiti,\n | \"put\"\n | \"get\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"synchronizeDiscover\"\n | \"synchronizeGet\"\n | \"synchronizeRecoverOrphans\"\n >\n{\n protected readonly ajv: Ajv;\n protected readonly graffiti: GraffitiDatabaseMethods;\n protected readonly callbacks = new Set<Callback>();\n\n // Pass in the ajv instance\n // and database methods to wrap\n constructor(graffiti: GraffitiDatabaseMethods, ajv?: Ajv) {\n this.ajv = ajv ?? new Ajv({ strict: false });\n this.graffiti = graffiti;\n }\n\n protected async synchronizeDispatch(\n oldObject: GraffitiObjectBase,\n newObject?: GraffitiObjectBase,\n macroTask = false,\n ) {\n for (const callback of this.callbacks) {\n callback(oldObject, newObject);\n }\n if (macroTask) {\n // Wait for one macro task cycle...\n // This way the yields, triggered by the callbacks,\n // will resolve first. Unfortunately, if we try to\n // use @repeaterjs's `await push` in the callback,\n // the promise won't resolve until the next\n // .next() call of the iterator, so if only\n // one .next() is called, this dispatch will hang.\n //\n // Only mutators (put, patch, delete) should bother\n // using this, so that they can ensure the application\n // state has been updated everywhere before returning,\n // for proper feedback.\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const object = await this.graffiti.get(...args);\n this.synchronizeDispatch(object);\n return object;\n };\n\n put: Graffiti[\"put\"] = async (...args) => {\n const oldObject = await this.graffiti.put(...args);\n const partialObject = args[0];\n const newObject: GraffitiObjectBase = {\n ...oldObject,\n value: partialObject.value,\n channels: partialObject.channels,\n allowed: partialObject.allowed,\n tombstone: false,\n };\n await this.synchronizeDispatch(oldObject, newObject, true);\n return oldObject;\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const oldObject = await this.graffiti.patch(...args);\n const newObject: GraffitiObjectBase = { ...oldObject };\n newObject.tombstone = false;\n for (const prop of [\"value\", \"channels\", \"allowed\"] as const) {\n applyGraffitiPatch(applyPatch, prop, args[0], newObject);\n }\n await this.synchronizeDispatch(oldObject, newObject, true);\n return oldObject;\n };\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const oldObject = await this.graffiti.delete(...args);\n await this.synchronizeDispatch(oldObject, undefined, true);\n return oldObject;\n };\n\n protected objectStream<Schema extends JSONSchema4>(\n iterator: ReturnType<typeof Graffiti.prototype.discover<Schema>>,\n ) {\n const dispatch = this.synchronizeDispatch.bind(this);\n const wrapper = async function* () {\n let result = await iterator.next();\n while (!result.done) {\n if (!result.value.error) {\n dispatch(result.value.value);\n }\n yield result.value;\n result = await iterator.next();\n }\n return result.value;\n };\n return wrapper();\n }\n\n discover: Graffiti[\"discover\"] = (...args) => {\n const iterator = this.graffiti.discover(...args);\n return this.objectStream(iterator);\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (...args) => {\n const iterator = this.graffiti.recoverOrphans(...args);\n return this.objectStream(iterator);\n };\n\n protected synchronize<Schema extends JSONSchema4>(\n matchObject: (object: GraffitiObjectBase) => boolean,\n channels: string[],\n schema: Schema,\n session?: GraffitiSession | null,\n ) {\n const validate = attemptAjvCompile(this.ajv, schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.synchronizeDiscover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const callback: Callback = (oldObjectRaw, newObjectRaw) => {\n for (const objectRaw of [newObjectRaw, oldObjectRaw]) {\n if (\n objectRaw &&\n matchObject(objectRaw) &&\n isActorAllowedGraffitiObject(objectRaw, session)\n ) {\n const object = { ...objectRaw };\n maskGraffitiObject(object, channels, session);\n if (validate(object)) {\n push({ value: object });\n break;\n }\n }\n }\n };\n\n this.callbacks.add(callback);\n await stop;\n this.callbacks.delete(callback);\n });\n\n return repeater;\n }\n\n synchronizeDiscover: Graffiti[\"synchronizeDiscover\"] = (...args) => {\n const [channels, schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n return object.channels.some((channel) => channels.includes(channel));\n }\n return this.synchronize(matchObject, channels, schema, session);\n };\n\n synchronizeGet: Graffiti[\"synchronizeGet\"] = (...args) => {\n const [locationOrUri, schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n const objectUri = locationToUri(object);\n const { uri } = unpackLocationOrUri(locationOrUri);\n return objectUri === uri;\n }\n return this.synchronize(matchObject, [], schema, session);\n };\n\n synchronizeRecoverOrphans: Graffiti[\"synchronizeRecoverOrphans\"] = (\n ...args\n ) => {\n const [schema, session] = args;\n function matchObject(object: GraffitiObjectBase) {\n return object.actor === session.actor && object.channels.length === 0;\n }\n return this.synchronize(matchObject, [], schema, session);\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["Ajv", "Repeater", "applyPatch", "applyGraffitiPatch", "attemptAjvCompile", "isActorAllowedGraffitiObject", "locationToUri", "maskGraffitiObject", "unpackLocationOrUri", "GraffitiSynchronize", "graffiti", "ajv", "oldObject", "newObject", "macroTask", "callback", "resolve", "args", "object", "partialObject", "prop", "iterator", "dispatch", "result", "matchObject", "channels", "schema", "session", "validate", "push", "stop", "oldObjectRaw", "newObjectRaw", "objectRaw", "channel", "locationOrUri", "objectUri", "uri"]
7
7
  }