@graffiti-garden/implementation-local 0.4.0 → 0.4.1

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 B=Object.create;var g=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty;var C=(u,i)=>{for(var e in i)g(u,e,{get:i[e],enumerable:!0})},S=(u,i,e,o)=>{if(i&&typeof i=="object"||typeof i=="function")for(let t of R(i))!k.call(u,t)&&t!==e&&g(u,t,{get:()=>i[t],enumerable:!(o=_(i,t))||o.enumerable});return u};var A=(u,i,e)=>(e=u!=null?B(P(u)):{},S(i||!u||!u.__esModule?g(e,"default",{value:u,enumerable:!0}):e,u)),I=u=>S(g({},"__esModule",{value:!0}),u);var E={};C(E,{GraffitiLocalDatabase:()=>U});module.exports=I(E);var h=require("@graffiti-garden/api"),x=A(require("pouchdb")),s=require("./utilities.js"),j=require("@repeaterjs/repeater"),D=A(require("ajv")),L=require("fast-json-patch");class U{db;source="local";tombstoneRetention=864e5;ajv;constructor(i){this.ajv=new D.default({strict:!1}),this.source=i?.sourceName??this.source,this.tombstoneRetention=i?.tombstoneRetention??this.tombstoneRetention;const e={name:"graffitiDb",...i?.pouchDBOptions};this.db=new x.default(e.name,e),this.db.put({_id:"_design/indexes",views:{objectsPerChannelAndLastModified:{map:function(o){const t=o.lastModified.toString().padStart(15,"0");o.channels.forEach(function(a){const r=encodeURIComponent(a)+"/"+t;emit(r)})}.toString()},orphansPerActorAndLastModified:{map:function(o){if(o.channels.length===0){const t=o.lastModified.toString().padStart(15,"0"),a=encodeURIComponent(o.actor)+"/"+t;emit(a)}}.toString()},channelStatsPerActor:{map:function(o){o.tombstone||o.channels.forEach(function(t){const a=encodeURIComponent(o.actor)+"/"+encodeURIComponent(t);emit(a,o.lastModified)})}.toString(),reduce:"_stats"}}}).catch(o=>{if(!(o&&typeof o=="object"&&"name"in o&&o.name==="conflict"))throw o})}async queryByLocation(i){const e=(0,s.locationToUri)(i)+"/";return(await this.db.allDocs({startkey:e,endkey:e+"\uFFFF",include_docs:!0})).rows.map(a=>a.doc).reduce((a,r)=>(r&&a.push(r),a),[])}docId(i){return(0,s.locationToUri)(i)+"/"+(0,s.randomBase64)()}get=async(...i)=>{const[e,o,t]=i,{location:a}=(0,s.unpackLocationOrUri)(e),n=(await this.queryByLocation(a)).filter(b=>(0,s.isActorAllowedGraffitiObject)(b,t));if(!n.length)throw new h.GraffitiErrorNotFound;const f=n.reduce((b,w)=>(0,s.isObjectNewer)(b,w)?b:w),{_id:p,_rev:l,_conflicts:c,_attachments:m,...d}=f;if((0,s.maskGraffitiObject)(d,[],t),!(0,s.compileGraffitiObjectSchema)(this.ajv,o)(d))throw new h.GraffitiErrorSchemaMismatch;return d};async deleteAtLocation(i,e=!1){const t=(await this.queryByLocation(i)).filter(c=>!c.tombstone);if(!t.length)return;const a=t.map(c=>c.lastModified).reduce((c,m)=>c>m?c:m),r=t.filter(c=>!e||c.lastModified<a),n=t.filter(c=>e&&c.lastModified===a);if(n.length){const c=n.map(d=>d._id).reduce((d,y)=>d>y?d:y),m=n.filter(d=>d._id!==c);r.push(...m)}const f=e?a:new Date().getTime(),p=await this.db.bulkDocs(r.map(c=>({...c,tombstone:!0,lastModified:f})));let l;for(const c of p)if("ok"in c){const{id:m}=c,d=r.find(y=>y._id===m);if(d){const{_id:y,_rev:b,_conflicts:w,_attachments:v,...G}=d;l={...G,tombstone:!0,lastModified:f};break}}return l}delete=async(...i)=>{const[e,o]=i,{location:t}=(0,s.unpackLocationOrUri)(e);if(t.actor!==o.actor)throw new h.GraffitiErrorForbidden;const a=await this.deleteAtLocation(t);if(!a)throw new h.GraffitiErrorNotFound;return a};put=async(...i)=>{const[e,o]=i;if(e.actor&&e.actor!==o.actor)throw new h.GraffitiErrorForbidden;if(e.source&&e.source!==this.source)throw new h.GraffitiErrorForbidden("Putting an object that does not match this source");const t={value:e.value,channels:e.channels,allowed:e.allowed,name:e.name??(0,s.randomBase64)(),source:this.source,actor:o.actor,tombstone:!1,lastModified:new Date().getTime()};await this.db.put({_id:this.docId(t),...t});const a=await this.deleteAtLocation(t,!0);return a||{...t,value:{},channels:[],allowed:void 0,tombstone:!0}};patch=async(...i)=>{const[e,o,t]=i,{location:a}=(0,s.unpackLocationOrUri)(o);if(a.actor!==t.actor)throw new h.GraffitiErrorForbidden;const r=await this.get(o,{},t);if(r.tombstone)throw new h.GraffitiErrorNotFound("The object you are trying to patch has been deleted");const n={...r};for(const f of["value","channels","allowed"])(0,s.applyGraffitiPatch)(L.applyPatch,f,e,n);if(typeof n.value!="object"||Array.isArray(n.value)||!n.value)throw new h.GraffitiErrorPatchError("value is no longer an object");if(!Array.isArray(n.channels)||!n.channels.every(f=>typeof f=="string"))throw new h.GraffitiErrorPatchError("channels are no longer an array of strings");if(n.allowed&&(!Array.isArray(n.allowed)||!n.allowed.every(f=>typeof f=="string")))throw new h.GraffitiErrorPatchError("allowed list is not an array of strings");return n.lastModified=new Date().getTime(),await this.db.put({...n,_id:this.docId(n)}),await this.deleteAtLocation(n,!0),{...r,tombstone:!0,lastModified:n.lastModified}};queryLastModifiedSuffixes(i){let e="",o="\uFFFF";if(typeof i=="object"&&i.properties?.lastModified&&typeof i.properties.lastModified=="object"){const t=i.properties.lastModified,a=t.minimum,r=t.exclusiveMinimum;let n;r!==void 0?(n=Math.ceil(r),n===r&&n++):a!==void 0&&(n=Math.ceil(a)),n!==void 0&&(e=n.toString().padStart(15,"0"));const f=t.maximum,p=t.exclusiveMaximum;let l;p!==void 0?(l=Math.floor(p),l===p&&l--):f!==void 0&&(l=Math.floor(f)),l!==void 0&&(o=l.toString().padStart(15,"0"))}return{startKeySuffix:e,endKeySuffix:o}}discover=(...i)=>{const[e,o,t]=i,a=(0,s.compileGraffitiObjectSchema)(this.ajv,o),{startKeySuffix:r,endKeySuffix:n}=this.queryLastModifiedSuffixes(o);return new j.Repeater(async(p,l)=>{const c=new Set;for(const m of e){const d=encodeURIComponent(m)+"/",y=d+r,b=d+n,w=await this.db.query("indexes/objectsPerChannelAndLastModified",{startkey:y,endkey:b,include_docs:!0});for(const v of w.rows){const G=v.doc;if(!G)continue;const{_id:O,_rev:T,...M}=G;c.has(O)||(c.add(O),(0,s.isActorAllowedGraffitiObject)(G,t)&&((0,s.maskGraffitiObject)(M,e,t),a(M)&&await p({value:M})))}}return l(),{tombstoneRetention:this.tombstoneRetention}})};recoverOrphans=(i,e)=>{const o=(0,s.compileGraffitiObjectSchema)(this.ajv,i),{startKeySuffix:t,endKeySuffix:a}=this.queryLastModifiedSuffixes(i),r=encodeURIComponent(e.actor)+"/",n=r+t,f=r+a;return new j.Repeater(async(l,c)=>{const m=await this.db.query("indexes/orphansPerActorAndLastModified",{startkey:n,endkey:f,include_docs:!0});for(const d of m.rows){const y=d.doc;if(!y)continue;const{_id:b,_rev:w,...v}=y;o(v)&&await l({value:v})}return c(),{tombstoneRetention:this.tombstoneRetention}})};channelStats=i=>new j.Repeater(async(o,t)=>{const a=encodeURIComponent(i.actor)+"/",r=await this.db.query("indexes/channelStatsPerActor",{startkey:a,endkey:a+"\uFFFF",reduce:!0,group:!0});for(const n of r.rows){const f=n.key.split("/")[1];if(typeof f!="string")continue;const{count:p,max:l}=n.value;typeof p!="number"||typeof l!="number"||await o({value:{channel:decodeURIComponent(f),count:p,lastModified:l}})}t()})}
1
+ "use strict";var B=Object.create;var G=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty;var C=(u,e)=>{for(var o in e)G(u,o,{get:e[o],enumerable:!0})},S=(u,e,o,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of R(e))!k.call(u,t)&&t!==o&&G(u,t,{get:()=>e[t],enumerable:!(i=_(e,t))||i.enumerable});return u};var A=(u,e,o)=>(o=u!=null?B(P(u)):{},S(e||!u||!u.__esModule?G(o,"default",{value:u,enumerable:!0}):o,u)),I=u=>S(G({},"__esModule",{value:!0}),u);var E={};C(E,{GraffitiLocalDatabase:()=>U});module.exports=I(E);var h=require("@graffiti-garden/api"),x=A(require("pouchdb")),s=require("./utilities.js"),g=require("@repeaterjs/repeater"),D=A(require("ajv")),L=require("fast-json-patch");class U{db;source="local";tombstoneRetention=864e5;ajv;constructor(e){this.ajv=e?.ajv??new D.default({strict:!1}),this.source=e?.sourceName??this.source,this.tombstoneRetention=e?.tombstoneRetention??this.tombstoneRetention;const o={name:"graffitiDb",...e?.pouchDBOptions};this.db=new x.default(o.name,o),this.db.put({_id:"_design/indexes",views:{objectsPerChannelAndLastModified:{map:function(i){const t=i.lastModified.toString().padStart(15,"0");i.channels.forEach(function(a){const r=encodeURIComponent(a)+"/"+t;emit(r)})}.toString()},orphansPerActorAndLastModified:{map:function(i){if(i.channels.length===0){const t=i.lastModified.toString().padStart(15,"0"),a=encodeURIComponent(i.actor)+"/"+t;emit(a)}}.toString()},channelStatsPerActor:{map:function(i){i.tombstone||i.channels.forEach(function(t){const a=encodeURIComponent(i.actor)+"/"+encodeURIComponent(t);emit(a,i.lastModified)})}.toString(),reduce:"_stats"}}}).catch(i=>{if(!(i&&typeof i=="object"&&"name"in i&&i.name==="conflict"))throw i})}async queryByLocation(e){const o=(0,s.locationToUri)(e)+"/";return(await this.db.allDocs({startkey:o,endkey:o+"\uFFFF",include_docs:!0})).rows.map(a=>a.doc).reduce((a,r)=>(r&&a.push(r),a),[])}docId(e){return(0,s.locationToUri)(e)+"/"+(0,s.randomBase64)()}get=async(...e)=>{const[o,i,t]=e,{location:a}=(0,s.unpackLocationOrUri)(o),n=(await this.queryByLocation(a)).filter(b=>(0,s.isActorAllowedGraffitiObject)(b,t));if(!n.length)throw new h.GraffitiErrorNotFound;const f=n.reduce((b,w)=>(0,s.isObjectNewer)(b,w)?b:w),{_id:p,_rev:l,_conflicts:c,_attachments:m,...d}=f;if((0,s.maskGraffitiObject)(d,[],t),!(0,s.compileGraffitiObjectSchema)(this.ajv,i)(d))throw new h.GraffitiErrorSchemaMismatch;return d};async deleteAtLocation(e,o=!1){const t=(await this.queryByLocation(e)).filter(c=>!c.tombstone);if(!t.length)return;const a=t.map(c=>c.lastModified).reduce((c,m)=>c>m?c:m),r=t.filter(c=>!o||c.lastModified<a),n=t.filter(c=>o&&c.lastModified===a);if(n.length){const c=n.map(d=>d._id).reduce((d,y)=>d>y?d:y),m=n.filter(d=>d._id!==c);r.push(...m)}const f=o?a:new Date().getTime(),p=await this.db.bulkDocs(r.map(c=>({...c,tombstone:!0,lastModified:f})));let l;for(const c of p)if("ok"in c){const{id:m}=c,d=r.find(y=>y._id===m);if(d){const{_id:y,_rev:b,_conflicts:w,_attachments:v,...j}=d;l={...j,tombstone:!0,lastModified:f};break}}return l}delete=async(...e)=>{const[o,i]=e,{location:t}=(0,s.unpackLocationOrUri)(o);if(t.actor!==i.actor)throw new h.GraffitiErrorForbidden;const a=await this.deleteAtLocation(t);if(!a)throw new h.GraffitiErrorNotFound;return a};put=async(...e)=>{const[o,i]=e;if(o.actor&&o.actor!==i.actor)throw new h.GraffitiErrorForbidden;if(o.source&&o.source!==this.source)throw new h.GraffitiErrorForbidden("Putting an object that does not match this source");const t={value:o.value,channels:o.channels,allowed:o.allowed,name:o.name??(0,s.randomBase64)(),source:this.source,actor:i.actor,tombstone:!1,lastModified:new Date().getTime()};await this.db.put({_id:this.docId(t),...t});const a=await this.deleteAtLocation(t,!0);return a||{...t,value:{},channels:[],allowed:void 0,tombstone:!0}};patch=async(...e)=>{const[o,i,t]=e,{location:a}=(0,s.unpackLocationOrUri)(i);if(a.actor!==t.actor)throw new h.GraffitiErrorForbidden;const r=await this.get(i,{},t);if(r.tombstone)throw new h.GraffitiErrorNotFound("The object you are trying to patch has been deleted");const n={...r};for(const f of["value","channels","allowed"])(0,s.applyGraffitiPatch)(L.applyPatch,f,o,n);if(typeof n.value!="object"||Array.isArray(n.value)||!n.value)throw new h.GraffitiErrorPatchError("value is no longer an object");if(!Array.isArray(n.channels)||!n.channels.every(f=>typeof f=="string"))throw new h.GraffitiErrorPatchError("channels are no longer an array of strings");if(n.allowed&&(!Array.isArray(n.allowed)||!n.allowed.every(f=>typeof f=="string")))throw new h.GraffitiErrorPatchError("allowed list is not an array of strings");return n.lastModified=new Date().getTime(),await this.db.put({...n,_id:this.docId(n)}),await this.deleteAtLocation(n,!0),{...r,tombstone:!0,lastModified:n.lastModified}};queryLastModifiedSuffixes(e){let o="",i="\uFFFF";if(typeof e=="object"&&e.properties?.lastModified&&typeof e.properties.lastModified=="object"){const t=e.properties.lastModified,a=t.minimum,r=t.exclusiveMinimum;let n;r!==void 0?(n=Math.ceil(r),n===r&&n++):a!==void 0&&(n=Math.ceil(a)),n!==void 0&&(o=n.toString().padStart(15,"0"));const f=t.maximum,p=t.exclusiveMaximum;let l;p!==void 0?(l=Math.floor(p),l===p&&l--):f!==void 0&&(l=Math.floor(f)),l!==void 0&&(i=l.toString().padStart(15,"0"))}return{startKeySuffix:o,endKeySuffix:i}}discover=(...e)=>{const[o,i,t]=e,a=(0,s.compileGraffitiObjectSchema)(this.ajv,i),{startKeySuffix:r,endKeySuffix:n}=this.queryLastModifiedSuffixes(i);return new g.Repeater(async(p,l)=>{const c=new Set;for(const m of o){const d=encodeURIComponent(m)+"/",y=d+r,b=d+n,w=await this.db.query("indexes/objectsPerChannelAndLastModified",{startkey:y,endkey:b,include_docs:!0});for(const v of w.rows){const j=v.doc;if(!j)continue;const{_id:O,_rev:T,...M}=j;c.has(O)||(c.add(O),(0,s.isActorAllowedGraffitiObject)(j,t)&&((0,s.maskGraffitiObject)(M,o,t),a(M)&&await p({value:M})))}}return l(),{tombstoneRetention:this.tombstoneRetention}})};recoverOrphans=(e,o)=>{const i=(0,s.compileGraffitiObjectSchema)(this.ajv,e),{startKeySuffix:t,endKeySuffix:a}=this.queryLastModifiedSuffixes(e),r=encodeURIComponent(o.actor)+"/",n=r+t,f=r+a;return new g.Repeater(async(l,c)=>{const m=await this.db.query("indexes/orphansPerActorAndLastModified",{startkey:n,endkey:f,include_docs:!0});for(const d of m.rows){const y=d.doc;if(!y)continue;const{_id:b,_rev:w,...v}=y;i(v)&&await l({value:v})}return c(),{tombstoneRetention:this.tombstoneRetention}})};channelStats=e=>new g.Repeater(async(i,t)=>{const a=encodeURIComponent(e.actor)+"/",r=await this.db.query("indexes/channelStatsPerActor",{startkey:a,endkey:a+"\uFFFF",reduce:!0,group:!0});for(const n of r.rows){const f=n.key.split("/")[1];if(typeof f!="string")continue;const{count:p,max:l}=n.value;typeof p!="number"||typeof l!="number"||await i({value:{channel:decodeURIComponent(f),count:p,lastModified:l}})}t()})}
2
2
  //# sourceMappingURL=database.js.map
