tinybase 4.3.12 → 4.3.13

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 +1 @@
1
- "use strict";const t=t=>typeof t,e="",a=t(e),s="t",n=(t,e)=>t.startsWith(e),r=Promise,i=t=>null==t,c=(t,e,a)=>i(t)?a?.():e(t),o=(t,e,a)=>t.slice(e,a),l=t=>t.length,u=(t,e)=>t.map(e),h=(t,...e)=>t.push(...e),f=Object,g=(t=[])=>f.fromEntries(t),w=(t,e)=>u(f.entries(t),(([t,a])=>e(a,t))),y=(t,e,a)=>(((t,e)=>!i(((t,e)=>c(t,(t=>t[e])))(t,e)))(t,e)||(t[e]=a()),t[e]),p=t=>JSON.stringify(t,((t,e)=>e instanceof Map?f.fromEntries([...e]):e)),S=JSON.parse,d=(e,s,n)=>e+s+(t(n)==a?n:p(n)),D=(t,e,a)=>{const s=l(t);return n(e,t)?[e[s],(a?S:String)(o(e,s+1))]:void 0},P=(t,e)=>((t,e)=>t?.forEach(e))(t,((t,a)=>e(a,t))),m="hasStore",R=g(u(["Origin","Methods","Headers"],(t=>["Access-Control-Allow-"+t,"*"]))),b=async t=>await t.party.storage.get((t.config.storagePrefix??e)+m),v=async(t,a,c,o)=>{const u=t.party.storage,f=t.config.storagePrefix??e,g=[u.put(f+m,1)],y=[];w(a[0],((e,a)=>i(e)?!c&&t.canDelTable(a,o)&&((t,...e)=>t.unshift(...e))(y,x(f,s,a)):t.canSetTable(a,c,o)&&w(e,((e,n)=>i(e)?!c&&t.canDelRow(a,n,o)&&h(y,x(f,s,a,n)):t.canSetRow(a,n,c,o)&&w(e,((e,r)=>i(e)?!c&&t.canDelCell(a,n,r,o)&&h(g,u.delete(x(f,s,a,n,r))):t.canSetCell(a,n,r,e,c,o)&&h(g,u.put(x(f,s,a,n,r),e)))))))),w(a[1],((e,a)=>i(e)?!c&&t.canDelValue(a,o)&&h(g,u.delete(f+"v"+a)):t.canSetValue(a,e,c,o)&&h(g,u.put(f+"v"+a,e)))),0!=l(y)&&P(await u.list(),(t=>y.every((e=>!n(t,e)||h(g,u.delete(t))&&0)))),await(async t=>r.all(t))(g)},x=(t,e,...a)=>d(t,e,o(p(a),1,-1)),T=async(t,e,a=null)=>new Response(a,{status:e,headers:t.config.responseHeaders??R});exports.TinyBasePartyKitServer=class{constructor(t){this.party=t,this.config={}}async onRequest(t){const a=this.config.storePath??"/store";if(new URL(t.url).pathname.endsWith(a)){const a=await b(this),n=await t.text();return"PUT"==t.method?a?T(this,205):(await v(this,S(n),!0,t),T(this,201)):T(this,200,a?p(await(async t=>{const a={},n={},r=t.config.storagePrefix??e;return P(await t.party.storage.list(),((t,e)=>c(D(r,t),(([t,r])=>{if(t==s){const[t,s,n]=S("["+r+"]");y(y(a,t,g),s,g)[n]=e}else"v"==t&&(n[r]=e)})))),[a,n]})(this)):e)}return T(this,404)}async onMessage(t,a){const s=this.config.messagePrefix??e;await c(D(s,t,1),(async([t,e])=>{"s"==t&&await b(this)&&(await v(this,e,!1,a),this.party.broadcast(d(s,"s",e)))}))}canSetTable(t,e,a){return!0}canDelTable(t,e){return!0}canSetRow(t,e,a,s){return!0}canDelRow(t,e,a){return!0}canSetCell(t,e,a,s,n,r){return!0}canDelCell(t,e,a,s){return!0}canSetValue(t,e,a,s){return!0}canDelValue(t,e){return!0}};
1
+ "use strict";const t=t=>typeof t,a="",e=t(a),s="t",n=(t,a)=>t.startsWith(a),r=Promise,i=t=>null==t,c=(t,a,e)=>i(t)?e?.():a(t),o=(t,a,e)=>t.slice(a,e),l=t=>t.length,h=async t=>r.all(t),u=(t,a)=>t.map(a),w=(t,...a)=>t.push(...a),g=Object,y=(t=[])=>g.fromEntries(t),f=(t,a)=>u(g.entries(t),(([t,e])=>a(e,t))),p=(t,a,e)=>(((t,a)=>!i(((t,a)=>c(t,(t=>t[a])))(t,a)))(t,a)||(t[a]=e()),t[a]),S=t=>JSON.stringify(t,((t,a)=>a instanceof Map?g.fromEntries([...a]):a)),d=JSON.parse,D=(a,s,n)=>a+s+(t(n)==e?n:S(n)),P=(t,a,e)=>{const s=l(t);return n(a,t)?[a[s],(e?d:String)(o(a,s+1))]:void 0},m=(t,a)=>((t,a)=>t?.forEach(a))(t,((t,e)=>a(e,t))),R="hasStore",b=y(u(["Origin","Methods","Headers"],(t=>["Access-Control-Allow-"+t,"*"]))),x=async t=>await t.party.storage.get((t.config.storagePrefix??a)+R),T=async(t,e,r,c)=>{const o=t.party.storage,u=t.config.storagePrefix??a,g={[u+R]:1},y=[],p=[];await h(f(e[0],(async(a,e)=>i(a)?!r&&t.canDelTable(e,c)&&((t,...a)=>t.unshift(...a))(p,v(u,s,e)):t.canSetTable(e,r,c)&&await h(f(a,(async(a,n)=>i(a)?!r&&t.canDelRow(e,n,c)&&w(p,v(u,s,e,n)):t.canSetRow(e,n,r,c)&&await h(f(a,(async(a,l)=>{const h=[e,n,l],f=v(u,s,...h);i(a)?!r&&t.canDelCell(...h,c)&&w(y,f):t.canSetCell(...h,a,r,c,await o.get(f))&&(g[f]=a)}))))))))),await h(f(e[1],(async(a,e)=>{const s=u+"v"+e;i(a)?!r&&t.canDelValue(e,c)&&w(y,s):t.canSetValue(e,a,r,c,await o.get(s))&&(g[s]=a)}))),0!=l(p)&&m(await o.list(),(t=>p.every((a=>!n(t,a)||w(y,t)&&0)))),await o.delete(y),await o.put(g)},v=(t,a,...e)=>D(t,a,o(S(e),1,-1)),C=async(t,a,e=null)=>new Response(e,{status:a,headers:t.config.responseHeaders??b});exports.TinyBasePartyKitServer=class{constructor(t){this.party=t,this.config={}}async onRequest(t){const e=this.config.storePath??"/store";if(new URL(t.url).pathname.endsWith(e)){const e=await x(this),n=await t.text();return"PUT"==t.method?e?C(this,205):(await T(this,d(n),!0,t),C(this,201)):C(this,200,e?S(await(async t=>{const e={},n={},r=t.config.storagePrefix??a;return m(await t.party.storage.list(),((t,a)=>c(P(r,t),(([t,r])=>{if(t==s){const[t,s,n]=d("["+r+"]");p(p(e,t,y),s,y)[n]=a}else"v"==t&&(n[r]=a)})))),[e,n]})(this)):a)}return C(this,404)}async onMessage(t,e){const s=this.config.messagePrefix??a;await c(P(s,t,1),(async([t,a])=>{"s"==t&&await x(this)&&(await T(this,a,!1,e),this.party.broadcast(D(s,"s",a)))}))}canSetTable(t,a,e){return!0}canDelTable(t,a){return!0}canSetRow(t,a,e,s){return!0}canDelRow(t,a,e){return!0}canSetCell(t,a,e,s,n,r,i){return!0}canDelCell(t,a,e,s){return!0}canSetValue(t,a,e,s,n){return!0}canDelValue(t,a){return!0}};
@@ -1 +1 @@
1
- "use strict";const e=e=>typeof e,t="",n=e(t),r="t",l=(e,t)=>e.startsWith(t),s=Promise,i=e=>null==e,a=(e,t,n)=>i(e)?null==n?void 0:n():t(e),o=(e,t,n)=>e.slice(t,n),u=e=>e.length,c=(e,t)=>e.map(t),h=(e,...t)=>e.push(...t),d=Object,v=(e=[])=>d.fromEntries(e),f=(e,t)=>c(d.entries(e),(([e,n])=>t(n,e))),y=(e,t,n)=>(((e,t)=>!i(((e,t)=>a(e,(e=>e[t])))(e,t)))(e,t)||(e[t]=n()),e[t]),p=e=>JSON.stringify(e,((e,t)=>t instanceof Map?d.fromEntries([...t]):t)),g=JSON.parse,S=(t,r,l)=>t+r+(e(l)==n?l:p(l)),P=(e,t,n)=>{const r=u(e);return l(t,e)?[t[r],(n?g:String)(o(t,r+1))]:void 0},m=(e,t)=>((e,t)=>null==e?void 0:e.forEach(t))(e,((e,n)=>t(n,e)));var w=(e,t,n)=>new Promise(((r,l)=>{var s=e=>{try{a(n.next(e))}catch(e){l(e)}},i=e=>{try{a(n.throw(e))}catch(e){l(e)}},a=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,i);a((n=n.apply(e,t)).next())}));const x="hasStore",D=v(c(["Origin","Methods","Headers"],(e=>["Access-Control-Allow-"+e,"*"]))),R=e=>w(void 0,null,(function*(){var n;return yield e.party.storage.get((null!=(n=e.config.storagePrefix)?n:t)+x)})),b=(e,n,a,o)=>w(void 0,null,(function*(){var c;const d=e.party.storage,v=null!=(c=e.config.storagePrefix)?c:t,y=[d.put(v+x,1)],p=[];f(n[0],((t,n)=>i(t)?!a&&e.canDelTable(n,o)&&((e,...t)=>e.unshift(...t))(p,T(v,r,n)):e.canSetTable(n,a,o)&&f(t,((t,l)=>i(t)?!a&&e.canDelRow(n,l,o)&&h(p,T(v,r,n,l)):e.canSetRow(n,l,a,o)&&f(t,((t,s)=>i(t)?!a&&e.canDelCell(n,l,s,o)&&h(y,d.delete(T(v,r,n,l,s))):e.canSetCell(n,l,s,t,a,o)&&h(y,d.put(T(v,r,n,l,s),t)))))))),f(n[1],((t,n)=>i(t)?!a&&e.canDelValue(n,o)&&h(y,d.delete(v+"v"+n)):e.canSetValue(n,t,a,o)&&h(y,d.put(v+"v"+n,t)))),0!=u(p)&&m(yield d.list(),(e=>p.every((t=>!l(e,t)||h(y,d.delete(e))&&0)))),yield(e=>{return t=function*(){return s.all(e)},new Promise(((e,n)=>{var r=e=>{try{s(t.next(e))}catch(e){n(e)}},l=e=>{try{s(t.throw(e))}catch(e){n(e)}},s=t=>t.done?e(t.value):Promise.resolve(t.value).then(r,l);s((t=t.apply(void 0,null)).next())}));var t})(y)})),T=(e,t,...n)=>S(e,t,o(p(n),1,-1)),C=(e,t,n=null)=>w(void 0,null,(function*(){var r;return new Response(n,{status:t,headers:null!=(r=e.config.responseHeaders)?r:D})}));exports.TinyBasePartyKitServer=class{constructor(e){this.party=e,this.config={}}onRequest(e){return w(this,null,(function*(){var n;const l=null!=(n=this.config.storePath)?n:"/store";if(new URL(e.url).pathname.endsWith(l)){const n=yield R(this),l=yield e.text();return"PUT"==e.method?n?C(this,205):(yield b(this,g(l),!0,e),C(this,201)):C(this,200,n?p(yield(s=this,w(void 0,null,(function*(){var e;const n={},l={},i=null!=(e=s.config.storagePrefix)?e:t;return m(yield s.party.storage.list(),((e,t)=>a(P(i,e),(([e,s])=>{if(e==r){const[e,r,l]=g("["+s+"]");y(y(n,e,v),r,v)[l]=t}else"v"==e&&(l[s]=t)})))),[n,l]})))):t)}var s;return C(this,404)}))}onMessage(e,n){return w(this,null,(function*(){var r;const l=null!=(r=this.config.messagePrefix)?r:t;yield a(P(l,e,1),(e=>w(this,[e],(function*([e,t]){"s"==e&&(yield R(this))&&(yield b(this,t,!1,n),this.party.broadcast(S(l,"s",t)))}))))}))}canSetTable(e,t,n){return!0}canDelTable(e,t){return!0}canSetRow(e,t,n,r){return!0}canDelRow(e,t,n){return!0}canSetCell(e,t,n,r,l,s){return!0}canDelCell(e,t,n,r){return!0}canSetValue(e,t,n,r){return!0}canDelValue(e,t){return!0}};
1
+ "use strict";const e=e=>typeof e,t="",n=e(t),r="t",l=(e,t)=>e.startsWith(t),i=Promise,s=e=>null==e,o=(e,t,n)=>s(e)?null==n?void 0:n():t(e),a=(e,t,n)=>e.slice(t,n),u=e=>e.length,c=e=>{return t=function*(){return i.all(e)},new Promise(((e,n)=>{var r=e=>{try{i(t.next(e))}catch(e){n(e)}},l=e=>{try{i(t.throw(e))}catch(e){n(e)}},i=t=>t.done?e(t.value):Promise.resolve(t.value).then(r,l);i((t=t.apply(void 0,null)).next())}));var t},d=(e,t)=>e.map(t),h=(e,...t)=>e.push(...t),y=Object,v=(e=[])=>y.fromEntries(e),f=(e,t)=>d(y.entries(e),(([e,n])=>t(n,e))),g=(e,t,n)=>(((e,t)=>!s(((e,t)=>o(e,(e=>e[t])))(e,t)))(e,t)||(e[t]=n()),e[t]),p=e=>JSON.stringify(e,((e,t)=>t instanceof Map?y.fromEntries([...t]):t)),S=JSON.parse,P=(t,r,l)=>t+r+(e(l)==n?l:p(l)),m=(e,t,n)=>{const r=u(e);return l(t,e)?[t[r],(n?S:String)(a(t,r+1))]:void 0},w=(e,t)=>((e,t)=>null==e?void 0:e.forEach(t))(e,((e,n)=>t(n,e)));var x=(e,t,n)=>new Promise(((r,l)=>{var i=e=>{try{o(n.next(e))}catch(e){l(e)}},s=e=>{try{o(n.throw(e))}catch(e){l(e)}},o=e=>e.done?r(e.value):Promise.resolve(e.value).then(i,s);o((n=n.apply(e,t)).next())}));const D="hasStore",R=v(d(["Origin","Methods","Headers"],(e=>["Access-Control-Allow-"+e,"*"]))),b=e=>x(void 0,null,(function*(){var n;return yield e.party.storage.get((null!=(n=e.config.storagePrefix)?n:t)+D)})),T=(e,n,i,o)=>x(void 0,null,(function*(){var a;const d=e.party.storage,y=null!=(a=e.config.storagePrefix)?a:t,v={[y+D]:1},g=[],p=[];yield c(f(n[0],((t,n)=>x(void 0,null,(function*(){return s(t)?!i&&e.canDelTable(n,o)&&((e,...t)=>e.unshift(...t))(p,C(y,r,n)):e.canSetTable(n,i,o)&&(yield c(f(t,((t,l)=>x(void 0,null,(function*(){return s(t)?!i&&e.canDelRow(n,l,o)&&h(p,C(y,r,n,l)):e.canSetRow(n,l,i,o)&&(yield c(f(t,((t,a)=>x(void 0,null,(function*(){const u=[n,l,a],c=C(y,r,...u);s(t)?!i&&e.canDelCell(...u,o)&&h(g,c):e.canSetCell(...u,t,i,o,yield d.get(c))&&(v[c]=t)}))))))}))))))}))))),yield c(f(n[1],((t,n)=>x(void 0,null,(function*(){const r=y+"v"+n;s(t)?!i&&e.canDelValue(n,o)&&h(g,r):e.canSetValue(n,t,i,o,yield d.get(r))&&(v[r]=t)}))))),0!=u(p)&&w(yield d.list(),(e=>p.every((t=>!l(e,t)||h(g,e)&&0)))),yield d.delete(g),yield d.put(v)})),C=(e,t,...n)=>P(e,t,a(p(n),1,-1)),O=(e,t,n=null)=>x(void 0,null,(function*(){var r;return new Response(n,{status:t,headers:null!=(r=e.config.responseHeaders)?r:R})}));exports.TinyBasePartyKitServer=class{constructor(e){this.party=e,this.config={}}onRequest(e){return x(this,null,(function*(){var n;const l=null!=(n=this.config.storePath)?n:"/store";if(new URL(e.url).pathname.endsWith(l)){const n=yield b(this),l=yield e.text();return"PUT"==e.method?n?O(this,205):(yield T(this,S(l),!0,e),O(this,201)):O(this,200,n?p(yield(i=this,x(void 0,null,(function*(){var e;const n={},l={},s=null!=(e=i.config.storagePrefix)?e:t;return w(yield i.party.storage.list(),((e,t)=>o(m(s,e),(([e,i])=>{if(e==r){const[e,r,l]=S("["+i+"]");g(g(n,e,v),r,v)[l]=t}else"v"==e&&(l[i]=t)})))),[n,l]})))):t)}var i;return O(this,404)}))}onMessage(e,n){return x(this,null,(function*(){var r;const l=null!=(r=this.config.messagePrefix)?r:t;yield o(m(l,e,1),(e=>x(this,[e],(function*([e,t]){"s"==e&&(yield b(this))&&(yield T(this,t,!1,n),this.party.broadcast(P(l,"s",t)))}))))}))}canSetTable(e,t,n){return!0}canDelTable(e,t){return!0}canSetRow(e,t,n,r){return!0}canDelRow(e,t,n){return!0}canSetCell(e,t,n,r,l,i,s){return!0}canDelCell(e,t,n,r){return!0}canSetValue(e,t,n,r,l){return!0}canDelValue(e,t){return!0}};
@@ -95,96 +95,86 @@ const saveStore = async (
95
95
  requestOrConnection,
96
96
  ) => {
97
97
  const storage = that.party.storage;
98
- const storagePrefix = that.config.storagePrefix ?? EMPTY_STRING;
99
- const promises = [storage.put(storagePrefix + HAS_STORE, 1)];
100
- const keyPrefixesToDelete = [];
101
- objMap(transactionChanges[0], (table, tableId) =>
102
- isUndefined(table)
103
- ? !initialSave &&
104
- that.canDelTable(tableId, requestOrConnection) &&
105
- arrayUnshift(
106
- keyPrefixesToDelete,
107
- constructStorageKey(storagePrefix, T, tableId),
108
- )
109
- : that.canSetTable(tableId, initialSave, requestOrConnection) &&
110
- objMap(table, (row, rowId) =>
111
- isUndefined(row)
112
- ? !initialSave &&
113
- that.canDelRow(tableId, rowId, requestOrConnection) &&
114
- arrayPush(
115
- keyPrefixesToDelete,
116
- constructStorageKey(storagePrefix, T, tableId, rowId),
117
- )
118
- : that.canSetRow(
119
- tableId,
120
- rowId,
121
- initialSave,
122
- requestOrConnection,
123
- ) &&
124
- objMap(row, (cell, cellId) =>
125
- isUndefined(cell)
126
- ? !initialSave &&
127
- that.canDelCell(
128
- tableId,
129
- rowId,
130
- cellId,
131
- requestOrConnection,
132
- ) &&
133
- arrayPush(
134
- promises,
135
- storage.delete(
136
- constructStorageKey(
137
- storagePrefix,
138
- T,
139
- tableId,
140
- rowId,
141
- cellId,
142
- ),
143
- ),
144
- )
145
- : that.canSetCell(
146
- tableId,
147
- rowId,
148
- cellId,
149
- cell,
150
- initialSave,
151
- requestOrConnection,
152
- ) &&
153
- arrayPush(
154
- promises,
155
- storage.put(
156
- constructStorageKey(
157
- storagePrefix,
158
- T,
159
- tableId,
160
- rowId,
161
- cellId,
162
- ),
163
- cell,
164
- ),
165
- ),
166
- ),
167
- ),
98
+ const prefix = that.config.storagePrefix ?? EMPTY_STRING;
99
+ const keysToSet = {
100
+ [prefix + HAS_STORE]: 1,
101
+ };
102
+ const keysToDel = [];
103
+ const keyPrefixesToDel = [];
104
+ await promiseAll(
105
+ objMap(transactionChanges[0], async (table, tableId) =>
106
+ isUndefined(table)
107
+ ? !initialSave &&
108
+ that.canDelTable(tableId, requestOrConnection) &&
109
+ arrayUnshift(
110
+ keyPrefixesToDel,
111
+ constructStorageKey(prefix, T, tableId),
112
+ )
113
+ : that.canSetTable(tableId, initialSave, requestOrConnection) &&
114
+ (await promiseAll(
115
+ objMap(table, async (row, rowId) =>
116
+ isUndefined(row)
117
+ ? !initialSave &&
118
+ that.canDelRow(tableId, rowId, requestOrConnection) &&
119
+ arrayPush(
120
+ keyPrefixesToDel,
121
+ constructStorageKey(prefix, T, tableId, rowId),
122
+ )
123
+ : that.canSetRow(
124
+ tableId,
125
+ rowId,
126
+ initialSave,
127
+ requestOrConnection,
128
+ ) &&
129
+ (await promiseAll(
130
+ objMap(row, async (cell, cellId) => {
131
+ const ids = [tableId, rowId, cellId];
132
+ const key = constructStorageKey(prefix, T, ...ids);
133
+ isUndefined(cell)
134
+ ? !initialSave &&
135
+ that.canDelCell(...ids, requestOrConnection) &&
136
+ arrayPush(keysToDel, key)
137
+ : that.canSetCell(
138
+ ...ids,
139
+ cell,
140
+ initialSave,
141
+ requestOrConnection,
142
+ await storage.get(key),
143
+ ) && (keysToSet[key] = cell);
144
+ }),
145
+ )),
146
+ ),
147
+ )),
148
+ ),
168
149
  );
169
- objMap(transactionChanges[1], (value, valueId) =>
170
- isUndefined(value)
171
- ? !initialSave &&
172
- that.canDelValue(valueId, requestOrConnection) &&
173
- arrayPush(promises, storage.delete(storagePrefix + V + valueId))
174
- : that.canSetValue(valueId, value, initialSave, requestOrConnection) &&
175
- arrayPush(promises, storage.put(storagePrefix + V + valueId, value)),
150
+ await promiseAll(
151
+ objMap(transactionChanges[1], async (value, valueId) => {
152
+ const key = prefix + V + valueId;
153
+ isUndefined(value)
154
+ ? !initialSave &&
155
+ that.canDelValue(valueId, requestOrConnection) &&
156
+ arrayPush(keysToDel, key)
157
+ : that.canSetValue(
158
+ valueId,
159
+ value,
160
+ initialSave,
161
+ requestOrConnection,
162
+ await storage.get(key),
163
+ ) && (keysToSet[key] = value);
164
+ }),
176
165
  );
177
- if (!arrayIsEmpty(keyPrefixesToDelete)) {
166
+ if (!arrayIsEmpty(keyPrefixesToDel)) {
178
167
  mapForEach(await storage.list(), (key) =>
179
168
  arrayEvery(
180
- keyPrefixesToDelete,
169
+ keyPrefixesToDel,
181
170
  (keyPrefixToDelete) =>
182
171
  !strStartsWith(key, keyPrefixToDelete) ||
183
- (arrayPush(promises, storage.delete(key)) && 0),
172
+ (arrayPush(keysToDel, key) && 0),
184
173
  ),
185
174
  );
186
175
  }
187
- await promiseAll(promises);
176
+ await storage.delete(keysToDel);
177
+ await storage.put(keysToSet);
188
178
  };
189
179
  const constructStorageKey = (storagePrefix, type, ...ids) =>
190
180
  construct(storagePrefix, type, slice(jsonString(ids), 1, -1));
@@ -249,13 +239,14 @@ class TinyBasePartyKitServer {
249
239
  _cell,
250
240
  _initialSave,
251
241
  _requestOrConnection,
242
+ _oldCell,
252
243
  ) {
253
244
  return true;
254
245
  }
255
246
  canDelCell(_tableId, _rowId, _cellId, _connection) {
256
247
  return true;
257
248
  }
258
- canSetValue(_valueId, _value, _initialSave, _requestOrConnection) {
249
+ canSetValue(_valueId, _value, _initialSave, _requestOrConnection, _oldValue) {
259
250
  return true;
260
251
  }
261
252
  canDelValue(_valueId, _connection) {
@@ -1 +1 @@
1
- const e=e=>typeof e,t="",n=e(t),r="t",l=(e,t)=>e.startsWith(t),s=Promise,i=e=>null==e,a=(e,t,n)=>i(e)?null==n?void 0:n():t(e),o=(e,t,n)=>e.slice(t,n),u=e=>e.length,c=(e,t)=>e.map(t),h=(e,...t)=>e.push(...t),d=Object,v=(e=[])=>d.fromEntries(e),f=(e,t)=>c(d.entries(e),(([e,n])=>t(n,e))),y=(e,t,n)=>(((e,t)=>!i(((e,t)=>a(e,(e=>e[t])))(e,t)))(e,t)||(e[t]=n()),e[t]),p=e=>JSON.stringify(e,((e,t)=>t instanceof Map?d.fromEntries([...t]):t)),g=JSON.parse,S=(t,r,l)=>t+r+(e(l)==n?l:p(l)),m=(e,t,n)=>{const r=u(e);return l(t,e)?[t[r],(n?g:String)(o(t,r+1))]:void 0},w=(e,t)=>((e,t)=>null==e?void 0:e.forEach(t))(e,((e,n)=>t(n,e)));var P=(e,t,n)=>new Promise(((r,l)=>{var s=e=>{try{a(n.next(e))}catch(e){l(e)}},i=e=>{try{a(n.throw(e))}catch(e){l(e)}},a=e=>e.done?r(e.value):Promise.resolve(e.value).then(s,i);a((n=n.apply(e,t)).next())}));const x="hasStore",D=v(c(["Origin","Methods","Headers"],(e=>["Access-Control-Allow-"+e,"*"]))),R=e=>P(void 0,null,(function*(){var n;return yield e.party.storage.get((null!=(n=e.config.storagePrefix)?n:t)+x)})),b=(e,n,a,o)=>P(void 0,null,(function*(){var c;const d=e.party.storage,v=null!=(c=e.config.storagePrefix)?c:t,y=[d.put(v+x,1)],p=[];f(n[0],((t,n)=>i(t)?!a&&e.canDelTable(n,o)&&((e,...t)=>e.unshift(...t))(p,C(v,r,n)):e.canSetTable(n,a,o)&&f(t,((t,l)=>i(t)?!a&&e.canDelRow(n,l,o)&&h(p,C(v,r,n,l)):e.canSetRow(n,l,a,o)&&f(t,((t,s)=>i(t)?!a&&e.canDelCell(n,l,s,o)&&h(y,d.delete(C(v,r,n,l,s))):e.canSetCell(n,l,s,t,a,o)&&h(y,d.put(C(v,r,n,l,s),t)))))))),f(n[1],((t,n)=>i(t)?!a&&e.canDelValue(n,o)&&h(y,d.delete(v+"v"+n)):e.canSetValue(n,t,a,o)&&h(y,d.put(v+"v"+n,t)))),0!=u(p)&&w(yield d.list(),(e=>p.every((t=>!l(e,t)||h(y,d.delete(e))&&0)))),yield(e=>{return t=function*(){return s.all(e)},new Promise(((e,n)=>{var r=e=>{try{s(t.next(e))}catch(e){n(e)}},l=e=>{try{s(t.throw(e))}catch(e){n(e)}},s=t=>t.done?e(t.value):Promise.resolve(t.value).then(r,l);s((t=t.apply(void 0,null)).next())}));var t})(y)})),C=(e,t,...n)=>S(e,t,o(p(n),1,-1)),T=(e,t,n=null)=>P(void 0,null,(function*(){var r;return new Response(n,{status:t,headers:null!=(r=e.config.responseHeaders)?r:D})}));class O{constructor(e){this.party=e,this.config={}}onRequest(e){return P(this,null,(function*(){var n;const l=null!=(n=this.config.storePath)?n:"/store";if(new URL(e.url).pathname.endsWith(l)){const n=yield R(this),l=yield e.text();return"PUT"==e.method?n?T(this,205):(yield b(this,g(l),!0,e),T(this,201)):T(this,200,n?p(yield(s=this,P(void 0,null,(function*(){var e;const n={},l={},i=null!=(e=s.config.storagePrefix)?e:t;return w(yield s.party.storage.list(),((e,t)=>a(m(i,e),(([e,s])=>{if(e==r){const[e,r,l]=g("["+s+"]");y(y(n,e,v),r,v)[l]=t}else"v"==e&&(l[s]=t)})))),[n,l]})))):t)}var s;return T(this,404)}))}onMessage(e,n){return P(this,null,(function*(){var r;const l=null!=(r=this.config.messagePrefix)?r:t;yield a(m(l,e,1),(e=>P(this,[e],(function*([e,t]){"s"==e&&(yield R(this))&&(yield b(this,t,!1,n),this.party.broadcast(S(l,"s",t)))}))))}))}canSetTable(e,t,n){return!0}canDelTable(e,t){return!0}canSetRow(e,t,n,r){return!0}canDelRow(e,t,n){return!0}canSetCell(e,t,n,r,l,s){return!0}canDelCell(e,t,n,r){return!0}canSetValue(e,t,n,r){return!0}canDelValue(e,t){return!0}}export{O as TinyBasePartyKitServer};
1
+ const e=e=>typeof e,t="",n=e(t),l="t",r=(e,t)=>e.startsWith(t),i=Promise,o=e=>null==e,s=(e,t,n)=>o(e)?null==n?void 0:n():t(e),a=(e,t,n)=>e.slice(t,n),u=e=>e.length,c=e=>{return t=function*(){return i.all(e)},new Promise(((e,n)=>{var l=e=>{try{i(t.next(e))}catch(e){n(e)}},r=e=>{try{i(t.throw(e))}catch(e){n(e)}},i=t=>t.done?e(t.value):Promise.resolve(t.value).then(l,r);i((t=t.apply(void 0,null)).next())}));var t},d=(e,t)=>e.map(t),h=(e,...t)=>e.push(...t),f=Object,v=(e=[])=>f.fromEntries(e),y=(e,t)=>d(f.entries(e),(([e,n])=>t(n,e))),g=(e,t,n)=>(((e,t)=>!o(((e,t)=>s(e,(e=>e[t])))(e,t)))(e,t)||(e[t]=n()),e[t]),p=e=>JSON.stringify(e,((e,t)=>t instanceof Map?f.fromEntries([...t]):t)),S=JSON.parse,m=(t,l,r)=>t+l+(e(r)==n?r:p(r)),w=(e,t,n)=>{const l=u(e);return r(t,e)?[t[l],(n?S:String)(a(t,l+1))]:void 0},P=(e,t)=>((e,t)=>null==e?void 0:e.forEach(t))(e,((e,n)=>t(n,e)));var x=(e,t,n)=>new Promise(((l,r)=>{var i=e=>{try{s(n.next(e))}catch(e){r(e)}},o=e=>{try{s(n.throw(e))}catch(e){r(e)}},s=e=>e.done?l(e.value):Promise.resolve(e.value).then(i,o);s((n=n.apply(e,t)).next())}));const D="hasStore",R=v(d(["Origin","Methods","Headers"],(e=>["Access-Control-Allow-"+e,"*"]))),b=e=>x(void 0,null,(function*(){var n;return yield e.party.storage.get((null!=(n=e.config.storagePrefix)?n:t)+D)})),C=(e,n,i,s)=>x(void 0,null,(function*(){var a;const d=e.party.storage,f=null!=(a=e.config.storagePrefix)?a:t,v={[f+D]:1},g=[],p=[];yield c(y(n[0],((t,n)=>x(void 0,null,(function*(){return o(t)?!i&&e.canDelTable(n,s)&&((e,...t)=>e.unshift(...t))(p,T(f,l,n)):e.canSetTable(n,i,s)&&(yield c(y(t,((t,r)=>x(void 0,null,(function*(){return o(t)?!i&&e.canDelRow(n,r,s)&&h(p,T(f,l,n,r)):e.canSetRow(n,r,i,s)&&(yield c(y(t,((t,a)=>x(void 0,null,(function*(){const u=[n,r,a],c=T(f,l,...u);o(t)?!i&&e.canDelCell(...u,s)&&h(g,c):e.canSetCell(...u,t,i,s,yield d.get(c))&&(v[c]=t)}))))))}))))))}))))),yield c(y(n[1],((t,n)=>x(void 0,null,(function*(){const l=f+"v"+n;o(t)?!i&&e.canDelValue(n,s)&&h(g,l):e.canSetValue(n,t,i,s,yield d.get(l))&&(v[l]=t)}))))),0!=u(p)&&P(yield d.list(),(e=>p.every((t=>!r(e,t)||h(g,e)&&0)))),yield d.delete(g),yield d.put(v)})),T=(e,t,...n)=>m(e,t,a(p(n),1,-1)),O=(e,t,n=null)=>x(void 0,null,(function*(){var l;return new Response(n,{status:t,headers:null!=(l=e.config.responseHeaders)?l:R})}));class V{constructor(e){this.party=e,this.config={}}onRequest(e){return x(this,null,(function*(){var n;const r=null!=(n=this.config.storePath)?n:"/store";if(new URL(e.url).pathname.endsWith(r)){const n=yield b(this),r=yield e.text();return"PUT"==e.method?n?O(this,205):(yield C(this,S(r),!0,e),O(this,201)):O(this,200,n?p(yield(i=this,x(void 0,null,(function*(){var e;const n={},r={},o=null!=(e=i.config.storagePrefix)?e:t;return P(yield i.party.storage.list(),((e,t)=>s(w(o,e),(([e,i])=>{if(e==l){const[e,l,r]=S("["+i+"]");g(g(n,e,v),l,v)[r]=t}else"v"==e&&(r[i]=t)})))),[n,r]})))):t)}var i;return O(this,404)}))}onMessage(e,n){return x(this,null,(function*(){var l;const r=null!=(l=this.config.messagePrefix)?l:t;yield s(w(r,e,1),(e=>x(this,[e],(function*([e,t]){"s"==e&&(yield b(this))&&(yield C(this,t,!1,n),this.party.broadcast(m(r,"s",t)))}))))}))}canSetTable(e,t,n){return!0}canDelTable(e,t){return!0}canSetRow(e,t,n,l){return!0}canDelRow(e,t,n){return!0}canSetCell(e,t,n,l,r,i,o){return!0}canDelCell(e,t,n,l){return!0}canSetValue(e,t,n,l,r){return!0}canDelValue(e,t){return!0}}export{V as TinyBasePartyKitServer};
@@ -1 +1 @@
1
- const t=t=>typeof t,e="",a=t(e),s="t",n=(t,e)=>t.startsWith(e),r=Promise,i=t=>null==t,c=(t,e,a)=>i(t)?a?.():e(t),o=(t,e,a)=>t.slice(e,a),l=t=>t.length,u=(t,e)=>t.map(e),h=(t,...e)=>t.push(...e),f=Object,g=(t=[])=>f.fromEntries(t),w=(t,e)=>u(f.entries(t),(([t,a])=>e(a,t))),p=(t,e,a)=>(((t,e)=>!i(((t,e)=>c(t,(t=>t[e])))(t,e)))(t,e)||(t[e]=a()),t[e]),y=t=>JSON.stringify(t,((t,e)=>e instanceof Map?f.fromEntries([...e]):e)),S=JSON.parse,d=(e,s,n)=>e+s+(t(n)==a?n:y(n)),D=(t,e,a)=>{const s=l(t);return n(e,t)?[e[s],(a?S:String)(o(e,s+1))]:void 0},m=(t,e)=>((t,e)=>t?.forEach(e))(t,((t,a)=>e(a,t))),P="hasStore",R=g(u(["Origin","Methods","Headers"],(t=>["Access-Control-Allow-"+t,"*"]))),b=async t=>await t.party.storage.get((t.config.storagePrefix??e)+P),x=async(t,a,c,o)=>{const u=t.party.storage,f=t.config.storagePrefix??e,g=[u.put(f+P,1)],p=[];w(a[0],((e,a)=>i(e)?!c&&t.canDelTable(a,o)&&((t,...e)=>t.unshift(...e))(p,v(f,s,a)):t.canSetTable(a,c,o)&&w(e,((e,n)=>i(e)?!c&&t.canDelRow(a,n,o)&&h(p,v(f,s,a,n)):t.canSetRow(a,n,c,o)&&w(e,((e,r)=>i(e)?!c&&t.canDelCell(a,n,r,o)&&h(g,u.delete(v(f,s,a,n,r))):t.canSetCell(a,n,r,e,c,o)&&h(g,u.put(v(f,s,a,n,r),e)))))))),w(a[1],((e,a)=>i(e)?!c&&t.canDelValue(a,o)&&h(g,u.delete(f+"v"+a)):t.canSetValue(a,e,c,o)&&h(g,u.put(f+"v"+a,e)))),0!=l(p)&&m(await u.list(),(t=>p.every((e=>!n(t,e)||h(g,u.delete(t))&&0)))),await(async t=>r.all(t))(g)},v=(t,e,...a)=>d(t,e,o(y(a),1,-1)),C=async(t,e,a=null)=>new Response(a,{status:e,headers:t.config.responseHeaders??R});class T{constructor(t){this.party=t,this.config={}}async onRequest(t){const a=this.config.storePath??"/store";if(new URL(t.url).pathname.endsWith(a)){const a=await b(this),n=await t.text();return"PUT"==t.method?a?C(this,205):(await x(this,S(n),!0,t),C(this,201)):C(this,200,a?y(await(async t=>{const a={},n={},r=t.config.storagePrefix??e;return m(await t.party.storage.list(),((t,e)=>c(D(r,t),(([t,r])=>{if(t==s){const[t,s,n]=S("["+r+"]");p(p(a,t,g),s,g)[n]=e}else"v"==t&&(n[r]=e)})))),[a,n]})(this)):e)}return C(this,404)}async onMessage(t,a){const s=this.config.messagePrefix??e;await c(D(s,t,1),(async([t,e])=>{"s"==t&&await b(this)&&(await x(this,e,!1,a),this.party.broadcast(d(s,"s",e)))}))}canSetTable(t,e,a){return!0}canDelTable(t,e){return!0}canSetRow(t,e,a,s){return!0}canDelRow(t,e,a){return!0}canSetCell(t,e,a,s,n,r){return!0}canDelCell(t,e,a,s){return!0}canSetValue(t,e,a,s){return!0}canDelValue(t,e){return!0}}export{T as TinyBasePartyKitServer};
1
+ const t=t=>typeof t,a="",e=t(a),s="t",n=(t,a)=>t.startsWith(a),r=Promise,i=t=>null==t,c=(t,a,e)=>i(t)?e?.():a(t),o=(t,a,e)=>t.slice(a,e),l=t=>t.length,h=async t=>r.all(t),u=(t,a)=>t.map(a),w=(t,...a)=>t.push(...a),g=Object,f=(t=[])=>g.fromEntries(t),y=(t,a)=>u(g.entries(t),(([t,e])=>a(e,t))),p=(t,a,e)=>(((t,a)=>!i(((t,a)=>c(t,(t=>t[a])))(t,a)))(t,a)||(t[a]=e()),t[a]),S=t=>JSON.stringify(t,((t,a)=>a instanceof Map?g.fromEntries([...a]):a)),d=JSON.parse,D=(a,s,n)=>a+s+(t(n)==e?n:S(n)),m=(t,a,e)=>{const s=l(t);return n(a,t)?[a[s],(e?d:String)(o(a,s+1))]:void 0},P=(t,a)=>((t,a)=>t?.forEach(a))(t,((t,e)=>a(e,t))),R="hasStore",b=f(u(["Origin","Methods","Headers"],(t=>["Access-Control-Allow-"+t,"*"]))),x=async t=>await t.party.storage.get((t.config.storagePrefix??a)+R),C=async(t,e,r,c)=>{const o=t.party.storage,u=t.config.storagePrefix??a,g={[u+R]:1},f=[],p=[];await h(y(e[0],(async(a,e)=>i(a)?!r&&t.canDelTable(e,c)&&((t,...a)=>t.unshift(...a))(p,T(u,s,e)):t.canSetTable(e,r,c)&&await h(y(a,(async(a,n)=>i(a)?!r&&t.canDelRow(e,n,c)&&w(p,T(u,s,e,n)):t.canSetRow(e,n,r,c)&&await h(y(a,(async(a,l)=>{const h=[e,n,l],y=T(u,s,...h);i(a)?!r&&t.canDelCell(...h,c)&&w(f,y):t.canSetCell(...h,a,r,c,await o.get(y))&&(g[y]=a)}))))))))),await h(y(e[1],(async(a,e)=>{const s=u+"v"+e;i(a)?!r&&t.canDelValue(e,c)&&w(f,s):t.canSetValue(e,a,r,c,await o.get(s))&&(g[s]=a)}))),0!=l(p)&&P(await o.list(),(t=>p.every((a=>!n(t,a)||w(f,t)&&0)))),await o.delete(f),await o.put(g)},T=(t,a,...e)=>D(t,a,o(S(e),1,-1)),v=async(t,a,e=null)=>new Response(e,{status:a,headers:t.config.responseHeaders??b});class O{constructor(t){this.party=t,this.config={}}async onRequest(t){const e=this.config.storePath??"/store";if(new URL(t.url).pathname.endsWith(e)){const e=await x(this),n=await t.text();return"PUT"==t.method?e?v(this,205):(await C(this,d(n),!0,t),v(this,201)):v(this,200,e?S(await(async t=>{const e={},n={},r=t.config.storagePrefix??a;return P(await t.party.storage.list(),((t,a)=>c(m(r,t),(([t,r])=>{if(t==s){const[t,s,n]=d("["+r+"]");p(p(e,t,f),s,f)[n]=a}else"v"==t&&(n[r]=a)})))),[e,n]})(this)):a)}return v(this,404)}async onMessage(t,e){const s=this.config.messagePrefix??a;await c(m(s,t,1),(async([t,a])=>{"s"==t&&await x(this)&&(await C(this,a,!1,e),this.party.broadcast(D(s,"s",a)))}))}canSetTable(t,a,e){return!0}canDelTable(t,a){return!0}canSetRow(t,a,e,s){return!0}canDelRow(t,a,e){return!0}canSetCell(t,a,e,s,n,r,i){return!0}canDelCell(t,a,e,s){return!0}canSetValue(t,a,e,s,n){return!0}canDelValue(t,a){return!0}}export{O as TinyBasePartyKitServer};
@@ -39,7 +39,7 @@ import {Store} from '../store';
39
39
  * to the TinyBasePartyKitServerConfig on the server side.
40
40
  *
41
41
  * ```js
42
- * const partyKitPersisterConfig: PartyKitPersisterConfig = {
42
+ * const partyKitPersisterConfig = {
43
43
  * storeProtocol: 'http',
44
44
  * storePath: '/my_tinybase',
45
45
  * };
@@ -18,7 +18,7 @@
18
18
  * @since 4.3.0
19
19
  */
20
20
 
21
- import {Cell, Value} from '../store';
21
+ import {Cell, CellOrUndefined, Value, ValueOrUndefined} from '../store';
22
22
  import {Connection, Party, Request, Server} from 'partykit/server';
23
23
  import {Id} from '../common';
24
24
 
@@ -42,7 +42,7 @@ import {Id} from '../common';
42
42
  *
43
43
  * ```js
44
44
  * class MyServer extends TinyBasePartyKitServer {
45
- * readonly config: TinyBasePartyKitServerConfig = {
45
+ * readonly config = {
46
46
  * storePath: '/my_tinybase',
47
47
  * storagePrefix: 'tinybase_',
48
48
  * };
@@ -119,8 +119,8 @@ export type TinyBasePartyKitServerConfig = {
119
119
  * console.log('Server started');
120
120
  * }
121
121
  *
122
- * async onMessage(message, client) {
123
- * await super.onMessage(message, client);
122
+ * async onMessage(message, connection) {
123
+ * await super.onMessage(message, connection);
124
124
  * // custom onMessage code
125
125
  * }
126
126
  *
@@ -182,8 +182,8 @@ export class TinyBasePartyKitServer implements Server {
182
182
  *
183
183
  * ```js
184
184
  * class MyServer extends TinyBasePartyKitServer {
185
- * async onMessage(message, client) {
186
- * await super.onMessage(message, client);
185
+ * async onMessage(message, connection) {
186
+ * await super.onMessage(message, connection);
187
187
  * // custom onMessage code
188
188
  * }
189
189
  * }
@@ -195,7 +195,7 @@ export class TinyBasePartyKitServer implements Server {
195
195
  * @category Connection
196
196
  * @since v4.3.0
197
197
  */
198
- onMessage(message: string, client: Connection): Promise<void>;
198
+ onMessage(message: string, connection: Connection): Promise<void>;
199
199
  /**
200
200
  * The canSetTable method lets you allow or disallow any changes to a Table
201
201
  * stored on the server, as sent from a client.
@@ -211,9 +211,13 @@ export class TinyBasePartyKitServer implements Server {
211
211
  * Store to the PartyKit room over HTTP (`true`), and subsequent incremental
212
212
  * updates over a web sockets (`false`).
213
213
  *
214
- * The final `requestOrConnection` parameter will either be the HTTP(S)
215
- * request or the web socket connection, in those two cases respectively. You
216
- * can, for instance, use this to distinguish between different users.
214
+ * The `requestOrConnection` parameter will either be the HTTP(S) request or
215
+ * the web socket connection, in those two cases respectively. You can, for
216
+ * instance, use this to distinguish between different users.
217
+ *
218
+ * Since v4.3.13, the final parameter is the Cell previously stored on the
219
+ * server, if any. Use this to distinguish between the addition of a new Cell
220
+ * (in which case it will be undefined) and the updating of an existing one.
217
221
  *
218
222
  * Return `false` from this method to disallow changes to this Table on the
219
223
  * server, or `true` to allow them (subject to subsequent canSetRow method,
@@ -393,6 +397,7 @@ export class TinyBasePartyKitServer implements Server {
393
397
  cell: Cell,
394
398
  initialSave: boolean,
395
399
  requestOrConnection: Request | Connection,
400
+ oldCell: CellOrUndefined,
396
401
  ): boolean;
397
402
  /**
398
403
  * The canDelCell method lets you allow or disallow deletions of a Cell stored
@@ -447,9 +452,13 @@ export class TinyBasePartyKitServer implements Server {
447
452
  * the first bulk save of the Store to the PartyKit room over HTTP (`true`),
448
453
  * and subsequent incremental updates over a web sockets (`false`).
449
454
  *
450
- * The final `requestOrConnection` parameter will either be the HTTP(S)
451
- * request or the web socket connection, in those two cases respectively. You
452
- * can, for instance, use this to distinguish between different users.
455
+ * The `requestOrConnection` parameter will either be the HTTP(S) request or
456
+ * the web socket connection, in those two cases respectively. You can, for
457
+ * instance, use this to distinguish between different users.
458
+ *
459
+ * Since v4.3.13, the final parameter is the Value previously stored on the
460
+ * server, if any. Use this to distinguish between the addition of a new Value
461
+ * (in which case it will be undefined) and the updating of an existing one.
453
462
  *
454
463
  * Return `false` from this method to disallow changes to this Value on the
455
464
  * server, or `true` to allow them. The default implementation returns `true`
@@ -473,6 +482,7 @@ export class TinyBasePartyKitServer implements Server {
473
482
  value: Value,
474
483
  initialSave: boolean,
475
484
  requestOrConnection: Request | Connection,
485
+ oldValue: ValueOrUndefined,
476
486
  ): boolean;
477
487
  /**
478
488
  * The canDelValue method lets you allow or disallow deletions of a Value
@@ -39,7 +39,7 @@ import {Persister} from '../persisters';
39
39
  * to the TinyBasePartyKitServerConfig on the server side.
40
40
  *
41
41
  * ```js
42
- * const partyKitPersisterConfig: PartyKitPersisterConfig = {
42
+ * const partyKitPersisterConfig = {
43
43
  * storeProtocol: 'http',
44
44
  * storePath: '/my_tinybase',
45
45
  * };
@@ -18,7 +18,14 @@
18
18
  * @since 4.3.0
19
19
  */
20
20
 
21
- import {Cell, NoTablesSchema, NoValuesSchema, Value} from '../store';
21
+ import {
22
+ Cell,
23
+ CellOrUndefined,
24
+ NoTablesSchema,
25
+ NoValuesSchema,
26
+ Value,
27
+ ValueOrUndefined,
28
+ } from '../store';
22
29
  import {Connection, Party, Request, Server} from 'partykit/server';
23
30
  import {Id} from '../common';
24
31
 
@@ -42,7 +49,7 @@ import {Id} from '../common';
42
49
  *
43
50
  * ```js
44
51
  * class MyServer extends TinyBasePartyKitServer {
45
- * readonly config: TinyBasePartyKitServerConfig = {
52
+ * readonly config = {
46
53
  * storePath: '/my_tinybase',
47
54
  * storagePrefix: 'tinybase_',
48
55
  * };
@@ -119,8 +126,8 @@ export type TinyBasePartyKitServerConfig = {
119
126
  * console.log('Server started');
120
127
  * }
121
128
  *
122
- * async onMessage(message, client) {
123
- * await super.onMessage(message, client);
129
+ * async onMessage(message, connection) {
130
+ * await super.onMessage(message, connection);
124
131
  * // custom onMessage code
125
132
  * }
126
133
  *
@@ -182,8 +189,8 @@ export class TinyBasePartyKitServer implements Server {
182
189
  *
183
190
  * ```js
184
191
  * class MyServer extends TinyBasePartyKitServer {
185
- * async onMessage(message, client) {
186
- * await super.onMessage(message, client);
192
+ * async onMessage(message, connection) {
193
+ * await super.onMessage(message, connection);
187
194
  * // custom onMessage code
188
195
  * }
189
196
  * }
@@ -195,7 +202,7 @@ export class TinyBasePartyKitServer implements Server {
195
202
  * @category Connection
196
203
  * @since v4.3.0
197
204
  */
198
- onMessage(message: string, client: Connection): Promise<void>;
205
+ onMessage(message: string, connection: Connection): Promise<void>;
199
206
  /**
200
207
  * The canSetTable method lets you allow or disallow any changes to a Table
201
208
  * stored on the server, as sent from a client.
@@ -211,9 +218,13 @@ export class TinyBasePartyKitServer implements Server {
211
218
  * Store to the PartyKit room over HTTP (`true`), and subsequent incremental
212
219
  * updates over a web sockets (`false`).
213
220
  *
214
- * The final `requestOrConnection` parameter will either be the HTTP(S)
215
- * request or the web socket connection, in those two cases respectively. You
216
- * can, for instance, use this to distinguish between different users.
221
+ * The `requestOrConnection` parameter will either be the HTTP(S) request or
222
+ * the web socket connection, in those two cases respectively. You can, for
223
+ * instance, use this to distinguish between different users.
224
+ *
225
+ * Since v4.3.13, the final parameter is the Cell previously stored on the
226
+ * server, if any. Use this to distinguish between the addition of a new Cell
227
+ * (in which case it will be undefined) and the updating of an existing one.
217
228
  *
218
229
  * Return `false` from this method to disallow changes to this Table on the
219
230
  * server, or `true` to allow them (subject to subsequent canSetRow method,
@@ -360,6 +371,7 @@ export class TinyBasePartyKitServer implements Server {
360
371
  * cell: Cell,
361
372
  * initialSave: boolean,
362
373
  * requestOrConnection: Request | Connection,
374
+ * oldCell: CellOrUndefined,
363
375
  * ): boolean;
364
376
  * ```
365
377
  *
@@ -406,6 +418,7 @@ export class TinyBasePartyKitServer implements Server {
406
418
  cell: Cell<NoTablesSchema, Id, Id>,
407
419
  initialSave: boolean,
408
420
  requestOrConnection: Request | Connection,
421
+ oldCell: CellOrUndefined<NoTablesSchema, Id, Id>,
409
422
  ): boolean;
410
423
  /**
411
424
  * The canDelCell method lets you allow or disallow deletions of a Cell stored
@@ -457,6 +470,7 @@ export class TinyBasePartyKitServer implements Server {
457
470
  * value: Value,
458
471
  * initialSave: boolean,
459
472
  * requestOrConnection: Request | Connection,
473
+ * oldValue: ValueOrUndefined,
460
474
  * ): boolean;
461
475
  * ```
462
476
  *
@@ -471,9 +485,13 @@ export class TinyBasePartyKitServer implements Server {
471
485
  * the first bulk save of the Store to the PartyKit room over HTTP (`true`),
472
486
  * and subsequent incremental updates over a web sockets (`false`).
473
487
  *
474
- * The final `requestOrConnection` parameter will either be the HTTP(S)
475
- * request or the web socket connection, in those two cases respectively. You
476
- * can, for instance, use this to distinguish between different users.
488
+ * The `requestOrConnection` parameter will either be the HTTP(S) request or
489
+ * the web socket connection, in those two cases respectively. You can, for
490
+ * instance, use this to distinguish between different users.
491
+ *
492
+ * Since v4.3.13, the final parameter is the Value previously stored on the
493
+ * server, if any. Use this to distinguish between the addition of a new Value
494
+ * (in which case it will be undefined) and the updating of an existing one.
477
495
  *
478
496
  * Return `false` from this method to disallow changes to this Value on the
479
497
  * server, or `true` to allow them. The default implementation returns `true`
@@ -497,6 +515,7 @@ export class TinyBasePartyKitServer implements Server {
497
515
  value: Value<NoValuesSchema, Id>,
498
516
  initialSave: boolean,
499
517
  requestOrConnection: Request | Connection,
518
+ oldValue: ValueOrUndefined<NoValuesSchema, Id>,
500
519
  ): boolean;
501
520
  /**
502
521
  * The canDelValue method lets you allow or disallow deletions of a Value
@@ -1 +1 @@
1
- var e,t;e=this,t=function(e){"use strict";const t=e=>typeof e,a="",s=t(a),n="t",r=(e,t)=>e.startsWith(t),i=Promise,o=e=>null==e,c=(e,t,a)=>o(e)?a?.():t(e),l=(e,t,a)=>e.slice(t,a),u=e=>e.length,f=(e,t)=>e.map(t),h=(e,...t)=>e.push(...t),y=Object,p=(e=[])=>y.fromEntries(e),g=(e,t)=>f(y.entries(e),(([e,a])=>t(a,e))),d=(e,t,a)=>(((e,t)=>!o(((e,t)=>c(e,(e=>e[t])))(e,t)))(e,t)||(e[t]=a()),e[t]),w=e=>JSON.stringify(e,((e,t)=>t instanceof Map?y.fromEntries([...t]):t)),S=JSON.parse,P=(e,a,n)=>e+a+(t(n)==s?n:w(n)),b=(e,t,a)=>{const s=u(e);return r(t,e)?[t[s],(a?S:String)(l(t,s+1))]:void 0},m=(e,t)=>((e,t)=>e?.forEach(t))(e,((e,a)=>t(a,e))),T="hasStore",v=p(f(["Origin","Methods","Headers"],(e=>["Access-Control-Allow-"+e,"*"]))),x=async e=>await e.party.storage.get((e.config.storagePrefix??a)+T),D=async(e,t,s,c)=>{const l=e.party.storage,f=e.config.storagePrefix??a,y=[l.put(f+T,1)],p=[];g(t[0],((t,a)=>o(t)?!s&&e.canDelTable(a,c)&&((e,...t)=>e.unshift(...t))(p,R(f,n,a)):e.canSetTable(a,s,c)&&g(t,((t,r)=>o(t)?!s&&e.canDelRow(a,r,c)&&h(p,R(f,n,a,r)):e.canSetRow(a,r,s,c)&&g(t,((t,i)=>o(t)?!s&&e.canDelCell(a,r,i,c)&&h(y,l.delete(R(f,n,a,r,i))):e.canSetCell(a,r,i,t,s,c)&&h(y,l.put(R(f,n,a,r,i),t)))))))),g(t[1],((t,a)=>o(t)?!s&&e.canDelValue(a,c)&&h(y,l.delete(f+"v"+a)):e.canSetValue(a,t,s,c)&&h(y,l.put(f+"v"+a,t)))),0!=u(p)&&m(await l.list(),(e=>p.every((t=>!r(e,t)||h(y,l.delete(e))&&0)))),await(async e=>i.all(e))(y)},R=(e,t,...a)=>P(e,t,l(w(a),1,-1)),C=async(e,t,a=null)=>new Response(a,{status:t,headers:e.config.responseHeaders??v});e.TinyBasePartyKitServer=class{constructor(e){this.party=e,this.config={}}async onRequest(e){const t=this.config.storePath??"/store";if(new URL(e.url).pathname.endsWith(t)){const t=await x(this),s=await e.text();return"PUT"==e.method?t?C(this,205):(await D(this,S(s),!0,e),C(this,201)):C(this,200,t?w(await(async e=>{const t={},s={},r=e.config.storagePrefix??a;return m(await e.party.storage.list(),((e,a)=>c(b(r,e),(([e,r])=>{if(e==n){const[e,s,n]=S("["+r+"]");d(d(t,e,p),s,p)[n]=a}else"v"==e&&(s[r]=a)})))),[t,s]})(this)):a)}return C(this,404)}async onMessage(e,t){const s=this.config.messagePrefix??a;await c(b(s,e,1),(async([e,a])=>{"s"==e&&await x(this)&&(await D(this,a,!1,t),this.party.broadcast(P(s,"s",a)))}))}canSetTable(e,t,a){return!0}canDelTable(e,t){return!0}canSetRow(e,t,a,s){return!0}canDelRow(e,t,a){return!0}canSetCell(e,t,a,s,n,r){return!0}canDelCell(e,t,a,s){return!0}canSetValue(e,t,a,s){return!0}canDelValue(e,t){return!0}}},"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TinyBasePersisterPartyKitServer={});
1
+ var t,e;t=this,e=function(t){"use strict";const e=t=>typeof t,a="",s=e(a),n="t",i=(t,e)=>t.startsWith(e),r=Promise,o=t=>null==t,c=(t,e,a)=>o(t)?a?.():e(t),l=(t,e,a)=>t.slice(e,a),f=t=>t.length,u=async t=>r.all(t),h=(t,e)=>t.map(e),y=(t,...e)=>t.push(...e),w=Object,g=(t=[])=>w.fromEntries(t),p=(t,e)=>h(w.entries(t),(([t,a])=>e(a,t))),d=(t,e,a)=>(((t,e)=>!o(((t,e)=>c(t,(t=>t[e])))(t,e)))(t,e)||(t[e]=a()),t[e]),S=t=>JSON.stringify(t,((t,e)=>e instanceof Map?w.fromEntries([...e]):e)),P=JSON.parse,b=(t,a,n)=>t+a+(e(n)==s?n:S(n)),m=(t,e,a)=>{const s=f(t);return i(e,t)?[e[s],(a?P:String)(l(e,s+1))]:void 0},T=(t,e)=>((t,e)=>t?.forEach(e))(t,((t,a)=>e(a,t))),x="hasStore",D=g(h(["Origin","Methods","Headers"],(t=>["Access-Control-Allow-"+t,"*"]))),v=async t=>await t.party.storage.get((t.config.storagePrefix??a)+x),R=async(t,e,s,r)=>{const c=t.party.storage,l=t.config.storagePrefix??a,h={[l+x]:1},w=[],g=[];await u(p(e[0],(async(e,a)=>o(e)?!s&&t.canDelTable(a,r)&&((t,...e)=>t.unshift(...e))(g,C(l,n,a)):t.canSetTable(a,s,r)&&await u(p(e,(async(e,i)=>o(e)?!s&&t.canDelRow(a,i,r)&&y(g,C(l,n,a,i)):t.canSetRow(a,i,s,r)&&await u(p(e,(async(e,f)=>{const u=[a,i,f],g=C(l,n,...u);o(e)?!s&&t.canDelCell(...u,r)&&y(w,g):t.canSetCell(...u,e,s,r,await c.get(g))&&(h[g]=e)}))))))))),await u(p(e[1],(async(e,a)=>{const n=l+"v"+a;o(e)?!s&&t.canDelValue(a,r)&&y(w,n):t.canSetValue(a,e,s,r,await c.get(n))&&(h[n]=e)}))),0!=f(g)&&T(await c.list(),(t=>g.every((e=>!i(t,e)||y(w,t)&&0)))),await c.delete(w),await c.put(h)},C=(t,e,...a)=>b(t,e,l(S(a),1,-1)),O=async(t,e,a=null)=>new Response(a,{status:e,headers:t.config.responseHeaders??D});t.TinyBasePartyKitServer=class{constructor(t){this.party=t,this.config={}}async onRequest(t){const e=this.config.storePath??"/store";if(new URL(t.url).pathname.endsWith(e)){const e=await v(this),s=await t.text();return"PUT"==t.method?e?O(this,205):(await R(this,P(s),!0,t),O(this,201)):O(this,200,e?S(await(async t=>{const e={},s={},i=t.config.storagePrefix??a;return T(await t.party.storage.list(),((t,a)=>c(m(i,t),(([t,i])=>{if(t==n){const[t,s,n]=P("["+i+"]");d(d(e,t,g),s,g)[n]=a}else"v"==t&&(s[i]=a)})))),[e,s]})(this)):a)}return O(this,404)}async onMessage(t,e){const s=this.config.messagePrefix??a;await c(m(s,t,1),(async([t,a])=>{"s"==t&&await v(this)&&(await R(this,a,!1,e),this.party.broadcast(b(s,"s",a)))}))}canSetTable(t,e,a){return!0}canDelTable(t,e){return!0}canSetRow(t,e,a,s){return!0}canDelRow(t,e,a){return!0}canSetCell(t,e,a,s,n,i,r){return!0}canDelCell(t,e,a,s){return!0}canSetValue(t,e,a,s,n){return!0}canDelValue(t,e){return!0}}},"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).TinyBasePersisterPartyKitServer={});
@@ -1 +1 @@
1
- var e,t;e=this,t=function(e){"use strict";const t=e=>typeof e,n="",r=t(n),l="t",i=(e,t)=>e.startsWith(t),s=Promise,o=e=>null==e,a=(e,t,n)=>o(e)?null==n?void 0:n():t(e),u=(e,t,n)=>e.slice(t,n),c=e=>e.length,d=(e,t)=>e.map(t),f=(e,...t)=>e.push(...t),h=Object,y=(e=[])=>h.fromEntries(e),v=(e,t)=>d(h.entries(e),(([e,n])=>t(n,e))),p=(e,t,n)=>(((e,t)=>!o(((e,t)=>a(e,(e=>e[t])))(e,t)))(e,t)||(e[t]=n()),e[t]),g=e=>JSON.stringify(e,((e,t)=>t instanceof Map?h.fromEntries([...t]):t)),P=JSON.parse,S=(e,n,l)=>e+n+(t(l)==r?l:g(l)),m=(e,t,n)=>{const r=c(e);return i(t,e)?[t[r],(n?P:String)(u(t,r+1))]:void 0},x=(e,t)=>((e,t)=>null==e?void 0:e.forEach(t))(e,((e,n)=>t(n,e)));var w=(e,t,n)=>new Promise(((r,l)=>{var i=e=>{try{o(n.next(e))}catch(e){l(e)}},s=e=>{try{o(n.throw(e))}catch(e){l(e)}},o=e=>e.done?r(e.value):Promise.resolve(e.value).then(i,s);o((n=n.apply(e,t)).next())}));const b="hasStore",T=y(d(["Origin","Methods","Headers"],(e=>["Access-Control-Allow-"+e,"*"]))),D=e=>w(void 0,null,(function*(){var t;return yield e.party.storage.get((null!=(t=e.config.storagePrefix)?t:n)+b)})),R=(e,t,r,a)=>w(void 0,null,(function*(){var u;const d=e.party.storage,h=null!=(u=e.config.storagePrefix)?u:n,y=[d.put(h+b,1)],p=[];v(t[0],((t,n)=>o(t)?!r&&e.canDelTable(n,a)&&((e,...t)=>e.unshift(...t))(p,C(h,l,n)):e.canSetTable(n,r,a)&&v(t,((t,i)=>o(t)?!r&&e.canDelRow(n,i,a)&&f(p,C(h,l,n,i)):e.canSetRow(n,i,r,a)&&v(t,((t,s)=>o(t)?!r&&e.canDelCell(n,i,s,a)&&f(y,d.delete(C(h,l,n,i,s))):e.canSetCell(n,i,s,t,r,a)&&f(y,d.put(C(h,l,n,i,s),t)))))))),v(t[1],((t,n)=>o(t)?!r&&e.canDelValue(n,a)&&f(y,d.delete(h+"v"+n)):e.canSetValue(n,t,r,a)&&f(y,d.put(h+"v"+n,t)))),0!=c(p)&&x(yield d.list(),(e=>p.every((t=>!i(e,t)||f(y,d.delete(e))&&0)))),yield(e=>{return t=function*(){return s.all(e)},new Promise(((e,n)=>{var r=e=>{try{i(t.next(e))}catch(e){n(e)}},l=e=>{try{i(t.throw(e))}catch(e){n(e)}},i=t=>t.done?e(t.value):Promise.resolve(t.value).then(r,l);i((t=t.apply(void 0,null)).next())}));var t})(y)})),C=(e,t,...n)=>S(e,t,u(g(n),1,-1)),O=(e,t,n=null)=>w(void 0,null,(function*(){var r;return new Response(n,{status:t,headers:null!=(r=e.config.responseHeaders)?r:T})}));e.TinyBasePartyKitServer=class{constructor(e){this.party=e,this.config={}}onRequest(e){return w(this,null,(function*(){var t;const r=null!=(t=this.config.storePath)?t:"/store";if(new URL(e.url).pathname.endsWith(r)){const t=yield D(this),r=yield e.text();return"PUT"==e.method?t?O(this,205):(yield R(this,P(r),!0,e),O(this,201)):O(this,200,t?g(yield(i=this,w(void 0,null,(function*(){var e;const t={},r={},s=null!=(e=i.config.storagePrefix)?e:n;return x(yield i.party.storage.list(),((e,n)=>a(m(s,e),(([e,i])=>{if(e==l){const[e,r,l]=P("["+i+"]");p(p(t,e,y),r,y)[l]=n}else"v"==e&&(r[i]=n)})))),[t,r]})))):n)}var i;return O(this,404)}))}onMessage(e,t){return w(this,null,(function*(){var r;const l=null!=(r=this.config.messagePrefix)?r:n;yield a(m(l,e,1),(e=>w(this,[e],(function*([e,n]){"s"==e&&(yield D(this))&&(yield R(this,n,!1,t),this.party.broadcast(S(l,"s",n)))}))))}))}canSetTable(e,t,n){return!0}canDelTable(e,t){return!0}canSetRow(e,t,n,r){return!0}canDelRow(e,t,n){return!0}canSetCell(e,t,n,r,l,i){return!0}canDelCell(e,t,n,r){return!0}canSetValue(e,t,n,r){return!0}canDelValue(e,t){return!0}}},"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TinyBasePersisterPartyKitServer={});
1
+ var e,t;e=this,t=function(e){"use strict";const t=e=>typeof e,n="",r=t(n),l="t",i=(e,t)=>e.startsWith(t),o=Promise,s=e=>null==e,a=(e,t,n)=>s(e)?null==n?void 0:n():t(e),u=(e,t,n)=>e.slice(t,n),c=e=>e.length,d=e=>{return t=function*(){return o.all(e)},new Promise(((e,n)=>{var r=e=>{try{i(t.next(e))}catch(e){n(e)}},l=e=>{try{i(t.throw(e))}catch(e){n(e)}},i=t=>t.done?e(t.value):Promise.resolve(t.value).then(r,l);i((t=t.apply(void 0,null)).next())}));var t},f=(e,t)=>e.map(t),h=(e,...t)=>e.push(...t),y=Object,v=(e=[])=>y.fromEntries(e),p=(e,t)=>f(y.entries(e),(([e,n])=>t(n,e))),g=(e,t,n)=>(((e,t)=>!s(((e,t)=>a(e,(e=>e[t])))(e,t)))(e,t)||(e[t]=n()),e[t]),P=e=>JSON.stringify(e,((e,t)=>t instanceof Map?y.fromEntries([...t]):t)),S=JSON.parse,m=(e,n,l)=>e+n+(t(l)==r?l:P(l)),x=(e,t,n)=>{const r=c(e);return i(t,e)?[t[r],(n?S:String)(u(t,r+1))]:void 0},w=(e,t)=>((e,t)=>null==e?void 0:e.forEach(t))(e,((e,n)=>t(n,e)));var b=(e,t,n)=>new Promise(((r,l)=>{var i=e=>{try{s(n.next(e))}catch(e){l(e)}},o=e=>{try{s(n.throw(e))}catch(e){l(e)}},s=e=>e.done?r(e.value):Promise.resolve(e.value).then(i,o);s((n=n.apply(e,t)).next())}));const T="hasStore",D=v(f(["Origin","Methods","Headers"],(e=>["Access-Control-Allow-"+e,"*"]))),R=e=>b(void 0,null,(function*(){var t;return yield e.party.storage.get((null!=(t=e.config.storagePrefix)?t:n)+T)})),C=(e,t,r,o)=>b(void 0,null,(function*(){var a;const u=e.party.storage,f=null!=(a=e.config.storagePrefix)?a:n,y={[f+T]:1},v=[],g=[];yield d(p(t[0],((t,n)=>b(void 0,null,(function*(){return s(t)?!r&&e.canDelTable(n,o)&&((e,...t)=>e.unshift(...t))(g,O(f,l,n)):e.canSetTable(n,r,o)&&(yield d(p(t,((t,i)=>b(void 0,null,(function*(){return s(t)?!r&&e.canDelRow(n,i,o)&&h(g,O(f,l,n,i)):e.canSetRow(n,i,r,o)&&(yield d(p(t,((t,a)=>b(void 0,null,(function*(){const c=[n,i,a],d=O(f,l,...c);s(t)?!r&&e.canDelCell(...c,o)&&h(v,d):e.canSetCell(...c,t,r,o,yield u.get(d))&&(y[d]=t)}))))))}))))))}))))),yield d(p(t[1],((t,n)=>b(void 0,null,(function*(){const l=f+"v"+n;s(t)?!r&&e.canDelValue(n,o)&&h(v,l):e.canSetValue(n,t,r,o,yield u.get(l))&&(y[l]=t)}))))),0!=c(g)&&w(yield u.list(),(e=>g.every((t=>!i(e,t)||h(v,e)&&0)))),yield u.delete(v),yield u.put(y)})),O=(e,t,...n)=>m(e,t,u(P(n),1,-1)),V=(e,t,n=null)=>b(void 0,null,(function*(){var r;return new Response(n,{status:t,headers:null!=(r=e.config.responseHeaders)?r:D})}));e.TinyBasePartyKitServer=class{constructor(e){this.party=e,this.config={}}onRequest(e){return b(this,null,(function*(){var t;const r=null!=(t=this.config.storePath)?t:"/store";if(new URL(e.url).pathname.endsWith(r)){const t=yield R(this),r=yield e.text();return"PUT"==e.method?t?V(this,205):(yield C(this,S(r),!0,e),V(this,201)):V(this,200,t?P(yield(i=this,b(void 0,null,(function*(){var e;const t={},r={},o=null!=(e=i.config.storagePrefix)?e:n;return w(yield i.party.storage.list(),((e,n)=>a(x(o,e),(([e,i])=>{if(e==l){const[e,r,l]=S("["+i+"]");g(g(t,e,v),r,v)[l]=n}else"v"==e&&(r[i]=n)})))),[t,r]})))):n)}var i;return V(this,404)}))}onMessage(e,t){return b(this,null,(function*(){var r;const l=null!=(r=this.config.messagePrefix)?r:n;yield a(x(l,e,1),(e=>b(this,[e],(function*([e,n]){"s"==e&&(yield R(this))&&(yield C(this,n,!1,t),this.party.broadcast(m(l,"s",n)))}))))}))}canSetTable(e,t,n){return!0}canDelTable(e,t){return!0}canSetRow(e,t,n,r){return!0}canDelRow(e,t,n){return!0}canSetCell(e,t,n,r,l,i,o){return!0}canDelCell(e,t,n,r){return!0}canSetValue(e,t,n,r,l){return!0}canDelValue(e,t){return!0}}},"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).TinyBasePersisterPartyKitServer={});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tinybase",
3
- "version": "4.3.12",
3
+ "version": "4.3.13",
4
4
  "author": "jamesgpearce",
5
5
  "repository": "github:tinyplex/tinybase",
6
6
  "license": "MIT",
@@ -218,9 +218,9 @@
218
218
  "@babel/preset-react": "^7.22.15",
219
219
  "@babel/preset-typescript": "^7.23.0",
220
220
  "@prettier/sync": "^0.3.0",
221
- "@rollup/plugin-image": "^3.0.2",
222
- "@rollup/plugin-replace": "^5.0.2",
223
- "@rollup/plugin-terser": "^0.4.3",
221
+ "@rollup/plugin-image": "^3.0.3",
222
+ "@rollup/plugin-replace": "^5.0.3",
223
+ "@rollup/plugin-terser": "^0.4.4",
224
224
  "@sqlite.org/sqlite-wasm": "^3.43.1-build1",
225
225
  "@types/asciichart": "^1.5.6",
226
226
  "@types/expect-puppeteer": "^5.0.4",
@@ -228,14 +228,14 @@
228
228
  "@types/jest": "^29.5.5",
229
229
  "@types/jest-environment-puppeteer": "^5.0.4",
230
230
  "@types/less": "^3.0.4",
231
- "@types/node": "^20.8.2",
231
+ "@types/node": "^20.8.4",
232
232
  "@types/puppeteer": "^5.4.7",
233
- "@types/react": "^18.2.25",
234
- "@types/react-dom": "^18.2.10",
233
+ "@types/react": "^18.2.27",
234
+ "@types/react-dom": "^18.2.12",
235
235
  "@types/react-test-renderer": "^18.0.3",
236
236
  "@types/tmp": "^0.2.4",
237
- "@typescript-eslint/eslint-plugin": "^6.7.4",
238
- "@typescript-eslint/parser": "^6.7.4",
237
+ "@typescript-eslint/eslint-plugin": "^6.7.5",
238
+ "@typescript-eslint/parser": "^6.7.5",
239
239
  "@vlcn.io/crsqlite-wasm": "^0.15.2",
240
240
  "asciichart": "^1.5.25",
241
241
  "automerge-repo": "^0.1.0",
@@ -248,7 +248,7 @@
248
248
  "country-flag-emoji-json": "^2.0.0",
249
249
  "cspell": "^7.3.7",
250
250
  "esbuild": "^0.19.4",
251
- "eslint": "^8.50.0",
251
+ "eslint": "^8.51.0",
252
252
  "eslint-config-prettier": "^9.0.0",
253
253
  "eslint-plugin-jest": "^27.4.2",
254
254
  "eslint-plugin-jsdoc": "^46.8.2",
@@ -265,15 +265,15 @@
265
265
  "jest-fetch-mock": "^3.0.3",
266
266
  "jest-puppeteer": "^9.0.1",
267
267
  "less": "^4.2.0",
268
- "partykit": "^0.0.27",
269
- "partysocket": "^0.0.8",
268
+ "partykit": "^0.0.30",
269
+ "partysocket": "^0.0.10",
270
270
  "prettier": "^3.0.3",
271
271
  "puppeteer": "21.1.1",
272
272
  "react": "^18.2.0",
273
273
  "react-dom": "^18.2.0",
274
274
  "react-test-renderer": "^18.2.0",
275
275
  "rollup": "^3.29.4",
276
- "rollup-plugin-esbuild": "^6.0.2",
276
+ "rollup-plugin-esbuild": "^6.1.0",
277
277
  "rollup-plugin-gzip": "^3.1.0",
278
278
  "rollup-plugin-preserve-shebang": "^1.0.1",
279
279
  "rollup-plugin-prettier": "^4.0.0",
@@ -289,8 +289,8 @@
289
289
  "@sqlite.org/sqlite-wasm": "^3.43.1-build1",
290
290
  "@vlcn.io/crsqlite-wasm": "^0.15.2",
291
291
  "automerge-repo": "^0.1.0",
292
- "partykit": "^0.0.27",
293
- "partysocket": "^0.0.8",
292
+ "partykit": "^0.0.30",
293
+ "partysocket": "^0.0.10",
294
294
  "prettier": "^3.0.3",
295
295
  "react": "^18.2.0",
296
296
  "react-dom": "^18.2.0",
package/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- <section id="hero"><h2 id="the-reactive-data-store-for-local-first-apps">The <em>reactive</em> data store for <span>local-first apps</span>.</h2><p id="copy">Build blisteringly fast web apps that work both online and offline. Manage your state locally, synchronize it to the cloud when you need to, or even make it collaborative. But, most importantly... have fun building stuff again!</p></section><p><a href="https://tinybase.org/guides/releases/#v4-3"><em>NEW!</em> v4.3 release</a> <span id="one-with">&quot;The One With PartyKit&quot;</span></p><p><a class="start" href="https://tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://tinybase.org/demos/">Try the demos</a></p><p><a href="https://tinybase.org/api/store/interfaces/store/store/">Read the docs</a></p><hr><ul><li>Manage <a href="#start-with-a-simple-key-value-store">key-value data</a>, <a href="#level-up-to-use-tabular-data">tabular data</a> - or both - with optional <a href="#apply-schemas-to-tables-values">schematization</a> to model your app&#x27;s data structures.</li><li><a href="#register-granular-listeners">Flexibly reactive</a> to reconciled updates, so you only spend rendering cycles on things that change.</li><li><a href="#build-complex-queries-with-tinyql">Powerful query engine</a> to select, join, filter, group, sort and paginate data - reactively - and without SQL.</li><li>Built-in <a href="#create-indexes-for-fast-lookups">indexing</a>, <a href="#define-metrics-and-aggregations">metric aggregation</a>, <a href="#model-table-relationships">tabular relationships</a> - and even an <a href="#set-checkpoints-for-an-undo-stack">undo stack</a> for your app state.</li><li>Create <a href="#type-definitions-orm-like-apis">type definitions &amp; ORM-like APIs</a>, from schema or inference. <a href="#an-inspector-for-your-data">Inspect your data</a> (<em>new!</em>) directly in the browser.</li><li>Easily <a href="#persist-to-storage-sqlite-crdts">sync your data</a> to browser <a href="https://tinybase.org/api/persister-browser">storage</a>, <a href="https://tinybase.org/api/persister-indexed-db/">IndexedDB</a>, <a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence/">SQLite</a>, <a href="https://tinybase.org/guides/schemas-and-persistence/synchronizing-data/">CRDTs</a>, and (<em>new!</em>) <a href="https://tinybase.org/api/persister-partykit-client/">PartyKit</a>.</li><li>Optional <a href="#call-hooks-to-bind-to-data">bindings to React</a> and (<em>new!</em>) <a href="#pre-built-reactive-components">pre-built components</a> that let you easily build fully reactive user interfaces.</li><li>Tiny by name, tiny by nature: <a href="#did-we-say-tiny">4.8kB - 9.2kB</a>, zero dependencies. <a href="#well-tested-and-documented">100% tested</a>, <a href="https://tinybase.org/guides/the-basics/getting-started/">fully documented</a>, and of course, <a href="https://github.com/tinyplex/tinybase">open source</a>!</li></ul><hr><section id="friends"><h2 id="tinybase-works-great-on-its-own-but-also-plays-well-with-friends">Tinybase works great on its own, but also plays well with friends!</h2><div><a href="https://tinybase.org/guides/building-uis/getting-started-with-ui-react"><img width="48" src="https://tinybase.org/react.svg"> React</a></div><div><a href="https://tinybase.org/api/persister-partykit-client"><img width="48" src="https://tinybase.org/partykit.svg"> PartyKit</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img width="48" src="https://tinybase.org/sqlite.svg"> SQLite</a></div><div><a href="https://tinybase.org/api/persister-indexed-db/functions/creation/createindexeddbpersister"><img width="48" src="https://tinybase.org/indexeddb.svg"> IndexedDB</a></div><div><a href="https://tinybase.org/api/persister-yjs/functions/creation/createyjspersister"><img width="48" src="https://tinybase.org/yjs.svg"> YJS</a></div><div><a href="https://tinybase.org/api/persister-cr-sqlite-wasm"><img width="48" src="https://tinybase.org/crsqlite.png"> CR-SQLite</a></div><div><a href="https://tinybase.org/api/persister-automerge"><img width="48" src="https://tinybase.org/automerge.svg"> Automerge</a></div></section><hr><section id="follow"><a href="https://github.com/tinyplex/tinybase" target="_blank"><img src="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=GitHub&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="https://discord.com/invite/mGz3mevwP8" target="_blank"><img src="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&amp;logo=discord&amp;logoColor=%23fff&amp;label=Discord&amp;labelColor=%233131e8&amp;color=%23333"> </a><a href="https://twitter.com/tinybasejs" target="_blank"><img src="https://img.shields.io/twitter/follow/tinybasejs?style=for-the-badge&amp;logo=x&amp;logoColor=%23fff&amp;label=Twitter&amp;labelColor=%23333&amp;color=%23333"></a><br><a href="https://github.com/tinyplex/tinybase/discussions" target="_blank"><img src="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Ideas&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="https://github.com/tinyplex/tinybase/issues" target="_blank"><img src="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Issues&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="#well-tested-and-documented"><img src="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&amp;logo=jest&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%2387c305"> </a><a href="https://www.npmjs.com/package/tinybase/v/4.3.12" target="_blank"><img src="https://img.shields.io/npm/v/tinybase?style=for-the-badge&amp;logo=npm&amp;logoColor=%23fff&amp;labelColor=%23bd0005&amp;color=%23333"></a></section><hr><section><h2 id="start-with-a-simple-key-value-store">Start with a simple key-value store.</h2><p>Creating a <a href="https://tinybase.org/api/store/interfaces/store/store/"><code>Store</code></a> requires just a simple call to the <a href="https://tinybase.org/api/store/functions/creation/createstore/"><code>createStore</code></a> function. Once you have one, you can easily set <a href="https://tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> in it by unique <a href="https://tinybase.org/api/common/type-aliases/identity/id/"><code>Id</code></a>. And of course you can easily get them back out again.</p><p>Read more about using keyed value data in <a href="https://tinybase.org/guides/the-basics/">The Basics</a> guide.</p></section>
1
+ <section id="hero"><h2 id="the-reactive-data-store-for-local-first-apps">The <em>reactive</em> data store for <span>local-first apps</span>.</h2><p id="copy">Build blisteringly fast web apps that work both online and offline. Manage your state locally, synchronize it to the cloud when you need to, or even make it collaborative. But, most importantly... have fun building stuff again!</p></section><p><a href="https://tinybase.org/guides/releases/#v4-3"><em>NEW!</em> v4.3 release</a> <span id="one-with">&quot;The One With PartyKit&quot;</span></p><p><a class="start" href="https://tinybase.org/guides/the-basics/getting-started/">Get started</a></p><p><a href="https://tinybase.org/demos/">Try the demos</a></p><p><a href="https://tinybase.org/api/store/interfaces/store/store/">Read the docs</a></p><hr><ul><li>Manage <a href="#start-with-a-simple-key-value-store">key-value data</a>, <a href="#level-up-to-use-tabular-data">tabular data</a> - or both - with optional <a href="#apply-schemas-to-tables-values">schematization</a> to model your app&#x27;s data structures.</li><li><a href="#register-granular-listeners">Flexibly reactive</a> to reconciled updates, so you only spend rendering cycles on things that change.</li><li><a href="#build-complex-queries-with-tinyql">Powerful query engine</a> to select, join, filter, group, sort and paginate data - reactively - and without SQL.</li><li>Built-in <a href="#create-indexes-for-fast-lookups">indexing</a>, <a href="#define-metrics-and-aggregations">metric aggregation</a>, <a href="#model-table-relationships">tabular relationships</a> - and even an <a href="#set-checkpoints-for-an-undo-stack">undo stack</a> for your app state.</li><li>Create <a href="#type-definitions-orm-like-apis">type definitions &amp; ORM-like APIs</a>, from schema or inference. <a href="#an-inspector-for-your-data">Inspect your data</a> (<em>new!</em>) directly in the browser.</li><li>Easily <a href="#persist-to-storage-sqlite-crdts">sync your data</a> to browser <a href="https://tinybase.org/api/persister-browser">storage</a>, <a href="https://tinybase.org/api/persister-indexed-db/">IndexedDB</a>, <a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence/">SQLite</a>, <a href="https://tinybase.org/guides/schemas-and-persistence/synchronizing-data/">CRDTs</a>, and (<em>new!</em>) <a href="https://tinybase.org/api/persister-partykit-client/">PartyKit</a>.</li><li>Optional <a href="#call-hooks-to-bind-to-data">bindings to React</a> and (<em>new!</em>) <a href="#pre-built-reactive-components">pre-built components</a> that let you easily build fully reactive user interfaces.</li><li>Tiny by name, tiny by nature: <a href="#did-we-say-tiny">4.8kB - 9.2kB</a>, zero dependencies. <a href="#well-tested-and-documented">100% tested</a>, <a href="https://tinybase.org/guides/the-basics/getting-started/">fully documented</a>, and of course, <a href="https://github.com/tinyplex/tinybase">open source</a>!</li></ul><hr><section id="friends"><h2 id="tinybase-works-great-on-its-own-but-also-plays-well-with-friends">Tinybase works great on its own, but also plays well with friends!</h2><div><a href="https://tinybase.org/guides/building-uis/getting-started-with-ui-react"><img width="48" src="https://tinybase.org/react.svg"> React</a></div><div><a href="https://tinybase.org/api/persister-partykit-client"><img width="48" src="https://tinybase.org/partykit.svg"> PartyKit</a></div><div><a href="https://tinybase.org/guides/schemas-and-persistence/database-persistence"><img width="48" src="https://tinybase.org/sqlite.svg"> SQLite</a></div><div><a href="https://tinybase.org/api/persister-indexed-db/functions/creation/createindexeddbpersister"><img width="48" src="https://tinybase.org/indexeddb.svg"> IndexedDB</a></div><div><a href="https://tinybase.org/api/persister-yjs/functions/creation/createyjspersister"><img width="48" src="https://tinybase.org/yjs.svg"> YJS</a></div><div><a href="https://tinybase.org/api/persister-cr-sqlite-wasm"><img width="48" src="https://tinybase.org/crsqlite.png"> CR-SQLite</a></div><div><a href="https://tinybase.org/api/persister-automerge"><img width="48" src="https://tinybase.org/automerge.svg"> Automerge</a></div></section><hr><section id="follow"><a href="https://github.com/tinyplex/tinybase" target="_blank"><img src="https://img.shields.io/github/stars/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=GitHub&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="https://discord.com/invite/mGz3mevwP8" target="_blank"><img src="https://img.shields.io/discord/1027918215323590676?style=for-the-badge&amp;logo=discord&amp;logoColor=%23fff&amp;label=Discord&amp;labelColor=%233131e8&amp;color=%23333"> </a><a href="https://twitter.com/tinybasejs" target="_blank"><img src="https://img.shields.io/twitter/follow/tinybasejs?style=for-the-badge&amp;logo=x&amp;logoColor=%23fff&amp;label=Twitter&amp;labelColor=%23333&amp;color=%23333"></a><br><a href="https://github.com/tinyplex/tinybase/discussions" target="_blank"><img src="https://img.shields.io/github/discussions/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Ideas&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="https://github.com/tinyplex/tinybase/issues" target="_blank"><img src="https://img.shields.io/github/issues/tinyplex/tinybase?style=for-the-badge&amp;logo=GitHub&amp;logoColor=%23fff&amp;label=Issues&amp;labelColor=%23d81b60&amp;color=%23333"> </a><a href="#well-tested-and-documented"><img src="https://img.shields.io/badge/Tests-100%25-green?style=for-the-badge&amp;logo=jest&amp;logoColor=%23fff&amp;color=%23333&amp;labelColor=%2387c305"> </a><a href="https://www.npmjs.com/package/tinybase/v/4.3.13" target="_blank"><img src="https://img.shields.io/npm/v/tinybase?style=for-the-badge&amp;logo=npm&amp;logoColor=%23fff&amp;labelColor=%23bd0005&amp;color=%23333"></a></section><hr><section><h2 id="start-with-a-simple-key-value-store">Start with a simple key-value store.</h2><p>Creating a <a href="https://tinybase.org/api/store/interfaces/store/store/"><code>Store</code></a> requires just a simple call to the <a href="https://tinybase.org/api/store/functions/creation/createstore/"><code>createStore</code></a> function. Once you have one, you can easily set <a href="https://tinybase.org/api/store/type-aliases/store/values/"><code>Values</code></a> in it by unique <a href="https://tinybase.org/api/common/type-aliases/identity/id/"><code>Id</code></a>. And of course you can easily get them back out again.</p><p>Read more about using keyed value data in <a href="https://tinybase.org/guides/the-basics/">The Basics</a> guide.</p></section>
2
2
 
3
3
  ```js
4
4
  const store = createStore()