@graffiti-garden/implementation-local 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/database.browser.js +1 -1
- package/dist/database.cjs.js +1 -1
- package/dist/database.js +1 -1
- package/dist/index.browser.js +5 -5
- package/dist/index.cjs.js +1 -1
- package/dist/index.js +1 -1
- package/dist/src/database.d.ts.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/database.ts +19 -22
- package/src/index.ts +2 -0
package/dist/index.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var t=require("@graffiti-garden/api"),e=require("ajv-draft-04"),n=require("pouchdb"),o=require("@repeaterjs/repeater"),i=require("fast-json-patch");class s{sessionEvents=new EventTarget;constructor(){(async()=>{await Promise.resolve();for(const t of this.getLoggedInActors()){const e=new CustomEvent("login",{detail:{session:{actor:t}}});this.sessionEvents.dispatchEvent(e)}const t=new CustomEvent("initialized");this.sessionEvents.dispatchEvent(t)})()}loggedInActors=[];getLoggedInActors(){if("undefined"!=typeof window){const t=window.localStorage.getItem("graffiti-actor");return t?t.split(",").map(decodeURIComponent):[]}return this.loggedInActors}setLoggedInActors(t){"undefined"!=typeof window?window.localStorage.setItem("graffiti-actor",t.map(encodeURIComponent).join(",")):this.loggedInActors=t}login=async t=>{let e,n=t?.actor;if(!n&&"undefined"!=typeof window){const t=window.prompt("This is an insecure implementation of the Graffiti API for *demo purposes only*. Do not store any sensitive information here. \n\n Simply choose a username to log in.");t&&(n=t)}if(n){const t=this.getLoggedInActors();t.includes(n)||this.setLoggedInActors([...t,n]),e={session:{actor:n}}}else e={error:new Error("No actor ID provided to login")};const o=new CustomEvent("login",{detail:e});this.sessionEvents.dispatchEvent(o)};logout=async t=>{const e=this.getLoggedInActors(),n=e.includes(t.actor);n&&this.setLoggedInActors(e.filter((e=>e!==t.actor)));const o=n?{actor:t.actor}:{actor:t.actor,error:new Error("Not logged in with that actor")},i=new CustomEvent("logout",{detail:o});this.sessionEvents.dispatchEvent(i)}}const r=t=>`${t.source}/${encodeURIComponent(t.actor)}/${encodeURIComponent(t.name)}`,a=e=>{const n=e.split("/"),o=n.pop(),i=n.pop();if(!o||!i||!n.length)throw new t.GraffitiErrorInvalidUri;return{name:decodeURIComponent(o),actor:decodeURIComponent(i),source:n.join("/")}};function c(t=16){const e=new Uint8Array(t);crypto.getRandomValues(e);return btoa(String.fromCodePoint(...e)).replace(/\+/g,"-").replace(/\//g,"_").replace(/\=+$/,"")}function d(t){return"string"==typeof t?{location:a(t),uri:t}:{location:{name:t.name,actor:t.actor,source:t.source},uri:r(t)}}function l(e,n,o,i){const s=o[n];if(s&&s.length)try{i[n]=e(i[n],s,!0,!1).newDocument}catch(e){throw"object"==typeof e&&e&&"name"in e&&"string"==typeof e.name&&"message"in e&&"string"==typeof e.message?"TEST_OPERATION_FAILED"===e.name?new t.GraffitiErrorPatchTestFailed(e.message):new t.GraffitiErrorPatchError(e.name+": "+e.message):e}}function h(e,n){try{return e.compile(n)}catch(e){throw new t.GraffitiErrorInvalidSchema(e instanceof Error?e.message:void 0)}}function f(t,e,n){t.actor!==n?.actor&&(t.allowed=t.allowed&&n?[n.actor]:void 0,t.channels=t.channels.filter((t=>e.includes(t))))}function u(t,e){return void 0===t.allowed||!!e?.actor&&(t.actor===e.actor||t.allowed.includes(e.actor))}class w{db;source="local";tombstoneRetention=864e5;ajv;constructor(t,o){this.ajv=o??new e({strict:!1}),this.source=t?.sourceName??this.source,this.tombstoneRetention=t?.tombstoneRetention??this.tombstoneRetention;const i={name:"graffitiDb",...t?.pouchDBOptions};this.db=new n(i.name,i),this.db.put({_id:"_design/index3",views:{byChannelAndLastModified:{map:function(t){const e=t.lastModified.toString().padStart(15,"0");t.channels.forEach((function(t){const n=encodeURIComponent(t)+"/"+e;emit(n)}))}.toString()}}}).catch((t=>{if(!t||"object"!=typeof t||!("name"in t)||"conflict"!==t.name)throw t}))}async queryByLocation(t){const e=r(t)+"/";return(await this.db.allDocs({startkey:e,endkey:e+"",include_docs:!0})).rows.map((t=>t.doc)).reduce(((t,e)=>(e&&t.push(e),t)),[]).filter((t=>!t.tombstone))}docId(t){return r(t)+"/"+c()}get=async(...e)=>{const[n,o,i]=e,{location:s}=d(n),r=await this.queryByLocation(s);if(!r.length)throw new t.GraffitiErrorNotFound;const a=r.reduce(((t,e)=>t.lastModified>e.lastModified?t:e)),{_id:c,_rev:l,...w}=a;if(!u(a,i))throw new t.GraffitiErrorNotFound;f(w,[],i);if(!h(this.ajv,o)(w))throw new t.GraffitiErrorSchemaMismatch;return w};async deleteAtLocation(t,e=!1){const n=await this.queryByLocation(t);if(!n.length)return;const o=n.map((t=>t.lastModified)).reduce(((t,e)=>t>e?t:e)),i=n.filter((t=>!e||t.lastModified<o)),s=n.filter((t=>e&&t.lastModified===o));if(s.length){const t=s.map((t=>t._id)).reduce(((t,e)=>t>e?t:e)),e=s.filter((e=>e._id!==t));i.push(...e)}const r=e?o:(new Date).getTime()
|
|
1
|
+
"use strict";var t=require("@graffiti-garden/api"),e=require("ajv-draft-04"),n=require("pouchdb"),o=require("@repeaterjs/repeater"),i=require("fast-json-patch");class s{sessionEvents=new EventTarget;constructor(){(async()=>{await Promise.resolve();for(const t of this.getLoggedInActors()){const e=new CustomEvent("login",{detail:{session:{actor:t}}});this.sessionEvents.dispatchEvent(e)}const t=new CustomEvent("initialized");this.sessionEvents.dispatchEvent(t)})()}loggedInActors=[];getLoggedInActors(){if("undefined"!=typeof window){const t=window.localStorage.getItem("graffiti-actor");return t?t.split(",").map(decodeURIComponent):[]}return this.loggedInActors}setLoggedInActors(t){"undefined"!=typeof window?window.localStorage.setItem("graffiti-actor",t.map(encodeURIComponent).join(",")):this.loggedInActors=t}login=async t=>{let e,n=t?.actor;if(!n&&"undefined"!=typeof window){const t=window.prompt("This is an insecure implementation of the Graffiti API for *demo purposes only*. Do not store any sensitive information here. \n\n Simply choose a username to log in.");t&&(n=t)}if(n){const t=this.getLoggedInActors();t.includes(n)||this.setLoggedInActors([...t,n]),e={session:{actor:n}}}else e={error:new Error("No actor ID provided to login")};const o=new CustomEvent("login",{detail:e});this.sessionEvents.dispatchEvent(o)};logout=async t=>{const e=this.getLoggedInActors(),n=e.includes(t.actor);n&&this.setLoggedInActors(e.filter((e=>e!==t.actor)));const o=n?{actor:t.actor}:{actor:t.actor,error:new Error("Not logged in with that actor")},i=new CustomEvent("logout",{detail:o});this.sessionEvents.dispatchEvent(i)}}const r=t=>`${t.source}/${encodeURIComponent(t.actor)}/${encodeURIComponent(t.name)}`,a=e=>{const n=e.split("/"),o=n.pop(),i=n.pop();if(!o||!i||!n.length)throw new t.GraffitiErrorInvalidUri;return{name:decodeURIComponent(o),actor:decodeURIComponent(i),source:n.join("/")}};function c(t=16){const e=new Uint8Array(t);crypto.getRandomValues(e);return btoa(String.fromCodePoint(...e)).replace(/\+/g,"-").replace(/\//g,"_").replace(/\=+$/,"")}function d(t){return"string"==typeof t?{location:a(t),uri:t}:{location:{name:t.name,actor:t.actor,source:t.source},uri:r(t)}}function l(e,n,o,i){const s=o[n];if(s&&s.length)try{i[n]=e(i[n],s,!0,!1).newDocument}catch(e){throw"object"==typeof e&&e&&"name"in e&&"string"==typeof e.name&&"message"in e&&"string"==typeof e.message?"TEST_OPERATION_FAILED"===e.name?new t.GraffitiErrorPatchTestFailed(e.message):new t.GraffitiErrorPatchError(e.name+": "+e.message):e}}function h(e,n){try{return e.compile(n)}catch(e){throw new t.GraffitiErrorInvalidSchema(e instanceof Error?e.message:void 0)}}function f(t,e,n){t.actor!==n?.actor&&(t.allowed=t.allowed&&n?[n.actor]:void 0,t.channels=t.channels.filter((t=>e.includes(t))))}function u(t,e){return void 0===t.allowed||!!e?.actor&&(t.actor===e.actor||t.allowed.includes(e.actor))}class w{db;source="local";tombstoneRetention=864e5;ajv;constructor(t,o){this.ajv=o??new e({strict:!1}),this.source=t?.sourceName??this.source,this.tombstoneRetention=t?.tombstoneRetention??this.tombstoneRetention;const i={name:"graffitiDb",...t?.pouchDBOptions};this.db=new n(i.name,i),this.db.put({_id:"_design/index3",views:{byChannelAndLastModified:{map:function(t){const e=t.lastModified.toString().padStart(15,"0");t.channels.forEach((function(t){const n=encodeURIComponent(t)+"/"+e;emit(n)}))}.toString()}}}).catch((t=>{if(!t||"object"!=typeof t||!("name"in t)||"conflict"!==t.name)throw t}))}async queryByLocation(t){const e=r(t)+"/";return(await this.db.allDocs({startkey:e,endkey:e+"",include_docs:!0})).rows.map((t=>t.doc)).reduce(((t,e)=>(e&&t.push(e),t)),[]).filter((t=>!t.tombstone))}docId(t){return r(t)+"/"+c()}get=async(...e)=>{const[n,o,i]=e,{location:s}=d(n),r=await this.queryByLocation(s);if(!r.length)throw new t.GraffitiErrorNotFound;const a=r.reduce(((t,e)=>t.lastModified>e.lastModified?t:e)),{_id:c,_rev:l,...w}=a;if(!u(a,i))throw new t.GraffitiErrorNotFound;f(w,[],i);if(!h(this.ajv,o)(w))throw new t.GraffitiErrorSchemaMismatch;return w};async deleteAtLocation(t,e=!1){const n=await this.queryByLocation(t);if(!n.length)return;const o=n.map((t=>t.lastModified)).reduce(((t,e)=>t>e?t:e)),i=n.filter((t=>!e||t.lastModified<o)),s=n.filter((t=>e&&t.lastModified===o));if(s.length){const t=s.map((t=>t._id)).reduce(((t,e)=>t>e?t:e)),e=s.filter((e=>e._id!==t));i.push(...e)}const r=e?o:(new Date).getTime(),a=await this.db.bulkDocs(i.map((t=>({...t,tombstone:!0,lastModified:r}))));let c;for(const t of a)if("ok"in t){const{id:e}=t,n=i.find((t=>t._id===e));if(n){const{_id:t,_rev:e,_conflicts:o,_attachments:i,...s}=n;c={...s,tombstone:!0,lastModified:r};break}}return c}delete=async(...e)=>{const[n,o]=e,{location:i}=d(n);if(i.actor!==o.actor)throw new t.GraffitiErrorForbidden;const s=await this.deleteAtLocation(i);if(!s)throw new t.GraffitiErrorNotFound;return s};put=async(...e)=>{const[n,o]=e;if(n.actor&&n.actor!==o.actor)throw new t.GraffitiErrorForbidden;const i={value:n.value,channels:n.channels,allowed:n.allowed,name:n.name??c(),source:n.source??this.source,actor:o.actor,tombstone:!1,lastModified:(new Date).getTime()};await this.db.put({_id:this.docId(i),...i});const s=await this.deleteAtLocation(i,!0);return s||{...i,value:{},channels:[],allowed:void 0,tombstone:!0}};patch=async(...e)=>{const[n,o,s]=e,{location:r}=d(o);if(r.actor!==s.actor)throw new t.GraffitiErrorForbidden;const a=await this.get(o,{},s),c={...a};for(const t of["value","channels","allowed"])l(i.applyPatch,t,n,c);if("object"!=typeof c.value||Array.isArray(c.value)||!c.value)throw new t.GraffitiErrorPatchError("value is no longer an object");if(!Array.isArray(c.channels)||!c.channels.every((t=>"string"==typeof t)))throw new t.GraffitiErrorPatchError("channels are no longer an array of strings");if(c.allowed&&(!Array.isArray(c.allowed)||!c.allowed.every((t=>"string"==typeof t))))throw new t.GraffitiErrorPatchError("allowed list is not an array of strings");return c.lastModified=(new Date).getTime(),await this.db.put({...c,_id:this.docId(c)}),await this.deleteAtLocation(c,!0),{...a,tombstone:!0,lastModified:c.lastModified}};discover=(...t)=>{const[e,n,i]=t,s=h(this.ajv,n);let r="",a="";const c=n.properties?.lastModified;if(c?.minimum){let t=Math.ceil(c.minimum);t===c.minimum&&c.exclusiveMinimum&&t++,r=t.toString().padStart(15,"0")}if(c?.maximum){let t=Math.floor(c.maximum);t===c.maximum&&c.exclusiveMaximum&&t--,a=t.toString().padStart(15,"0")}return new o.Repeater((async(t,n)=>{const o=new Set;for(const n of e){const c=encodeURIComponent(n),d=c+"/"+r,l=c+"/"+a,h=await this.db.query("index3/byChannelAndLastModified",{startkey:d,endkey:l,include_docs:!0});for(const n of h.rows){const r=n.doc;if(!r)continue;const{_id:a,_rev:c,...d}=r;o.has(a)||(o.add(a),u(r,i)&&(f(d,e,i),s(d)&&t({value:d})))}}return n(),{tombstoneRetention:this.tombstoneRetention}}))};listChannels=(...t)=>async function*(){}();listOrphans=(...t)=>async function*(){}()}class m{synchronizeEvents=new EventTarget;ajv;graffiti;constructor(t,n){this.ajv=n??new e({strict:!1}),this.graffiti=t}synchronizeDispatch(t,e){const n=new CustomEvent("change",{detail:{oldObject:t,newObject:e}});this.synchronizeEvents.dispatchEvent(n)}get=async(...t)=>{const e=await this.graffiti.get(...t);return this.synchronizeDispatch(e),e};put=async(...t)=>{const e=await this.graffiti.put(...t),n=t[0],o={...e,value:n.value,channels:n.channels,allowed:n.allowed,tombstone:!1};return this.synchronizeDispatch(e,o),e};patch=async(...t)=>{const e=await this.graffiti.patch(...t),n={...e};n.tombstone=!1;for(const e of["value","channels","allowed"])l(i.applyPatch,e,t[0],n);return this.synchronizeDispatch(e,n),e};delete=async(...t)=>{const e=await this.graffiti.delete(...t);return this.synchronizeDispatch(e),e};discover=(...t)=>{const e=this.graffiti.discover(...t),n=this.synchronizeDispatch.bind(this);return async function*(){let t=await e.next();for(;!t.done;)t.value.error||n(t.value.value),yield t.value,t=await e.next();return t.value}()};synchronize=(...t)=>{const[e,n,i]=t,s=h(this.ajv,n);return new o.Repeater((async(t,n)=>{const o=n=>{const{oldObject:o,newObject:r}=n.detail;for(const n of[r,o])if(n&&n.channels.some((t=>e.includes(t)))&&u(n,i)){const o={...n};if(f(o,e,i),s(o)){t({value:o});break}}};this.synchronizeEvents.addEventListener("change",o),await n,this.synchronizeEvents.removeEventListener("change",o)}))}}class g extends t.Graffiti{locationToUri=r;uriToLocation=a;login;logout;sessionEvents;put;get;patch;delete;discover;synchronize;listChannels;listOrphans;constructor(t){super();const n=new s;this.login=n.login.bind(n),this.logout=n.logout.bind(n),this.sessionEvents=n.sessionEvents;const o=new e({strict:!1}),i=new w(t,o),r=new m(i,o);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.synchronize=r.synchronize.bind(r),this.listChannels=i.listChannels.bind(i),this.listOrphans=i.listOrphans.bind(i)}}exports.GraffitiLocal=g;
|
|
2
2
|
//# sourceMappingURL=index.cjs.js.map
|