@@ -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 GraffitiLocation,\n JSONSchema,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorPatchError,\n} from \"@graffiti-garden/api\";\nimport PouchDB from \"pouchdb\";\nimport {\n locationToUri,\n unpackLocationOrUri,\n randomBase64,\n applyGraffitiPatch,\n maskGraffitiObject,\n isActorAllowedGraffitiObject,\n isObjectNewer,\n compileGraffitiObjectSchema,\n} from \"./utilities.js\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport Ajv from \"ajv\";\nimport { 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 * Defines the name of the {@link https://api.graffiti.garden/interfaces/GraffitiObjectBase.html#source | `source` }\n * under which to store objects.\n * Defaults to `\"local\"`.\n */\n sourceName?: string;\n /**\n * The time in milliseconds to keep tombstones before deleting them.\n * See the {@link https://api.graffiti.garden/classes/Graffiti.html#discover | `discover` }\n * documentation for more information.\n */\n tombstoneRetention?: number;\n}\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\n Pick<\n Graffiti,\n | \"get\"\n | \"put\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"channelStats\"\n >\n{\n protected readonly db: PouchDB.Database<GraffitiObjectBase>;\n protected readonly source: string = \"local\";\n protected readonly tombstoneRetention: number = 86400000; // 1 day in ms\n protected readonly ajv: Ajv;\n\n constructor(options?: GraffitiLocalOptions) {\n this.ajv = new Ajv({ strict: false });\n this.source = options?.sourceName ?? this.source;\n this.tombstoneRetention =\n options?.tombstoneRetention ?? this.tombstoneRetention;\n const pouchDbOptions = {\n name: \"graffitiDb\",\n ...options?.pouchDBOptions,\n };\n this.db = new PouchDB<GraffitiObjectBase>(\n pouchDbOptions.name,\n pouchDbOptions,\n );\n\n this.db\n //@ts-ignore\n .put({\n _id: \"_design/indexes\",\n views: {\n objectsPerChannelAndLastModified: {\n map: function (object: GraffitiObjectBase) {\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: GraffitiObjectBase) {\n if (object.channels.length === 0) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n const id =\n encodeURIComponent(object.actor) + \"/\" + paddedLastModified;\n //@ts-ignore\n emit(id);\n }\n }.toString(),\n },\n channelStatsPerActor: {\n map: function (object: GraffitiObjectBase) {\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 }\n\n protected async queryByLocation(location: GraffitiLocation) {\n const uri = locationToUri(location) + \"/\";\n const results = await this.db.allDocs({\n startkey: uri,\n endkey: uri + \"\\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 GraffitiObjectBase & 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(location: GraffitiLocation) {\n return locationToUri(location) + \"/\" + randomBase64();\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [locationOrUri, schema, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n\n const docsAll = await this.queryByLocation(location);\n\n // Filter out ones not allowed\n const docs = docsAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, session),\n );\n if (!docs.length) throw new GraffitiErrorNotFound();\n\n // Get the most recent document\n const doc = docs.reduce((a, b) => (isObjectNewer(a, b) ? a : b));\n\n // Strip out the _id and _rev\n const { _id, _rev, _conflicts, _attachments, ...object } = 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(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 location: GraffitiLocation,\n keepLatest: boolean = false,\n ) {\n const docsAtLocationAll = await this.queryByLocation(location);\n const docsAtLocation = docsAtLocationAll.filter((doc) => !doc.tombstone);\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) => !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) => 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 = keepLatest ? latestModified : new Date().getTime();\n\n const deleteResults = await this.db.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 const { _id, _rev, _conflicts, _attachments, ...object } = deletedDoc;\n deletedObject = {\n ...object,\n tombstone: true,\n lastModified,\n };\n break;\n }\n }\n }\n\n return deletedObject;\n }\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const [locationOrUri, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n if (location.actor !== session.actor) {\n throw new GraffitiErrorForbidden();\n }\n\n const deletedObject = await this.deleteAtLocation(location);\n if (!deletedObject) {\n throw new GraffitiErrorNotFound();\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 }\n if (objectPartial.source && objectPartial.source !== this.source) {\n throw new GraffitiErrorForbidden(\n \"Putting an object that does not match this source\",\n );\n }\n\n const object: GraffitiObjectBase = {\n value: objectPartial.value,\n channels: objectPartial.channels,\n allowed: objectPartial.allowed,\n name: objectPartial.name ?? randomBase64(),\n source: this.source,\n actor: session.actor,\n tombstone: false,\n lastModified: new Date().getTime(),\n };\n\n await this.db.put({\n _id: this.docId(object),\n ...object,\n });\n\n // Delete the old object\n const previousObject = await this.deleteAtLocation(object, true);\n if (previousObject) {\n return previousObject;\n } else {\n return {\n ...object,\n value: {},\n channels: [],\n allowed: undefined,\n tombstone: true,\n };\n }\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const [patch, locationOrUri, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n if (location.actor !== session.actor) {\n throw new GraffitiErrorForbidden();\n }\n const originalObject = await this.get(locationOrUri, {}, session);\n if (originalObject.tombstone) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch has been deleted\",\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(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 this.db.put({\n ...patchObject,\n _id: this.docId(patchObject),\n });\n\n // Delete the old object\n await this.deleteAtLocation(patchObject, true);\n\n return {\n ...originalObject,\n tombstone: true,\n lastModified: patchObject.lastModified,\n };\n };\n\n protected queryLastModifiedSuffixes(schema: JSONSchema) {\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 = 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 discover: Graffiti[\"discover\"] = (...args) => {\n const [channels, schema, session] = args;\n const validate = compileGraffitiObjectSchema(this.ajv, schema);\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.discover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const processedIds = new Set<string>();\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 result = await this.db.query<GraffitiObjectBase>(\n \"indexes/objectsPerChannelAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n const { _id, _rev, ...object } = doc;\n\n // Don't double return the same object\n // (which can happen if it's in multiple channels)\n if (processedIds.has(_id)) continue;\n processedIds.add(_id);\n\n // Make sure the user is allowed to see it\n if (!isActorAllowedGraffitiObject(doc, session)) continue;\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, channels, session);\n\n // Check that it matches the schema\n if (validate(object)) {\n await push({ value: object });\n }\n }\n }\n stop();\n return {\n tombstoneRetention: this.tombstoneRetention,\n };\n });\n\n return repeater;\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (schema, session) => {\n const validate = compileGraffitiObjectSchema(this.ajv, schema);\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.recoverOrphans<typeof schema>\n > = new Repeater(async (push, stop) => {\n const result = await this.db.query<GraffitiObjectBase>(\n \"indexes/orphansPerActorAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n // No masking/access necessary because\n // the objects are all owned by the querier\n\n const { _id, _rev, ...object } = doc;\n if (validate(object)) {\n await push({ value: object });\n }\n }\n stop();\n return {\n tombstoneRetention: this.tombstoneRetention,\n };\n });\n\n return repeater;\n };\n\n channelStats: Graffiti[\"channelStats\"] = (session) => {\n const repeater: ReturnType<typeof Graffiti.prototype.channelStats> =\n new Repeater(async (push, stop) => {\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const result = await this.db.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 await push({\n value: {\n channel: decodeURIComponent(channelEncoded),\n count,\n lastModified,\n },\n });\n }\n stop();\n });\n\n return repeater;\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n Graffiti,\n GraffitiObjectBase,\n GraffitiLocation,\n JSONSchema,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorPatchError,\n} from \"@graffiti-garden/api\";\nimport PouchDB from \"pouchdb\";\nimport {\n locationToUri,\n unpackLocationOrUri,\n randomBase64,\n applyGraffitiPatch,\n maskGraffitiObject,\n isActorAllowedGraffitiObject,\n isObjectNewer,\n compileGraffitiObjectSchema,\n} from \"./utilities.js\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport Ajv from \"ajv\";\nimport { 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 * Defines the name of the {@link https://api.graffiti.garden/interfaces/GraffitiObjectBase.html#source | `source` }\n * under which to store objects.\n * Defaults to `\"local\"`.\n */\n sourceName?: string;\n /**\n * The time in milliseconds to keep tombstones before deleting them.\n * See the {@link https://api.graffiti.garden/classes/Graffiti.html#discover | `discover` }\n * documentation for more information.\n */\n tombstoneRetention?: number;\n /**\n * An optional Ajv instance to use for schema validation.\n */\n ajv?: Ajv;\n}\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\n Pick<\n Graffiti,\n | \"get\"\n | \"put\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"channelStats\"\n >\n{\n protected readonly db: PouchDB.Database<GraffitiObjectBase>;\n protected readonly source: string = \"local\";\n protected readonly tombstoneRetention: number = 86400000; // 1 day in ms\n protected readonly ajv: Ajv;\n\n constructor(options?: GraffitiLocalOptions) {\n this.ajv = options?.ajv ?? new Ajv({ strict: false });\n this.source = options?.sourceName ?? this.source;\n this.tombstoneRetention =\n options?.tombstoneRetention ?? this.tombstoneRetention;\n const pouchDbOptions = {\n name: \"graffitiDb\",\n ...options?.pouchDBOptions,\n };\n this.db = new PouchDB<GraffitiObjectBase>(\n pouchDbOptions.name,\n pouchDbOptions,\n );\n\n this.db\n //@ts-ignore\n .put({\n _id: \"_design/indexes\",\n views: {\n objectsPerChannelAndLastModified: {\n map: function (object: GraffitiObjectBase) {\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: GraffitiObjectBase) {\n if (object.channels.length === 0) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n const id =\n encodeURIComponent(object.actor) + \"/\" + paddedLastModified;\n //@ts-ignore\n emit(id);\n }\n }.toString(),\n },\n channelStatsPerActor: {\n map: function (object: GraffitiObjectBase) {\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 }\n\n protected async queryByLocation(location: GraffitiLocation) {\n const uri = locationToUri(location) + \"/\";\n const results = await this.db.allDocs({\n startkey: uri,\n endkey: uri + \"\\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 GraffitiObjectBase & 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(location: GraffitiLocation) {\n return locationToUri(location) + \"/\" + randomBase64();\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [locationOrUri, schema, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n\n const docsAll = await this.queryByLocation(location);\n\n // Filter out ones not allowed\n const docs = docsAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, session),\n );\n if (!docs.length) throw new GraffitiErrorNotFound();\n\n // Get the most recent document\n const doc = docs.reduce((a, b) => (isObjectNewer(a, b) ? a : b));\n\n // Strip out the _id and _rev\n const { _id, _rev, _conflicts, _attachments, ...object } = 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(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 location: GraffitiLocation,\n keepLatest: boolean = false,\n ) {\n const docsAtLocationAll = await this.queryByLocation(location);\n const docsAtLocation = docsAtLocationAll.filter((doc) => !doc.tombstone);\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) => !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) => 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 = keepLatest ? latestModified : new Date().getTime();\n\n const deleteResults = await this.db.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 const { _id, _rev, _conflicts, _attachments, ...object } = deletedDoc;\n deletedObject = {\n ...object,\n tombstone: true,\n lastModified,\n };\n break;\n }\n }\n }\n\n return deletedObject;\n }\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const [locationOrUri, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n if (location.actor !== session.actor) {\n throw new GraffitiErrorForbidden();\n }\n\n const deletedObject = await this.deleteAtLocation(location);\n if (!deletedObject) {\n throw new GraffitiErrorNotFound();\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 }\n if (objectPartial.source && objectPartial.source !== this.source) {\n throw new GraffitiErrorForbidden(\n \"Putting an object that does not match this source\",\n );\n }\n\n const object: GraffitiObjectBase = {\n value: objectPartial.value,\n channels: objectPartial.channels,\n allowed: objectPartial.allowed,\n name: objectPartial.name ?? randomBase64(),\n source: this.source,\n actor: session.actor,\n tombstone: false,\n lastModified: new Date().getTime(),\n };\n\n await this.db.put({\n _id: this.docId(object),\n ...object,\n });\n\n // Delete the old object\n const previousObject = await this.deleteAtLocation(object, true);\n if (previousObject) {\n return previousObject;\n } else {\n return {\n ...object,\n value: {},\n channels: [],\n allowed: undefined,\n tombstone: true,\n };\n }\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const [patch, locationOrUri, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n if (location.actor !== session.actor) {\n throw new GraffitiErrorForbidden();\n }\n const originalObject = await this.get(locationOrUri, {}, session);\n if (originalObject.tombstone) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch has been deleted\",\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(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 this.db.put({\n ...patchObject,\n _id: this.docId(patchObject),\n });\n\n // Delete the old object\n await this.deleteAtLocation(patchObject, true);\n\n return {\n ...originalObject,\n tombstone: true,\n lastModified: patchObject.lastModified,\n };\n };\n\n protected queryLastModifiedSuffixes(schema: JSONSchema) {\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 = 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 discover: Graffiti[\"discover\"] = (...args) => {\n const [channels, schema, session] = args;\n const validate = compileGraffitiObjectSchema(this.ajv, schema);\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.discover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const processedIds = new Set<string>();\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 result = await this.db.query<GraffitiObjectBase>(\n \"indexes/objectsPerChannelAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n const { _id, _rev, ...object } = doc;\n\n // Don't double return the same object\n // (which can happen if it's in multiple channels)\n if (processedIds.has(_id)) continue;\n processedIds.add(_id);\n\n // Make sure the user is allowed to see it\n if (!isActorAllowedGraffitiObject(doc, session)) continue;\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, channels, session);\n\n // Check that it matches the schema\n if (validate(object)) {\n await push({ value: object });\n }\n }\n }\n stop();\n return {\n tombstoneRetention: this.tombstoneRetention,\n };\n });\n\n return repeater;\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (schema, session) => {\n const validate = compileGraffitiObjectSchema(this.ajv, schema);\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.recoverOrphans<typeof schema>\n > = new Repeater(async (push, stop) => {\n const result = await this.db.query<GraffitiObjectBase>(\n \"indexes/orphansPerActorAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n // No masking/access necessary because\n // the objects are all owned by the querier\n\n const { _id, _rev, ...object } = doc;\n if (validate(object)) {\n await push({ value: object });\n }\n }\n stop();\n return {\n tombstoneRetention: this.tombstoneRetention,\n };\n });\n\n return repeater;\n };\n\n channelStats: Graffiti[\"channelStats\"] = (session) => {\n const repeater: ReturnType<typeof Graffiti.prototype.channelStats> =\n new Repeater(async (push, stop) => {\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const result = await this.db.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 await push({\n value: {\n channel: decodeURIComponent(channelEncoded),\n count,\n lastModified,\n },\n });\n }\n stop();\n });\n\n return repeater;\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["database_exports", "__export", "GraffitiLocalDatabase", "__toCommonJS", "import_api", "import_pouchdb", "import_utilities", "import_repeater", "import_ajv", "import_fast_json_patch", "options", "Ajv", "pouchDbOptions", "PouchDB", "object", "paddedLastModified", "channel", "id", "error", "location", "uri", "row", "acc", "doc", "args", "locationOrUri", "schema", "session", "docs", "a", "b", "_id", "_rev", "_conflicts", "_attachments", "keepLatest", "docsAtLocation", "latestModified", "docsToDelete", "concurrentDocsAll", "keepDocId", "concurrentDocsToDelete", "lastModified", "deleteResults", "deletedObject", "resultOrError", "deletedDoc", "objectPartial", "previousObject", "patch", "originalObject", "patchObject", "prop", "allowed", "startKeySuffix", "endKeySuffix", "lastModifiedSchema", "minimum", "exclusiveMinimum", "intMinimum", "maximum", "exclusiveMaximum", "intMaximum", "channels", "validate", "push", "stop", "processedIds", "keyPrefix", "startkey", "endkey", "result", "channelEncoded", "count"]
7
7
  }
@@ -24,6 +24,10 @@ export interface GraffitiLocalOptions {
24
24
  * documentation for more information.
25
25
  */
26
26
  tombstoneRetention?: number;
27
+ /**
28
+ * An optional Ajv instance to use for schema validation.
29
+ */
30
+ ajv?: Ajv;
27
31
  }
28
32
  /**
29
33
  * An implementation of only the database operations of the
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,EACX,MAAM,sBAAsB,CAAC;AAmB9B,OAAO,GAAG,MAAM,KAAK,CAAC;AAGtB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,qBAAqB,CAAC;IAC7D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,qBAAa,qBACX,YACE,IAAI,CACF,QAAQ,EACN,KAAK,GACL,KAAK,GACL,OAAO,GACP,QAAQ,GACR,UAAU,GACV,gBAAgB,GAChB,cAAc,CACjB;IAEH,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC5D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAW;IAC5C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAY;IACzD,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;gBAEhB,OAAO,CAAC,EAAE,oBAAoB;cA6E1B,eAAe,CAAC,QAAQ,EAAE,gBAAgB;IAqB1D,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,gBAAgB;IAI1C,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CA2BlB;IAEF;;;;;;;OAOG;cACa,gBAAgB,CAC9B,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,GAAE,OAAe;IA+D7B,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAYxB;IAEF,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAwClB;IAEF,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CA+DtB;IAEF,SAAS,CAAC,yBAAyB,CAAC,MAAM,EAAE,UAAU;;;;IA+CtD,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAqD5B;IAEF,cAAc,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAoCxC;IAEF,YAAY,EAAE,QAAQ,CAAC,cAAc,CAAC,CA4BpC;CACH"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EAChB,UAAU,EACX,MAAM,sBAAsB,CAAC;AAmB9B,OAAO,GAAG,MAAM,KAAK,CAAC;AAGtB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,qBAAqB,CAAC;IAC7D;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;OAEG;IACH,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AAED;;;GAGG;AACH,qBAAa,qBACX,YACE,IAAI,CACF,QAAQ,EACN,KAAK,GACL,KAAK,GACL,OAAO,GACP,QAAQ,GACR,UAAU,GACV,gBAAgB,GAChB,cAAc,CACjB;IAEH,SAAS,CAAC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;IAC5D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAW;IAC5C,SAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAY;IACzD,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;gBAEhB,OAAO,CAAC,EAAE,oBAAoB;cA6E1B,eAAe,CAAC,QAAQ,EAAE,gBAAgB;IAqB1D,SAAS,CAAC,KAAK,CAAC,QAAQ,EAAE,gBAAgB;IAI1C,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CA2BlB;IAEF;;;;;;;OAOG;cACa,gBAAgB,CAC9B,QAAQ,EAAE,gBAAgB,EAC1B,UAAU,GAAE,OAAe;IA+D7B,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAYxB;IAEF,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAwClB;IAEF,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,CA+DtB;IAEF,SAAS,CAAC,yBAAyB,CAAC,MAAM,EAAE,UAAU;;;;IA+CtD,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAqD5B;IAEF,cAAc,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAoCxC;IAEF,YAAY,EAAE,QAAQ,CAAC,cAAc,CAAC,CA4BpC;CACH"}
@@ -1,2 +1,2 @@
1
- import{GraffitiErrorNotFound as G,GraffitiErrorSchemaMismatch as B,GraffitiErrorForbidden as w,GraffitiErrorPatchError as g}from"@graffiti-garden/api";import _ from"pouchdb";import{locationToUri as A,unpackLocationOrUri as j,randomBase64 as x,applyGraffitiPatch as R,maskGraffitiObject as D,isActorAllowedGraffitiObject as L,isObjectNewer as P,compileGraffitiObjectSchema as M}from"./utilities.js";import{Repeater as O}from"@repeaterjs/repeater";import k from"ajv";import{applyPatch as C}from"fast-json-patch";class J{db;source="local";tombstoneRetention=864e5;ajv;constructor(a){this.ajv=new k({strict:!1}),this.source=a?.sourceName??this.source,this.tombstoneRetention=a?.tombstoneRetention??this.tombstoneRetention;const n={name:"graffitiDb",...a?.pouchDBOptions};this.db=new _(n.name,n),this.db.put({_id:"_design/indexes",views:{objectsPerChannelAndLastModified:{map:function(t){const e=t.lastModified.toString().padStart(15,"0");t.channels.forEach(function(i){const r=encodeURIComponent(i)+"/"+e;emit(r)})}.toString()},orphansPerActorAndLastModified:{map:function(t){if(t.channels.length===0){const e=t.lastModified.toString().padStart(15,"0"),i=encodeURIComponent(t.actor)+"/"+e;emit(i)}}.toString()},channelStatsPerActor:{map:function(t){t.tombstone||t.channels.forEach(function(e){const i=encodeURIComponent(t.actor)+"/"+encodeURIComponent(e);emit(i,t.lastModified)})}.toString(),reduce:"_stats"}}}).catch(t=>{if(!(t&&typeof t=="object"&&"name"in t&&t.name==="conflict"))throw t})}async queryByLocation(a){const n=A(a)+"/";return(await this.db.allDocs({startkey:n,endkey:n+"\uFFFF",include_docs:!0})).rows.map(i=>i.doc).reduce((i,r)=>(r&&i.push(r),i),[])}docId(a){return A(a)+"/"+x()}get=async(...a)=>{const[n,t,e]=a,{location:i}=j(n),o=(await this.queryByLocation(i)).filter(p=>L(p,e));if(!o.length)throw new G;const c=o.reduce((p,m)=>P(p,m)?p:m),{_id:l,_rev:d,_conflicts:s,_attachments:u,...f}=c;if(D(f,[],e),!M(this.ajv,t)(f))throw new B;return f};async deleteAtLocation(a,n=!1){const e=(await this.queryByLocation(a)).filter(s=>!s.tombstone);if(!e.length)return;const i=e.map(s=>s.lastModified).reduce((s,u)=>s>u?s:u),r=e.filter(s=>!n||s.lastModified<i),o=e.filter(s=>n&&s.lastModified===i);if(o.length){const s=o.map(f=>f._id).reduce((f,h)=>f>h?f:h),u=o.filter(f=>f._id!==s);r.push(...u)}const c=n?i:new Date().getTime(),l=await this.db.bulkDocs(r.map(s=>({...s,tombstone:!0,lastModified:c})));let d;for(const s of l)if("ok"in s){const{id:u}=s,f=r.find(h=>h._id===u);if(f){const{_id:h,_rev:p,_conflicts:m,_attachments:y,...b}=f;d={...b,tombstone:!0,lastModified:c};break}}return d}delete=async(...a)=>{const[n,t]=a,{location:e}=j(n);if(e.actor!==t.actor)throw new w;const i=await this.deleteAtLocation(e);if(!i)throw new G;return i};put=async(...a)=>{const[n,t]=a;if(n.actor&&n.actor!==t.actor)throw new w;if(n.source&&n.source!==this.source)throw new w("Putting an object that does not match this source");const e={value:n.value,channels:n.channels,allowed:n.allowed,name:n.name??x(),source:this.source,actor:t.actor,tombstone:!1,lastModified:new Date().getTime()};await this.db.put({_id:this.docId(e),...e});const i=await this.deleteAtLocation(e,!0);return i||{...e,value:{},channels:[],allowed:void 0,tombstone:!0}};patch=async(...a)=>{const[n,t,e]=a,{location:i}=j(t);if(i.actor!==e.actor)throw new w;const r=await this.get(t,{},e);if(r.tombstone)throw new G("The object you are trying to patch has been deleted");const o={...r};for(const c of["value","channels","allowed"])R(C,c,n,o);if(typeof o.value!="object"||Array.isArray(o.value)||!o.value)throw new g("value is no longer an object");if(!Array.isArray(o.channels)||!o.channels.every(c=>typeof c=="string"))throw new g("channels are no longer an array of strings");if(o.allowed&&(!Array.isArray(o.allowed)||!o.allowed.every(c=>typeof c=="string")))throw new g("allowed list is not an array of strings");return o.lastModified=new Date().getTime(),await this.db.put({...o,_id:this.docId(o)}),await this.deleteAtLocation(o,!0),{...r,tombstone:!0,lastModified:o.lastModified}};queryLastModifiedSuffixes(a){let n="",t="\uFFFF";if(typeof a=="object"&&a.properties?.lastModified&&typeof a.properties.lastModified=="object"){const e=a.properties.lastModified,i=e.minimum,r=e.exclusiveMinimum;let o;r!==void 0?(o=Math.ceil(r),o===r&&o++):i!==void 0&&(o=Math.ceil(i)),o!==void 0&&(n=o.toString().padStart(15,"0"));const c=e.maximum,l=e.exclusiveMaximum;let d;l!==void 0?(d=Math.floor(l),d===l&&d--):c!==void 0&&(d=Math.floor(c)),d!==void 0&&(t=d.toString().padStart(15,"0"))}return{startKeySuffix:n,endKeySuffix:t}}discover=(...a)=>{const[n,t,e]=a,i=M(this.ajv,t),{startKeySuffix:r,endKeySuffix:o}=this.queryLastModifiedSuffixes(t);return new O(async(l,d)=>{const s=new Set;for(const u of n){const f=encodeURIComponent(u)+"/",h=f+r,p=f+o,m=await this.db.query("indexes/objectsPerChannelAndLastModified",{startkey:h,endkey:p,include_docs:!0});for(const y of m.rows){const b=y.doc;if(!b)continue;const{_id:S,_rev:U,...v}=b;s.has(S)||(s.add(S),L(b,e)&&(D(v,n,e),i(v)&&await l({value:v})))}}return d(),{tombstoneRetention:this.tombstoneRetention}})};recoverOrphans=(a,n)=>{const t=M(this.ajv,a),{startKeySuffix:e,endKeySuffix:i}=this.queryLastModifiedSuffixes(a),r=encodeURIComponent(n.actor)+"/",o=r+e,c=r+i;return new O(async(d,s)=>{const u=await this.db.query("indexes/orphansPerActorAndLastModified",{startkey:o,endkey:c,include_docs:!0});for(const f of u.rows){const h=f.doc;if(!h)continue;const{_id:p,_rev:m,...y}=h;t(y)&&await d({value:y})}return s(),{tombstoneRetention:this.tombstoneRetention}})};channelStats=a=>new O(async(t,e)=>{const i=encodeURIComponent(a.actor)+"/",r=await this.db.query("indexes/channelStatsPerActor",{startkey:i,endkey:i+"\uFFFF",reduce:!0,group:!0});for(const o of r.rows){const c=o.key.split("/")[1];if(typeof c!="string")continue;const{count:l,max:d}=o.value;typeof l!="number"||typeof d!="number"||await t({value:{channel:decodeURIComponent(c),count:l,lastModified:d}})}e()})}export{J as GraffitiLocalDatabase};
1
+ import{GraffitiErrorNotFound as j,GraffitiErrorSchemaMismatch as B,GraffitiErrorForbidden as w,GraffitiErrorPatchError as G}from"@graffiti-garden/api";import _ from"pouchdb";import{locationToUri as A,unpackLocationOrUri as g,randomBase64 as x,applyGraffitiPatch as R,maskGraffitiObject as D,isActorAllowedGraffitiObject as L,isObjectNewer as P,compileGraffitiObjectSchema as M}from"./utilities.js";import{Repeater as O}from"@repeaterjs/repeater";import k from"ajv";import{applyPatch as C}from"fast-json-patch";class J{db;source="local";tombstoneRetention=864e5;ajv;constructor(a){this.ajv=a?.ajv??new k({strict:!1}),this.source=a?.sourceName??this.source,this.tombstoneRetention=a?.tombstoneRetention??this.tombstoneRetention;const n={name:"graffitiDb",...a?.pouchDBOptions};this.db=new _(n.name,n),this.db.put({_id:"_design/indexes",views:{objectsPerChannelAndLastModified:{map:function(t){const e=t.lastModified.toString().padStart(15,"0");t.channels.forEach(function(i){const r=encodeURIComponent(i)+"/"+e;emit(r)})}.toString()},orphansPerActorAndLastModified:{map:function(t){if(t.channels.length===0){const e=t.lastModified.toString().padStart(15,"0"),i=encodeURIComponent(t.actor)+"/"+e;emit(i)}}.toString()},channelStatsPerActor:{map:function(t){t.tombstone||t.channels.forEach(function(e){const i=encodeURIComponent(t.actor)+"/"+encodeURIComponent(e);emit(i,t.lastModified)})}.toString(),reduce:"_stats"}}}).catch(t=>{if(!(t&&typeof t=="object"&&"name"in t&&t.name==="conflict"))throw t})}async queryByLocation(a){const n=A(a)+"/";return(await this.db.allDocs({startkey:n,endkey:n+"\uFFFF",include_docs:!0})).rows.map(i=>i.doc).reduce((i,r)=>(r&&i.push(r),i),[])}docId(a){return A(a)+"/"+x()}get=async(...a)=>{const[n,t,e]=a,{location:i}=g(n),o=(await this.queryByLocation(i)).filter(p=>L(p,e));if(!o.length)throw new j;const c=o.reduce((p,m)=>P(p,m)?p:m),{_id:l,_rev:d,_conflicts:s,_attachments:u,...f}=c;if(D(f,[],e),!M(this.ajv,t)(f))throw new B;return f};async deleteAtLocation(a,n=!1){const e=(await this.queryByLocation(a)).filter(s=>!s.tombstone);if(!e.length)return;const i=e.map(s=>s.lastModified).reduce((s,u)=>s>u?s:u),r=e.filter(s=>!n||s.lastModified<i),o=e.filter(s=>n&&s.lastModified===i);if(o.length){const s=o.map(f=>f._id).reduce((f,h)=>f>h?f:h),u=o.filter(f=>f._id!==s);r.push(...u)}const c=n?i:new Date().getTime(),l=await this.db.bulkDocs(r.map(s=>({...s,tombstone:!0,lastModified:c})));let d;for(const s of l)if("ok"in s){const{id:u}=s,f=r.find(h=>h._id===u);if(f){const{_id:h,_rev:p,_conflicts:m,_attachments:y,...b}=f;d={...b,tombstone:!0,lastModified:c};break}}return d}delete=async(...a)=>{const[n,t]=a,{location:e}=g(n);if(e.actor!==t.actor)throw new w;const i=await this.deleteAtLocation(e);if(!i)throw new j;return i};put=async(...a)=>{const[n,t]=a;if(n.actor&&n.actor!==t.actor)throw new w;if(n.source&&n.source!==this.source)throw new w("Putting an object that does not match this source");const e={value:n.value,channels:n.channels,allowed:n.allowed,name:n.name??x(),source:this.source,actor:t.actor,tombstone:!1,lastModified:new Date().getTime()};await this.db.put({_id:this.docId(e),...e});const i=await this.deleteAtLocation(e,!0);return i||{...e,value:{},channels:[],allowed:void 0,tombstone:!0}};patch=async(...a)=>{const[n,t,e]=a,{location:i}=g(t);if(i.actor!==e.actor)throw new w;const r=await this.get(t,{},e);if(r.tombstone)throw new j("The object you are trying to patch has been deleted");const o={...r};for(const c of["value","channels","allowed"])R(C,c,n,o);if(typeof o.value!="object"||Array.isArray(o.value)||!o.value)throw new G("value is no longer an object");if(!Array.isArray(o.channels)||!o.channels.every(c=>typeof c=="string"))throw new G("channels are no longer an array of strings");if(o.allowed&&(!Array.isArray(o.allowed)||!o.allowed.every(c=>typeof c=="string")))throw new G("allowed list is not an array of strings");return o.lastModified=new Date().getTime(),await this.db.put({...o,_id:this.docId(o)}),await this.deleteAtLocation(o,!0),{...r,tombstone:!0,lastModified:o.lastModified}};queryLastModifiedSuffixes(a){let n="",t="\uFFFF";if(typeof a=="object"&&a.properties?.lastModified&&typeof a.properties.lastModified=="object"){const e=a.properties.lastModified,i=e.minimum,r=e.exclusiveMinimum;let o;r!==void 0?(o=Math.ceil(r),o===r&&o++):i!==void 0&&(o=Math.ceil(i)),o!==void 0&&(n=o.toString().padStart(15,"0"));const c=e.maximum,l=e.exclusiveMaximum;let d;l!==void 0?(d=Math.floor(l),d===l&&d--):c!==void 0&&(d=Math.floor(c)),d!==void 0&&(t=d.toString().padStart(15,"0"))}return{startKeySuffix:n,endKeySuffix:t}}discover=(...a)=>{const[n,t,e]=a,i=M(this.ajv,t),{startKeySuffix:r,endKeySuffix:o}=this.queryLastModifiedSuffixes(t);return new O(async(l,d)=>{const s=new Set;for(const u of n){const f=encodeURIComponent(u)+"/",h=f+r,p=f+o,m=await this.db.query("indexes/objectsPerChannelAndLastModified",{startkey:h,endkey:p,include_docs:!0});for(const y of m.rows){const b=y.doc;if(!b)continue;const{_id:S,_rev:U,...v}=b;s.has(S)||(s.add(S),L(b,e)&&(D(v,n,e),i(v)&&await l({value:v})))}}return d(),{tombstoneRetention:this.tombstoneRetention}})};recoverOrphans=(a,n)=>{const t=M(this.ajv,a),{startKeySuffix:e,endKeySuffix:i}=this.queryLastModifiedSuffixes(a),r=encodeURIComponent(n.actor)+"/",o=r+e,c=r+i;return new O(async(d,s)=>{const u=await this.db.query("indexes/orphansPerActorAndLastModified",{startkey:o,endkey:c,include_docs:!0});for(const f of u.rows){const h=f.doc;if(!h)continue;const{_id:p,_rev:m,...y}=h;t(y)&&await d({value:y})}return s(),{tombstoneRetention:this.tombstoneRetention}})};channelStats=a=>new O(async(t,e)=>{const i=encodeURIComponent(a.actor)+"/",r=await this.db.query("indexes/channelStatsPerActor",{startkey:i,endkey:i+"\uFFFF",reduce:!0,group:!0});for(const o of r.rows){const c=o.key.split("/")[1];if(typeof c!="string")continue;const{count:l,max:d}=o.value;typeof l!="number"||typeof d!="number"||await t({value:{channel:decodeURIComponent(c),count:l,lastModified:d}})}e()})}export{J as GraffitiLocalDatabase};
2
2
  //# sourceMappingURL=database.js.map
@@ -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 GraffitiLocation,\n JSONSchema,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorPatchError,\n} from \"@graffiti-garden/api\";\nimport PouchDB from \"pouchdb\";\nimport {\n locationToUri,\n unpackLocationOrUri,\n randomBase64,\n applyGraffitiPatch,\n maskGraffitiObject,\n isActorAllowedGraffitiObject,\n isObjectNewer,\n compileGraffitiObjectSchema,\n} from \"./utilities.js\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport Ajv from \"ajv\";\nimport { 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 * Defines the name of the {@link https://api.graffiti.garden/interfaces/GraffitiObjectBase.html#source | `source` }\n * under which to store objects.\n * Defaults to `\"local\"`.\n */\n sourceName?: string;\n /**\n * The time in milliseconds to keep tombstones before deleting them.\n * See the {@link https://api.graffiti.garden/classes/Graffiti.html#discover | `discover` }\n * documentation for more information.\n */\n tombstoneRetention?: number;\n}\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\n Pick<\n Graffiti,\n | \"get\"\n | \"put\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"channelStats\"\n >\n{\n protected readonly db: PouchDB.Database<GraffitiObjectBase>;\n protected readonly source: string = \"local\";\n protected readonly tombstoneRetention: number = 86400000; // 1 day in ms\n protected readonly ajv: Ajv;\n\n constructor(options?: GraffitiLocalOptions) {\n this.ajv = new Ajv({ strict: false });\n this.source = options?.sourceName ?? this.source;\n this.tombstoneRetention =\n options?.tombstoneRetention ?? this.tombstoneRetention;\n const pouchDbOptions = {\n name: \"graffitiDb\",\n ...options?.pouchDBOptions,\n };\n this.db = new PouchDB<GraffitiObjectBase>(\n pouchDbOptions.name,\n pouchDbOptions,\n );\n\n this.db\n //@ts-ignore\n .put({\n _id: \"_design/indexes\",\n views: {\n objectsPerChannelAndLastModified: {\n map: function (object: GraffitiObjectBase) {\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: GraffitiObjectBase) {\n if (object.channels.length === 0) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n const id =\n encodeURIComponent(object.actor) + \"/\" + paddedLastModified;\n //@ts-ignore\n emit(id);\n }\n }.toString(),\n },\n channelStatsPerActor: {\n map: function (object: GraffitiObjectBase) {\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 }\n\n protected async queryByLocation(location: GraffitiLocation) {\n const uri = locationToUri(location) + \"/\";\n const results = await this.db.allDocs({\n startkey: uri,\n endkey: uri + \"\\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 GraffitiObjectBase & 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(location: GraffitiLocation) {\n return locationToUri(location) + \"/\" + randomBase64();\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [locationOrUri, schema, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n\n const docsAll = await this.queryByLocation(location);\n\n // Filter out ones not allowed\n const docs = docsAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, session),\n );\n if (!docs.length) throw new GraffitiErrorNotFound();\n\n // Get the most recent document\n const doc = docs.reduce((a, b) => (isObjectNewer(a, b) ? a : b));\n\n // Strip out the _id and _rev\n const { _id, _rev, _conflicts, _attachments, ...object } = 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(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 location: GraffitiLocation,\n keepLatest: boolean = false,\n ) {\n const docsAtLocationAll = await this.queryByLocation(location);\n const docsAtLocation = docsAtLocationAll.filter((doc) => !doc.tombstone);\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) => !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) => 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 = keepLatest ? latestModified : new Date().getTime();\n\n const deleteResults = await this.db.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 const { _id, _rev, _conflicts, _attachments, ...object } = deletedDoc;\n deletedObject = {\n ...object,\n tombstone: true,\n lastModified,\n };\n break;\n }\n }\n }\n\n return deletedObject;\n }\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const [locationOrUri, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n if (location.actor !== session.actor) {\n throw new GraffitiErrorForbidden();\n }\n\n const deletedObject = await this.deleteAtLocation(location);\n if (!deletedObject) {\n throw new GraffitiErrorNotFound();\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 }\n if (objectPartial.source && objectPartial.source !== this.source) {\n throw new GraffitiErrorForbidden(\n \"Putting an object that does not match this source\",\n );\n }\n\n const object: GraffitiObjectBase = {\n value: objectPartial.value,\n channels: objectPartial.channels,\n allowed: objectPartial.allowed,\n name: objectPartial.name ?? randomBase64(),\n source: this.source,\n actor: session.actor,\n tombstone: false,\n lastModified: new Date().getTime(),\n };\n\n await this.db.put({\n _id: this.docId(object),\n ...object,\n });\n\n // Delete the old object\n const previousObject = await this.deleteAtLocation(object, true);\n if (previousObject) {\n return previousObject;\n } else {\n return {\n ...object,\n value: {},\n channels: [],\n allowed: undefined,\n tombstone: true,\n };\n }\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const [patch, locationOrUri, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n if (location.actor !== session.actor) {\n throw new GraffitiErrorForbidden();\n }\n const originalObject = await this.get(locationOrUri, {}, session);\n if (originalObject.tombstone) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch has been deleted\",\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(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 this.db.put({\n ...patchObject,\n _id: this.docId(patchObject),\n });\n\n // Delete the old object\n await this.deleteAtLocation(patchObject, true);\n\n return {\n ...originalObject,\n tombstone: true,\n lastModified: patchObject.lastModified,\n };\n };\n\n protected queryLastModifiedSuffixes(schema: JSONSchema) {\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 = 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 discover: Graffiti[\"discover\"] = (...args) => {\n const [channels, schema, session] = args;\n const validate = compileGraffitiObjectSchema(this.ajv, schema);\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.discover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const processedIds = new Set<string>();\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 result = await this.db.query<GraffitiObjectBase>(\n \"indexes/objectsPerChannelAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n const { _id, _rev, ...object } = doc;\n\n // Don't double return the same object\n // (which can happen if it's in multiple channels)\n if (processedIds.has(_id)) continue;\n processedIds.add(_id);\n\n // Make sure the user is allowed to see it\n if (!isActorAllowedGraffitiObject(doc, session)) continue;\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, channels, session);\n\n // Check that it matches the schema\n if (validate(object)) {\n await push({ value: object });\n }\n }\n }\n stop();\n return {\n tombstoneRetention: this.tombstoneRetention,\n };\n });\n\n return repeater;\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (schema, session) => {\n const validate = compileGraffitiObjectSchema(this.ajv, schema);\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.recoverOrphans<typeof schema>\n > = new Repeater(async (push, stop) => {\n const result = await this.db.query<GraffitiObjectBase>(\n \"indexes/orphansPerActorAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n // No masking/access necessary because\n // the objects are all owned by the querier\n\n const { _id, _rev, ...object } = doc;\n if (validate(object)) {\n await push({ value: object });\n }\n }\n stop();\n return {\n tombstoneRetention: this.tombstoneRetention,\n };\n });\n\n return repeater;\n };\n\n channelStats: Graffiti[\"channelStats\"] = (session) => {\n const repeater: ReturnType<typeof Graffiti.prototype.channelStats> =\n new Repeater(async (push, stop) => {\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const result = await this.db.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 await push({\n value: {\n channel: decodeURIComponent(channelEncoded),\n count,\n lastModified,\n },\n });\n }\n stop();\n });\n\n return repeater;\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type {\n Graffiti,\n GraffitiObjectBase,\n GraffitiLocation,\n JSONSchema,\n} from \"@graffiti-garden/api\";\nimport {\n GraffitiErrorNotFound,\n GraffitiErrorSchemaMismatch,\n GraffitiErrorForbidden,\n GraffitiErrorPatchError,\n} from \"@graffiti-garden/api\";\nimport PouchDB from \"pouchdb\";\nimport {\n locationToUri,\n unpackLocationOrUri,\n randomBase64,\n applyGraffitiPatch,\n maskGraffitiObject,\n isActorAllowedGraffitiObject,\n isObjectNewer,\n compileGraffitiObjectSchema,\n} from \"./utilities.js\";\nimport { Repeater } from \"@repeaterjs/repeater\";\nimport Ajv from \"ajv\";\nimport { 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 * Defines the name of the {@link https://api.graffiti.garden/interfaces/GraffitiObjectBase.html#source | `source` }\n * under which to store objects.\n * Defaults to `\"local\"`.\n */\n sourceName?: string;\n /**\n * The time in milliseconds to keep tombstones before deleting them.\n * See the {@link https://api.graffiti.garden/classes/Graffiti.html#discover | `discover` }\n * documentation for more information.\n */\n tombstoneRetention?: number;\n /**\n * An optional Ajv instance to use for schema validation.\n */\n ajv?: Ajv;\n}\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\n Pick<\n Graffiti,\n | \"get\"\n | \"put\"\n | \"patch\"\n | \"delete\"\n | \"discover\"\n | \"recoverOrphans\"\n | \"channelStats\"\n >\n{\n protected readonly db: PouchDB.Database<GraffitiObjectBase>;\n protected readonly source: string = \"local\";\n protected readonly tombstoneRetention: number = 86400000; // 1 day in ms\n protected readonly ajv: Ajv;\n\n constructor(options?: GraffitiLocalOptions) {\n this.ajv = options?.ajv ?? new Ajv({ strict: false });\n this.source = options?.sourceName ?? this.source;\n this.tombstoneRetention =\n options?.tombstoneRetention ?? this.tombstoneRetention;\n const pouchDbOptions = {\n name: \"graffitiDb\",\n ...options?.pouchDBOptions,\n };\n this.db = new PouchDB<GraffitiObjectBase>(\n pouchDbOptions.name,\n pouchDbOptions,\n );\n\n this.db\n //@ts-ignore\n .put({\n _id: \"_design/indexes\",\n views: {\n objectsPerChannelAndLastModified: {\n map: function (object: GraffitiObjectBase) {\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: GraffitiObjectBase) {\n if (object.channels.length === 0) {\n const paddedLastModified = object.lastModified\n .toString()\n .padStart(15, \"0\");\n const id =\n encodeURIComponent(object.actor) + \"/\" + paddedLastModified;\n //@ts-ignore\n emit(id);\n }\n }.toString(),\n },\n channelStatsPerActor: {\n map: function (object: GraffitiObjectBase) {\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 }\n\n protected async queryByLocation(location: GraffitiLocation) {\n const uri = locationToUri(location) + \"/\";\n const results = await this.db.allDocs({\n startkey: uri,\n endkey: uri + \"\\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 GraffitiObjectBase & 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(location: GraffitiLocation) {\n return locationToUri(location) + \"/\" + randomBase64();\n }\n\n get: Graffiti[\"get\"] = async (...args) => {\n const [locationOrUri, schema, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n\n const docsAll = await this.queryByLocation(location);\n\n // Filter out ones not allowed\n const docs = docsAll.filter((doc) =>\n isActorAllowedGraffitiObject(doc, session),\n );\n if (!docs.length) throw new GraffitiErrorNotFound();\n\n // Get the most recent document\n const doc = docs.reduce((a, b) => (isObjectNewer(a, b) ? a : b));\n\n // Strip out the _id and _rev\n const { _id, _rev, _conflicts, _attachments, ...object } = 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(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 location: GraffitiLocation,\n keepLatest: boolean = false,\n ) {\n const docsAtLocationAll = await this.queryByLocation(location);\n const docsAtLocation = docsAtLocationAll.filter((doc) => !doc.tombstone);\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) => !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) => 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 = keepLatest ? latestModified : new Date().getTime();\n\n const deleteResults = await this.db.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 const { _id, _rev, _conflicts, _attachments, ...object } = deletedDoc;\n deletedObject = {\n ...object,\n tombstone: true,\n lastModified,\n };\n break;\n }\n }\n }\n\n return deletedObject;\n }\n\n delete: Graffiti[\"delete\"] = async (...args) => {\n const [locationOrUri, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n if (location.actor !== session.actor) {\n throw new GraffitiErrorForbidden();\n }\n\n const deletedObject = await this.deleteAtLocation(location);\n if (!deletedObject) {\n throw new GraffitiErrorNotFound();\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 }\n if (objectPartial.source && objectPartial.source !== this.source) {\n throw new GraffitiErrorForbidden(\n \"Putting an object that does not match this source\",\n );\n }\n\n const object: GraffitiObjectBase = {\n value: objectPartial.value,\n channels: objectPartial.channels,\n allowed: objectPartial.allowed,\n name: objectPartial.name ?? randomBase64(),\n source: this.source,\n actor: session.actor,\n tombstone: false,\n lastModified: new Date().getTime(),\n };\n\n await this.db.put({\n _id: this.docId(object),\n ...object,\n });\n\n // Delete the old object\n const previousObject = await this.deleteAtLocation(object, true);\n if (previousObject) {\n return previousObject;\n } else {\n return {\n ...object,\n value: {},\n channels: [],\n allowed: undefined,\n tombstone: true,\n };\n }\n };\n\n patch: Graffiti[\"patch\"] = async (...args) => {\n const [patch, locationOrUri, session] = args;\n const { location } = unpackLocationOrUri(locationOrUri);\n if (location.actor !== session.actor) {\n throw new GraffitiErrorForbidden();\n }\n const originalObject = await this.get(locationOrUri, {}, session);\n if (originalObject.tombstone) {\n throw new GraffitiErrorNotFound(\n \"The object you are trying to patch has been deleted\",\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(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 this.db.put({\n ...patchObject,\n _id: this.docId(patchObject),\n });\n\n // Delete the old object\n await this.deleteAtLocation(patchObject, true);\n\n return {\n ...originalObject,\n tombstone: true,\n lastModified: patchObject.lastModified,\n };\n };\n\n protected queryLastModifiedSuffixes(schema: JSONSchema) {\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 = 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 discover: Graffiti[\"discover\"] = (...args) => {\n const [channels, schema, session] = args;\n const validate = compileGraffitiObjectSchema(this.ajv, schema);\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.discover<typeof schema>\n > = new Repeater(async (push, stop) => {\n const processedIds = new Set<string>();\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 result = await this.db.query<GraffitiObjectBase>(\n \"indexes/objectsPerChannelAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n const { _id, _rev, ...object } = doc;\n\n // Don't double return the same object\n // (which can happen if it's in multiple channels)\n if (processedIds.has(_id)) continue;\n processedIds.add(_id);\n\n // Make sure the user is allowed to see it\n if (!isActorAllowedGraffitiObject(doc, session)) continue;\n\n // Mask out the allowed list and channels\n // if the user is not the owner\n maskGraffitiObject(object, channels, session);\n\n // Check that it matches the schema\n if (validate(object)) {\n await push({ value: object });\n }\n }\n }\n stop();\n return {\n tombstoneRetention: this.tombstoneRetention,\n };\n });\n\n return repeater;\n };\n\n recoverOrphans: Graffiti[\"recoverOrphans\"] = (schema, session) => {\n const validate = compileGraffitiObjectSchema(this.ajv, schema);\n\n const { startKeySuffix, endKeySuffix } =\n this.queryLastModifiedSuffixes(schema);\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const startkey = keyPrefix + startKeySuffix;\n const endkey = keyPrefix + endKeySuffix;\n\n const repeater: ReturnType<\n typeof Graffiti.prototype.recoverOrphans<typeof schema>\n > = new Repeater(async (push, stop) => {\n const result = await this.db.query<GraffitiObjectBase>(\n \"indexes/orphansPerActorAndLastModified\",\n { startkey, endkey, include_docs: true },\n );\n\n for (const row of result.rows) {\n const doc = row.doc;\n if (!doc) continue;\n\n // No masking/access necessary because\n // the objects are all owned by the querier\n\n const { _id, _rev, ...object } = doc;\n if (validate(object)) {\n await push({ value: object });\n }\n }\n stop();\n return {\n tombstoneRetention: this.tombstoneRetention,\n };\n });\n\n return repeater;\n };\n\n channelStats: Graffiti[\"channelStats\"] = (session) => {\n const repeater: ReturnType<typeof Graffiti.prototype.channelStats> =\n new Repeater(async (push, stop) => {\n const keyPrefix = encodeURIComponent(session.actor) + \"/\";\n const result = await this.db.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 await push({\n value: {\n channel: decodeURIComponent(channelEncoded),\n count,\n lastModified,\n },\n });\n }\n stop();\n });\n\n return repeater;\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["GraffitiErrorNotFound", "GraffitiErrorSchemaMismatch", "GraffitiErrorForbidden", "GraffitiErrorPatchError", "PouchDB", "locationToUri", "unpackLocationOrUri", "randomBase64", "applyGraffitiPatch", "maskGraffitiObject", "isActorAllowedGraffitiObject", "isObjectNewer", "compileGraffitiObjectSchema", "Repeater", "Ajv", "applyPatch", "GraffitiLocalDatabase", "options", "pouchDbOptions", "object", "paddedLastModified", "channel", "id", "error", "location", "uri", "row", "acc", "doc", "args", "locationOrUri", "schema", "session", "docs", "a", "b", "_id", "_rev", "_conflicts", "_attachments", "keepLatest", "docsAtLocation", "latestModified", "docsToDelete", "concurrentDocsAll", "keepDocId", "concurrentDocsToDelete", "lastModified", "deleteResults", "deletedObject", "resultOrError", "deletedDoc", "objectPartial", "previousObject", "patch", "originalObject", "patchObject", "prop", "allowed", "startKeySuffix", "endKeySuffix", "lastModifiedSchema", "minimum", "exclusiveMinimum", "intMinimum", "maximum", "exclusiveMaximum", "intMaximum", "channels", "validate", "push", "stop", "processedIds", "keyPrefix", "startkey", "endkey", "result", "channelEncoded", "count"]
7
7
  }
@@ -14,7 +14,7 @@ return `+t+";",{})}function Gm(t){var e=["return function(doc) {",' "use strict
14
14
  You can debug this error by doing:
15
15
  myDatabase.on('error', function (err) { debugger; });
16
16
  Please double-check your map/reduce function.`),dt("error",e,r)}}function jv(t,e,r,n){function i(q,k,L){try{k(L)}catch(B){bf(q,B,{fun:k,doc:L})}}function s(q,k,L,B,F){try{return{output:k(L,B,F)}}catch(X){return bf(q,X,{fun:k,keys:L,values:B,rereduce:F}),{error:X}}}function o(q,k){let L=Be(q.key,k.key);return L!==0?L:Be(q.value,k.value)}function a(q,k,L){return L=L||0,typeof k=="number"?q.slice(L,k+L):L>0?q.slice(L):q}function c(q){let k=q.value;return k&&typeof k=="object"&&k._id||q.id}function d(q){for(let k of q.rows){let L=k.doc&&k.doc._attachments;if(L)for(let B of Object.keys(L)){let F=L[B];L[B].data=oo(F.data,F.content_type)}}}function m(q){return function(k){return q.include_docs&&q.attachments&&q.binary&&d(k),k}}function f(q,k,L,B){let F=k[q];typeof F<"u"&&(B&&(F=encodeURIComponent(JSON.stringify(F))),L.push(q+"="+F))}function g(q){if(typeof q<"u"){let k=Number(q);return!isNaN(k)&&k===parseInt(q,10)?k:q}}function _(q){return q.group_level=g(q.group_level),q.limit=g(q.limit),q.skip=g(q.skip),q}function E(q){if(q){if(typeof q!="number")return new sr(`Invalid value for integer: "${q}"`);if(q<0)return new sr(`Invalid value for positive integer: "${q}"`)}}function P(q,k){let L=q.descending?"endkey":"startkey",B=q.descending?"startkey":"endkey";if(typeof q[L]<"u"&&typeof q[B]<"u"&&Be(q[L],q[B])>0)throw new sr("No rows can match your key range, reverse your start_key and end_key or set {descending : true}");if(k.reduce&&q.reduce!==!1){if(q.include_docs)throw new sr("{include_docs:true} is invalid for reduce");if(q.keys&&q.keys.length>1&&!q.group&&!q.group_level)throw new sr("Multi-key fetches for reduce views must use {group: true}")}for(let F of["group_level","limit","skip"]){let X=E(q[F]);if(X)throw X}}async function S(q,k,L){let B=[],F,X="GET",ie;if(f("reduce",L,B),f("include_docs",L,B),f("attachments",L,B),f("limit",L,B),f("descending",L,B),f("group",L,B),f("group_level",L,B),f("skip",L,B),f("stale",L,B),f("conflicts",L,B),f("startkey",L,B,!0),f("start_key",L,B,!0),f("endkey",L,B,!0),f("end_key",L,B,!0),f("inclusive_end",L,B),f("key",L,B,!0),f("update_seq",L,B),B=B.join("&"),B=B===""?"":"?"+B,typeof L.keys<"u"){let W=`keys=${encodeURIComponent(JSON.stringify(L.keys))}`;W.length+B.length+1<=2e3?B+=(B[0]==="?"?"&":"?")+W:(X="POST",typeof k=="string"?F={keys:L.keys}:k.keys=L.keys)}if(typeof k=="string"){let M=Is(k),W=await q.fetch("_design/"+M[0]+"/_view/"+M[1]+B,{headers:new Rr({"Content-Type":"application/json"}),method:X,body:JSON.stringify(F)});ie=W.ok;let ee=await W.json();if(!ie)throw ee.status=W.status,kr(ee);for(let ne of ee.rows)if(ne.value&&ne.value.error&&ne.value.error==="builtin_reduce_error")throw new Error(ne.reason);return new Promise(function(ne){ne(ee)}).then(m(L))}F=F||{};for(let M of Object.keys(k))Array.isArray(k[M])?F[M]=k[M]:F[M]=k[M].toString();let J=await q.fetch("_temp_view"+B,{headers:new Rr({"Content-Type":"application/json"}),method:"POST",body:JSON.stringify(F)});ie=J.ok;let D=await J.json();if(!ie)throw D.status=J.status,kr(D);return new Promise(function(M){M(D)}).then(m(L))}function y(q,k,L){return new Promise(function(B,F){q._query(k,L,function(X,ie){if(X)return F(X);B(ie)})})}function w(q){return new Promise(function(k,L){q._viewCleanup(function(B,F){if(B)return L(B);k(F)})})}function p(q){return function(k){if(k.status===404)return q;throw k}}async function h(q,k,L){let B="_local/doc_"+q,F={_id:B,keys:[]},X=L.get(q),ie=X[0],J=X[1];function D(){return xv(J)?Promise.resolve(F):k.db.get(B).catch(p(F))}function M(Ee){return Ee.keys.length?k.db.allDocs({keys:Ee.keys,include_docs:!0}):Promise.resolve({rows:[]})}function W(Ee,$e){let Re=[],We=new Set;for(let ve of $e.rows){let ge=ve.doc;if(ge&&(Re.push(ge),We.add(ge._id),ge._deleted=!ie.has(ge._id),!ge._deleted)){let Se=ie.get(ge._id);"value"in Se&&(ge.value=Se.value)}}let ct=As(ie);for(let ve of ct)if(!We.has(ve)){let ge={_id:ve},Se=ie.get(ve);"value"in Se&&(ge.value=Se.value),Re.push(ge)}return Ee.keys=mf(ct.concat(Ee.keys)),Re.push(Ee),Re}let ee=await D(),ne=await M(ee);return W(ee,ne)}function v(q){return q.sourceDB.get("_local/purges").then(function(k){let L=k.purgeSeq;return q.db.get("_local/purgeSeq").then(function(B){return B._rev}).catch(p(void 0)).then(function(B){return q.db.put({_id:"_local/purgeSeq",_rev:B,purgeSeq:L})})}).catch(function(k){if(k.status!==404)throw k})}function b(q,k,L){var B="_local/lastSeq";return q.db.get(B).catch(p({_id:B,seq:0})).then(function(F){var X=As(k);return Promise.all(X.map(function(ie){return h(ie,q,k)})).then(function(ie){var J=ie.flat();return F.seq=L,J.push(F),q.db.bulkDocs({docs:J})}).then(()=>v(q))})}function N(q){let k=typeof q=="string"?q:q.name,L=_f[k];return L||(L=_f[k]=new an),L}async function C(q,k){return Os(N(q),function(){return j(q,k)})()}async function j(q,k){let L,B,F;function X(ve,ge){let Se={id:B._id,key:lr(ve)};typeof ge<"u"&&ge!==null&&(Se.value=lr(ge)),L.push(Se)}let ie=e(q.mapFun,X),J=q.seq||0;function D(){return q.sourceDB.info().then(function(ve){F=q.sourceDB.activeTasks.add({name:"view_indexing",total_items:ve.update_seq-J})})}function M(ve,ge){return function(){return b(q,ve,ge)}}let W=0,ee={view:q.name,indexed_docs:W};q.sourceDB.emit("indexing",ee);let ne=new an;async function Ee(){let ve=await q.sourceDB.changes({return_docs:!0,conflicts:!0,include_docs:!0,style:"all_docs",since:J,limit:k.changes_batch_size}),ge=await $e();return Re(ve,ge)}function $e(){return q.db.get("_local/purgeSeq").then(function(ve){return ve.purgeSeq}).catch(p(-1)).then(function(ve){return q.sourceDB.get("_local/purges").then(function(ge){let Se=ge.purges.filter(function(Fe,Pe){return Pe>ve}).map(Fe=>Fe.docId),nt=Se.filter(function(Fe,Pe){return Se.indexOf(Fe)===Pe});return Promise.all(nt.map(function(Fe){return q.sourceDB.get(Fe).then(function(Pe){return{docId:Fe,doc:Pe}}).catch(p({docId:Fe}))}))}).catch(p([]))})}function Re(ve,ge){let Se=ve.results;if(!Se.length&&!ge.length)return;for(let Pe of ge)if(Se.findIndex(function(Zt){return Zt.id===Pe.docId})<0){let Zt={_id:Pe.docId,doc:{_id:Pe.docId,_deleted:1},changes:[]};Pe.doc&&(Zt.doc=Pe.doc,Zt.changes.push({rev:Pe.doc._rev})),Se.push(Zt)}let nt=We(Se);ne.add(M(nt,J)),W=W+Se.length;let Fe={view:q.name,last_seq:ve.last_seq,results_count:Se.length,indexed_docs:W};if(q.sourceDB.emit("indexing",Fe),q.sourceDB.activeTasks.update(F,{completed_items:W}),!(Se.length<k.changes_batch_size))return Ee()}function We(ve){let ge=new Map;for(let Se of ve){if(Se.doc._id[0]!=="_"){L=[],B=Se.doc,B._deleted||i(q.sourceDB,ie,B),L.sort(o);let nt=ct(L);ge.set(Se.doc._id,[nt,Se.changes])}J=Se.seq}return ge}function ct(ve){let ge=new Map,Se;for(let nt=0,Fe=ve.length;nt<Fe;nt++){let Pe=ve[nt],Xt=[Pe.key,Pe.id];nt>0&&Be(Pe.key,Se)===0&&Xt.push(nt),ge.set(gt(Xt),Pe),Se=Pe.key}return ge}try{await D(),await Ee(),await ne.finish(),q.seq=J,q.sourceDB.activeTasks.remove(F)}catch(ve){q.sourceDB.activeTasks.remove(F,ve)}}function G(q,k,L){L.group_level===0&&delete L.group_level;let B=L.group||L.group_level,F=r(q.reduceFun),X=[],ie=isNaN(L.group_level)?Number.POSITIVE_INFINITY:L.group_level;for(let J of k){let D=X[X.length-1],M=B?J.key:null;if(B&&Array.isArray(M)&&(M=M.slice(0,ie)),D&&Be(D.groupKey,M)===0){D.keys.push([J.key,J.id]),D.values.push(J.value);continue}X.push({keys:[[J.key,J.id]],values:[J.value],groupKey:M})}k=[];for(let J of X){let D=s(q.sourceDB,F,J.keys,J.values,!1);if(D.error&&D.error instanceof fi)throw D.error;k.push({value:D.error?null:D.output,key:J.groupKey})}return{rows:a(k,L.limit,L.skip)}}function H(q,k){return Os(N(q),function(){return re(q,k)})()}async function re(q,k){let L,B=q.reduceFun&&k.reduce!==!1,F=k.skip||0;typeof k.keys<"u"&&!k.keys.length&&(k.limit=0,delete k.keys);async function X(J){J.include_docs=!0;let D=await q.db.allDocs(J);return L=D.total_rows,D.rows.map(function(M){if("value"in M.doc&&typeof M.doc.value=="object"&&M.doc.value!==null){let ee=Object.keys(M.doc.value).sort(),ne=["id","key","value"];if(!(ee<ne||ee>ne))return M.doc.value}let W=Am(M.doc._id);return{key:W[0],id:W[1],value:"value"in M.doc?M.doc.value:null}})}async function ie(J){let D;if(B?D=G(q,J,k):typeof k.keys>"u"?D={total_rows:L,offset:F,rows:J}:D={total_rows:L,offset:F,rows:a(J,k.limit,k.skip)},k.update_seq&&(D.update_seq=q.seq),k.include_docs){let M=mf(J.map(c)),W=await q.sourceDB.allDocs({keys:M,include_docs:!0,conflicts:k.conflicts,attachments:k.attachments,binary:k.binary}),ee=new Map;for(let ne of W.rows)ee.set(ne.id,ne.doc);for(let ne of J){let Ee=c(ne),$e=ee.get(Ee);$e&&(ne.doc=$e)}}return D}if(typeof k.keys<"u"){let D=k.keys.map(function(ee){let ne={startkey:gt([ee]),endkey:gt([ee,{}])};return k.update_seq&&(ne.update_seq=!0),X(ne)}),W=(await Promise.all(D)).flat();return ie(W)}else{let J={descending:k.descending};k.update_seq&&(J.update_seq=!0);let D,M;if("start_key"in k&&(D=k.start_key),"startkey"in k&&(D=k.startkey),"end_key"in k&&(M=k.end_key),"endkey"in k&&(M=k.endkey),typeof D<"u"&&(J.startkey=k.descending?gt([D,{}]):gt([D])),typeof M<"u"){let ee=k.inclusive_end!==!1;k.descending&&(ee=!ee),J.endkey=gt(ee?[M,{}]:[M])}if(typeof k.key<"u"){let ee=gt([k.key]),ne=gt([k.key,{}]);J.descending?(J.endkey=ee,J.startkey=ne):(J.startkey=ee,J.endkey=ne)}B||(typeof k.limit=="number"&&(J.limit=k.limit),J.skip=F);let W=await X(J);return ie(W)}}async function Y(q){return(await q.fetch("_view_cleanup",{headers:new Rr({"Content-Type":"application/json"}),method:"POST"})).json()}async function Z(q){try{let k=await q.get("_local/"+t),L=new Map;for(let D of Object.keys(k.views)){let M=Is(D),W="_design/"+M[0],ee=M[1],ne=L.get(W);ne||(ne=new Set,L.set(W,ne)),ne.add(ee)}let B={keys:As(L),include_docs:!0},F=await q.allDocs(B),X={};for(let D of F.rows){let M=D.key.substring(8);for(let W of L.get(D.key)){let ee=M+"/"+W;k.views[ee]||(ee=W);let ne=Object.keys(k.views[ee]),Ee=D.doc&&D.doc.views&&D.doc.views[W];for(let $e of ne)X[$e]=X[$e]||Ee}}let J=Object.keys(X).filter(function(D){return!X[D]}).map(function(D){return Os(N(D),function(){return new q.constructor(D,q.__opts).destroy()})()});return Promise.all(J).then(function(){return{ok:!0}})}catch(k){if(k.status===404)return{ok:!0};throw k}}async function ce(q,k,L){if(typeof q._query=="function")return y(q,k,L);if(Ot(q))return S(q,k,L);let B={changes_batch_size:q.__opts.view_update_changes_batch_size||Cv};if(typeof k!="string")return P(L,k),wf.add(async function(){let F=await gf(q,"temp_view/temp_view",k.map,k.reduce,!0,t);return Tv(C(F,B).then(function(){return H(F,L)}),function(){return F.db.destroy()})}),wf.finish();{let F=k,X=Is(F),ie=X[0],J=X[1],D=await q.get("_design/"+ie);if(k=D.views&&D.views[J],!k)throw new ci(`ddoc ${D._id} has no view named ${J}`);n(D,J),P(L,k);let M=await gf(q,F,k.map,k.reduce,!1,t);return L.stale==="ok"||L.stale==="update_after"?(L.stale==="update_after"&&At(function(){C(M,B)}),H(M,L)):(await C(M,B),H(M,L))}}function fe(q,k,L){let B=this;typeof k=="function"&&(L=k,k={}),k=k?_(k):{},typeof q=="function"&&(q={map:q});let F=Promise.resolve().then(function(){return ce(B,q,k)});return il(F,L),F}let me=Iv(function(){let q=this;return typeof q._viewCleanup=="function"?w(q):Ot(q)?Y(q):Z(q)});return{query:fe,viewCleanup:me}}var Ts={_sum:function(t,e){return Vs(e)},_count:function(t,e){return e.length},_stats:function(t,e){function r(n){for(var i=0,s=0,o=n.length;s<o;s++){var a=n[s];i+=a*a}return i}return{sum:Vs(e),min:Math.min.apply(null,e),max:Math.max.apply(null,e),count:e.length,sumsqr:r(e)}}};function Dv(t){if(/^_sum/.test(t))return Ts._sum;if(/^_count/.test(t))return Ts._count;if(/^_stats/.test(t))return Ts._stats;if(/^_/.test(t))throw new Error(t+" is not a supported reduce function.")}function Bv(t,e){if(typeof t=="function"&&t.length===2){var r=t;return function(n){return r(n,e)}}else return sl(t.toString(),e)}function Lv(t){var e=t.toString(),r=Dv(e);return r||sl(e)}function Mv(t,e){var r=t.views&&t.views[e];if(typeof r.map!="string")throw new ci("ddoc "+t._id+" has no string view named "+e+", instead found object of type: "+typeof r.map)}var Uv="mrviews",ol=jv(Uv,Bv,Lv,Mv);function Gv(t,e,r){return ol.query.call(this,t,e,r)}function Fv(t){return ol.viewCleanup.call(this,t)}var Kv={query:Gv,viewCleanup:Fv};function zv(t,e,r){return!t._attachments||!t._attachments[r]||t._attachments[r].digest!==e._attachments[r].digest}function Ef(t,e){var r=Object.keys(e._attachments);return Promise.all(r.map(function(n){return t.getAttachment(e._id,n,{rev:e._rev})}))}function Vv(t,e,r){var n=Ot(e)&&!Ot(t),i=Object.keys(r._attachments);return n?t.get(r._id).then(function(s){return Promise.all(i.map(function(o){return zv(s,r,o)?e.getAttachment(r._id,o):t.getAttachment(s._id,o)}))}).catch(function(s){if(s.status!==404)throw s;return Ef(e,r)}):Ef(e,r)}function Jv(t){var e=[];return Object.keys(t).forEach(function(r){var n=t[r].missing;n.forEach(function(i){e.push({id:r,rev:i})})}),{docs:e,revs:!0,latest:!0}}function Hv(t,e,r,n){r=Ge(r);var i=[],s=!0;function o(){var c=Jv(r);if(c.docs.length)return t.bulkGet(c).then(function(d){if(n.cancelled)throw new Error("cancelled");return Promise.all(d.results.map(function(m){return Promise.all(m.docs.map(function(f){var g=f.ok;return f.error&&(s=!1),!g||!g._attachments?g:Vv(e,t,g).then(_=>{var E=Object.keys(g._attachments);return _.forEach(function(P,S){var y=g._attachments[E[S]];delete y.stub,delete y.length,y.data=P}),g})}))})).then(function(m){i=i.concat(m.flat().filter(Boolean))})})}function a(){return{ok:s,docs:i}}return Promise.resolve().then(o).then(a)}var $f=1,Sf="pouchdb",Wv=5,yt=0;function Js(t,e,r,n,i){return t.get(e).catch(function(s){if(s.status===404)return(t.adapter==="http"||t.adapter==="https")&&Ns(404,"PouchDB is just checking if a remote checkpoint exists."),{session_id:n,_id:e,history:[],replicator:Sf,version:$f};throw s}).then(function(s){if(!i.cancelled&&s.last_seq!==r)return s.history=(s.history||[]).filter(function(o){return o.session_id!==n}),s.history.unshift({last_seq:r,session_id:n}),s.history=s.history.slice(0,Wv),s.version=$f,s.replicator=Sf,s.session_id=n,s.last_seq=r,t.put(s).catch(function(o){if(o.status===409)return Js(t,e,r,n,i);throw o})})}var li=class{constructor(e,r,n,i,s={writeSourceCheckpoint:!0,writeTargetCheckpoint:!0}){this.src=e,this.target=r,this.id=n,this.returnValue=i,this.opts=s,typeof s.writeSourceCheckpoint>"u"&&(s.writeSourceCheckpoint=!0),typeof s.writeTargetCheckpoint>"u"&&(s.writeTargetCheckpoint=!0)}writeCheckpoint(e,r){var n=this;return this.updateTarget(e,r).then(function(){return n.updateSource(e,r)})}updateTarget(e,r){return this.opts.writeTargetCheckpoint?Js(this.target,this.id,e,r,this.returnValue):Promise.resolve(!0)}updateSource(e,r){if(this.opts.writeSourceCheckpoint){var n=this;return Js(this.src,this.id,e,r,this.returnValue).catch(function(i){if(Of(i))return n.opts.writeSourceCheckpoint=!1,!0;throw i})}else return Promise.resolve(!0)}getCheckpoint(){var e=this;return!e.opts.writeSourceCheckpoint&&!e.opts.writeTargetCheckpoint?Promise.resolve(yt):e.opts&&e.opts.writeSourceCheckpoint&&!e.opts.writeTargetCheckpoint?e.src.get(e.id).then(function(r){return r.last_seq||yt}).catch(function(r){if(r.status!==404)throw r;return yt}):e.target.get(e.id).then(function(r){return e.opts&&e.opts.writeTargetCheckpoint&&!e.opts.writeSourceCheckpoint?r.last_seq||yt:e.src.get(e.id).then(function(n){if(r.version!==n.version)return yt;var i;return r.version?i=r.version.toString():i="undefined",i in Pf?Pf[i](r,n):yt},function(n){if(n.status===404&&r.last_seq)return e.src.put({_id:e.id,last_seq:yt}).then(function(){return yt},function(i){return Of(i)?(e.opts.writeSourceCheckpoint=!1,r.last_seq):yt});throw n})}).catch(function(r){if(r.status!==404)throw r;return yt})}},Pf={undefined:function(t,e){return Be(t.last_seq,e.last_seq)===0?e.last_seq:0},1:function(t,e){return Qv(e,t).last_seq}};function Qv(t,e){return t.session_id===e.session_id?{last_seq:t.last_seq,history:t.history}:al(t.history,e.history)}function al(t,e){var r=t[0],n=t.slice(1),i=e[0],s=e.slice(1);if(!r||e.length===0)return{last_seq:yt,history:[]};var o=r.session_id;if(Hs(o,e))return{last_seq:r.last_seq,history:t};var a=i.session_id;return Hs(a,n)?{last_seq:i.last_seq,history:s}:al(n,s)}function Hs(t,e){var r=e[0],n=e.slice(1);return!t||e.length===0?!1:t===r.session_id?!0:Hs(t,n)}function Of(t){return typeof t.status=="number"&&Math.floor(t.status/100)===4}function ul(t,e,r,n,i){return this instanceof li?ul:new li(t,e,r,n,i)}var Af=0;function Yv(t,e,r,n){if(t.retry===!1){e.emit("error",r),e.removeAllListeners();return}if(typeof t.back_off_function!="function"&&(t.back_off_function=$p),e.emit("requestError",r),e.state==="active"||e.state==="pending"){e.emit("paused",r),e.state="stopped";var i=function(){t.current_back_off=Af},s=function(){e.removeListener("active",i)};e.once("paused",s),e.once("active",i)}t.current_back_off=t.current_back_off||Af,t.current_back_off=t.back_off_function(t.current_back_off),setTimeout(n,t.current_back_off)}function Xv(t){return Object.keys(t).sort(Be).reduce(function(e,r){return e[r]=t[r],e},{})}function Zv(t,e,r){var n=r.doc_ids?r.doc_ids.sort(Be):"",i=r.filter?r.filter.toString():"",s="",o="",a="";return r.selector&&(a=JSON.stringify(r.selector)),r.filter&&r.query_params&&(s=JSON.stringify(Xv(r.query_params))),r.filter&&r.filter==="_view"&&(o=r.view.toString()),Promise.all([t.id(),e.id()]).then(function(c){var d=c[0]+c[1]+i+o+s+n+a;return new Promise(function(m){uo(d,m)})}).then(function(c){return c=c.replace(/\//g,".").replace(/\+/g,"_"),"_local/"+c})}function cl(t,e,r,n,i){var s=[],o,a={seq:0,changes:[],docs:[]},c=!1,d=!1,m=!1,f=0,g=0,_=r.continuous||r.live||!1,E=r.batch_size||100,P=r.batches_limit||10,S=r.style||"all_docs",y=!1,w=r.doc_ids,p=r.selector,h,v,b=[],N=pi(),C;i=i||{ok:!0,start_time:new Date().toISOString(),docs_read:0,docs_written:0,doc_write_failures:0,errors:[]};var j={};n.ready(t,e);function G(){return v?Promise.resolve():Zv(t,e,r).then(function(D){h=D;var M={};r.checkpoint===!1?M={writeSourceCheckpoint:!1,writeTargetCheckpoint:!1}:r.checkpoint==="source"?M={writeSourceCheckpoint:!0,writeTargetCheckpoint:!1}:r.checkpoint==="target"?M={writeSourceCheckpoint:!1,writeTargetCheckpoint:!0}:M={writeSourceCheckpoint:!0,writeTargetCheckpoint:!0},v=new ul(t,e,h,n,M)})}function H(){if(b=[],o.docs.length!==0){var D=o.docs,M={timeout:r.timeout};return e.bulkDocs({docs:D,new_edits:!1},M).then(function(W){if(n.cancelled)throw q(),new Error("cancelled");var ee=Object.create(null);W.forEach(function(Ee){Ee.error&&(ee[Ee.id]=Ee)});var ne=Object.keys(ee).length;i.doc_write_failures+=ne,i.docs_written+=D.length-ne,D.forEach(function(Ee){var $e=ee[Ee._id];if($e){i.errors.push($e);var Re=($e.name||"").toLowerCase();if(Re==="unauthorized"||Re==="forbidden")n.emit("denied",Ge($e));else throw $e}else b.push(Ee)})},function(W){throw i.doc_write_failures+=D.length,W})}}function re(){if(o.error)throw new Error("There was a problem getting docs.");i.last_seq=g=o.seq;var D=Ge(i);return b.length&&(D.docs=b,typeof o.pending=="number"&&(D.pending=o.pending,delete o.pending),n.emit("change",D)),c=!0,t.info().then(function(M){var W=t.activeTasks.get(C);if(!(!o||!W)){var ee=W.completed_items||0,ne=parseInt(M.update_seq,10)-parseInt(f,10);t.activeTasks.update(C,{completed_items:ee+o.changes.length,total_items:ne})}}),v.writeCheckpoint(o.seq,N).then(function(){if(n.emit("checkpoint",{checkpoint:o.seq}),c=!1,n.cancelled)throw q(),new Error("cancelled");o=void 0,F()}).catch(function(M){throw J(M),M})}function Y(){var D={};return o.changes.forEach(function(M){n.emit("checkpoint",{revs_diff:M}),M.id!=="_user/"&&(D[M.id]=M.changes.map(function(W){return W.rev}))}),e.revsDiff(D).then(function(M){if(n.cancelled)throw q(),new Error("cancelled");o.diffs=M})}function Z(){return Hv(t,e,o.diffs,n).then(function(D){o.error=!D.ok,D.docs.forEach(function(M){delete o.diffs[M._id],i.docs_read++,o.docs.push(M)})})}function ce(){if(!(n.cancelled||o)){if(s.length===0){fe(!0);return}o=s.shift(),n.emit("checkpoint",{start_next_batch:o.seq}),Y().then(Z).then(H).then(re).then(ce).catch(function(D){me("batch processing terminated with error",D)})}}function fe(D){if(a.changes.length===0){s.length===0&&!o&&((_&&j.live||d)&&(n.state="pending",n.emit("paused")),d&&q());return}(D||d||a.changes.length>=E)&&(s.push(a),a={seq:0,changes:[],docs:[]},(n.state==="pending"||n.state==="stopped")&&(n.state="active",n.emit("active")),ce())}function me(D,M){m||(M.message||(M.message=D),i.ok=!1,i.status="aborting",s=[],a={seq:0,changes:[],docs:[]},q(M))}function q(D){if(!m&&!(n.cancelled&&(i.status="cancelled",c)))if(i.status=i.status||"complete",i.end_time=new Date().toISOString(),i.last_seq=g,m=!0,t.activeTasks.remove(C,D),D){D=oe(D),D.result=i;var M=(D.name||"").toLowerCase();M==="unauthorized"||M==="forbidden"?(n.emit("error",D),n.removeAllListeners()):Yv(r,n,D,function(){cl(t,e,r,n)})}else n.emit("complete",i),n.removeAllListeners()}function k(D,M,W){if(n.cancelled)return q();typeof M=="number"&&(a.pending=M);var ee=to(r)(D);if(!ee){var ne=t.activeTasks.get(C);if(ne){var Ee=ne.completed_items||0;t.activeTasks.update(C,{completed_items:++Ee})}return}a.seq=D.seq||W,a.changes.push(D),n.emit("checkpoint",{pending_batch:a.seq}),At(function(){fe(s.length===0&&j.live)})}function L(D){if(y=!1,n.cancelled)return q();if(D.results.length>0)j.since=D.results[D.results.length-1].seq,F(),fe(!0);else{var M=function(){_?(j.live=!0,F()):d=!0,fe(!0)};!o&&D.results.length===0?(c=!0,v.writeCheckpoint(D.last_seq,N).then(function(){if(c=!1,i.last_seq=g=D.last_seq,n.cancelled)throw q(),new Error("cancelled");M()}).catch(J)):M()}}function B(D){if(y=!1,n.cancelled)return q();me("changes rejected",D)}function F(){if(!(!y&&!d&&s.length<P))return;y=!0;function D(){W.cancel()}function M(){n.removeListener("cancel",D)}n._changes&&(n.removeListener("cancel",n._abortChanges),n._changes.cancel()),n.once("cancel",D);var W=t.changes(j).on("change",k);W.then(M,M),W.then(L).catch(B),r.retry&&(n._changes=W,n._abortChanges=D)}function X(D){return t.info().then(function(M){var W=typeof r.since>"u"?parseInt(M.update_seq,10)-parseInt(D,10):parseInt(M.update_seq,10);return C=t.activeTasks.add({name:`${_?"continuous ":""}replication from ${M.db_name}`,total_items:W}),D})}function ie(){G().then(function(){if(n.cancelled){q();return}return v.getCheckpoint().then(X).then(function(D){g=D,f=D,j={since:g,limit:E,batch_size:E,style:S,doc_ids:w,selector:p,return_docs:!0},r.filter&&(typeof r.filter!="string"?j.include_docs=!0:j.filter=r.filter),"heartbeat"in r&&(j.heartbeat=r.heartbeat),"timeout"in r&&(j.timeout=r.timeout),r.query_params&&(j.query_params=r.query_params),r.view&&(j.view=r.view),F()})}).catch(function(D){me("getCheckpoint rejected with ",D)})}function J(D){c=!1,me("writeCheckpoint completed with error",D)}if(n.cancelled){q();return}n._addedListeners||(n.once("cancel",q),typeof r.complete=="function"&&(n.once("error",r.complete),n.once("complete",function(D){r.complete(null,D)})),n._addedListeners=!0),typeof r.since>"u"?ie():G().then(function(){return c=!0,v.writeCheckpoint(r.since,N)}).then(function(){if(c=!1,n.cancelled){q();return}g=r.since,ie()}).catch(J)}var Ws=class extends it{constructor(){super(),this.cancelled=!1,this.state="pending";let e=new Promise((r,n)=>{this.once("complete",r),this.once("error",n)});this.then=function(r,n){return e.then(r,n)},this.catch=function(r){return e.catch(r)},this.catch(function(){})}cancel(){this.cancelled=!0,this.state="cancelled",this.emit("cancel")}ready(e,r){if(this._readyCalled)return;this._readyCalled=!0;let n=()=>{this.cancel()};e.once("destroyed",n),r.once("destroyed",n);function i(){e.removeListener("destroyed",n),r.removeListener("destroyed",n)}this.once("complete",i),this.once("error",i)}};function di(t,e){var r=e.PouchConstructor;return typeof t=="string"?new r(t,e):t}function Qs(t,e,r,n){if(typeof r=="function"&&(n=r,r={}),typeof r>"u"&&(r={}),r.doc_ids&&!Array.isArray(r.doc_ids))throw oe(hi,"`doc_ids` filter parameter is not a list.");r.complete=n,r=Ge(r),r.continuous=r.continuous||r.live,r.retry="retry"in r?r.retry:!1,r.PouchConstructor=r.PouchConstructor||this;var i=new Ws(r),s=di(t,r),o=di(e,r);return cl(s,o,r,i),i}function ey(t,e,r,n){return typeof r=="function"&&(n=r,r={}),typeof r>"u"&&(r={}),r=Ge(r),r.PouchConstructor=r.PouchConstructor||this,t=di(t,r),e=di(e,r),new Ys(t,e,r,n)}var Ys=class extends it{constructor(e,r,n,i){super(),this.canceled=!1;let s=n.push?Object.assign({},n,n.push):n,o=n.pull?Object.assign({},n,n.pull):n;this.push=Qs(e,r,s),this.pull=Qs(r,e,o),this.pushPaused=!0,this.pullPaused=!0;let a=p=>{this.emit("change",{direction:"pull",change:p})},c=p=>{this.emit("change",{direction:"push",change:p})},d=p=>{this.emit("denied",{direction:"push",doc:p})},m=p=>{this.emit("denied",{direction:"pull",doc:p})},f=()=>{this.pushPaused=!0,this.pullPaused&&this.emit("paused")},g=()=>{this.pullPaused=!0,this.pushPaused&&this.emit("paused")},_=()=>{this.pushPaused=!1,this.pullPaused&&this.emit("active",{direction:"push"})},E=()=>{this.pullPaused=!1,this.pushPaused&&this.emit("active",{direction:"pull"})},P={},S=p=>(h,v)=>{(h==="change"&&(v===a||v===c)||h==="denied"&&(v===m||v===d)||h==="paused"&&(v===g||v===f)||h==="active"&&(v===E||v===_))&&(h in P||(P[h]={}),P[h][p]=!0,Object.keys(P[h]).length===2&&this.removeAllListeners(h))};n.live&&(this.push.on("complete",this.pull.cancel.bind(this.pull)),this.pull.on("complete",this.push.cancel.bind(this.push)));function y(p,h,v){p.listeners(h).indexOf(v)==-1&&p.on(h,v)}this.on("newListener",function(p){p==="change"?(y(this.pull,"change",a),y(this.push,"change",c)):p==="denied"?(y(this.pull,"denied",m),y(this.push,"denied",d)):p==="active"?(y(this.pull,"active",E),y(this.push,"active",_)):p==="paused"&&(y(this.pull,"paused",g),y(this.push,"paused",f))}),this.on("removeListener",function(p){p==="change"?(this.pull.removeListener("change",a),this.push.removeListener("change",c)):p==="denied"?(this.pull.removeListener("denied",m),this.push.removeListener("denied",d)):p==="active"?(this.pull.removeListener("active",E),this.push.removeListener("active",_)):p==="paused"&&(this.pull.removeListener("paused",g),this.push.removeListener("paused",f))}),this.pull.on("removeListener",S("pull")),this.push.on("removeListener",S("push"));let w=Promise.all([this.push,this.pull]).then(p=>{let h={push:p[0],pull:p[1]};return this.emit("complete",h),i&&i(null,h),this.removeAllListeners(),h},p=>{if(this.cancel(),i?i(p):this.emit("error",p),this.removeAllListeners(),i)throw p});this.then=function(p,h){return w.then(p,h)},this.catch=function(p){return w.catch(p)}}cancel(){this.canceled||(this.canceled=!0,this.push.cancel(),this.pull.cancel())}};function ty(t){t.replicate=Qs,t.sync=ey,Object.defineProperty(t.prototype,"replicate",{get:function(){var e=this;return typeof this.replicateMethods>"u"&&(this.replicateMethods={from:function(r,n,i){return e.constructor.replicate(r,e,n,i)},to:function(r,n,i){return e.constructor.replicate(e,r,n,i)}}),this.replicateMethods}}),t.prototype.sync=function(e,r,n){return this.constructor.sync(this,e,r,n)}}ae.plugin(_v).plugin(Av).plugin(Kv).plugin(ty);var fl=ae;I();R();T();var Cr=t=>`${t.source}/${encodeURIComponent(t.actor)}/${encodeURIComponent(t.name)}`,po=t=>{let e=t.split("/"),r=e.pop(),n=e.pop();if(!r||!n||!e.length)throw new Kc;return{name:decodeURIComponent(r),actor:decodeURIComponent(n),source:e.join("/")}};function mo(t=16){let e=new Uint8Array(t);return crypto.getRandomValues(e),btoa(String.fromCodePoint(...e)).replace(/\+/g,"-").replace(/\//g,"_").replace(/\=+$/,"")}function mi(t){return typeof t=="string"?{location:po(t),uri:t}:{location:{name:t.name,actor:t.actor,source:t.source},uri:Cr(t)}}function ll(t,e){return t.lastModified>e.lastModified||t.lastModified===e.lastModified&&!t.tombstone&&e.tombstone}function dl(t,e,r,n){let i=r[e];if(!(!i||!i.length))try{n[e]=t(n[e],i,!0,!1).newDocument}catch(s){throw typeof s=="object"&&s&&"name"in s&&typeof s.name=="string"&&"message"in s&&typeof s.message=="string"?s.name==="TEST_OPERATION_FAILED"?new Uc(s.message):new Ar(s.name+": "+s.message):s}}function vi(t,e){try{return t.compile(e)}catch(r){throw new Dc(r instanceof Error?r.message:void 0)}}function vo(t,e,r){t.actor!==r?.actor&&(t.allowed=t.allowed&&r?[r.actor]:void 0,t.channels=t.channels.filter(n=>e.includes(n)))}function yo(t,e){return t.allowed===void 0||t.allowed===null||!!e?.actor&&(t.actor===e.actor||t.allowed.includes(e.actor))}I();R();T();var _o=function(t,e){return _o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(r,n){r.__proto__=n}||function(r,n){for(var i in n)n.hasOwnProperty(i)&&(r[i]=n[i])},_o(t,e)};function ry(t,e){_o(t,e);function r(){this.constructor=t}t.prototype=e===null?Object.create(e):(r.prototype=e.prototype,new r)}function jr(t,e,r,n){function i(s){return s instanceof r?s:new r(function(o){o(s)})}return new(r||(r=Promise))(function(s,o){function a(m){try{d(n.next(m))}catch(f){o(f)}}function c(m){try{d(n.throw(m))}catch(f){o(f)}}function d(m){m.done?s(m.value):i(m.value).then(a,c)}d((n=n.apply(t,e||[])).next())})}function Ft(t,e){var r={label:0,sent:function(){if(s[0]&1)throw s[1];return s[1]},trys:[],ops:[]},n,i,s,o;return o={next:a(0),throw:a(1),return:a(2)},typeof Symbol=="function"&&(o[Symbol.iterator]=function(){return this}),o;function a(d){return function(m){return c([d,m])}}function c(d){if(n)throw new TypeError("Generator is already executing.");for(;r;)try{if(n=1,i&&(s=d[0]&2?i.return:d[0]?i.throw||((s=i.return)&&s.call(i),0):i.next)&&!(s=s.call(i,d[1])).done)return s;switch(i=0,s&&(d=[d[0]&2,s.value]),d[0]){case 0:case 1:s=d;break;case 4:return r.label++,{value:d[1],done:!1};case 5:r.label++,i=d[1],d=[0];continue;case 7:d=r.ops.pop(),r.trys.pop();continue;default:if(s=r.trys,!(s=s.length>0&&s[s.length-1])&&(d[0]===6||d[0]===2)){r=0;continue}if(d[0]===3&&(!s||d[1]>s[0]&&d[1]<s[3])){r.label=d[1];break}if(d[0]===6&&r.label<s[1]){r.label=s[1],s=d;break}if(s&&r.label<s[2]){r.label=s[2],r.ops.push(d);break}s[2]&&r.ops.pop(),r.trys.pop();continue}d=e.call(t,r)}catch(m){d=[6,m],i=0}finally{n=s=0}if(d[0]&5)throw d[1];return{value:d[0]?d[1]:void 0,done:!0}}}function Dr(t){var e=typeof Symbol=="function"&&Symbol.iterator,r=e&&t[e],n=0;if(r)return r.call(t);if(t&&typeof t.length=="number")return{next:function(){return t&&n>=t.length&&(t=void 0),{value:t&&t[n++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function ln(t){return this instanceof ln?(this.v=t,this):new ln(t)}function ny(t,e,r){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var n=r.apply(t,e||[]),i,s=[];return i={},o("next"),o("throw"),o("return"),i[Symbol.asyncIterator]=function(){return this},i;function o(g){n[g]&&(i[g]=function(_){return new Promise(function(E,P){s.push([g,_,E,P])>1||a(g,_)})})}function a(g,_){try{c(n[g](_))}catch(E){f(s[0][3],E)}}function c(g){g.value instanceof ln?Promise.resolve(g.value.v).then(d,m):f(s[0][2],g)}function d(g){a("next",g)}function m(g){a("throw",g)}function f(g,_){g(_),s.shift(),s.length&&a(s[0][0],s[0][1])}}var ml=function(t){ry(e,t);function e(r){var n=t.call(this,r)||this;return Object.defineProperty(n,"name",{value:"RepeaterOverflowError",enumerable:!1}),typeof Object.setPrototypeOf=="function"?Object.setPrototypeOf(n,n.constructor.prototype):n.__proto__=n.constructor.prototype,typeof Error.captureStackTrace=="function"&&Error.captureStackTrace(n,n.constructor),n}return e}(Error),jE=function(){function t(e){if(e<0)throw new RangeError("Capacity may not be less than 0");this._c=e,this._q=[]}return Object.defineProperty(t.prototype,"empty",{get:function(){return this._q.length===0},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"full",{get:function(){return this._q.length>=this._c},enumerable:!1,configurable:!0}),t.prototype.add=function(e){if(this.full)throw new Error("Buffer full");this._q.push(e)},t.prototype.remove=function(){if(this.empty)throw new Error("Buffer empty");return this._q.shift()},t}(),DE=function(){function t(e){if(e<1)throw new RangeError("Capacity may not be less than 1");this._c=e,this._q=[]}return Object.defineProperty(t.prototype,"empty",{get:function(){return this._q.length===0},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"full",{get:function(){return!1},enumerable:!1,configurable:!0}),t.prototype.add=function(e){for(;this._q.length>=this._c;)this._q.shift();this._q.push(e)},t.prototype.remove=function(){if(this.empty)throw new Error("Buffer empty");return this._q.shift()},t}(),BE=function(){function t(e){if(e<1)throw new RangeError("Capacity may not be less than 1");this._c=e,this._q=[]}return Object.defineProperty(t.prototype,"empty",{get:function(){return this._q.length===0},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"full",{get:function(){return!1},enumerable:!1,configurable:!0}),t.prototype.add=function(e){this._q.length<this._c&&this._q.push(e)},t.prototype.remove=function(){if(this.empty)throw new Error("Buffer empty");return this._q.shift()},t}();function wo(t){t!=null&&typeof t.then=="function"&&t.then(wi,wi)}var go=0,hl=1,hr=2,gi=3,bo=4,_i=1024,wi=function(){};function xr(t){var e=t.err,r=Promise.resolve(t.execution).then(function(n){if(e!=null)throw e;return n});return t.err=void 0,t.execution=r.then(function(){},function(){}),t.pending===void 0?r:t.pending.then(function(){return r})}function dr(t,e){var r=t.state>=gi;return Promise.resolve(e).then(function(n){return!r&&t.state>=bo?xr(t).then(function(i){return{value:i,done:!0}}):{value:n,done:r}})}function Eo(t,e){var r,n;if(!(t.state>=hr))if(t.state=hr,t.onnext(),t.onstop(),t.err==null&&(t.err=e),t.pushes.length===0&&(typeof t.buffer>"u"||t.buffer.empty))fn(t);else try{for(var i=Dr(t.pushes),s=i.next();!s.done;s=i.next()){var o=s.value;o.resolve()}}catch(a){r={error:a}}finally{try{s&&!s.done&&(n=i.return)&&n.call(i)}finally{if(r)throw r.error}}}function fn(t){var e,r;if(!(t.state>=gi)){t.state<hr&&Eo(t),t.state=gi,t.buffer=void 0;try{for(var n=Dr(t.nexts),i=n.next();!i.done;i=n.next()){var s=i.value,o=t.pending===void 0?xr(t):t.pending.then(function(){return xr(t)});s.resolve(dr(t,o))}}catch(a){e={error:a}}finally{try{i&&!i.done&&(r=n.return)&&r.call(n)}finally{if(e)throw e.error}}t.pushes=[],t.nexts=[]}}function pl(t){t.state>=bo||(t.state<gi&&fn(t),t.state=bo)}function iy(t,e){if(wo(e),t.pushes.length>=_i)throw new ml("No more than "+_i+" pending calls to push are allowed on a single repeater.");if(t.state>=hr)return Promise.resolve(void 0);var r=t.pending===void 0?Promise.resolve(e):t.pending.then(function(){return e});r=r.catch(function(c){t.state<hr&&(t.err=c),pl(t)});var n;if(t.nexts.length){var i=t.nexts.shift();i.resolve(dr(t,r)),t.nexts.length?n=Promise.resolve(t.nexts[0].value):typeof t.buffer<"u"&&!t.buffer.full?n=Promise.resolve(void 0):n=new Promise(function(c){return t.onnext=c})}else typeof t.buffer<"u"&&!t.buffer.full?(t.buffer.add(r),n=Promise.resolve(void 0)):n=new Promise(function(c){return t.pushes.push({resolve:c,value:r})});var s=!0,o={},a=n.catch(function(c){if(s)throw c});return o.then=function(c,d){return s=!1,Promise.prototype.then.call(n,c,d)},o.catch=function(c){return s=!1,Promise.prototype.catch.call(n,c)},o.finally=n.finally.bind(n),t.pending=r.then(function(){return a}).catch(function(c){t.err=c,pl(t)}),o}function sy(t){var e=Eo.bind(null,t),r=new Promise(function(n){return t.onstop=n});return e.then=r.then.bind(r),e.catch=r.catch.bind(r),e.finally=r.finally.bind(r),e}function oy(t){if(!(t.state>=hl)){t.state=hl;var e=iy.bind(null,t),r=sy(t);t.execution=new Promise(function(n){return n(t.executor(e,r))}),t.execution.catch(function(){return Eo(t)})}}var yi=new WeakMap,Kt=function(){function t(e,r){yi.set(this,{executor:e,buffer:r,err:void 0,state:go,pushes:[],nexts:[],pending:void 0,execution:void 0,onnext:wi,onstop:wi})}return t.prototype.next=function(e){wo(e);var r=yi.get(this);if(r===void 0)throw new Error("WeakMap error");if(r.nexts.length>=_i)throw new ml("No more than "+_i+" pending calls to next are allowed on a single repeater.");if(r.state<=go&&oy(r),r.onnext(e),typeof r.buffer<"u"&&!r.buffer.empty){var n=dr(r,r.buffer.remove());if(r.pushes.length){var i=r.pushes.shift();r.buffer.add(i.value),r.onnext=i.resolve}return n}else if(r.pushes.length){var s=r.pushes.shift();return r.onnext=s.resolve,dr(r,s.value)}else if(r.state>=hr)return fn(r),dr(r,xr(r));return new Promise(function(o){return r.nexts.push({resolve:o,value:e})})},t.prototype.return=function(e){wo(e);var r=yi.get(this);if(r===void 0)throw new Error("WeakMap error");return fn(r),r.execution=Promise.resolve(r.execution).then(function(){return e}),dr(r,xr(r))},t.prototype.throw=function(e){var r=yi.get(this);if(r===void 0)throw new Error("WeakMap error");return r.state<=go||r.state>=hr||typeof r.buffer<"u"&&!r.buffer.empty?(fn(r),r.err==null&&(r.err=e),dr(r,xr(r))):this.next(Promise.reject(e))},t.prototype[Symbol.asyncIterator]=function(){return this},t.race=ay,t.merge=uy,t.zip=cy,t.latest=fy,t}();function bi(t,e){var r,n,i=[],s=function(d){d!=null&&typeof d[Symbol.asyncIterator]=="function"?i.push(d[Symbol.asyncIterator]()):d!=null&&typeof d[Symbol.iterator]=="function"?i.push(d[Symbol.iterator]()):i.push(function(){return ny(this,arguments,function(){return Ft(this,function(g){switch(g.label){case 0:return e.yieldValues?[4,ln(d)]:[3,3];case 1:return[4,g.sent()];case 2:g.sent(),g.label=3;case 3:return e.returnValues?[4,ln(d)]:[3,5];case 4:return[2,g.sent()];case 5:return[2]}})})}())};try{for(var o=Dr(t),a=o.next();!a.done;a=o.next()){var c=a.value;s(c)}}catch(d){r={error:d}}finally{try{a&&!a.done&&(n=o.return)&&n.call(o)}finally{if(r)throw r.error}}return i}function ay(t){var e=this,r=bi(t,{returnValues:!0});return new Kt(function(n,i){return jr(e,void 0,void 0,function(){var s,o,a,c,d,m;return Ft(this,function(f){switch(f.label){case 0:if(!r.length)return i(),[2];o=!1,i.then(function(){s(),o=!0}),f.label=1;case 1:f.trys.push([1,,5,7]),c=void 0,d=0,m=function(){var g,_,E,P,S,y;return Ft(this,function(w){switch(w.label){case 0:g=d;try{for(_=(S=void 0,Dr(r)),E=_.next();!E.done;E=_.next())P=E.value,Promise.resolve(P.next()).then(function(p){p.done?(i(),a===void 0&&(a=p)):d===g&&(d++,s(p))},function(p){return i(p)})}catch(p){S={error:p}}finally{try{E&&!E.done&&(y=_.return)&&y.call(_)}finally{if(S)throw S.error}}return[4,new Promise(function(p){return s=p})];case 1:return c=w.sent(),c===void 0?[3,3]:[4,n(c.value)];case 2:w.sent(),w.label=3;case 3:return[2]}})},f.label=2;case 2:return o?[3,4]:[5,m()];case 3:return f.sent(),[3,2];case 4:return[2,a&&a.value];case 5:return i(),[4,Promise.race(r.map(function(g){return g.return&&g.return()}))];case 6:return f.sent(),[7];case 7:return[2]}})})})}function uy(t){var e=this,r=bi(t,{yieldValues:!0});return new Kt(function(n,i){return jr(e,void 0,void 0,function(){var s,o,a,c=this;return Ft(this,function(d){switch(d.label){case 0:if(!r.length)return i(),[2];s=[],o=!1,i.then(function(){var m,f;o=!0;try{for(var g=Dr(s),_=g.next();!_.done;_=g.next()){var E=_.value;E()}}catch(P){m={error:P}}finally{try{_&&!_.done&&(f=g.return)&&f.call(g)}finally{if(m)throw m.error}}}),d.label=1;case 1:return d.trys.push([1,,3,4]),[4,Promise.all(r.map(function(m,f){return jr(c,void 0,void 0,function(){var g,_;return Ft(this,function(E){switch(E.label){case 0:E.trys.push([0,,6,9]),E.label=1;case 1:return o?[3,5]:(Promise.resolve(m.next()).then(function(P){return s[f](P)},function(P){return i(P)}),[4,new Promise(function(P){s[f]=P})]);case 2:return g=E.sent(),g===void 0?[3,4]:g.done?(a=g,[2]):[4,n(g.value)];case 3:E.sent(),E.label=4;case 4:return[3,1];case 5:return[3,9];case 6:return _=m.return,_?[4,m.return()]:[3,8];case 7:_=E.sent(),E.label=8;case 8:return[7];case 9:return[2]}})})}))];case 2:return d.sent(),[2,a&&a.value];case 3:return i(),[7];case 4:return[2]}})})})}function cy(t){var e=this,r=bi(t,{returnValues:!0});return new Kt(function(n,i){return jr(e,void 0,void 0,function(){var s,o,a,c;return Ft(this,function(d){switch(d.label){case 0:if(!r.length)return i(),[2,[]];o=!1,i.then(function(){s(),o=!0}),d.label=1;case 1:d.trys.push([1,,6,8]),d.label=2;case 2:return o?[3,5]:(Promise.all(r.map(function(m){return m.next()})).then(function(m){return s(m)},function(m){return i(m)}),[4,new Promise(function(m){return s=m})]);case 3:return a=d.sent(),a===void 0?[2]:(c=a.map(function(m){return m.value}),a.some(function(m){return m.done})?[2,c]:[4,n(c)]);case 4:return d.sent(),[3,2];case 5:return[3,8];case 6:return i(),[4,Promise.all(r.map(function(m){return m.return&&m.return()}))];case 7:return d.sent(),[7];case 8:return[2]}})})})}function fy(t){var e=this,r=bi(t,{yieldValues:!0,returnValues:!0});return new Kt(function(n,i){return jr(e,void 0,void 0,function(){var s,o,a,c,d,m=this;return Ft(this,function(f){switch(f.label){case 0:if(!r.length)return i(),[2,[]];o=[],a=!1,i.then(function(){var g,_;s();try{for(var E=Dr(o),P=E.next();!P.done;P=E.next()){var S=P.value;S()}}catch(y){g={error:y}}finally{try{P&&!P.done&&(_=E.return)&&_.call(E)}finally{if(g)throw g.error}}a=!0}),f.label=1;case 1:return f.trys.push([1,,5,7]),Promise.all(r.map(function(g){return g.next()})).then(function(g){return s(g)},function(g){return i(g)}),[4,new Promise(function(g){return s=g})];case 2:return c=f.sent(),c===void 0?[2]:(d=c.map(function(g){return g.value}),c.every(function(g){return g.done})?[2,d]:[4,n(d.slice())]);case 3:return f.sent(),[4,Promise.all(r.map(function(g,_){return jr(m,void 0,void 0,function(){var E;return Ft(this,function(P){switch(P.label){case 0:if(c[_].done)return[2,c[_].value];P.label=1;case 1:return a?[3,4]:(Promise.resolve(g.next()).then(function(S){return o[_](S)},function(S){return i(S)}),[4,new Promise(function(S){return o[_]=S})]);case 2:return E=P.sent(),E===void 0?[2,c[_].value]:E.done?[2,E.value]:(d[_]=E.value,[4,n(d.slice())]);case 3:return P.sent(),[3,1];case 4:return[2]}})})}))];case 4:return[2,f.sent()];case 5:return i(),[4,Promise.all(r.map(function(g){return g.return&&g.return()}))];case 6:return f.sent(),[7];case 7:return[2]}})})})}var Yh=ls(Hh());I();R();T();var ou={};fs(ou,{JsonPatchError:()=>je,_areEquals:()=>Gn,applyOperation:()=>Sr,applyPatch:()=>Zr,applyReducer:()=>L1,deepClone:()=>D1,getValueByPointer:()=>os,validate:()=>Qh,validator:()=>as});I();R();T();I();R();T();var x1=function(){var t=function(e,r){return t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,i){n.__proto__=i}||function(n,i){for(var s in i)i.hasOwnProperty(s)&&(n[s]=i[s])},t(e,r)};return function(e,r){t(e,r);function n(){this.constructor=e}e.prototype=r===null?Object.create(r):(n.prototype=r.prototype,new n)}}(),j1=Object.prototype.hasOwnProperty;function ns(t,e){return j1.call(t,e)}function is(t){if(Array.isArray(t)){for(var e=new Array(t.length),r=0;r<e.length;r++)e[r]=""+r;return e}if(Object.keys)return Object.keys(t);var n=[];for(var i in t)ns(t,i)&&n.push(i);return n}function He(t){switch(typeof t){case"object":return JSON.parse(JSON.stringify(t));case"undefined":return null;default:return t}}function ss(t){for(var e=0,r=t.length,n;e<r;){if(n=t.charCodeAt(e),n>=48&&n<=57){e++;continue}return!1}return!0}function Nt(t){return t.indexOf("/")===-1&&t.indexOf("~")===-1?t:t.replace(/~/g,"~0").replace(/\//g,"~1")}function Mn(t){return t.replace(/~1/g,"/").replace(/~0/g,"~")}function rs(t){if(t===void 0)return!0;if(t){if(Array.isArray(t)){for(var e=0,r=t.length;e<r;e++)if(rs(t[e]))return!0}else if(typeof t=="object"){for(var n=is(t),i=n.length,s=0;s<i;s++)if(rs(t[n[s]]))return!0}}return!1}function Wh(t,e){var r=[t];for(var n in e){var i=typeof e[n]=="object"?JSON.stringify(e[n],null,2):e[n];typeof i<"u"&&r.push(n+": "+i)}return r.join(`
17
- `)}var Un=function(t){x1(e,t);function e(r,n,i,s,o){var a=this.constructor,c=t.call(this,Wh(r,{name:n,index:i,operation:s,tree:o}))||this;return c.name=n,c.index=i,c.operation=s,c.tree=o,Object.setPrototypeOf(c,a.prototype),c.message=Wh(r,{name:n,index:i,operation:s,tree:o}),c}return e}(Error);var je=Un,D1=He,Xr={add:function(t,e,r){return t[e]=this.value,{newDocument:r}},remove:function(t,e,r){var n=t[e];return delete t[e],{newDocument:r,removed:n}},replace:function(t,e,r){var n=t[e];return t[e]=this.value,{newDocument:r,removed:n}},move:function(t,e,r){var n=os(r,this.path);n&&(n=He(n));var i=Sr(r,{op:"remove",path:this.from}).removed;return Sr(r,{op:"add",path:this.path,value:i}),{newDocument:r,removed:n}},copy:function(t,e,r){var n=os(r,this.from);return Sr(r,{op:"add",path:this.path,value:He(n)}),{newDocument:r}},test:function(t,e,r){return{newDocument:r,test:Gn(t[e],this.value)}},_get:function(t,e,r){return this.value=t[e],{newDocument:r}}},B1={add:function(t,e,r){return ss(e)?t.splice(e,0,this.value):t[e]=this.value,{newDocument:r,index:e}},remove:function(t,e,r){var n=t.splice(e,1);return{newDocument:r,removed:n[0]}},replace:function(t,e,r){var n=t[e];return t[e]=this.value,{newDocument:r,removed:n}},move:Xr.move,copy:Xr.copy,test:Xr.test,_get:Xr._get};function os(t,e){if(e=="")return t;var r={op:"_get",path:e};return Sr(t,r),r.value}function Sr(t,e,r,n,i,s){if(r===void 0&&(r=!1),n===void 0&&(n=!0),i===void 0&&(i=!0),s===void 0&&(s=0),r&&(typeof r=="function"?r(e,0,t,e.path):as(e,0)),e.path===""){var o={newDocument:t};if(e.op==="add")return o.newDocument=e.value,o;if(e.op==="replace")return o.newDocument=e.value,o.removed=t,o;if(e.op==="move"||e.op==="copy")return o.newDocument=os(t,e.from),e.op==="move"&&(o.removed=t),o;if(e.op==="test"){if(o.test=Gn(t,e.value),o.test===!1)throw new je("Test operation failed","TEST_OPERATION_FAILED",s,e,t);return o.newDocument=t,o}else{if(e.op==="remove")return o.removed=t,o.newDocument=null,o;if(e.op==="_get")return e.value=t,o;if(r)throw new je("Operation `op` property is not one of operations defined in RFC-6902","OPERATION_OP_INVALID",s,e,t);return o}}else{n||(t=He(t));var a=e.path||"",c=a.split("/"),d=t,m=1,f=c.length,g=void 0,_=void 0,E=void 0;for(typeof r=="function"?E=r:E=as;;){if(_=c[m],_&&_.indexOf("~")!=-1&&(_=Mn(_)),i&&(_=="__proto__"||_=="prototype"&&m>0&&c[m-1]=="constructor"))throw new TypeError("JSON-Patch: modifying `__proto__` or `constructor/prototype` prop is banned for security reasons, if this was on purpose, please set `banPrototypeModifications` flag false and pass it to this function. More info in fast-json-patch README");if(r&&g===void 0&&(d[_]===void 0?g=c.slice(0,m).join("/"):m==f-1&&(g=e.path),g!==void 0&&E(e,0,t,g)),m++,Array.isArray(d)){if(_==="-")_=d.length;else{if(r&&!ss(_))throw new je("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index","OPERATION_PATH_ILLEGAL_ARRAY_INDEX",s,e,t);ss(_)&&(_=~~_)}if(m>=f){if(r&&e.op==="add"&&_>d.length)throw new je("The specified index MUST NOT be greater than the number of elements in the array","OPERATION_VALUE_OUT_OF_BOUNDS",s,e,t);var o=B1[e.op].call(e,d,_,t);if(o.test===!1)throw new je("Test operation failed","TEST_OPERATION_FAILED",s,e,t);return o}}else if(m>=f){var o=Xr[e.op].call(e,d,_,t);if(o.test===!1)throw new je("Test operation failed","TEST_OPERATION_FAILED",s,e,t);return o}if(d=d[_],r&&m<f&&(!d||typeof d!="object"))throw new je("Cannot perform operation at the desired path","OPERATION_PATH_UNRESOLVABLE",s,e,t)}}}function Zr(t,e,r,n,i){if(n===void 0&&(n=!0),i===void 0&&(i=!0),r&&!Array.isArray(e))throw new je("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");n||(t=He(t));for(var s=new Array(e.length),o=0,a=e.length;o<a;o++)s[o]=Sr(t,e[o],r,!0,i,o),t=s[o].newDocument;return s.newDocument=t,s}function L1(t,e,r){var n=Sr(t,e);if(n.test===!1)throw new je("Test operation failed","TEST_OPERATION_FAILED",r,e,t);return n.newDocument}function as(t,e,r,n){if(typeof t!="object"||t===null||Array.isArray(t))throw new je("Operation is not an object","OPERATION_NOT_AN_OBJECT",e,t,r);if(Xr[t.op]){if(typeof t.path!="string")throw new je("Operation `path` property is not a string","OPERATION_PATH_INVALID",e,t,r);if(t.path.indexOf("/")!==0&&t.path.length>0)throw new je('Operation `path` property must start with "/"',"OPERATION_PATH_INVALID",e,t,r);if((t.op==="move"||t.op==="copy")&&typeof t.from!="string")throw new je("Operation `from` property is not present (applicable in `move` and `copy` operations)","OPERATION_FROM_REQUIRED",e,t,r);if((t.op==="add"||t.op==="replace"||t.op==="test")&&t.value===void 0)throw new je("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_REQUIRED",e,t,r);if((t.op==="add"||t.op==="replace"||t.op==="test")&&rs(t.value))throw new je("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED",e,t,r);if(r){if(t.op=="add"){var i=t.path.split("/").length,s=n.split("/").length;if(i!==s+1&&i!==s)throw new je("Cannot perform an `add` operation at the desired path","OPERATION_PATH_CANNOT_ADD",e,t,r)}else if(t.op==="replace"||t.op==="remove"||t.op==="_get"){if(t.path!==n)throw new je("Cannot perform the operation at a path that does not exist","OPERATION_PATH_UNRESOLVABLE",e,t,r)}else if(t.op==="move"||t.op==="copy"){var o={op:"_get",path:t.from,value:void 0},a=Qh([o],r);if(a&&a.name==="OPERATION_PATH_UNRESOLVABLE")throw new je("Cannot perform the operation from a path that does not exist","OPERATION_FROM_UNRESOLVABLE",e,t,r)}}}else throw new je("Operation `op` property is not one of operations defined in RFC-6902","OPERATION_OP_INVALID",e,t,r)}function Qh(t,e,r){try{if(!Array.isArray(t))throw new je("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");if(e)Zr(He(e),He(t),r||!0);else{r=r||as;for(var n=0;n<t.length;n++)r(t[n],n,e,void 0)}}catch(i){if(i instanceof je)return i;throw i}}function Gn(t,e){if(t===e)return!0;if(t&&e&&typeof t=="object"&&typeof e=="object"){var r=Array.isArray(t),n=Array.isArray(e),i,s,o;if(r&&n){if(s=t.length,s!=e.length)return!1;for(i=s;i--!==0;)if(!Gn(t[i],e[i]))return!1;return!0}if(r!=n)return!1;var a=Object.keys(t);if(s=a.length,s!==Object.keys(e).length)return!1;for(i=s;i--!==0;)if(!e.hasOwnProperty(a[i]))return!1;for(i=s;i--!==0;)if(o=a[i],!Gn(t[o],e[o]))return!1;return!0}return t!==t&&e!==e}var fu={};fs(fu,{compare:()=>J1,generate:()=>au,observe:()=>V1,unobserve:()=>z1});I();R();T();var uu=new WeakMap,M1=function(){function t(e){this.observers=new Map,this.obj=e}return t}(),U1=function(){function t(e,r){this.callback=e,this.observer=r}return t}();function G1(t){return uu.get(t)}function F1(t,e){return t.observers.get(e)}function K1(t,e){t.observers.delete(e.callback)}function z1(t,e){e.unobserve()}function V1(t,e){var r=[],n,i=G1(t);if(!i)i=new M1(t),uu.set(t,i);else{var s=F1(i,e);n=s&&s.observer}if(n)return n;if(n={},i.value=He(t),e){n.callback=e,n.next=null;var o=function(){au(n)},a=function(){clearTimeout(n.next),n.next=setTimeout(o)};typeof window<"u"&&(window.addEventListener("mouseup",a),window.addEventListener("keyup",a),window.addEventListener("mousedown",a),window.addEventListener("keydown",a),window.addEventListener("change",a))}return n.patches=r,n.object=t,n.unobserve=function(){au(n),clearTimeout(n.next),K1(i,n),typeof window<"u"&&(window.removeEventListener("mouseup",a),window.removeEventListener("keyup",a),window.removeEventListener("mousedown",a),window.removeEventListener("keydown",a),window.removeEventListener("change",a))},i.observers.set(e,new U1(e,n)),n}function au(t,e){e===void 0&&(e=!1);var r=uu.get(t.object);cu(r.value,t.object,t.patches,"",e),t.patches.length&&Zr(r.value,t.patches);var n=t.patches;return n.length>0&&(t.patches=[],t.callback&&t.callback(n)),n}function cu(t,e,r,n,i){if(e!==t){typeof e.toJSON=="function"&&(e=e.toJSON());for(var s=is(e),o=is(t),a=!1,c=!1,d=o.length-1;d>=0;d--){var m=o[d],f=t[m];if(ns(e,m)&&!(e[m]===void 0&&f!==void 0&&Array.isArray(e)===!1)){var g=e[m];typeof f=="object"&&f!=null&&typeof g=="object"&&g!=null&&Array.isArray(f)===Array.isArray(g)?cu(f,g,r,n+"/"+Nt(m),i):f!==g&&(a=!0,i&&r.push({op:"test",path:n+"/"+Nt(m),value:He(f)}),r.push({op:"replace",path:n+"/"+Nt(m),value:He(g)}))}else Array.isArray(t)===Array.isArray(e)?(i&&r.push({op:"test",path:n+"/"+Nt(m),value:He(f)}),r.push({op:"remove",path:n+"/"+Nt(m)}),c=!0):(i&&r.push({op:"test",path:n,value:t}),r.push({op:"replace",path:n,value:e}),a=!0)}if(!(!c&&s.length==o.length))for(var d=0;d<s.length;d++){var m=s[d];!ns(t,m)&&e[m]!==void 0&&r.push({op:"add",path:n+"/"+Nt(m),value:He(e[m])})}}}function J1(t,e,r){r===void 0&&(r=!1);var n=[];return cu(t,e,n,"",r),n}var rI=Object.assign({},ou,fu,{JsonPatchError:Un,deepClone:He,escapePathComponent:Nt,unescapePathComponent:Mn});var us=class{db;source="local";tombstoneRetention=864e5;ajv;constructor(e){this.ajv=new Yh.default({strict:!1}),this.source=e?.sourceName??this.source,this.tombstoneRetention=e?.tombstoneRetention??this.tombstoneRetention;let r={name:"graffitiDb",...e?.pouchDBOptions};this.db=new fl(r.name,r),this.db.put({_id:"_design/indexes",views:{objectsPerChannelAndLastModified:{map:function(n){let i=n.lastModified.toString().padStart(15,"0");n.channels.forEach(function(s){let o=encodeURIComponent(s)+"/"+i;emit(o)})}.toString()},orphansPerActorAndLastModified:{map:function(n){if(n.channels.length===0){let i=n.lastModified.toString().padStart(15,"0"),s=encodeURIComponent(n.actor)+"/"+i;emit(s)}}.toString()},channelStatsPerActor:{map:function(n){n.tombstone||n.channels.forEach(function(i){let s=encodeURIComponent(n.actor)+"/"+encodeURIComponent(i);emit(s,n.lastModified)})}.toString(),reduce:"_stats"}}}).catch(n=>{if(!(n&&typeof n=="object"&&"name"in n&&n.name==="conflict"))throw n})}async queryByLocation(e){let r=Cr(e)+"/";return(await this.db.allDocs({startkey:r,endkey:r+"\uFFFF",include_docs:!0})).rows.map(s=>s.doc).reduce((s,o)=>(o&&s.push(o),s),[])}docId(e){return Cr(e)+"/"+mo()}get=async(...e)=>{let[r,n,i]=e,{location:s}=mi(r),a=(await this.queryByLocation(s)).filter(P=>yo(P,i));if(!a.length)throw new Jn;let c=a.reduce((P,S)=>ll(P,S)?P:S),{_id:d,_rev:m,_conflicts:f,_attachments:g,..._}=c;if(vo(_,[],i),!vi(this.ajv,n)(_))throw new Lc;return _};async deleteAtLocation(e,r=!1){let i=(await this.queryByLocation(e)).filter(f=>!f.tombstone);if(!i.length)return;let s=i.map(f=>f.lastModified).reduce((f,g)=>f>g?f:g),o=i.filter(f=>!r||f.lastModified<s),a=i.filter(f=>r&&f.lastModified===s);if(a.length){let f=a.map(_=>_._id).reduce((_,E)=>_>E?_:E),g=a.filter(_=>_._id!==f);o.push(...g)}let c=r?s:new Date().getTime(),d=await this.db.bulkDocs(o.map(f=>({...f,tombstone:!0,lastModified:c}))),m;for(let f of d)if("ok"in f){let{id:g}=f,_=o.find(E=>E._id===g);if(_){let{_id:E,_rev:P,_conflicts:S,_attachments:y,...w}=_;m={...w,tombstone:!0,lastModified:c};break}}return m}delete=async(...e)=>{let[r,n]=e,{location:i}=mi(r);if(i.actor!==n.actor)throw new tn;let s=await this.deleteAtLocation(i);if(!s)throw new Jn;return s};put=async(...e)=>{let[r,n]=e;if(r.actor&&r.actor!==n.actor)throw new tn;if(r.source&&r.source!==this.source)throw new tn("Putting an object that does not match this source");let i={value:r.value,channels:r.channels,allowed:r.allowed,name:r.name??mo(),source:this.source,actor:n.actor,tombstone:!1,lastModified:new Date().getTime()};await this.db.put({_id:this.docId(i),...i});let s=await this.deleteAtLocation(i,!0);return s||{...i,value:{},channels:[],allowed:void 0,tombstone:!0}};patch=async(...e)=>{let[r,n,i]=e,{location:s}=mi(n);if(s.actor!==i.actor)throw new tn;let o=await this.get(n,{},i);if(o.tombstone)throw new Jn("The object you are trying to patch has been deleted");let a={...o};for(let c of["value","channels","allowed"])dl(Zr,c,r,a);if(typeof a.value!="object"||Array.isArray(a.value)||!a.value)throw new Ar("value is no longer an object");if(!Array.isArray(a.channels)||!a.channels.every(c=>typeof c=="string"))throw new Ar("channels are no longer an array of strings");if(a.allowed&&(!Array.isArray(a.allowed)||!a.allowed.every(c=>typeof c=="string")))throw new Ar("allowed list is not an array of strings");return a.lastModified=new Date().getTime(),await this.db.put({...a,_id:this.docId(a)}),await this.deleteAtLocation(a,!0),{...o,tombstone:!0,lastModified:a.lastModified}};queryLastModifiedSuffixes(e){let r="",n="\uFFFF";if(typeof e=="object"&&e.properties?.lastModified&&typeof e.properties.lastModified=="object"){let i=e.properties.lastModified,s=i.minimum,o=i.exclusiveMinimum,a;o!==void 0?(a=Math.ceil(o),a===o&&a++):s!==void 0&&(a=Math.ceil(s)),a!==void 0&&(r=a.toString().padStart(15,"0"));let c=i.maximum,d=i.exclusiveMaximum,m;d!==void 0?(m=Math.floor(d),m===d&&m--):c!==void 0&&(m=Math.floor(c)),m!==void 0&&(n=m.toString().padStart(15,"0"))}return{startKeySuffix:r,endKeySuffix:n}}discover=(...e)=>{let[r,n,i]=e,s=vi(this.ajv,n),{startKeySuffix:o,endKeySuffix:a}=this.queryLastModifiedSuffixes(n);return new Kt(async(d,m)=>{let f=new Set;for(let g of r){let _=encodeURIComponent(g)+"/",E=_+o,P=_+a,S=await this.db.query("indexes/objectsPerChannelAndLastModified",{startkey:E,endkey:P,include_docs:!0});for(let y of S.rows){let w=y.doc;if(!w)continue;let{_id:p,_rev:h,...v}=w;f.has(p)||(f.add(p),yo(w,i)&&(vo(v,r,i),s(v)&&await d({value:v})))}}return m(),{tombstoneRetention:this.tombstoneRetention}})};recoverOrphans=(e,r)=>{let n=vi(this.ajv,e),{startKeySuffix:i,endKeySuffix:s}=this.queryLastModifiedSuffixes(e),o=encodeURIComponent(r.actor)+"/",a=o+i,c=o+s;return new Kt(async(m,f)=>{let g=await this.db.query("indexes/orphansPerActorAndLastModified",{startkey:a,endkey:c,include_docs:!0});for(let _ of g.rows){let E=_.doc;if(!E)continue;let{_id:P,_rev:S,...y}=E;n(y)&&await m({value:y})}return f(),{tombstoneRetention:this.tombstoneRetention}})};channelStats=e=>new Kt(async(n,i)=>{let s=encodeURIComponent(e.actor)+"/",o=await this.db.query("indexes/channelStatsPerActor",{startkey:s,endkey:s+"\uFFFF",reduce:!0,group:!0});for(let a of o.rows){let c=a.key.split("/")[1];if(typeof c!="string")continue;let{count:d,max:m}=a.value;typeof d!="number"||typeof m!="number"||await n({value:{channel:decodeURIComponent(c),count:d,lastModified:m}})}i()})};var Xh=class extends Cc{locationToUri=Cr;uriToLocation=po;sessionManagerLocal=new Hn;login=this.sessionManagerLocal.login.bind(this.sessionManagerLocal);logout=this.sessionManagerLocal.logout.bind(this.sessionManagerLocal);sessionEvents=this.sessionManagerLocal.sessionEvents;put;get;patch;delete;discover;recoverOrphans;channelStats;constructor(e){super();let r=new us(e);this.put=r.put.bind(r),this.get=r.get.bind(r),this.patch=r.patch.bind(r),this.delete=r.delete.bind(r),this.discover=r.discover.bind(r),this.recoverOrphans=r.recoverOrphans.bind(r),this.channelStats=r.channelStats.bind(r)}};export{Xh as GraffitiLocal};
17
+ `)}var Un=function(t){x1(e,t);function e(r,n,i,s,o){var a=this.constructor,c=t.call(this,Wh(r,{name:n,index:i,operation:s,tree:o}))||this;return c.name=n,c.index=i,c.operation=s,c.tree=o,Object.setPrototypeOf(c,a.prototype),c.message=Wh(r,{name:n,index:i,operation:s,tree:o}),c}return e}(Error);var je=Un,D1=He,Xr={add:function(t,e,r){return t[e]=this.value,{newDocument:r}},remove:function(t,e,r){var n=t[e];return delete t[e],{newDocument:r,removed:n}},replace:function(t,e,r){var n=t[e];return t[e]=this.value,{newDocument:r,removed:n}},move:function(t,e,r){var n=os(r,this.path);n&&(n=He(n));var i=Sr(r,{op:"remove",path:this.from}).removed;return Sr(r,{op:"add",path:this.path,value:i}),{newDocument:r,removed:n}},copy:function(t,e,r){var n=os(r,this.from);return Sr(r,{op:"add",path:this.path,value:He(n)}),{newDocument:r}},test:function(t,e,r){return{newDocument:r,test:Gn(t[e],this.value)}},_get:function(t,e,r){return this.value=t[e],{newDocument:r}}},B1={add:function(t,e,r){return ss(e)?t.splice(e,0,this.value):t[e]=this.value,{newDocument:r,index:e}},remove:function(t,e,r){var n=t.splice(e,1);return{newDocument:r,removed:n[0]}},replace:function(t,e,r){var n=t[e];return t[e]=this.value,{newDocument:r,removed:n}},move:Xr.move,copy:Xr.copy,test:Xr.test,_get:Xr._get};function os(t,e){if(e=="")return t;var r={op:"_get",path:e};return Sr(t,r),r.value}function Sr(t,e,r,n,i,s){if(r===void 0&&(r=!1),n===void 0&&(n=!0),i===void 0&&(i=!0),s===void 0&&(s=0),r&&(typeof r=="function"?r(e,0,t,e.path):as(e,0)),e.path===""){var o={newDocument:t};if(e.op==="add")return o.newDocument=e.value,o;if(e.op==="replace")return o.newDocument=e.value,o.removed=t,o;if(e.op==="move"||e.op==="copy")return o.newDocument=os(t,e.from),e.op==="move"&&(o.removed=t),o;if(e.op==="test"){if(o.test=Gn(t,e.value),o.test===!1)throw new je("Test operation failed","TEST_OPERATION_FAILED",s,e,t);return o.newDocument=t,o}else{if(e.op==="remove")return o.removed=t,o.newDocument=null,o;if(e.op==="_get")return e.value=t,o;if(r)throw new je("Operation `op` property is not one of operations defined in RFC-6902","OPERATION_OP_INVALID",s,e,t);return o}}else{n||(t=He(t));var a=e.path||"",c=a.split("/"),d=t,m=1,f=c.length,g=void 0,_=void 0,E=void 0;for(typeof r=="function"?E=r:E=as;;){if(_=c[m],_&&_.indexOf("~")!=-1&&(_=Mn(_)),i&&(_=="__proto__"||_=="prototype"&&m>0&&c[m-1]=="constructor"))throw new TypeError("JSON-Patch: modifying `__proto__` or `constructor/prototype` prop is banned for security reasons, if this was on purpose, please set `banPrototypeModifications` flag false and pass it to this function. More info in fast-json-patch README");if(r&&g===void 0&&(d[_]===void 0?g=c.slice(0,m).join("/"):m==f-1&&(g=e.path),g!==void 0&&E(e,0,t,g)),m++,Array.isArray(d)){if(_==="-")_=d.length;else{if(r&&!ss(_))throw new je("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index","OPERATION_PATH_ILLEGAL_ARRAY_INDEX",s,e,t);ss(_)&&(_=~~_)}if(m>=f){if(r&&e.op==="add"&&_>d.length)throw new je("The specified index MUST NOT be greater than the number of elements in the array","OPERATION_VALUE_OUT_OF_BOUNDS",s,e,t);var o=B1[e.op].call(e,d,_,t);if(o.test===!1)throw new je("Test operation failed","TEST_OPERATION_FAILED",s,e,t);return o}}else if(m>=f){var o=Xr[e.op].call(e,d,_,t);if(o.test===!1)throw new je("Test operation failed","TEST_OPERATION_FAILED",s,e,t);return o}if(d=d[_],r&&m<f&&(!d||typeof d!="object"))throw new je("Cannot perform operation at the desired path","OPERATION_PATH_UNRESOLVABLE",s,e,t)}}}function Zr(t,e,r,n,i){if(n===void 0&&(n=!0),i===void 0&&(i=!0),r&&!Array.isArray(e))throw new je("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");n||(t=He(t));for(var s=new Array(e.length),o=0,a=e.length;o<a;o++)s[o]=Sr(t,e[o],r,!0,i,o),t=s[o].newDocument;return s.newDocument=t,s}function L1(t,e,r){var n=Sr(t,e);if(n.test===!1)throw new je("Test operation failed","TEST_OPERATION_FAILED",r,e,t);return n.newDocument}function as(t,e,r,n){if(typeof t!="object"||t===null||Array.isArray(t))throw new je("Operation is not an object","OPERATION_NOT_AN_OBJECT",e,t,r);if(Xr[t.op]){if(typeof t.path!="string")throw new je("Operation `path` property is not a string","OPERATION_PATH_INVALID",e,t,r);if(t.path.indexOf("/")!==0&&t.path.length>0)throw new je('Operation `path` property must start with "/"',"OPERATION_PATH_INVALID",e,t,r);if((t.op==="move"||t.op==="copy")&&typeof t.from!="string")throw new je("Operation `from` property is not present (applicable in `move` and `copy` operations)","OPERATION_FROM_REQUIRED",e,t,r);if((t.op==="add"||t.op==="replace"||t.op==="test")&&t.value===void 0)throw new je("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_REQUIRED",e,t,r);if((t.op==="add"||t.op==="replace"||t.op==="test")&&rs(t.value))throw new je("Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)","OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED",e,t,r);if(r){if(t.op=="add"){var i=t.path.split("/").length,s=n.split("/").length;if(i!==s+1&&i!==s)throw new je("Cannot perform an `add` operation at the desired path","OPERATION_PATH_CANNOT_ADD",e,t,r)}else if(t.op==="replace"||t.op==="remove"||t.op==="_get"){if(t.path!==n)throw new je("Cannot perform the operation at a path that does not exist","OPERATION_PATH_UNRESOLVABLE",e,t,r)}else if(t.op==="move"||t.op==="copy"){var o={op:"_get",path:t.from,value:void 0},a=Qh([o],r);if(a&&a.name==="OPERATION_PATH_UNRESOLVABLE")throw new je("Cannot perform the operation from a path that does not exist","OPERATION_FROM_UNRESOLVABLE",e,t,r)}}}else throw new je("Operation `op` property is not one of operations defined in RFC-6902","OPERATION_OP_INVALID",e,t,r)}function Qh(t,e,r){try{if(!Array.isArray(t))throw new je("Patch sequence must be an array","SEQUENCE_NOT_AN_ARRAY");if(e)Zr(He(e),He(t),r||!0);else{r=r||as;for(var n=0;n<t.length;n++)r(t[n],n,e,void 0)}}catch(i){if(i instanceof je)return i;throw i}}function Gn(t,e){if(t===e)return!0;if(t&&e&&typeof t=="object"&&typeof e=="object"){var r=Array.isArray(t),n=Array.isArray(e),i,s,o;if(r&&n){if(s=t.length,s!=e.length)return!1;for(i=s;i--!==0;)if(!Gn(t[i],e[i]))return!1;return!0}if(r!=n)return!1;var a=Object.keys(t);if(s=a.length,s!==Object.keys(e).length)return!1;for(i=s;i--!==0;)if(!e.hasOwnProperty(a[i]))return!1;for(i=s;i--!==0;)if(o=a[i],!Gn(t[o],e[o]))return!1;return!0}return t!==t&&e!==e}var fu={};fs(fu,{compare:()=>J1,generate:()=>au,observe:()=>V1,unobserve:()=>z1});I();R();T();var uu=new WeakMap,M1=function(){function t(e){this.observers=new Map,this.obj=e}return t}(),U1=function(){function t(e,r){this.callback=e,this.observer=r}return t}();function G1(t){return uu.get(t)}function F1(t,e){return t.observers.get(e)}function K1(t,e){t.observers.delete(e.callback)}function z1(t,e){e.unobserve()}function V1(t,e){var r=[],n,i=G1(t);if(!i)i=new M1(t),uu.set(t,i);else{var s=F1(i,e);n=s&&s.observer}if(n)return n;if(n={},i.value=He(t),e){n.callback=e,n.next=null;var o=function(){au(n)},a=function(){clearTimeout(n.next),n.next=setTimeout(o)};typeof window<"u"&&(window.addEventListener("mouseup",a),window.addEventListener("keyup",a),window.addEventListener("mousedown",a),window.addEventListener("keydown",a),window.addEventListener("change",a))}return n.patches=r,n.object=t,n.unobserve=function(){au(n),clearTimeout(n.next),K1(i,n),typeof window<"u"&&(window.removeEventListener("mouseup",a),window.removeEventListener("keyup",a),window.removeEventListener("mousedown",a),window.removeEventListener("keydown",a),window.removeEventListener("change",a))},i.observers.set(e,new U1(e,n)),n}function au(t,e){e===void 0&&(e=!1);var r=uu.get(t.object);cu(r.value,t.object,t.patches,"",e),t.patches.length&&Zr(r.value,t.patches);var n=t.patches;return n.length>0&&(t.patches=[],t.callback&&t.callback(n)),n}function cu(t,e,r,n,i){if(e!==t){typeof e.toJSON=="function"&&(e=e.toJSON());for(var s=is(e),o=is(t),a=!1,c=!1,d=o.length-1;d>=0;d--){var m=o[d],f=t[m];if(ns(e,m)&&!(e[m]===void 0&&f!==void 0&&Array.isArray(e)===!1)){var g=e[m];typeof f=="object"&&f!=null&&typeof g=="object"&&g!=null&&Array.isArray(f)===Array.isArray(g)?cu(f,g,r,n+"/"+Nt(m),i):f!==g&&(a=!0,i&&r.push({op:"test",path:n+"/"+Nt(m),value:He(f)}),r.push({op:"replace",path:n+"/"+Nt(m),value:He(g)}))}else Array.isArray(t)===Array.isArray(e)?(i&&r.push({op:"test",path:n+"/"+Nt(m),value:He(f)}),r.push({op:"remove",path:n+"/"+Nt(m)}),c=!0):(i&&r.push({op:"test",path:n,value:t}),r.push({op:"replace",path:n,value:e}),a=!0)}if(!(!c&&s.length==o.length))for(var d=0;d<s.length;d++){var m=s[d];!ns(t,m)&&e[m]!==void 0&&r.push({op:"add",path:n+"/"+Nt(m),value:He(e[m])})}}}function J1(t,e,r){r===void 0&&(r=!1);var n=[];return cu(t,e,n,"",r),n}var rI=Object.assign({},ou,fu,{JsonPatchError:Un,deepClone:He,escapePathComponent:Nt,unescapePathComponent:Mn});var us=class{db;source="local";tombstoneRetention=864e5;ajv;constructor(e){this.ajv=e?.ajv??new Yh.default({strict:!1}),this.source=e?.sourceName??this.source,this.tombstoneRetention=e?.tombstoneRetention??this.tombstoneRetention;let r={name:"graffitiDb",...e?.pouchDBOptions};this.db=new fl(r.name,r),this.db.put({_id:"_design/indexes",views:{objectsPerChannelAndLastModified:{map:function(n){let i=n.lastModified.toString().padStart(15,"0");n.channels.forEach(function(s){let o=encodeURIComponent(s)+"/"+i;emit(o)})}.toString()},orphansPerActorAndLastModified:{map:function(n){if(n.channels.length===0){let i=n.lastModified.toString().padStart(15,"0"),s=encodeURIComponent(n.actor)+"/"+i;emit(s)}}.toString()},channelStatsPerActor:{map:function(n){n.tombstone||n.channels.forEach(function(i){let s=encodeURIComponent(n.actor)+"/"+encodeURIComponent(i);emit(s,n.lastModified)})}.toString(),reduce:"_stats"}}}).catch(n=>{if(!(n&&typeof n=="object"&&"name"in n&&n.name==="conflict"))throw n})}async queryByLocation(e){let r=Cr(e)+"/";return(await this.db.allDocs({startkey:r,endkey:r+"\uFFFF",include_docs:!0})).rows.map(s=>s.doc).reduce((s,o)=>(o&&s.push(o),s),[])}docId(e){return Cr(e)+"/"+mo()}get=async(...e)=>{let[r,n,i]=e,{location:s}=mi(r),a=(await this.queryByLocation(s)).filter(P=>yo(P,i));if(!a.length)throw new Jn;let c=a.reduce((P,S)=>ll(P,S)?P:S),{_id:d,_rev:m,_conflicts:f,_attachments:g,..._}=c;if(vo(_,[],i),!vi(this.ajv,n)(_))throw new Lc;return _};async deleteAtLocation(e,r=!1){let i=(await this.queryByLocation(e)).filter(f=>!f.tombstone);if(!i.length)return;let s=i.map(f=>f.lastModified).reduce((f,g)=>f>g?f:g),o=i.filter(f=>!r||f.lastModified<s),a=i.filter(f=>r&&f.lastModified===s);if(a.length){let f=a.map(_=>_._id).reduce((_,E)=>_>E?_:E),g=a.filter(_=>_._id!==f);o.push(...g)}let c=r?s:new Date().getTime(),d=await this.db.bulkDocs(o.map(f=>({...f,tombstone:!0,lastModified:c}))),m;for(let f of d)if("ok"in f){let{id:g}=f,_=o.find(E=>E._id===g);if(_){let{_id:E,_rev:P,_conflicts:S,_attachments:y,...w}=_;m={...w,tombstone:!0,lastModified:c};break}}return m}delete=async(...e)=>{let[r,n]=e,{location:i}=mi(r);if(i.actor!==n.actor)throw new tn;let s=await this.deleteAtLocation(i);if(!s)throw new Jn;return s};put=async(...e)=>{let[r,n]=e;if(r.actor&&r.actor!==n.actor)throw new tn;if(r.source&&r.source!==this.source)throw new tn("Putting an object that does not match this source");let i={value:r.value,channels:r.channels,allowed:r.allowed,name:r.name??mo(),source:this.source,actor:n.actor,tombstone:!1,lastModified:new Date().getTime()};await this.db.put({_id:this.docId(i),...i});let s=await this.deleteAtLocation(i,!0);return s||{...i,value:{},channels:[],allowed:void 0,tombstone:!0}};patch=async(...e)=>{let[r,n,i]=e,{location:s}=mi(n);if(s.actor!==i.actor)throw new tn;let o=await this.get(n,{},i);if(o.tombstone)throw new Jn("The object you are trying to patch has been deleted");let a={...o};for(let c of["value","channels","allowed"])dl(Zr,c,r,a);if(typeof a.value!="object"||Array.isArray(a.value)||!a.value)throw new Ar("value is no longer an object");if(!Array.isArray(a.channels)||!a.channels.every(c=>typeof c=="string"))throw new Ar("channels are no longer an array of strings");if(a.allowed&&(!Array.isArray(a.allowed)||!a.allowed.every(c=>typeof c=="string")))throw new Ar("allowed list is not an array of strings");return a.lastModified=new Date().getTime(),await this.db.put({...a,_id:this.docId(a)}),await this.deleteAtLocation(a,!0),{...o,tombstone:!0,lastModified:a.lastModified}};queryLastModifiedSuffixes(e){let r="",n="\uFFFF";if(typeof e=="object"&&e.properties?.lastModified&&typeof e.properties.lastModified=="object"){let i=e.properties.lastModified,s=i.minimum,o=i.exclusiveMinimum,a;o!==void 0?(a=Math.ceil(o),a===o&&a++):s!==void 0&&(a=Math.ceil(s)),a!==void 0&&(r=a.toString().padStart(15,"0"));let c=i.maximum,d=i.exclusiveMaximum,m;d!==void 0?(m=Math.floor(d),m===d&&m--):c!==void 0&&(m=Math.floor(c)),m!==void 0&&(n=m.toString().padStart(15,"0"))}return{startKeySuffix:r,endKeySuffix:n}}discover=(...e)=>{let[r,n,i]=e,s=vi(this.ajv,n),{startKeySuffix:o,endKeySuffix:a}=this.queryLastModifiedSuffixes(n);return new Kt(async(d,m)=>{let f=new Set;for(let g of r){let _=encodeURIComponent(g)+"/",E=_+o,P=_+a,S=await this.db.query("indexes/objectsPerChannelAndLastModified",{startkey:E,endkey:P,include_docs:!0});for(let y of S.rows){let w=y.doc;if(!w)continue;let{_id:p,_rev:h,...v}=w;f.has(p)||(f.add(p),yo(w,i)&&(vo(v,r,i),s(v)&&await d({value:v})))}}return m(),{tombstoneRetention:this.tombstoneRetention}})};recoverOrphans=(e,r)=>{let n=vi(this.ajv,e),{startKeySuffix:i,endKeySuffix:s}=this.queryLastModifiedSuffixes(e),o=encodeURIComponent(r.actor)+"/",a=o+i,c=o+s;return new Kt(async(m,f)=>{let g=await this.db.query("indexes/orphansPerActorAndLastModified",{startkey:a,endkey:c,include_docs:!0});for(let _ of g.rows){let E=_.doc;if(!E)continue;let{_id:P,_rev:S,...y}=E;n(y)&&await m({value:y})}return f(),{tombstoneRetention:this.tombstoneRetention}})};channelStats=e=>new Kt(async(n,i)=>{let s=encodeURIComponent(e.actor)+"/",o=await this.db.query("indexes/channelStatsPerActor",{startkey:s,endkey:s+"\uFFFF",reduce:!0,group:!0});for(let a of o.rows){let c=a.key.split("/")[1];if(typeof c!="string")continue;let{count:d,max:m}=a.value;typeof d!="number"||typeof m!="number"||await n({value:{channel:decodeURIComponent(c),count:d,lastModified:m}})}i()})};var Xh=class extends Cc{locationToUri=Cr;uriToLocation=po;sessionManagerLocal=new Hn;login=this.sessionManagerLocal.login.bind(this.sessionManagerLocal);logout=this.sessionManagerLocal.logout.bind(this.sessionManagerLocal);sessionEvents=this.sessionManagerLocal.sessionEvents;put;get;patch;delete;discover;recoverOrphans;channelStats;constructor(e){super();let r=new us(e);this.put=r.put.bind(r),this.get=r.get.bind(r),this.patch=r.patch.bind(r),this.delete=r.delete.bind(r),this.discover=r.discover.bind(r),this.recoverOrphans=r.recoverOrphans.bind(r),this.channelStats=r.channelStats.bind(r)}};export{Xh as GraffitiLocal};
18
18
  /*! Bundled license information:
19
19
 
20
20
  @jspm/core/nodelibs/browser/chunk-DtuTasat.js: