snapback2 0.0.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.
- package/README.md +127 -0
- package/bin/snapback2.mjs +36 -0
- package/dist/api.d.ts +20 -0
- package/dist/assets.d.ts +34 -0
- package/dist/client-assets.d.ts +26 -0
- package/dist/client-offline.d.ts +94 -0
- package/dist/client-outbox.d.ts +58 -0
- package/dist/client-upload.d.ts +41 -0
- package/dist/client-wire.d.ts +41 -0
- package/dist/client.d.ts +12 -0
- package/dist/client.mjs +5 -0
- package/dist/client.mjs.map +7 -0
- package/dist/compiler-core.mjs +60 -0
- package/dist/compiler-core.mjs.map +7 -0
- package/dist/compiler-lib.d.ts +71 -0
- package/dist/compiler.mjs +5 -0
- package/dist/compiler.mjs.map +7 -0
- package/dist/drain.d.ts +33 -0
- package/dist/expo/files.d.ts +3 -0
- package/dist/expo/index.d.ts +16 -0
- package/dist/expo/token-store.d.ts +7 -0
- package/dist/expo/witness.d.ts +28 -0
- package/dist/expo/witness.mjs +2 -0
- package/dist/expo/witness.mjs.map +7 -0
- package/dist/expo.d.ts +4 -0
- package/dist/expo.mjs +9 -0
- package/dist/expo.mjs.map +7 -0
- package/dist/guide/auth.md +89 -0
- package/dist/guide/effects.md +52 -0
- package/dist/guide/families.json +446 -0
- package/dist/guide/grammar.md +52 -0
- package/dist/guide/live-query.md +27 -0
- package/dist/guide/offline.md +75 -0
- package/dist/guide/personas.md +15 -0
- package/dist/guide/quarry.md +297 -0
- package/dist/guide/testing.md +57 -0
- package/dist/index.d.ts +362 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +7 -0
- package/dist/offline-protocol.d.ts +180 -0
- package/dist/offline-schema.d.ts +1 -0
- package/dist/offline.d.ts +177 -0
- package/dist/react-core.d.ts +91 -0
- package/dist/react-core.mjs +2 -0
- package/dist/react-core.mjs.map +7 -0
- package/dist/react-native/components.d.ts +23 -0
- package/dist/react-native/files.d.ts +43 -0
- package/dist/react-native/source.d.ts +16 -0
- package/dist/react-native.d.ts +4 -0
- package/dist/react-native.mjs +2 -0
- package/dist/react-native.mjs.map +7 -0
- package/dist/react.d.ts +19 -0
- package/dist/react.mjs +2 -0
- package/dist/react.mjs.map +7 -0
- package/dist/sqlite-test.mjs +1720 -0
- package/dist/sqlite-test.mjs.map +7 -0
- package/dist/sse.d.ts +44 -0
- package/dist/store/byte-cache.d.ts +162 -0
- package/dist/store/canonical.d.ts +2 -0
- package/dist/store/indexeddb.d.ts +23 -0
- package/dist/store/locks.d.ts +11 -0
- package/dist/store/outbox.d.ts +113 -0
- package/dist/store/overlay-retirement.d.ts +17 -0
- package/dist/store/projection.d.ts +11 -0
- package/dist/store/range-store.d.ts +388 -0
- package/dist/store/sqlite-driver.conformance.d.ts +7 -0
- package/dist/store/sqlite-driver.d.ts +16 -0
- package/dist/store/sqlite-expo.d.ts +3 -0
- package/dist/store/sqlite.d.ts +31 -0
- package/dist/templates/chat/expo/App.tsx +29 -0
- package/dist/templates/chat/expo/app.json +11 -0
- package/dist/templates/chat/expo/index.js +3 -0
- package/dist/templates/chat/expo/shared/log.js +92 -0
- package/dist/templates/chat/expo/shared/log.ts +130 -0
- package/dist/templates/chat/expo/shared/offline.js +8 -0
- package/dist/templates/chat/expo/shared/offline.ts +9 -0
- package/dist/templates/chat/expo/src/Chat.tsx +23 -0
- package/dist/templates/chat/expo/src/Composer.tsx +23 -0
- package/dist/templates/chat/expo/src/MediaView.tsx +29 -0
- package/dist/templates/chat/expo/src/Witness.tsx +131 -0
- package/dist/templates/chat/expo/src/screens/Inbox.tsx +9 -0
- package/dist/templates/chat/expo/src/screens/Search.tsx +10 -0
- package/dist/templates/chat/expo/src/screens/Thread.tsx +22 -0
- package/dist/templates/chat/expo/src/witness-state.ts +68 -0
- package/dist/templates/chat/expo/tsconfig.json +5 -0
- package/dist/templates/chat/react/index.html +5 -0
- package/dist/templates/chat/react/shared/log.js +92 -0
- package/dist/templates/chat/react/shared/log.ts +130 -0
- package/dist/templates/chat/react/shared/offline.js +8 -0
- package/dist/templates/chat/react/shared/offline.ts +9 -0
- package/dist/templates/chat/react/src/App.tsx +36 -0
- package/dist/templates/chat/react/src/Composer.tsx +45 -0
- package/dist/templates/chat/react/src/Inbox.tsx +24 -0
- package/dist/templates/chat/react/src/Search.tsx +26 -0
- package/dist/templates/chat/react/src/Thread.tsx +126 -0
- package/dist/templates/chat/react/src/env.d.ts +1 -0
- package/dist/templates/chat/react/src/main.tsx +20 -0
- package/dist/templates/chat/shared/log.js +92 -0
- package/dist/templates/chat/shared/log.ts +130 -0
- package/dist/templates/chat/shared/offline.js +8 -0
- package/dist/templates/chat/shared/offline.ts +9 -0
- package/dist/templates/chat/snapback/deliveries.q +33 -0
- package/dist/templates/chat/snapback/delivery.ts +30 -0
- package/dist/templates/chat/snapback/feeds.q +14 -0
- package/dist/templates/chat/snapback/follows.q +11 -0
- package/dist/templates/chat/snapback/groups.q +40 -0
- package/dist/templates/chat/snapback/messages.q +32 -0
- package/dist/templates/chat/snapback/notifications.q +7 -0
- package/dist/templates/chat/snapback/posts.q +4 -0
- package/dist/templates/chat/snapback/profiles.q +17 -0
- package/dist/templates/chat/snapback/schema.q +136 -0
- package/dist/templates/chat/snapback/seed.ts +45 -0
- package/dist/templates/chat/snapback/tests/chat.test.ts +759 -0
- package/dist/templates/react/index.html +5 -0
- package/dist/templates/react/src/App.tsx +5 -0
- package/dist/templates/react/src/main.tsx +18 -0
- package/dist/templates/todos/snapback/schema.q +11 -0
- package/dist/templates/todos/snapback/seed.ts +10 -0
- package/dist/templates/todos/snapback/tests/todos.test.ts +13 -0
- package/dist/templates/todos/snapback/todos.q +6 -0
- package/dist/test-runner.mjs +8541 -0
- package/dist/test-runner.mjs.map +7 -0
- package/dist/test.d.ts +28 -0
- package/dist/test.mjs +8541 -0
- package/dist/test.mjs.map +7 -0
- package/dist/token-store.d.ts +3 -0
- package/dist/twin-hydrate.d.ts +43 -0
- package/dist/twin.d.ts +70 -0
- package/dist/types.d.ts +410 -0
- package/dist/witness-test.mjs +2 -0
- package/dist/witness-test.mjs.map +7 -0
- package/package.json +117 -0
package/dist/react.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import E,{useEffect as H,useMemo as je,useRef as _e,useState as U,useSyncExternalStore as $e}from"react";import{useAssetUrl as Ce,useSnapbackClient as Ne,useSnapbackSnapshot as Re}from"snapback2/react-core";import{isSnapbackRefusal as he}from"snapback2/client";var Fe=Symbol.for("snapback2.SnapbackRefusal"),X=class extends Error{constructor(n,s=!1,o){super(n.message);this.retryable=s;this.status=o;this.name="SnapbackRefusal",this.envelope=n,this.code=n.code}[Fe]=!0;envelope;code};var de=/^s2id-[0-9a-f]{32}-[0-9a-f]{16}$/;function ue(t,e){return e===null?t:`${t}.w${e}`}function Ue(t){return`${t.table}\0${t.id}`}function Z(t){return typeof t=="number"&&Number.isSafeInteger(t)&&t>0}function Me(t){if(!t||typeof t!="object"||Array.isArray(t))return;let e=t,n=Object.keys(e).sort().join(",");if(!(n!=="height,id,width"&&n!=="duration,height,id,width")&&!(typeof e.id!="string"||!de.test(e.id))&&!(!Z(e.width)||!Z(e.height))&&!("duration"in e&&!Z(e.duration)))return e.id}function C(t,e=new Set){let n=Me(t);if(n!==void 0)e.add(n);else if(Array.isArray(t))for(let s of t)C(s,e);else if(t&&typeof t=="object")for(let s of Object.values(t))C(s,e);return e}function ve(t,e){let n=new Set;for(let s of t)C(s.row,n);for(let s of e)s.data!==void 0&&C(s.data,n);return n}function le(t){let e=new Set;for(let n of Object.values(t.viewed))for(let s of n.assets)e.add(s);if(e.size===0)return e;for(let[n,s]of Object.entries(t.rows))if(!t.viewed[n])for(let o of C(s.row))e.delete(o);return e}function We(t){if(!t||typeof t!="object"||typeof t.assetId!="string"||!de.test(t.assetId))throw new TypeError("byte cache put must name an engine-minted asset id");if(t.width!==null&&!Z(t.width))throw new TypeError("byte cache put width must be null or a positive integer");if(!(t.bytes instanceof Uint8Array))throw new TypeError("byte cache put bytes must be a Uint8Array");if(typeof t.type!="string")throw new TypeError("byte cache put type must be a string")}function Se(t,e,n){let s={put:[],remove:[]};for(let a of e.viewed??[]){if(!a||typeof a.table!="string"||typeof a.id!="string")throw new TypeError("viewed rows must be row references");let d=Ue(a),p=new Set(t.viewed[d]?.assets??[]);C(t.rows[d]?.row,p),t.viewed[d]={at:Date.now(),assets:[...p]}}let o=le(t);for(let[a,d]of Object.entries(t.assets))n.has(d.assetId)&&!o.has(d.assetId)||(delete t.assets[a],s.remove.push(a));for(let a of e.bytes?.touch??[]){let d=t.assets[a];d&&(d.lastRead=++t.clock)}let i=e.bytes?.ceiling??Number.POSITIVE_INFINITY;if(!(i>0))throw new TypeError("byte cache ceiling must be positive");for(let a of e.bytes?.put??[]){if(We(a),!n.has(a.assetId)||o.has(a.assetId))continue;let d=a.bytes.byteLength;if(d===0||d>i)continue;let p=ue(a.assetId,a.width);t.assets[p]={assetId:a.assetId,width:a.width,size:d,type:a.type,lastRead:++t.clock},s.put.push({key:p,bytes:a.bytes})}let c=Object.values(t.assets).reduce((a,d)=>a+d.size,0);for(;c>i;){let[a,d]=Object.entries(t.assets).reduce((p,m)=>m[1].lastRead<p[1].lastRead?m:p);delete t.assets[a],s.remove.push(a),c-=d.size}return s.put=s.put.filter(a=>t.assets[a.key]!==void 0),s.remove=[...new Set(s.remove)].filter(a=>t.assets[a]===void 0),s}function ee(t){return new X({code:"E_ASSET_VIEWED",family:"offline",message:`asset ${t} belongs to a view-once row that was already viewed on this device`,site:"assetBlob",rewrite:"render a view-once row once; do not fetch its bytes again",guide:"offline"})}export*from"snapback2/react-core";function w(t){return t===void 0?"undefined":t===null||typeof t!="object"?JSON.stringify(t):Array.isArray(t)?`[${t.map(w).join(",")}]`:`{${Object.keys(t).sort().map(e=>`${JSON.stringify(e)}:${w(t[e])}`).join(",")}}`}function fe(t){return t!==null&&typeof t=="object"&&!Array.isArray(t)}function te(t,e){if(t.op!==e.op||!fe(t.args)||!fe(e.args))return;let n=t.cursorArg??e.cursorArg,s={...e.args},o={...t.args};if(delete s[Object.hasOwn(s,e.cursorArg)?e.cursorArg:n],delete o[n],w(s)!==w(o))return;let i=t.args[n];return i===null||typeof i=="string"?i:void 0}function ke(t,e,n){let s=new Map;for(let a of t){if((a.nextSeq??a.seq)<n||typeof a.next!="string")continue;let d=te(a,e);d!==void 0&&s.set(d,s.has(d)&&s.get(d)!==a.next?null:a.next)}let o=new Set([e.watermark]),i=[],c=e.watermark;for(;s.has(c);){let a=s.get(c);if(a==null||o.has(a))break;o.add(a),i.push(a),c=a}return i}function Ae(t,e,n){if(!e||te({...e,args:fe(e.args)?{...e.args,[e.cursorArg??t.cursorArg]:e.watermark}:e.args},t)===void 0||typeof e.watermark!="string"||(t.consumed??[]).includes(e.watermark))return!1;let s=n.indexOf(e.watermark);t.progress!==void 0&&!n.includes(t.progress)&&(t.progress=[...t.consumed??[]].reverse().find(i=>n.includes(i)));let o=t.progress===void 0?-1:n.indexOf(t.progress);return s<0||s<=o?!1:(t.progress=e.watermark,t.consumed=[...new Set([...t.consumed??[],...n.slice(0,s+1)])],!0)}var I=class extends Error{constructor(n,s,o){super(s);this.code=n;this.rewrite=o;this.name="OfflineStoreFailure"}},xe={put:[],remove:[]};function z(){return{version:1,sealed:!1,clock:0,rows:{},answers:{},watermarks:{},outbox:{},grants:{},overlay:{},overlayMisses:{},overlayWatermarks:{},overlayNegatives:{},bounds:{},programs:{},negative:{},rowSeq:{},assets:{},viewed:{}}}function y(t){return structuredClone(t)}function N(t,e){return`${t}\0${w(e===void 0?e:K(e))}`}function h(t){return`${t.table}\0${t.id}`}function ne(t){let e=t.indexOf("\0");return{table:t.slice(0,e),id:t.slice(e+1)}}function re(t,e){let n=h(e);(t.get(n)?.seq??-1)<=e.seq&&t.set(n,e)}function se(t){if(!t||typeof t!="object"||Array.isArray(t))return;let e=t.$row;return e!==null&&typeof e=="object"&&!Array.isArray(e)&&Object.keys(e).sort().join(",")==="id,table"&&typeof e.table=="string"&&typeof e.id=="string"?{table:e.table,id:e.id}:void 0}function L(t,e=new Map){let n=se(t);if(n)e.set(h(n),n);else if(Array.isArray(t))for(let s of t)L(s,e);else if(t&&typeof t=="object")for(let s of Object.values(t))L(s,e);return[...e.values()]}function ye(t,e,n){let s=se(t);return s?n?.[h(s)]?null:e[h(s)]?.row??null:Array.isArray(t)?t.map(o=>ye(o,e,n)):!t||typeof t!="object"?t:Object.fromEntries(Object.entries(t).map(([o,i])=>[o,ye(i,e,n)]))}function pe(t,e,n=new Map){if(e==null){for(let o of L(t))n.set(h(o),o);return[...n.values()]}let s=se(t);if(s&&e===null)n.set(h(s),s);else if(Array.isArray(t)&&Array.isArray(e))for(let o=0;o<t.length;o+=1)pe(t[o],o<e.length?e[o]:void 0,n);else if(t&&e&&typeof t=="object"&&typeof e=="object"&&!Array.isArray(t)&&!Array.isArray(e))for(let o of Object.keys(t))pe(t[o],Object.prototype.hasOwnProperty.call(e,o)?e[o]:void 0,n);return[...n.values()]}function we(t,e,n){let s=se(t);if(s&&e==null&&n.has(h(s)))return t;if(Array.isArray(t)&&Array.isArray(e)){let o=e.map((i,c)=>c<t.length?we(t[c],i,n):i);for(let i=e.length;i<t.length;i+=1)L(t[i]).some(c=>n.has(h(c)))&&o.push(y(t[i]));return o}if(t&&e&&typeof t=="object"&&typeof e=="object"&&!Array.isArray(t)&&!Array.isArray(e)){let o=y(e);for(let i of Object.keys(t)){let c=t[i];Object.prototype.hasOwnProperty.call(o,i)?o[i]=we(c,o[i],n):L(c).some(a=>n.has(h(a)))&&(o[i]=y(c))}return o}return e==null&&L(t).some(o=>n.has(h(o)))?y(t):e}function ze(t,e){return t.site===e.site&&t.table===e.table&&t.index===e.index&&w(t.prefix)===w(e.prefix)&&t.order===e.order&&w(t.after)===w(e.after)&&w(t.before)===w(e.before)&&w(t.gt)===w(e.gt)&&w(t.gte)===w(e.gte)&&w(t.lt)===w(e.lt)&&w(t.lte)===w(e.lte)&&t.ruleHash===e.ruleHash}function V(t,e){if(t===e)return 0;if(typeof t=="number"&&typeof e=="number"||typeof t=="string"&&typeof e=="string")return t<e?-1:1;if(typeof t=="boolean"&&typeof e=="boolean")return t?1:-1;let n=w(t),s=w(e);return n<s?-1:n>s?1:0}function j(t,e){for(let n=0;n<Math.min(t.length,e.length);n+=1){let s=V(t[n],e[n]);if(s!==0)return s}return t.length-e.length}function Ee(t,e,n){let s=t?.tables?.[e.table]?.indexes?.[e.index]?.columns;if(!n||!Array.isArray(s)||!s.every(i=>typeof i=="string"))return;let o=s.map(i=>n.row[i]);return o.some(i=>i===void 0)?void 0:o}function Pe(t,e){if(t!=null)return Array.isArray(t)?t.length===e?t:void 0:e===1?[t]:void 0}function He(t,e){if(t.length<e.prefix.length||j(t.slice(0,e.prefix.length),e.prefix)!==0)return!1;let n=t.slice(e.prefix.length),s=Pe(e.after,n.length),o=Pe(e.before,n.length);if(s&&(e.order==="Asc"?j(n,s)<=0:j(n,s)>=0)||o&&(e.order==="Asc"?j(n,o)>=0:j(n,o)<=0))return!1;let i=n[0];return!(e.gt!==null&&e.gt!==void 0&&V(i,e.gt)<=0||e.gte!==null&&e.gte!==void 0&&V(i,e.gte)<0||e.lt!==null&&e.lt!==void 0&&V(i,e.lt)>=0||e.lte!==null&&e.lte!==void 0&&V(i,e.lte)>0)}function Ye(t,e,n,s,o){let i=Ee(o,e,s[h({table:e.table,id:t})]);if(!i)return n.stop==="Exhausted";if(!He(i,n))return!1;if(n.stop==="Exhausted")return!0;let c=n.rowIds.map(p=>Ee(o,n,s[h({table:n.table,id:p})])).filter(Array.isArray);if(c.length===0)return!1;let a=c.reduce((p,m)=>j(p,m)<=0?p:m),d=c.reduce((p,m)=>j(p,m)>=0?p:m);return j(i,a)>=0&&j(i,d)<=0}function K(t){return JSON.parse(JSON.stringify(t))}function Oe(t){if(!t)return z();if(t=K(t),t.version!==1||typeof t.rows!="object"||typeof t.answers!="object")throw new I("E_OFFLINE_CARRIER","range store contains an unsupported format");return{...t,watermarks:t.watermarks??{},outbox:t.outbox??{},grants:t.grants??{},overlay:t.overlay??{},overlayMisses:t.overlayMisses??{},overlayWatermarks:t.overlayWatermarks??{},overlayNegatives:t.overlayNegatives??{},bounds:t.bounds??{},programs:t.programs??{},negative:t.negative??{},rowSeq:t.rowSeq??{},assets:t.assets??{},viewed:t.viewed??{}}}function Be(t){return[...t].sort((e,n)=>(e.order??Number.MAX_SAFE_INTEGER)-(n.order??Number.MAX_SAFE_INTEGER)||e.updatedAt-n.updatedAt||N(e.op,e.args).localeCompare(N(n.op,n.args)))[0]}var Ve=2;function Ge(t){return Object.values(t).sort((e,n)=>(e.order??e.createdAt)-(n.order??n.createdAt)||e.createdAt-n.createdAt||(e.intent<n.intent?-1:1))}var G=class{constructor(e){this.backend=e}state=z();partition;tail=Promise.resolve();outbox={all:async()=>this.read(()=>(this.ensureUnsealed(),y(Ge(this.state.outbox)))),get:async e=>this.read(()=>(this.ensureUnsealed(),this.state.outbox[e]&&y(this.state.outbox[e]))),put:async e=>this.commit({outbox:{put:[e]}}),remove:async e=>this.commit({outbox:{remove:[e]}}),grant:async()=>this.read(()=>{this.ensureUnsealed();let e=this.state.currentGrant===void 0?void 0:this.state.grants[this.state.currentGrant];return e&&y(e)}),grants:async()=>this.read(()=>(this.ensureUnsealed(),y(Object.values(this.state.grants)))),bounds:async()=>this.read(()=>(this.ensureUnsealed(),y(this.state.bounds))),overlay:async()=>this.read(()=>(this.ensureUnsealed(),y(this.state.overlay))),programs:async()=>this.read(()=>(this.ensureUnsealed(),y(this.state.programs)))};async open(e){if(typeof e!="string"||e.length===0)throw new I("E_OFFLINE_CARRIER","range store partition must be a principal id");await this.enqueue(async()=>{this.partition!==e&&(this.partition!==void 0&&this.partition!==e&&await this.backend.close(),this.partition=e,this.state=Oe(await this.backend.open(e)))})}async unseal(){await this.enqueue(async()=>{if(this.ensureOpen(),!this.state.sealed)return;let e={...y(this.state),sealed:!1};await this.backend.replace(e,xe),this.state=e})}async seal(){await this.enqueue(async()=>{this.ensureOpen();let e={...y(this.state),sealed:!0};await this.backend.replace(e,xe),this.state=e})}async wipe(e){await this.enqueue(async()=>{await this.backend.wipe(e),this.partition===e&&(this.partition=void 0,this.state=z())})}async answer(e,n){return this.read(()=>{if(this.state.sealed)return;let s=N(e,n),o=this.state.answers[s];if(!o)return;let i=this.state.watermarks[s],{refs:c,order:a,fingerprint:d,cursorArg:p,data:m,...P}=y(o);return{...P,...m===void 0?{}:{data:ye(m,this.state.rows,this.state.viewed)},...i===void 0?{}:{caughtUp:!0,watermark:i.watermark}}})}async coverage(){return this.read(()=>{if(this.state.sealed)return{rows:[],ranges:[],absences:[],verdicts:[],watermarks:[],viewed:[],evicted:[]};let e=new Map,n=new Map,s=new Map;for(let c of Object.values(this.state.answers)){for(let a of c.receipt?.ranges??[])e.set(`${a.site}\0${w(a.prefix)}\0${w([a.order,a.after,a.before,a.gt,a.gte,a.lt,a.lte])}`,y(a));for(let a of c.receipt?.absences??[])n.set(w(a),y(a));for(let a of c.receipt?.verdicts??[])s.set(w(a),y(a))}let o=Object.keys(this.state.viewed).map(ne);for(let c of o){let a=[c.table,"byId",[c.id]];n.set(w(a),a)}let i;for(let c of Object.values(this.state.answers))(i===void 0||c.deliveredAt>i)&&(i=c.deliveredAt);return{rows:y(Object.entries(this.state.rows).filter(([c])=>!this.state.viewed[c]).map(([,c])=>c)),ranges:[...e.values()],absences:[...n.values()],verdicts:[...s.values()],watermarks:y(Object.values(this.state.watermarks)),viewed:o,evicted:Object.keys(this.state.negative).map(ne),...this.state.facts===void 0?{}:{facts:y(this.state.facts)},...this.state.superseded===void 0?{}:{superseded:y(this.state.superseded)},...i===void 0?{}:{deliveredAt:i}}})}async commit(e){await this.enqueue(async()=>{this.ensureOpen();let{bytes:n,...s}=e,o={put:[],remove:[]},i=Oe(this.applySwap(y(this.state),{...K(s),...n===void 0?{}:{bytes:n}},o));await this.backend.replace(i,o),this.state=i})}async readBytes(e,n){return this.read(async()=>{if(this.state.sealed)return;let s=ue(e,n),o=this.state.assets[s];if(!o)return;let i=await this.backend.readBytes?.(s);return i&&i.byteLength===o.size?{bytes:i,type:o.type}:void 0})}async bytes(){return this.read(()=>{if(this.state.sealed)return{entries:[],totalBytes:0,viewed:[]};let e=y(Object.values(this.state.assets));return{entries:e,totalBytes:e.reduce((n,s)=>n+s.size,0),viewed:Object.keys(this.state.viewed).map(ne)}})}async rowsReferencing(e){return this.read(()=>this.state.sealed?[]:y(Object.values(this.state.rows).filter(n=>C(n.row).has(e))))}async viewedAsset(e){return this.read(()=>!this.state.sealed&&le(this.state).has(e))}async viewedRows(){return this.read(()=>this.state.sealed?[]:Object.keys(this.state.viewed).map(ne))}async touchBytes(e){await this.enqueue(async()=>{if(!(this.partition===void 0||this.state.sealed))for(let n of e){let s=this.state.assets[n];s&&(s.lastRead=++this.state.clock)}})}async close(){await this.enqueue(async()=>{this.partition=void 0,this.state=z(),await this.backend.close()})}applySwap(e,n,s){if(e.sealed)throw new I("E_OFFLINE_CARRIER","range store is sealed");if(n.resetCoverage&&(e.rows={},e.rowSeq={},e.negative={},e.answers={},e.watermarks={},e.overlayWatermarks=Object.fromEntries(Object.keys(e.overlay).map(r=>[r,null])),e.overlayMisses={},delete e.facts),n.superseded===null&&delete e.superseded,n.resumeSeq!==void 0&&(!Number.isSafeInteger(n.resumeSeq)||n.resumeSeq<0))throw new TypeError("store resume seq must be a non-negative safe integer");n.facts&&(e.facts=y(n.facts)),n.superseded&&(e.superseded=y(n.superseded));let o=new Map,i=new Map,c=(r,u)=>{let l=h(r);(i.get(l)?.seq??-1)<=r.seq&&i.set(l,{seq:r.seq,source:u}),re(o,r)},a=r=>{for(let[u,l,f]of r.receipt?.absences??[]){if(l!=="byId"||f.length!==1)throw new TypeError("store receipts may evict only a primary byId absence");typeof f[0]=="string"&&c({table:u,id:f[0],seq:r.seq},"absence")}};for(let r of n.dropAnswers??[])delete e.answers[r];for(let r of n.refreshes??[]){let u=e.answers[N(r.op,r.args)];if(!(!u||r.seq<u.seq)){if(u.validator!==void 0&&u.validator!==r.validator)throw new TypeError(`conditional validator changed for ${r.op}`);r.seq!==u.seq&&(u.nextSeq??=u.seq,u.seq=r.seq,u.validator=r.validator,u.deliveredAt=r.deliveredAt??Date.now(),u.order=++e.clock,a(u))}}let d=y(e.answers),p=[];for(let r of n.tombstones??[])c(r,"tombstone");for(let r of n.deliveries??[]){if(!Number.isSafeInteger(r.seq)||r.seq<0)throw new TypeError("store delivery seq must be a non-negative safe integer");let u=N(r.op,r.args),l=d[u],f=w({op:r.op,args:r.args,state:r.state,data:r.data,next:r.next,seq:r.seq,validator:r.validator,receipt:r.receipt,rows:r.rows,reason:r.reason,rule:r.rule});if(l&&r.seq<l.seq)continue;if(l&&r.seq===l.seq){if(l.fingerprint===f)continue;throw new TypeError(`conflicting deliveries for ${r.op} at seq ${r.seq}`)}for(let g of r.rows??[]){if(!g.table||!g.id||!g.row||typeof g.row!="object")throw new TypeError("store delivery row is malformed");let B=h(g);if((e.negative[B]??-1)>=r.seq){re(o,{table:g.table,id:g.id,seq:e.negative[B]});continue}if(e.rowSeq[B]===r.seq&&w(e.rows[B])!==w(g))throw new TypeError(`conflicting row ${g.table}/${g.id} at seq ${r.seq}`);(e.rowSeq[B]??-1)>r.seq||(e.rows[B]=y(g),e.rowSeq[B]=r.seq)}let b=y(r.data),k=r.state,A=!1,$=r.state==="denied"&&l?l.refs:l?pe(l.data,b):[],x=new Set;for(let g of $)(n.retention?.[g.table]??"until-revoked")==="delivered-history"?(x.add(h(g)),A=!0):re(o,{...g,seq:r.seq});r.state==="denied"&&l&&x.size>0?(b=y(l.data),k=l.state):l&&x.size>0&&(b=we(l.data,b,x));let R=L(b);for(let g of r.receipt?.ranges??[])for(let B of[...g.rowIds,...g.haloId?[g.haloId]:[]])R.some(Q=>Q.table===g.table&&Q.id===B)||R.push({table:g.table,id:B});for(let g of r.rows??[])R.some(B=>B.table===g.table&&B.id===g.id)||R.push({table:g.table,id:g.id});let Y={op:r.op,...r.cursorArg===void 0?{}:{cursorArg:r.cursorArg},args:y(r.args),state:k,...b===void 0?{}:{data:b},...r.next===void 0?{}:{next:r.next},nextSeq:r.seq,seq:r.seq,...r.validator===void 0?{}:{validator:r.validator},...r.receipt===void 0?{}:{receipt:y(r.receipt)},deliveredAt:r.deliveredAt??Date.now(),...A?{retained:!0}:{},...r.reason===void 0?{}:{reason:r.reason},...r.rule===void 0?{}:{rule:r.rule},refs:R,order:++e.clock,fingerprint:f};e.answers[u]=Y,p.push(...(r.receipt?.ranges??[]).map(g=>({range:g,seq:r.seq}))),a(Y)}let m=Object.values(d).flatMap(r=>r.receipt?.ranges??[]);for(let r of m){let u=p.filter(({range:f})=>ze(r,f));if(u.length===0)continue;let l=new Set(u.flatMap(({range:f})=>[...f.rowIds,...f.haloId?[f.haloId]:[]]));for(let f of r.rowIds){if(l.has(f))continue;let b=u.filter(({range:k})=>Ye(f,r,k,e.rows,n.schema)).reduce((k,A)=>Math.max(k,A.seq),-1);b>=0&&re(o,{table:r.table,id:f,seq:b})}}let P=new Set;for(let[r,u]of o)if(!((e.negative[r]??-1)>u.seq)&&!((e.rowSeq[r]??-1)>u.seq)){e.negative[r]=u.seq,P.add(r),delete e.rows[r],delete e.rowSeq[r];for(let l of Object.values(e.answers)){for(let f of l.receipt?.ranges??[]){if(f.table!==u.table)continue;let b=u.id;f.rowIds.includes(b)&&(f.rowIds=f.rowIds.filter(k=>k!==b),f.evictedIds=[...f.evictedIds??[],b]),f.haloId===b&&delete f.haloId}l.refs.some(f=>h(f)===r)&&(l.refs=l.refs.filter(f=>h(f)!==r),!l.retained&&l.state!=="denied"&&(l.state="partial",l.reason="evicted",delete l.next))}}for(let r of Object.values(e.answers))r.receipt&&(r.receipt.absences=r.receipt.absences.filter(([u,l,f])=>{let b=l==="byId"&&f.length===1?f[0]:void 0,k=typeof b=="string"?h({table:u,id:b}):void 0;return k===void 0||(e.rowSeq[k]??-1)<0||P.has(k)}));let S=new Set(Object.values(e.answers).flatMap(r=>r.refs.map(h)));for(let r of Object.keys(e.rows))S.has(r)||(delete e.rows[r],delete e.rowSeq[r]);let _=Se(e,n,ve(Object.values(e.rows),Object.values(e.answers)));s.put.push(..._.put),s.remove.push(..._.remove);let M=Be(Object.values(e.watermarks));if(n.watermark){let r=N(n.watermark.op,n.watermark.args),u=e.watermarks[r]?.order??++e.clock;e.watermarks[r]={...y(n.watermark),order:u}}let O=Be(Object.values(e.watermarks));for(let r of n.outbox?.remove??[])delete e.outbox[r],delete e.overlayMisses[r],delete e.overlay[r],delete e.overlayWatermarks[r],delete e.overlayNegatives[r];let D=new Set;for(let r of n.outbox?.put??[]){if(typeof r.intent!="string"||r.intent.length===0)throw new TypeError("outbox entry needs an intent");let u=e.outbox[r.intent];r.state==="committed"&&u?.state!=="committed"&&D.add(r.intent);let l=u?.order??r.order??++e.clock;e.outbox[r.intent]={...y(r),order:l}}n.bounds&&(e.bounds=y(n.bounds)),n.programs&&(e.programs=y(n.programs));for(let r of n.grants?.remove??[])delete e.grants[r],e.currentGrant===r&&delete e.currentGrant;for(let r of n.grants?.put??[])e.grants[r.id]=y(r);if(n.grants?.current===null)delete e.currentGrant;else if(typeof n.grants?.current=="string"){if(!e.grants[n.grants.current])throw new TypeError("current grant must be a held grant");e.currentGrant=n.grants.current}for(let r of n.overlay?.remove??[])delete e.overlay[r],delete e.overlayMisses[r],delete e.overlayWatermarks[r],delete e.overlayNegatives[r];for(let[r,u]of Object.entries(n.overlay?.put??{}))e.overlay[r]=y(u),delete e.overlayMisses[r],delete e.overlayWatermarks[r],delete e.overlayNegatives[r];let F=Object.keys(e.overlay).some(r=>e.outbox[r]?.state==="committed")?Object.values(e.answers):[],W=F.filter(r=>{let u=Array.isArray(r.data)?r.data.length>0:L(r.data).length>0;return(r.state==="complete"||r.state==="capped")&&r.receipt!==void 0&&!r.receipt.ranges.some(l=>(l.evictedIds?.length??0)>0)&&u&&r.refs.length>0&&r.refs.every(l=>e.rows[h(l)]!==void 0)}),q=new Map;for(let r of Object.keys(e.overlay)){let u=e.outbox[r];if(u===void 0||u.state==="rejected"||u.state==="expired"){delete e.overlay[r],delete e.overlayMisses[r],delete e.overlayWatermarks[r],delete e.overlayNegatives[r],u&&delete u.predicted;continue}for(let v of e.overlay[r]){let T=h(v),ce=i.get(T);ce!==void 0&&ce.seq>=(e.overlayNegatives[r]?.[T]?.seq??-1)&&((e.overlayNegatives[r]??={})[T]=ce)}if(u.state!=="committed")continue;if(e.overlayWatermarks[r]==null&&O!==void 0){let v=D.has(r)&&e.overlayWatermarks[r]!==null?M??O:O;e.overlayWatermarks[r]={op:v.op,args:y(v.args),cursorArg:v.cursorArg??"c",watermark:v.watermark}}let l=u.response?.seq;if(!Number.isSafeInteger(l)){delete e.overlay[r],delete e.overlayMisses[r],delete e.overlayWatermarks[r],delete e.overlayNegatives[r],delete u.predicted;continue}let f=e.overlay[r],b=Number(l),k=new Set(f.filter(v=>!v.removed).map(h)),A=e.overlayWatermarks[r]??void 0,$=A?w({op:A.op,args:A.args,cursorArg:A.cursorArg,watermark:A.watermark,seq:b}):"";if(!q.has($)){let v=A?ke(W,A,b):[];q.set($,{chain:v,reached:new Set(v)})}let{chain:x,reached:R}=q.get($),g=f.some(v=>{let T=e.overlayNegatives[r]?.[h(v)];return T!==void 0&&T.seq>=b&&(e.rowSeq[h(v)]??-1)<=T.seq})||F.some(v=>v.seq>=b&&!v.retained&&v.state!=="denied"&&v.refs.some(T=>k.has(h(T))&&e.rows[h(T)]!==void 0))||k.size>0&&A!==void 0&&W.some(v=>v.seq>=b&&R.has(te(v,A))),Q=A!==void 0&&n.watermark!==void 0&&O!==void 0&&N(O.op,O.args)===N(n.watermark.op,n.watermark.args)&&Ae(A,O,x)||n.resumeSeq!==void 0&&n.resumeSeq>b,ae=g?0:(e.overlayMisses[r]??0)+(Q&&!D.has(r)?1:0);if(!g&&ae<Ve){ae>0&&(e.overlayMisses[r]=ae);continue}delete e.overlay[r],delete e.overlayMisses[r],delete e.overlayWatermarks[r],delete e.overlayNegatives[r],delete u.predicted}return e}ensureOpen(){if(this.partition===void 0)throw new I("E_OFFLINE_CARRIER",`${this.backend.carrier} range store is not open`)}ensureUnsealed(){if(this.state.sealed)throw new I("E_OFFLINE_CARRIER","range store is sealed")}enqueue(e){let n=this.tail.then(e);return this.tail=n.then(()=>{},()=>{}),n}async read(e){return await this.tail,this.ensureOpen(),e()}};function Ie(t){let{rows:e={},answers:n={},outbox:s={},...o}=K(t),i=c=>Object.entries(c).map(([a,d])=>({key:a,value:d}));return{rows:i(e),answers:i(n),outbox:i(s),meta:[{key:"state",value:o}]}}function Te(t){let e=t.meta.find(({key:s})=>s==="state");if(!e&&!t.rows.length&&!t.answers.length&&!t.outbox.length)return;let n=s=>Object.fromEntries(s.map(({key:o,value:i})=>[o,i]));return{...z(),...e?.value,rows:n(t.rows),answers:n(t.answers),outbox:n(t.outbox)}}var me=["rows","answers","outbox","meta"],Ke=["ranges","absences","verdicts"],oe="bytes",qe=[...me,oe],Je=3;function J(t){return new Promise((e,n)=>{t.onsuccess=()=>e(t.result),t.onerror=()=>n(t.error??new Error("IndexedDB request failed"))})}function ge(t){return new Promise((e,n)=>{t.oncomplete=()=>e(),t.onabort=()=>n(t.error??new Error("IndexedDB transaction aborted")),t.onerror=()=>n(t.error??new Error("IndexedDB transaction failed"))})}function Qe(t,e){return new Promise((n,s)=>{let o=t.open(e,Je);o.onupgradeneeded=()=>{for(let i of qe)o.result.objectStoreNames.contains(i)||o.result.createObjectStore(i,{keyPath:"key"});for(let i of Ke)o.result.objectStoreNames.contains(i)&&o.result.deleteObjectStore(i)},o.onsuccess=()=>n(o.result),o.onerror=()=>s(o.error??new Error("IndexedDB open failed")),o.onblocked=()=>s(new Error("IndexedDB open was blocked"))})}function Xe(t,e){return new Promise((n,s)=>{let o=t.deleteDatabase(e);o.onsuccess=()=>n(),o.onerror=()=>s(o.error??new Error("IndexedDB delete failed")),o.onblocked=()=>s(new Error("IndexedDB delete was blocked"))})}var be=class{constructor(e,n,s,o){this.factory=e;this.locks=n;this.prefix=s;this.beforeReplace=o}carrier="IndexedDB";database;databaseName;releaseLock;async open(e){await this.close();let n=`${this.prefix}${e}`;await this.acquireLock(e);try{let s=await Qe(this.factory,n);this.database=s,this.databaseName=n;let o=s.transaction(me,"readonly"),i=o.objectStore("rows").getAll(),c=o.objectStore("answers").getAll(),a=o.objectStore("outbox").getAll(),d=o.objectStore("meta").get("state"),[p,m,P,S]=await Promise.all([J(i),J(c),J(a),J(d),ge(o)]);return Te({rows:p,answers:m,outbox:P,meta:S?[S]:[]})}catch(s){throw await this.close(),s instanceof I?s:new I("E_OFFLINE_CARRIER",`IndexedDB carrier could not open ${n}: ${s instanceof Error?s.message:String(s)}`)}}async replace(e,n){let s=this.database;if(!s)throw new I("E_OFFLINE_CARRIER","IndexedDB carrier is not open");let o=Ie(e);await this.beforeReplace?.(e);let i=s.transaction(qe,"readwrite");try{for(let c of me){let a=i.objectStore(c);a.clear();for(let d of o[c])a.put(d)}if(n.remove.length>0||n.put.length>0){let c=i.objectStore(oe);for(let a of n.remove)c.delete(a);for(let a of n.put)c.put({key:a.key,value:a.bytes})}}catch(c){throw i.abort(),c}await ge(i)}async readBytes(e){let n=this.database;if(!n)return;let s=n.transaction([oe],"readonly"),o=s.objectStore(oe).get(e),[i]=await Promise.all([J(o),ge(s)]),c=i?.value;if(c instanceof Uint8Array)return c;if(c instanceof ArrayBuffer)return new Uint8Array(c)}async wipe(e){let n=`${this.prefix}${e}`;this.databaseName===n&&await this.close(),await Xe(this.factory,n)}async close(){this.database?.close(),this.database=void 0,this.databaseName=void 0,this.releaseLock?.(),this.releaseLock=void 0}async acquireLock(e){let n,s,o,i=new Promise((d,p)=>{n=d,s=p}),c=new Promise(d=>{o=d});this.locks.request(`snapback2:${e}`,{ifAvailable:!0},async d=>{if(!d){s(new I("E_OFFLINE_LOCK","this account is open in another tab"));return}this.releaseLock=o,n(),await c}).catch(s),await i}};function Ze(t={}){let e=t.indexedDB??globalThis.indexedDB,n=t.locks??(typeof navigator>"u"?void 0:navigator.locks);if(!e||!n||typeof n.request!="function"){let i=(()=>new G({carrier:"IndexedDB",open:async()=>{throw new I("E_OFFLINE_CARRIER","IndexedDB and Web Locks are required")},replace:async()=>{throw new I("E_OFFLINE_CARRIER","IndexedDB is unavailable")},wipe:async()=>{},close:()=>{}}));return Object.defineProperty(i,"carrier",{value:"IndexedDB"}),i}let s=t.databasePrefix??"snapback2:",o=(()=>new G(new be(e,n,s,t.beforeReplace)));return Object.defineProperty(o,"carrier",{value:"IndexedDB"}),o}var Le=()=>()=>{},ie=()=>0;function De(t){let e=Ne(),n=Re(),s=e.assetCache,o=$e(s?.subscribeCustody??Le,s?.getCustody??ie,ie),i=_e({}).current,c=je(()=>({client:e,url:t,auth:n.authGeneration,custody:o}),[e,t,n.authGeneration,o]),[a,d]=U();return H(()=>{if(!t||typeof URL.createObjectURL!="function")return;let p=!0,m,P=new AbortController;if(t.startsWith("blob:")){d({identity:c,url:t});return}return e.assetBlob(t,{signal:P.signal,viewing:i}).then(S=>{!p||(s?.getCustody?.()??0)!==o||(m=URL.createObjectURL(S),d({identity:c,url:m}))}).catch(S=>{p&&he(S)&&d({identity:c,refusal:S})}),()=>{p=!1,P.abort(),m&&URL.revokeObjectURL(m)}},[c]),a?.identity===c?a:void 0}function At({asset:t,width:e,height:n,style:s,...o}){let[i,c]=U(null),[a,d]=U(),[p,m]=U(!1);H(()=>{if(!i)return;let _=O=>{let D=typeof e=="number"?e:t.width,F=O>0?O:D,W=typeof window>"u"?1:window.devicePixelRatio||1;d(Math.max(1,Math.ceil(F*W))),m(!0)};if(_(i.getBoundingClientRect().width),typeof ResizeObserver>"u")return;let M=new ResizeObserver(O=>_(O[0]?.contentRect.width??0));return M.observe(i),()=>M.disconnect()},[i,e,t.id,t.width]);let P=Ce(p?t:null,{width:a}),S=De(P);return E.createElement("img",{...o,ref:c,src:S?.url,width:e??t.width,height:n??t.height,style:{aspectRatio:`${t.width} / ${t.height}`,...s}})}function xt({asset:t,width:e,height:n,style:s,controls:o,onPlay:i,onRefusal:c,...a}){let d=Ne(),p=Re(),m=d.assetCache,P=$e(m?.subscribeCustody??Le,m?.getCustody??ie,ie),S=je(()=>({client:d,id:t.id,auth:p.authGeneration,custody:P}),[d,t.id,p.authGeneration,P]),[_,M]=U(),[O,D]=U(),[F,W]=U(),q=_e(c);q.current=c,H(()=>{let x=!0;return(async()=>{await d.ready;let R=await m?.viewed(t.id)??!1,Y=R||(await m?.viewOnce(t.id)??!1);x&&(M({identity:S,once:Y,viewed:R}),R&&q.current?.(ee(t.id)))})().catch(R=>{x&&he(R)&&q.current?.(R)}),()=>{x=!1}},[S,m]);let r=_?.identity===S?_:void 0,u=r?.once===!1,l=r?.once===!0&&!r.viewed&&O===S,f=Ce(u?t:null,{carrier:!0});H(()=>{if(!l)return;let x=!0;return(async()=>{if(await m?.viewed(t.id))throw ee(t.id);let R=await d.assetUrl(t);if(!R)throw ee(t.id);x&&W({identity:S,url:R})})().catch(R=>{x&&he(R)&&q.current?.(R)}),()=>{x=!1}},[S,l]);let b=F?.identity===S?F.url:void 0,k=De(b);H(()=>{k?.refusal&&q.current?.(k.refusal)},[k?.refusal]);let A=m!==void 0&&u&&f!==void 0&&!f.startsWith("blob:");H(()=>{if(!A||p.connection==="offline")return;let x=new AbortController;return d.assetUrl(t).then(R=>R===void 0?void 0:d.assetBlob(R,{signal:x.signal})).catch(()=>{}),()=>x.abort()},[d,t.id,A]);let $=E.createElement("video",{...a,onPlay:i,controls:o??!0,autoPlay:l||a.autoPlay,src:u?f:l?k?.url:void 0,width:e??t.width,height:n??t.height,style:{aspectRatio:`${t.width} / ${t.height}`,...s}});return r?.once&&!r.viewed&&!l?E.createElement(E.Fragment,null,E.createElement("button",{type:"button",onClick:()=>D(S)},"Play once"),$):$}function Et(){let t=Re(),e=t.lastRefusal;return E.createElement("aside",{"aria-label":"Snapback development status"},E.createElement("strong",null,"Snapback"),E.createElement("dl",null,E.createElement("dt",null,"Persona"),E.createElement("dd",null,t.persona??"token"),E.createElement("dt",null,"Connection"),E.createElement("dd",null,t.connection),E.createElement("dt",null,"Generation"),E.createElement("dd",null,t.generation??"\u2014"),E.createElement("dt",null,"Last refusal"),E.createElement("dd",null,e?`${e.code}: ${e.message}`:"\u2014")))}export{At as AssetImage,xt as AssetVideo,Et as DevOverlay,Ze as indexedDbRangeStore};
|
|
2
|
+
//# sourceMappingURL=react.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/react.tsx", "../src/client-wire.ts", "../src/store/byte-cache.ts", "../src/client-assets.ts", "../src/store/canonical.ts", "../src/store/overlay-retirement.ts", "../src/store/range-store.ts", "../src/store/projection.ts", "../src/store/indexeddb.ts"],
|
|
4
|
+
"sourcesContent": ["import React, { useEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { useAssetUrl, useSnapbackClient, useSnapbackSnapshot } from \"./react-core.js\";\nimport { isSnapbackRefusal, type SnapbackRefusal } from \"./client.js\";\nimport { viewedRefusal } from \"./client-assets.js\";\nimport type { ImageAsset, VideoAsset } from \"./types.js\";\nexport * from \"./react-core.js\";\nexport { indexedDbRangeStore } from \"./store/indexeddb.js\";\n\nconst noSubscription = () => () => {};\nconst noCustody = () => 0;\n\n/** Each mounted byte consumer owns one allowance and every object URL it creates. */\nfunction useAssetBlob(url: string | undefined) {\n const client = useSnapbackClient();\n const snapshot = useSnapbackSnapshot();\n const cache = client.assetCache;\n const custody = useSyncExternalStore(cache?.subscribeCustody ?? noSubscription, cache?.getCustody ?? noCustody, noCustody);\n const viewing = useRef({}).current;\n const identity = useMemo(() => ({ client, url, auth: snapshot.authGeneration, custody }), [client, url, snapshot.authGeneration, custody]);\n const [result, setResult] = useState<{ identity: typeof identity; url?: string; refusal?: SnapbackRefusal }>();\n useEffect(() => {\n if (!url || typeof URL.createObjectURL !== \"function\") return;\n let active = true;\n let created: string | undefined;\n const controller = new AbortController();\n if (url.startsWith(\"blob:\")) { setResult({ identity, url }); return; }\n void client.assetBlob(url, { signal: controller.signal, viewing }).then((blob) => {\n if (!active || (cache?.getCustody?.() ?? 0) !== custody) return;\n created = URL.createObjectURL(blob);\n setResult({ identity, url: created });\n }).catch((error) => { if (active && isSnapbackRefusal(error)) setResult({ identity, refusal: error }); });\n return () => {\n active = false;\n controller.abort();\n if (created) URL.revokeObjectURL(created);\n };\n }, [identity]);\n return result?.identity === identity ? result : undefined;\n}\n\nexport type AssetImageProps = Omit<React.ImgHTMLAttributes<HTMLImageElement>, \"src\" | \"width\" | \"height\"> & {\n asset: ImageAsset;\n width?: number | string;\n height?: number | string;\n};\n\n// @ref LLP 1006#8-sizes-ask-for-any-width \u2014 the web image measures its box,\n// asks for device pixels, and keeps intrinsic record dimensions before bytes arrive.\nexport function AssetImage({ asset, width, height, style, ...props }: AssetImageProps): React.ReactElement {\n const [element, setElement] = useState<HTMLImageElement | null>(null);\n const [requestedWidth, setRequestedWidth] = useState<number>();\n const [measured, setMeasured] = useState(false);\n useEffect(() => {\n if (!element) return;\n const update = (layoutWidth: number) => {\n const fallback = typeof width === \"number\" ? width : asset.width;\n const cssWidth = layoutWidth > 0 ? layoutWidth : fallback;\n const ratio = typeof window === \"undefined\" ? 1 : window.devicePixelRatio || 1;\n setRequestedWidth(Math.max(1, Math.ceil(cssWidth * ratio)));\n setMeasured(true);\n };\n update(element.getBoundingClientRect().width);\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver((entries) => update(entries[0]?.contentRect.width ?? 0));\n observer.observe(element);\n return () => observer.disconnect();\n }, [element, width, asset.id, asset.width]);\n const deliveryUrl = useAssetUrl(measured ? asset : null, { width: requestedWidth });\n const blob = useAssetBlob(deliveryUrl);\n return <img\n {...props}\n ref={setElement}\n src={blob?.url}\n width={width ?? asset.width}\n height={height ?? asset.height}\n style={{ aspectRatio: `${asset.width} / ${asset.height}`, ...style }}\n />;\n}\n\nexport type AssetVideoProps = Omit<React.VideoHTMLAttributes<HTMLVideoElement>, \"src\" | \"width\" | \"height\"> & {\n asset: VideoAsset;\n onRefusal?: (refusal: SnapbackRefusal) => void;\n width?: number | string;\n height?: number | string;\n};\n\n// @ref LLP 1012#9-asset-bytes-on-the-device \u2014 a view-once clip gets a source\n// only after its play request durably admits bytes to this mounted instance.\nexport function AssetVideo({ asset, width, height, style, controls, onPlay, onRefusal, ...props }: AssetVideoProps): React.ReactElement {\n const client = useSnapbackClient();\n const snapshot = useSnapbackSnapshot();\n const cache = client.assetCache;\n const custody = useSyncExternalStore(cache?.subscribeCustody ?? noSubscription, cache?.getCustody ?? noCustody, noCustody);\n const identity = useMemo(() => ({ client, id: asset.id, auth: snapshot.authGeneration, custody }), [client, asset.id, snapshot.authGeneration, custody]);\n const [policy, setPolicy] = useState<{ identity: typeof identity; once: boolean; viewed: boolean }>();\n const [started, setStarted] = useState<typeof identity>();\n const [request, setRequest] = useState<{ identity: typeof identity; url: string }>();\n const callback = useRef(onRefusal);\n callback.current = onRefusal;\n useEffect(() => {\n let active = true;\n void (async () => {\n await client.ready;\n const viewed = await cache?.viewed(asset.id) ?? false;\n const once = viewed || (await cache?.viewOnce(asset.id) ?? false);\n if (active) {\n setPolicy({ identity, once, viewed });\n if (viewed) callback.current?.(viewedRefusal(asset.id));\n }\n })().catch((error) => { if (active && isSnapbackRefusal(error)) callback.current?.(error); });\n return () => { active = false; };\n }, [identity, cache]);\n const current = policy?.identity === identity ? policy : undefined;\n const ordinary = current?.once === false;\n const admitted = current?.once === true && !current.viewed && started === identity;\n const carrier = useAssetUrl(ordinary ? asset : null, { carrier: true });\n // Resolve at the play gesture, so concurrent players cannot retain a carrier.\n useEffect(() => {\n if (!admitted) return;\n let active = true;\n void (async () => {\n if (await cache?.viewed(asset.id)) throw viewedRefusal(asset.id);\n const url = await client.assetUrl(asset);\n if (!url) throw viewedRefusal(asset.id);\n if (active) setRequest({ identity, url });\n })().catch((error) => { if (active && isSnapbackRefusal(error)) callback.current?.(error); });\n return () => { active = false; };\n }, [identity, admitted]);\n const tokenless = request?.identity === identity ? request.url : undefined;\n const blob = useAssetBlob(tokenless);\n useEffect(() => { if (blob?.refusal) callback.current?.(blob.refusal); }, [blob?.refusal]);\n const cacheable = cache !== undefined && ordinary && carrier !== undefined && !carrier.startsWith(\"blob:\");\n useEffect(() => {\n if (!cacheable || snapshot.connection === \"offline\") return;\n const controller = new AbortController();\n void client.assetUrl(asset)\n .then((url) => url === undefined ? undefined : client.assetBlob(url, { signal: controller.signal }))\n .catch(() => undefined);\n return () => controller.abort();\n }, [client, asset.id, cacheable]);\n const video = <video {...props} onPlay={onPlay} controls={controls ?? true}\n autoPlay={admitted || props.autoPlay} src={ordinary ? carrier : admitted ? blob?.url : undefined}\n width={width ?? asset.width} height={height ?? asset.height}\n style={{ aspectRatio: `${asset.width} / ${asset.height}`, ...style }} />;\n return current?.once && !current.viewed && !admitted\n ? <><button type=\"button\" onClick={() => setStarted(identity)}>Play once</button>{video}</>\n : video;\n}\n\nexport function DevOverlay(): React.ReactElement {\n const snapshot = useSnapbackSnapshot();\n const refusal = snapshot.lastRefusal;\n return (\n <aside aria-label=\"Snapback development status\">\n <strong>Snapback</strong>\n <dl>\n <dt>Persona</dt><dd>{snapshot.persona ?? \"token\"}</dd>\n <dt>Connection</dt><dd>{snapshot.connection}</dd>\n <dt>Generation</dt><dd>{snapshot.generation ?? \"\u2014\"}</dd>\n <dt>Last refusal</dt><dd>{refusal ? `${refusal.code}: ${refusal.message}` : \"\u2014\"}</dd>\n </dl>\n </aside>\n );\n}\n", "// @ref LLP 1002#4-the-wire \u2014 every owner response is validated before public client code observes it.\nimport type {\n AuthMe,\n AuthSession,\n ChannelDelivery,\n ChannelPublishResult,\n Cursor,\n LiveQueryDelivery,\n Manifest,\n MutationResult,\n Principal,\n QueryRefusedDelivery,\n RefusalEnvelope,\n RefusedDelivery,\n ServerQueryResult,\n} from \"./types.js\";\n\nexport function fallbackRefusal(code: string, message: string): RefusalEnvelope {\n return { code, family: \"owner\", message, guide: \"owner/connect\" };\n}\n\nconst snapbackRefusalBrand = Symbol.for(\"snapback2.SnapbackRefusal\");\n\nexport class SnapbackRefusal extends Error {\n readonly [snapbackRefusalBrand] = true;\n readonly envelope: RefusalEnvelope;\n readonly code: string;\n\n constructor(envelope: RefusalEnvelope, readonly retryable = false, readonly status?: number) {\n super(envelope.message);\n this.name = \"SnapbackRefusal\";\n this.envelope = envelope;\n this.code = envelope.code;\n }\n}\n\nexport function isSnapbackRefusal(value: unknown): value is SnapbackRefusal {\n return typeof value === \"object\"\n && value !== null\n && (value as { name?: unknown }).name === \"SnapbackRefusal\"\n && (value as Record<symbol, unknown>)[snapbackRefusalBrand] === true;\n}\n\nexport function wireShape(message: string): SnapbackRefusal {\n return new SnapbackRefusal({ code: \"E_WIRE_SHAPE\", family: \"op\", message, guide: \"op/wire-shape\" });\n}\n\nexport function wireObject(value: unknown, surface: string): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) throw wireShape(`${surface} must be an object`);\n return value as Record<string, unknown>;\n}\n\nfunction has(record: Record<string, unknown>, field: string): boolean {\n return Object.prototype.hasOwnProperty.call(record, field);\n}\n\nfunction present(record: Record<string, unknown>, field: string, surface: string): unknown {\n if (!has(record, field)) throw wireShape(`${surface} is missing ${field}`);\n return record[field];\n}\n\nfunction stringField(record: Record<string, unknown>, field: string, surface: string): string {\n const value = present(record, field, surface);\n if (typeof value !== \"string\" || value.length === 0) throw wireShape(`${surface}.${field} must be a non-empty string`);\n return value;\n}\n\nfunction numberField(record: Record<string, unknown>, field: string, surface: string): number {\n const value = present(record, field, surface);\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw wireShape(`${surface}.${field} must be a number`);\n return value;\n}\n\nfunction optionalString(record: Record<string, unknown>, field: string, surface: string): string | undefined {\n if (!has(record, field)) return undefined;\n const value = record[field];\n if (typeof value !== \"string\") throw wireShape(`${surface}.${field} must be a string`);\n return value;\n}\n\nfunction optionalNumber(record: Record<string, unknown>, field: string, surface: string): number | undefined {\n if (!has(record, field)) return undefined;\n const value = record[field];\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw wireShape(`${surface}.${field} must be a number`);\n return value;\n}\n\nfunction nullableString(record: Record<string, unknown>, field: string, surface: string): string | null {\n const value = present(record, field, surface);\n if (value !== null && typeof value !== \"string\") throw wireShape(`${surface}.${field} must be a string or null`);\n return value;\n}\n\nexport function wireRefusalEnvelope(value: unknown, surface: string): RefusalEnvelope {\n const record = wireObject(value, surface);\n const envelope: RefusalEnvelope = {\n code: stringField(record, \"code\", surface),\n family: stringField(record, \"family\", surface),\n message: stringField(record, \"message\", surface),\n guide: stringField(record, \"guide\", surface),\n };\n for (const field of [\"site\", \"rule\", \"rewrite\"] as const) {\n const item = optionalString(record, field, surface);\n if (item !== undefined) envelope[field] = item;\n }\n const which = optionalString(record, \"which\", surface);\n if (which !== undefined) envelope.which = which;\n const cap = optionalNumber(record, \"cap\", surface);\n if (cap !== undefined) envelope.cap = cap;\n return envelope;\n}\n\nexport function copyRefusal(envelope: RefusalEnvelope): RefusalEnvelope {\n const refusal: RefusalEnvelope = {\n code: envelope.code, family: envelope.family, message: envelope.message, guide: envelope.guide,\n };\n if (envelope.site !== undefined) refusal.site = envelope.site;\n if (envelope.rule !== undefined) refusal.rule = envelope.rule;\n if (envelope.rewrite !== undefined) refusal.rewrite = envelope.rewrite;\n if (envelope.which !== undefined) refusal.which = envelope.which;\n if (envelope.cap !== undefined) refusal.cap = envelope.cap;\n return refusal;\n}\n\nexport function isTerminalSession(envelope: Pick<RefusalEnvelope, \"code\" | \"family\">): boolean {\n return envelope.code === \"E_AUTH_SESSION\" && envelope.family === \"auth\";\n}\n\nexport function wireQuery<Result>(value: unknown, surface = \"query response\"): ServerQueryResult<Result> {\n const record = wireObject(value, surface);\n switch (stringField(record, \"state\", surface)) {\n case \"complete\":\n return {\n state: \"complete\", data: present(record, \"data\", surface) as Result,\n seq: numberField(record, \"seq\", surface), next: nullableString(record, \"next\", surface) as Cursor | null,\n };\n case \"capped\":\n for (const field of [\"site\", \"take\", \"reason\"]) {\n if (has(record, field)) throw wireShape(`${surface}.capped must not carry ${field}`);\n }\n return {\n state: \"capped\", data: present(record, \"data\", surface) as Result,\n seq: numberField(record, \"seq\", surface), next: nullableString(record, \"next\", surface) as Cursor | null,\n };\n case \"partial\": {\n if (has(record, \"next\")) throw wireShape(`${surface}.partial must not carry next`);\n const partial = {\n state: \"partial\" as const,\n seq: numberField(record, \"seq\", surface),\n reason: stringField(record, \"reason\", surface),\n };\n return has(record, \"data\") ? { ...partial, data: record.data as Result } : partial;\n }\n case \"denied\":\n if (has(record, \"next\")) throw wireShape(`${surface}.denied must not carry next`);\n return { state: \"denied\", seq: numberField(record, \"seq\", surface), rule: stringField(record, \"rule\", surface) };\n default:\n throw wireShape(`${surface}.state must be complete, capped, partial, or denied`);\n }\n}\n\nexport function wireMutation<Result>(value: unknown): MutationResult<Result> {\n const surface = \"mutation response\";\n const record = wireObject(value, surface);\n if (has(record, \"next\")) throw wireShape(`${surface} must not carry next`);\n switch (stringField(record, \"state\", surface)) {\n case \"committed\":\n return { state: \"committed\", data: present(record, \"data\", surface) as Result, seq: numberField(record, \"seq\", surface) };\n case \"rejected\":\n return { state: \"rejected\", ...wireRefusalEnvelope(record, \"mutation rejected response\") };\n default:\n throw wireShape(`${surface}.state must be committed or rejected`);\n }\n}\n\nexport function wireSubscription<Result>(data: string): LiveQueryDelivery<Result> | QueryRefusedDelivery {\n const surface = \"subscription delivery\";\n const record = sseObject(data, surface);\n if (stringField(record, \"state\", surface) === \"refused\") {\n if (has(record, \"next\")) throw wireShape(`${surface}.refused must not carry next`);\n const refusal = wireRefusalEnvelope(record, `${surface} refusal`);\n const seq = optionalNumber(record, \"seq\", surface);\n return { state: \"refused\", live: false, ...refusal, ...(seq === undefined ? {} : { seq }) };\n }\n return { ...wireQuery<Result>(record, surface), live: true };\n}\n\nexport function wireChannelDelivery<Payload>(data: string): ChannelDelivery<Payload> {\n const surface = \"channel delivery\";\n const record = sseObject(data, surface);\n if (record.state === \"refused\") {\n return { state: \"refused\", ...wireRefusalEnvelope(record, `${surface} refusal`) } as RefusedDelivery;\n }\n return {\n from: stringField(record, \"from\", surface) as Principal,\n payload: present(record, \"payload\", surface) as Payload,\n at: numberField(record, \"at\", surface),\n };\n}\n\nexport function wireChannelPublish(value: unknown): ChannelPublishResult {\n const surface = \"channel publish response\";\n const record = wireObject(value, surface);\n if (record.ok === true) return { ok: true };\n if (record.state !== \"refused\") throw wireShape(`${surface} must contain ok: true or state: refused`);\n return { state: \"refused\", ...wireRefusalEnvelope(record, `${surface} refusal`) };\n}\n\nexport function terminalSessionEnvelope(value: unknown): RefusalEnvelope | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n if (record.state !== \"rejected\" && record.state !== \"refused\") return undefined;\n // A replayed write's trace conflict carries no code (LLP 1012 \u00A77); it is never a session terminal.\n if (record.state === \"rejected\" && record.reason === \"conflict\") return undefined;\n const refusal = wireRefusalEnvelope(record, \"terminal session response\");\n return isTerminalSession(refusal) ? refusal : undefined;\n}\n\nexport function wireAuthSession(value: unknown, surface: string): AuthSession {\n const record = wireObject(value, surface);\n return { token: stringField(record, \"token\", surface), viewer: stringField(record, \"viewer\", surface) as Principal };\n}\n\nexport function wireAuthMe(value: unknown): AuthMe {\n const surface = \"auth me response\";\n const record = wireObject(value, surface);\n return { viewer: stringField(record, \"viewer\", surface) as Principal, kind: stringField(record, \"kind\", surface) };\n}\n\nexport function wireLogout(value: unknown): { ok: boolean } {\n const surface = \"auth logout response\";\n const record = wireObject(value, surface);\n if (typeof present(record, \"ok\", surface) !== \"boolean\") throw wireShape(`${surface}.ok must be a boolean`);\n return { ok: record.ok as boolean };\n}\n\nexport function wireManifest(value: unknown): Manifest {\n const surface = \"manifest response\";\n const record = wireObject(value, surface);\n const ops = wireObject(present(record, \"ops\", surface), `${surface}.ops`);\n for (const [name, operation] of Object.entries(ops)) {\n const item = wireObject(operation, `${surface}.ops.${name}`);\n stringField(item, \"kind\", `${surface}.ops.${name}`);\n stringField(item, \"planHash\", `${surface}.ops.${name}`);\n present(item, \"args\", `${surface}.ops.${name}`);\n }\n const manifest: Manifest = {\n generation: stringField(record, \"generation\", surface),\n programGeneration: stringField(record, \"programGeneration\", surface),\n ops: ops as unknown as Manifest[\"ops\"],\n channels: wireObject(present(record, \"channels\", surface), `${surface}.channels`),\n auth: wireObject(present(record, \"auth\", surface), `${surface}.auth`),\n };\n if (typeof record.schemaHash === \"string\") manifest.schemaHash = record.schemaHash;\n if (record.tables && typeof record.tables === \"object\" && !Array.isArray(record.tables)) {\n manifest.tables = record.tables as Manifest[\"tables\"];\n }\n if (record.schema && typeof record.schema === \"object\" && !Array.isArray(record.schema)) {\n manifest.schema = record.schema as Manifest[\"schema\"];\n }\n return manifest;\n}\n\nexport function wireAssetSession(value: unknown): { token: string; expiresAt: number } {\n const surface = \"asset session response\";\n const record = wireObject(value, surface);\n return { token: stringField(record, \"token\", surface), expiresAt: numberField(record, \"expiresAt\", surface) };\n}\n\nexport async function responseRefusal(response: Response): Promise<SnapbackRefusal> {\n let value: unknown;\n try {\n value = await response.json();\n } catch {\n throw new SnapbackRefusal(\n fallbackRefusal(\"E_TRANSPORT\", `HTTP ${response.status} did not contain a refusal envelope`),\n true,\n response.status,\n );\n }\n if (!value || typeof value !== \"object\" || Array.isArray(value)\n || ![\"code\", \"family\", \"guide\"].some((field) => has(value as Record<string, unknown>, field))) {\n throw new SnapbackRefusal(\n fallbackRefusal(\"E_TRANSPORT\", `HTTP ${response.status} did not contain a refusal envelope`),\n true,\n response.status,\n );\n }\n return new SnapbackRefusal(wireRefusalEnvelope(value, `HTTP ${response.status} refusal`), false, response.status);\n}\n\nexport function sseObject(data: string, surface: string): Record<string, unknown> {\n try {\n return wireObject(JSON.parse(data), surface);\n } catch (error) {\n if (isSnapbackRefusal(error)) throw error;\n throw wireShape(`${surface} must contain valid JSON`);\n }\n}\n\n/**\n * `AbortSignal.prototype.throwIfAborted` does not exist on React Native's AbortSignal\n * (Hermes, RN 0.81 / Expo SDK 54), so every abort check goes through this helper.\n */\nexport function throwIfAborted(signal?: AbortSignal | null): void {\n if (!signal?.aborted) return;\n const reason: unknown = (signal as { reason?: unknown }).reason;\n if (reason instanceof Error) throw reason;\n const error = new Error(typeof reason === \"string\" ? reason : \"The operation was aborted\");\n error.name = \"AbortError\";\n throw error;\n}\n", "// @ref LLP 1006#9b-bytes-on-the-device-author-ruling-2026-09-04 \u2014 bytes are cached under the owning row's lease, or not at all.\n// @ref LLP 1012#9-asset-bytes-on-the-device \u2014 the ByteCache sits beside the range store and joins its swap; view-once is excluded at view time.\n\nimport type { RangeStore, RowRef, StoredRow } from \"./range-store.js\";\n\n/** One cached rendition: what a component fetched at the width it asked for. */\nexport interface ByteCacheEntry {\n assetId: string;\n width: number | null;\n size: number;\n type: string;\n /** Logical last-read stamp on the range store's clock; the LRU orders by it. */\n lastRead: number;\n}\n\n/** A view-once row that was viewed, with the asset ids it carried at that moment. */\nexport interface ViewedRecord { at: number; assets: string[] }\n\nexport interface ByteCachePut { assetId: string; width: number | null; bytes: Uint8Array; type: string }\nexport interface ByteSwapRequest { put?: ByteCachePut[]; touch?: string[]; ceiling?: number }\n\n/** What a carrier persists beside the state in the same swap: payloads to write and keys to drop. */\nexport interface ByteDelta { put: Array<{ key: string; bytes: Uint8Array }>; remove: string[] }\n\nexport interface ByteCacheStatus { entries: ByteCacheEntry[]; totalBytes: number; viewed: RowRef[] }\nexport interface AssetBytes { bytes: Uint8Array; type: string }\n/** An opaque identity held by one mounted viewing instance, never shared by asset id. */\nexport interface AssetFetchOptions { signal?: AbortSignal; viewing?: object }\nexport type ByteCacheOutcome = \"cached\" | \"viewed\" | \"unleased\" | \"refused\";\nexport type ViewOncePredicate = (table: string, row: Record<string, unknown>) => boolean;\n\n/** The byte surface the swap engine exposes beside `RangeStore`; only the carriers implement it. */\nexport interface ByteCarrier {\n readBytes(assetId: string, width: number | null): Promise<{ bytes: Uint8Array; type: string } | undefined>;\n bytes(): Promise<ByteCacheStatus>;\n rowsReferencing(assetId: string): Promise<StoredRow[]>;\n viewedAsset(assetId: string): Promise<boolean>;\n viewedRows(): Promise<RowRef[]>;\n /** LRU read stamps, coalesced: stamped in memory now, persisted by the next swap. */\n touchBytes(keys: string[]): Promise<void>;\n commit(swap: { bytes?: ByteSwapRequest; viewed?: RowRef[] }): Promise<void>;\n}\n\n/** The client-facing byte cache: `client.assetCache` when the client has an offline store. */\nexport interface AssetCache {\n /** Session custody changes revoke mounted object URLs. */\n subscribeCustody?(listener: () => void): () => void;\n getCustody?(): number;\n getBytes(assetId: string, width: number | null, viewing?: object): Promise<AssetBytes | undefined>;\n putBytes(assetId: string, width: number | null, value: AssetBytes, viewing?: object): Promise<ByteCacheOutcome>;\n canServe(assetId: string, viewing?: object): Promise<boolean>;\n /** The held bytes for an asset at a width, or nothing: never fetched, evicted with its row, viewed, or sealed. */\n get(assetId: string, width: number | null, viewing?: object): Promise<Blob | undefined>;\n /** True once a view-once row carrying this asset was viewed on this partition. */\n viewed(assetId: string): Promise<boolean>;\n /** True while a held row carrying this asset is view-once (`offline.viewOnce`) and not yet viewed. */\n viewOnce(assetId: string): Promise<boolean>;\n /** Marks the held view-once rows carrying this asset viewed: what a player calls when playback starts. */\n markViewed(assetId: string): Promise<boolean>;\n status(): Promise<ByteCacheStatus>;\n}\n\nexport const ASSET_ID = /^s2id-[0-9a-f]{32}-[0-9a-f]{16}$/;\nconst SESSION_VIEW_LIMIT = 8;\n\nexport function byteKey(assetId: string, width: number | null): string {\n return width === null ? assetId : `${assetId}.w${width}`;\n}\n\nfunction rowKey(ref: RowRef): string {\n return `${ref.table}\\u0000${ref.id}`;\n}\n\nfunction positive(value: unknown): boolean {\n return typeof value === \"number\" && Number.isSafeInteger(value) && value > 0;\n}\n\n/** The closed asset record shape (LLP 1006 \u00A71): exactly id, width, height, and duration for video. */\nexport function assetRecordId(value: unknown): string | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n const record = value as Record<string, unknown>;\n const keys = Object.keys(record).sort().join(\",\");\n if (keys !== \"height,id,width\" && keys !== \"duration,height,id,width\") return undefined;\n if (typeof record.id !== \"string\" || !ASSET_ID.test(record.id)) return undefined;\n if (!positive(record.width) || !positive(record.height)) return undefined;\n if (\"duration\" in record && !positive(record.duration)) return undefined;\n return record.id;\n}\n\nexport function assetIdsIn(value: unknown, output = new Set<string>()): Set<string> {\n const id = assetRecordId(value);\n if (id !== undefined) output.add(id);\n else if (Array.isArray(value)) for (const item of value) assetIdsIn(item, output);\n else if (value && typeof value === \"object\") {\n for (const item of Object.values(value as Record<string, unknown>)) assetIdsIn(item, output);\n }\n return output;\n}\n\n/** Assets a held delivery references: through pooled rows and through inline answer data. */\nexport function leasedAssets(rows: Iterable<StoredRow>, answers: Iterable<{ data?: unknown }>): Set<string> {\n const leased = new Set<string>();\n for (const row of rows) assetIdsIn(row.row, leased);\n for (const answer of answers) if (answer.data !== undefined) assetIdsIn(answer.data, leased);\n return leased;\n}\n\nexport interface ByteSwapState {\n clock: number;\n rows: Record<string, StoredRow>;\n assets: Record<string, ByteCacheEntry>;\n viewed: Record<string, ViewedRecord>;\n}\n\n/**\n * View-once is tracked per row, never per asset id: an asset is refused only while\n * every held row carrying it was viewed. A row that is not viewed keeps its lease,\n * so one shared id never poisons an ordinary row's bytes.\n */\nexport function viewedOnlyAssets(state: Pick<ByteSwapState, \"rows\" | \"viewed\">): Set<string> {\n const viewed = new Set<string>();\n for (const record of Object.values(state.viewed)) for (const id of record.assets) viewed.add(id);\n if (viewed.size === 0) return viewed;\n for (const [key, row] of Object.entries(state.rows)) {\n if (state.viewed[key]) continue;\n for (const id of assetIdsIn(row.row)) viewed.delete(id);\n }\n return viewed;\n}\n\nfunction checkedPut(put: ByteCachePut): void {\n if (!put || typeof put !== \"object\" || typeof put.assetId !== \"string\" || !ASSET_ID.test(put.assetId)) {\n throw new TypeError(\"byte cache put must name an engine-minted asset id\");\n }\n if (put.width !== null && !positive(put.width)) throw new TypeError(\"byte cache put width must be null or a positive integer\");\n if (!(put.bytes instanceof Uint8Array)) throw new TypeError(\"byte cache put bytes must be a Uint8Array\");\n if (typeof put.type !== \"string\") throw new TypeError(\"byte cache put type must be a string\");\n}\n\n/**\n * The byte half of one swap, run after the row rules settled `state.rows`: viewed\n * marks, the lease purge, read touches, puts, then the ceiling. Returns what the\n * carrier must write and drop in the same transaction.\n */\nexport function applyByteSwap(\n state: ByteSwapState,\n swap: { bytes?: ByteSwapRequest; viewed?: RowRef[] },\n leased: Set<string>,\n): ByteDelta {\n const delta: ByteDelta = { put: [], remove: [] };\n for (const ref of swap.viewed ?? []) {\n if (!ref || typeof ref.table !== \"string\" || typeof ref.id !== \"string\") throw new TypeError(\"viewed rows must be row references\");\n const key = rowKey(ref);\n const assets = new Set(state.viewed[key]?.assets ?? []);\n assetIdsIn(state.rows[key]?.row, assets);\n state.viewed[key] = { at: Date.now(), assets: [...assets] };\n }\n const viewedAssets = viewedOnlyAssets(state);\n for (const [key, entry] of Object.entries(state.assets)) {\n if (leased.has(entry.assetId) && !viewedAssets.has(entry.assetId)) continue;\n delete state.assets[key];\n delta.remove.push(key);\n }\n for (const key of swap.bytes?.touch ?? []) {\n const entry = state.assets[key];\n if (entry) entry.lastRead = ++state.clock;\n }\n const ceiling = swap.bytes?.ceiling ?? Number.POSITIVE_INFINITY;\n if (!(ceiling > 0)) throw new TypeError(\"byte cache ceiling must be positive\");\n for (const put of swap.bytes?.put ?? []) {\n checkedPut(put);\n if (!leased.has(put.assetId) || viewedAssets.has(put.assetId)) continue;\n const size = put.bytes.byteLength;\n if (size === 0 || size > ceiling) continue;\n const key = byteKey(put.assetId, put.width);\n state.assets[key] = { assetId: put.assetId, width: put.width, size, type: put.type, lastRead: ++state.clock };\n delta.put.push({ key, bytes: put.bytes });\n }\n let total = Object.values(state.assets).reduce((sum, entry) => sum + entry.size, 0);\n while (total > ceiling) {\n const [key, victim] = Object.entries(state.assets)\n .reduce((least, item) => item[1].lastRead < least[1].lastRead ? item : least);\n delete state.assets[key];\n delta.remove.push(key);\n total -= victim.size;\n }\n delta.put = delta.put.filter((item) => state.assets[item.key] !== undefined);\n delta.remove = [...new Set(delta.remove)].filter((key) => state.assets[key] === undefined);\n return delta;\n}\n\nfunction isByteCarrier(store: RangeStore): store is RangeStore & ByteCarrier {\n const candidate = store as Partial<ByteCarrier>;\n return typeof candidate.readBytes === \"function\"\n && typeof candidate.bytes === \"function\"\n && typeof candidate.rowsReferencing === \"function\"\n && typeof candidate.viewedAsset === \"function\"\n && typeof candidate.viewedRows === \"function\"\n && typeof candidate.touchBytes === \"function\";\n}\n\nfunction checkedAssetId(assetId: string): string {\n if (typeof assetId !== \"string\" || !ASSET_ID.test(assetId)) throw new TypeError(\"asset id must be engine-minted\");\n return assetId;\n}\n\n/**\n * Bytes a component fetched, kept under the owning row's lease in the same\n * partition as the rows. A store without a byte carrier caches nothing.\n */\nexport class ByteCache implements AssetCache {\n /**\n * View-once bytes stay renderable inside the instance that viewed them, keyed by\n * the partition that viewed them; nothing here is durable. The runtime forgets it\n * on seal, wipe, partition change, and close, and `get` serves it only under the\n * custody the carrier path applies: this partition, unsealed, the row still held.\n */\n private readonly session = new Map<string, { viewing: object; value: AssetBytes }>();\n private partition?: string;\n private custody = 0;\n private readonly custodyListeners = new Set<() => void>();\n readonly getCustody = () => this.custody;\n readonly subscribeCustody = (listener: () => void) => {\n this.custodyListeners.add(listener);\n return () => { this.custodyListeners.delete(listener); };\n };\n private admissions: Promise<unknown> = Promise.resolve();\n\n constructor(\n readonly store: RangeStore,\n private readonly options: { maxAssetBytes: number; viewOnce?: ViewOncePredicate },\n ) {}\n\n /** The partition the runtime opened; a change drops every session blob. */\n bind(partition: string | undefined): void {\n if (this.partition !== partition) this.forget();\n this.partition = partition;\n }\n\n /** Drops the session blobs: seal, close, and wipe call this. */\n forget(): void {\n this.custody++;\n this.session.clear();\n for (const listener of this.custodyListeners) listener();\n }\n\n async get(assetId: string, width: number | null, viewing?: object): Promise<Blob | undefined> {\n const held = await this.getBytes(assetId, width, viewing);\n return held ? new Blob([held.bytes as BlobPart], { type: held.type }) : undefined;\n }\n\n // @ref LLP 1013#2-decisions \u2014 native paths exchange bytes, never RN Blobs.\n async getBytes(assetId: string, width: number | null, viewing?: object): Promise<AssetBytes | undefined> {\n const custody = this.custody;\n checkedAssetId(assetId);\n const store = this.carrier();\n if (!store) return undefined;\n // `viewedAsset` is false on a sealed partition, so the session is never consulted past a seal.\n if (await store.viewedAsset(assetId)) {\n const held = await this.sessionBytes(assetId, width, viewing);\n return custody === this.custody ? held : undefined;\n }\n if (await this.viewOnce(assetId)) return undefined;\n const held = await store.readBytes(assetId, width);\n if (!held) return undefined;\n // The touch is the LRU stamp, coalesced into the next swap; a closing partition may refuse it.\n await store.touchBytes([byteKey(assetId, width)]).catch(() => undefined);\n return await this.canServe(assetId, viewing) && custody === this.custody ? held : undefined;\n }\n\n /** Completion fence for both a cached source and an uncached ordinary source. */\n async canServe(assetId: string, viewing?: object): Promise<boolean> {\n const custody = this.custody;\n const store = this.carrier();\n if (!store) return false;\n const rows = await store.rowsReferencing(assetId);\n if (rows.length === 0) return false;\n const viewed = await store.viewedAsset(assetId);\n const once = rows.every((row) => this.options.viewOnce?.(row.table, row.row) === true);\n const owns = (!viewed && !once) || [...this.session.entries()].some(([key, entry]) =>\n entry.viewing === viewing && key.startsWith(this.sessionKey(assetId)));\n return custody === this.custody && owns;\n }\n\n async viewed(assetId: string): Promise<boolean> {\n checkedAssetId(assetId);\n const store = this.carrier();\n return store ? store.viewedAsset(assetId) : false;\n }\n\n async viewOnce(assetId: string): Promise<boolean> {\n checkedAssetId(assetId);\n const store = this.carrier();\n if (!store) return false;\n const once = await this.viewOnceRows(assetId);\n if (once.length === 0) return false;\n const viewed = new Set((await store.viewedRows()).map(rowKey));\n return once.some((ref) => !viewed.has(rowKey(ref)));\n }\n\n async markViewed(assetId: string): Promise<boolean> {\n checkedAssetId(assetId);\n const store = this.carrier();\n if (!store) return false;\n const once = await this.viewOnceRows(assetId);\n if (once.length === 0) return false;\n await store.commit({ viewed: once });\n return true;\n }\n\n /** After a network fetch: cache under the row's lease, or mark the view-once rows viewed and cache nothing. */\n async put(assetId: string, width: number | null, blob: Blob, viewing?: object): Promise<ByteCacheOutcome> {\n const custody = this.custody;\n const bytes = new Uint8Array(await blob.arrayBuffer());\n if (custody !== this.custody) return \"refused\";\n return this.putBytes(assetId, width, { bytes, type: blob.type }, viewing);\n }\n\n putBytes(assetId: string, width: number | null, value: AssetBytes, viewing?: object): Promise<ByteCacheOutcome> {\n const custody = this.custody;\n // Two concurrent consumers may fetch; only one can acquire the viewing allowance.\n const result = this.admissions.then(() => custody === this.custody\n ? this.admit(assetId, width, value, viewing) : \"refused\" as const);\n this.admissions = result.catch(() => undefined);\n return result;\n }\n\n private async admit(assetId: string, width: number | null, value: AssetBytes, viewing?: object): Promise<ByteCacheOutcome> {\n const custody = this.custody;\n checkedAssetId(assetId);\n checkedPut({ assetId, width, ...value });\n const store = this.carrier();\n if (!store) return \"unleased\";\n if (await store.viewedAsset(assetId)) return \"refused\";\n const rows = await store.rowsReferencing(assetId);\n if (rows.length === 0 || custody !== this.custody) return \"unleased\";\n const once = rows\n .filter((row) => this.options.viewOnce?.(row.table, row.row) === true)\n .map(({ table, id }) => ({ table, id }));\n // Per row: the view-once rows are marked viewed; an ordinary row sharing the id still leases the bytes.\n if (once.length > 0 && !viewing) return \"refused\";\n if (once.length === rows.length) {\n try {\n await store.commit({ viewed: once });\n } catch {\n return \"refused\";\n }\n if (custody !== this.custody || (await store.rowsReferencing(assetId)).length === 0\n || !await store.viewedAsset(assetId) || custody !== this.custody) return \"unleased\";\n if (this.session.size >= SESSION_VIEW_LIMIT) this.session.delete(this.session.keys().next().value!);\n if (viewing) this.session.set(this.sessionKey(assetId, width), { viewing, value: { bytes: value.bytes.slice(), type: value.type } });\n return \"viewed\";\n }\n try {\n await store.commit({\n ...(once.length === 0 ? {} : { viewed: once }),\n bytes: { put: [{ assetId, width, ...value }], ceiling: this.options.maxAssetBytes },\n });\n } catch {\n return \"refused\";\n }\n const status = await store.bytes();\n return custody === this.custody && status.entries.some((entry) => entry.assetId === assetId && entry.width === width) ? \"cached\" : \"refused\";\n }\n\n async status(): Promise<ByteCacheStatus> {\n const store = this.carrier();\n return store ? store.bytes() : { entries: [], totalBytes: 0, viewed: [] };\n }\n\n /** Nothing is served, marked, or cached without an open partition and a byte carrier. */\n private carrier(): (RangeStore & ByteCarrier) | undefined {\n return this.partition !== undefined && isByteCarrier(this.store) ? this.store : undefined;\n }\n\n private sessionKey(assetId: string, width?: number | null): string {\n return `${this.partition}\\u0000${assetId}\\u0000${width === undefined ? \"\" : width}`;\n }\n\n /** The session blob, only while the row that was viewed is still held on this partition. */\n private async sessionBytes(assetId: string, width: number | null, viewing?: object): Promise<AssetBytes | undefined> {\n const store = this.carrier();\n if (!store) return undefined;\n const key = this.sessionKey(assetId, width);\n const blob = this.session.get(key);\n if (!viewing || blob?.viewing !== viewing) return undefined;\n if ((await store.rowsReferencing(assetId)).length > 0) return blob.value;\n this.session.delete(key);\n return undefined;\n }\n\n private async viewOnceRows(assetId: string): Promise<RowRef[]> {\n const store = this.carrier();\n if (!store) return [];\n const rows = await store.rowsReferencing(assetId);\n return rows\n .filter((row) => this.options.viewOnce?.(row.table, row.row) === true)\n .map(({ table, id }) => ({ table, id }));\n }\n}\n", "// @ref LLP 1012#9-asset-bytes-on-the-device \u2014 the byte cache is read before the\n// network and filled after it; a viewed view-once row is refused before any byte moves.\nimport { AssetInputError } from \"./assets.js\";\nimport { SnapbackRefusal } from \"./client-wire.js\";\nimport { ASSET_ID, type AssetCache, type AssetBytes, type ByteCache } from \"./store/byte-cache.js\";\nimport type { RefusalEnvelope } from \"./types.js\";\n\nexport interface AssetBlobTarget { url: string; assetId: string; width: number | null }\n\n/** The tokenless asset URL this client issued, split into the cache key it names. */\nexport function assetBlobTarget(baseUrl: string, url: string): AssetBlobTarget {\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n throw new AssetInputError(\"E_ASSET_TYPE\", \"asset blob URL must be absolute\");\n }\n const base = new URL(baseUrl);\n if (parsed.origin !== base.origin || !parsed.pathname.startsWith(\"/api/asset/\") || parsed.searchParams.has(\"s\")) {\n throw new AssetInputError(\"E_ASSET_TYPE\", \"asset blob fetch requires a tokenless URL issued by this client\");\n }\n const assetId = decodeURIComponent(parsed.pathname.slice(\"/api/asset/\".length));\n const raw = parsed.searchParams.get(\"w\");\n let width: number | null = null;\n if (raw !== null) {\n width = Number(raw);\n if (!Number.isSafeInteger(width) || width <= 0) throw new AssetInputError(\"E_ASSET_TYPE\", \"asset width must be a positive integer\");\n }\n return { url, assetId: ASSET_ID.test(assetId) ? assetId : \"\", width };\n}\n\nexport function viewedRefusal(assetId: string): SnapbackRefusal {\n return new SnapbackRefusal({\n code: \"E_ASSET_VIEWED\",\n family: \"offline\",\n message: `asset ${assetId} belongs to a view-once row that was already viewed on this device`,\n site: \"assetBlob\",\n rewrite: \"render a view-once row once; do not fetch its bytes again\",\n guide: \"offline\",\n });\n}\n\n/**\n * The one viewed guard every byte path consults after the cache missed and before\n * a URL is minted or a byte moves: the ids whose view-once row was already viewed\n * on this partition. `assetBlob` refuses them; `useAssetUrl` mints no URL for them.\n */\nexport async function viewedAssetIds(cache: AssetCache | undefined, ids: readonly string[]): Promise<Set<string>> {\n const viewed = new Set<string>();\n if (!cache) return viewed;\n await Promise.all(ids.map(async (id) => {\n if (ASSET_ID.test(id) && await cache.viewed(id)) viewed.add(id);\n }));\n return viewed;\n}\n\n/**\n * Cache-first bytes for one asset rendition. Without a byte cache this is the\n * network fetch; with one, a held rendition (or what this instance showed for a\n * view-once row) is answered without the network, a viewed view-once row is refused\n * before any byte moves, and a fetched rendition is kept under its row's lease.\n */\nexport async function cachedAssetBlob(\n cache: ByteCache | undefined,\n target: AssetBlobTarget,\n network: () => Promise<Blob>,\n record: (refusal: RefusalEnvelope) => void, current: () => void, viewing?: object,\n): Promise<Blob> {\n const value = await cachedAssetBytes(cache, target, async () => {\n const blob = await network();\n return { bytes: new Uint8Array(await blob.arrayBuffer()), type: blob.type };\n }, record, current, viewing);\n return new Blob([value.bytes as BlobPart], { type: value.type });\n}\n\n/** Native byte ingress; the caller fences custody after each awaited read. */\nexport async function cachedAssetBytes(\n cache: ByteCache | undefined, target: AssetBlobTarget, network: () => Promise<AssetBytes>,\n record: (refusal: RefusalEnvelope) => void, current: () => void, viewing?: object,\n): Promise<AssetBytes> {\n if (!cache || target.assetId === \"\") return network();\n const held = await cache.getBytes(target.assetId, target.width, viewing);\n current();\n if (held) return held;\n const viewed = await cache.viewed(target.assetId);\n current();\n if (viewed) {\n const refusal = viewedRefusal(target.assetId);\n record(refusal.envelope);\n throw refusal;\n }\n const initiallyOnce = await cache.viewOnce(target.assetId);\n if (initiallyOnce && !viewing) {\n const refusal = new SnapbackRefusal({ code: \"E_ASSET_TYPE\", family: \"input\", site: \"assetBlob\",\n message: \"view-once bytes require a mounted viewing instance\",\n rewrite: \"pass the same viewing token for the lifetime of the mounted consumer\", guide: \"assets/client\" });\n record(refusal.envelope);\n throw refusal;\n }\n // Revocation during the fetch must also suppress an initially view-once row.\n const leased = initiallyOnce || await cache.canServe(target.assetId);\n current();\n const value = await network();\n current();\n const admitted = await cache.putBytes(target.assetId, target.width, value, viewing);\n current();\n const once = await cache.viewOnce(target.assetId);\n const viewedNow = await cache.viewed(target.assetId);\n const allowed = await cache.canServe(target.assetId, viewing);\n current();\n if ((once && admitted !== \"viewed\" && admitted !== \"cached\") || ((leased || once || viewedNow || admitted === \"viewed\") && !allowed)) {\n if (viewedNow && !allowed) {\n const refusal = viewedRefusal(target.assetId);\n record(refusal.envelope);\n throw refusal;\n }\n const refusal = new SnapbackRefusal({ code: \"E_OFFLINE_CARRIER\", family: \"offline\",\n site: \"assetBytes\", message: \"asset viewing allowance was not durably admitted or its row lease changed\",\n rewrite: \"restore the carrier and fetch a currently held, unviewed row\", guide: \"offline\" });\n record(refusal.envelope);\n throw refusal;\n }\n return value;\n}\n", "/** The store's answer and cursor-chain keys share one shape-preserving encoding. */\nexport function canonical(value: unknown): string {\n if (value === undefined) return \"undefined\";\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(canonical).join(\",\")}]`;\n return `{${Object.keys(value as object).sort().map((key) =>\n `${JSON.stringify(key)}:${canonical((value as Record<string, unknown>)[key])}`).join(\",\")}}`;\n}\n", "// @ref LLP 1012#7-writes-offline \u2014 cursor identity is not order. Only held,\n// post-commit next links prove progress; explicit negatives settle deletions.\nimport type { StoredAnswer, WatermarkRecord } from \"./range-store.js\";\nimport { canonical } from \"./canonical.js\";\n\nexport interface OverlayWatermark extends Pick<WatermarkRecord, \"op\" | \"args\" | \"watermark\"> {\n cursorArg: string;\n /** Last proven progress, and positions already consumed, survive a remount/reopen. */\n progress?: string;\n consumed?: string[];\n}\n\nfunction object(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/** Each page keeps the name used when it was filed, including a pre-manifest c. */\nexport function pagePosition(page: Pick<StoredAnswer, \"op\" | \"args\" | \"cursorArg\">, mark: OverlayWatermark): string | null | undefined {\n if (page.op !== mark.op || !object(page.args) || !object(mark.args)) return undefined;\n const cursor = page.cursorArg ?? mark.cursorArg;\n const base = { ...mark.args };\n const args = { ...page.args };\n // Before the manifest, a caller can already pass { after: null } while the\n // recorded name is c. Only the now-known cursor substitutes for that missing\n // field; other nullable/string arguments remain part of the query identity.\n delete base[Object.hasOwn(base, mark.cursorArg) ? mark.cursorArg : cursor];\n delete args[cursor];\n if (canonical(base) !== canonical(args)) return undefined;\n const position = page.args[cursor];\n return position === null || typeof position === \"string\" ? position : undefined;\n}\n\n/**\n * An ordered path starting at the commit snapshot, never inferred from a newer\n * seq or a different opaque string. A cycle, ambiguity, or missing link ends\n * the proven prefix. The caller supplies only non-empty, intact held pages.\n */\nexport function cursorChain(pages: StoredAnswer[], mark: OverlayWatermark, committedSeq: number): string[] {\n const links = new Map<string | null, string | null>();\n for (const page of pages) {\n if ((page.nextSeq ?? page.seq) < committedSeq || typeof page.next !== \"string\") continue;\n const position = pagePosition(page, mark);\n if (position === undefined) continue;\n // Conflicting links quarantine only this position, including off-path ones.\n links.set(position, links.has(position) && links.get(position) !== page.next ? null : page.next);\n }\n const seen = new Set<string | null>([mark.watermark]);\n const chain: string[] = [];\n let position = mark.watermark;\n while (links.has(position)) {\n const next = links.get(position);\n if (next == null || seen.has(next)) break;\n seen.add(next);\n chain.push(next);\n position = next;\n }\n return chain;\n}\n\n/** A re-mark can consume progress only once and only beyond the last proven mark. */\nexport function advanceOverlay(mark: OverlayWatermark, tail: WatermarkRecord | undefined, chain: string[]): boolean {\n if (!tail || pagePosition({ ...tail, args: object(tail.args)\n ? { ...tail.args, [tail.cursorArg ?? mark.cursorArg]: tail.watermark } : tail.args }, mark) === undefined) return false;\n if (typeof tail.watermark !== \"string\" || (mark.consumed ?? []).includes(tail.watermark)) return false;\n const at = chain.indexOf(tail.watermark);\n if (mark.progress !== undefined && !chain.includes(mark.progress)) {\n // A page can grow or be evicted. Re-anchor at the nearest surviving consumed\n // position (or the snapshot root), without forgetting what already counted.\n mark.progress = [...(mark.consumed ?? [])].reverse().find((position) => chain.includes(position));\n }\n const previous = mark.progress === undefined ? -1 : chain.indexOf(mark.progress);\n if (at < 0 || at <= previous) return false;\n mark.progress = tail.watermark;\n mark.consumed = [...new Set([...(mark.consumed ?? []), ...chain.slice(0, at + 1)])];\n return true;\n}\n", "// @ref LLP 1012#4-the-range-store \u2014 every carrier persists the same per-principal answer/range model.\n// @ref LLP 1012#5-retention-revocation-and-the-fence \u2014 eviction is decided once over a complete swap.\n// @ref LLP 1012#9-asset-bytes-on-the-device \u2014 asset bytes leave in the same commit as the row whose lease held them.\n\nimport {\n applyByteSwap,\n assetIdsIn,\n byteKey,\n leasedAssets,\n viewedOnlyAssets,\n type ByteCacheEntry,\n type ByteCacheStatus,\n type ByteDelta,\n type ByteSwapRequest,\n type ViewedRecord,\n} from \"./byte-cache.js\";\n\nimport { advanceOverlay, cursorChain, pagePosition, type OverlayWatermark } from \"./overlay-retirement.js\";\nimport { canonical } from \"./canonical.js\";\n\nexport type PrincipalPartition = string;\nexport type RetentionPolicy = \"until-revoked\" | \"delivered-history\";\n\nexport interface RowRef { table: string; id: string }\nexport interface StoredRow extends RowRef { row: Record<string, unknown> }\n\nexport interface ReceiptRange {\n site: string;\n table: string;\n index: string;\n prefix: unknown[];\n order: \"Asc\" | \"Desc\";\n take: number;\n after: unknown;\n before: unknown;\n gt: unknown;\n gte: unknown;\n lt: unknown;\n lte: unknown;\n rowIds: string[];\n stop: \"Limit\" | \"Exhausted\";\n absence: boolean;\n haloId?: string;\n ruleHash: string;\n /**\n * Members this page was recorded with that a later swap evicted (LLP 1012 \u00A75):\n * the page's answer is `partial/evicted` from then on, and the twin's\n * drained-prefix rule (\u00A76) no longer counts the page as a link in a complete chain.\n */\n evictedIds?: string[];\n}\n\nexport interface Receipt {\n ranges: ReceiptRange[];\n absences: Array<[table: string, index: string, key: unknown[]]>;\n verdicts: unknown[];\n}\n\nexport interface HeldAnswer<Result = unknown> {\n op: string;\n args: unknown;\n state: \"complete\" | \"capped\" | \"partial\" | \"denied\";\n data?: Result;\n next?: string | null;\n seq: number;\n validator?: string;\n receipt?: Receipt;\n deliveredAt: number;\n retained?: boolean;\n caughtUp?: boolean;\n watermark?: string | null;\n reason?: string;\n rule?: string;\n}\n\nexport interface StoredAnswer extends Omit<HeldAnswer, \"data\"> {\n data?: unknown;\n refs: RowRef[];\n order: number;\n fingerprint?: string;\n /** Cursor argument used when this page was filed, before or after manifest load. */\n cursorArg?: string;\n /** Seq of the delivery that recorded `next`; conditional refreshes cannot renew a link. */\n nextSeq?: number;\n}\n\nexport interface WatermarkRecord {\n op: string;\n args: unknown;\n /** The argument the manifest types as this query's cursor; `c` before the manifest loads. */\n cursorArg?: string;\n watermark: string | null;\n validator?: string;\n generation?: string;\n schemaHash?: string;\n authEpoch?: number;\n updatedAt: number;\n /**\n * Durable position among this partition's drained queries: assigned by the store\n * when the query first records a watermark, kept across every later mark. The\n * lowest order is the log a settlement and a resume name (LLP 1012 \u00A77).\n */\n order?: number;\n}\n\n/** The generation and authority every held envelope of a partition was delivered under. */\nexport interface CoverageFacts {\n generation: string;\n schemaHash: string;\n authEpoch: number;\n}\n\n/** One certified operation as `GET /api/program` serves it: the IR the twin runs and its certificate. */\nexport interface HeldOperation {\n kind: \"query\" | \"mutation\";\n planHash: string;\n ir: unknown;\n certificate: unknown;\n}\n\n// @ref LLP 1012#8-the-delivery-envelope-the-validator-and-resume \u2014 the program\n// custody the evaluator ticket names: the certified IR, certificates, and the\n// schema of one generation, held in the partition so a cold start with the\n// network cut still evaluates and prices from the certificate.\nexport interface HeldProgram {\n generation: string;\n schemaHash: string;\n schema: OfflineSchema & Record<string, unknown>;\n programs: Record<string, HeldOperation>;\n}\n\nexport interface Coverage {\n rows: StoredRow[];\n ranges: ReceiptRange[];\n absences: Receipt[\"absences\"];\n verdicts: unknown[];\n watermarks: WatermarkRecord[];\n /**\n * View-once rows already viewed on this partition: absent from `rows`, listed under\n * `absences` as a `byId` point, and named here so a replay never renders them (LLP 1012 \u00A79).\n */\n viewed?: RowRef[];\n /** Rows a swap evicted (LLP 1012 \u00A75): the twin reports a read of one as `evicted`, not `never-held`. */\n evicted?: RowRef[];\n /** The generation and auth epoch the held coverage was delivered under; absent when nothing is held. */\n facts?: CoverageFacts;\n /**\n * The facts a later delivery arrived under when its generation or schema differ\n * from `facts`: the held answers predate the program the server now runs, so the\n * twin serves nothing from them \u2014 every read is `hydrating` \u2014 until the reset\n * path drops this coverage and rebuilds it under the live generation (LLP 1012 \u00A78).\n */\n superseded?: CoverageFacts;\n /** The newest delivery's time: what an answer the twin computes reports as `stale.since`. */\n deliveredAt?: number;\n}\n\nexport type OutboxState = \"queued\" | \"committed\" | \"rejected\" | \"expired\";\n/** What the twin read when the intent was queued: the replay envelope's `trace` (LLP 1012 \u00A77). */\nexport interface OutboxTrace {\n points: Array<{ table: string; index: string; key: unknown[]; digest: string | null }>;\n verdicts: Array<{ ruleHash: string; inputsDigest: string; result: boolean }>;\n}\n// @ref LLP 1012#7-writes-offline \u2014 one durable intent: its pinned id slice, its\n// bytes, and its terminal response, so a retry is the same envelope.\nexport interface OutboxEntry {\n intent: string;\n grant: string;\n offset: number;\n count: number;\n ids: string[];\n op: string;\n args: unknown;\n issuedSeq: number;\n state: OutboxState;\n response?: unknown;\n predicted?: boolean;\n /** Prediction and its trace were skipped; the program will check this write on the server. */\n reason?: \"fence\";\n /** Engine-owned aggregate targets the prediction's overlay omits by design (the server writes them); absent when none. */\n omitted?: string[];\n trace?: OutboxTrace;\n createdAt: number;\n updatedAt: number;\n /** Durable FIFO position; assigned by the store when absent. */\n order?: number;\n}\n\n/** A principal-bound replay grant plus the client's own consumption cursor. */\nexport interface OutboxGrant {\n id: string;\n from: string;\n count: number;\n mintedAt: number;\n expiresAt: number;\n used: number;\n}\n\nexport interface OutboxStore {\n all(): Promise<OutboxEntry[]>;\n get(intent: string): Promise<OutboxEntry | undefined>;\n put(entry: OutboxEntry): Promise<void>;\n remove(intent: string): Promise<void>;\n /** The grant new intents consume from, if one is held. */\n grant(): Promise<OutboxGrant | undefined>;\n /** Every held grant, including those older queued intents still name. */\n grants(): Promise<OutboxGrant[]>;\n /** Each op's persisted write bound (`maxNewIds`); an enqueue refuses without one. */\n bounds(): Promise<Record<string, number>>;\n /** The prediction overlay by intent: the rows a queued intent's local run wrote, `removed` for a delete. */\n overlay(): Promise<Record<string, OverlayRow[]>>;\n /** The certified programs held for this partition, keyed by generation. */\n programs(): Promise<Record<string, HeldProgram>>;\n}\n\n/** A predicted row: the write's final image, or a `removed` marker for a row the intent deletes. */\nexport interface OverlayRow extends StoredRow { removed?: true }\n\nexport interface StoreDelivery {\n cursorArg?: string;\n op: string;\n args: unknown;\n state: HeldAnswer[\"state\"];\n data?: unknown;\n next?: string | null;\n seq: number;\n validator?: string;\n receipt?: Receipt;\n rows?: StoredRow[];\n deliveredAt?: number;\n reason?: string;\n rule?: string;\n}\n\nexport interface StoreTombstone extends RowRef { seq: number }\nexport interface StoreRefresh {\n op: string;\n args: unknown;\n seq: number;\n validator: string;\n deliveredAt?: number;\n}\n\nexport interface OfflineSchema {\n tables?: Record<string, {\n columns?: Record<string, unknown>;\n indexes?: Record<string, { columns?: string[] }>;\n retain?: RetentionPolicy;\n }>;\n}\n\nexport interface StoreSwap {\n deliveries?: StoreDelivery[];\n refreshes?: StoreRefresh[];\n tombstones?: StoreTombstone[];\n retention?: Record<string, RetentionPolicy>;\n schema?: OfflineSchema;\n watermark?: WatermarkRecord;\n resetCoverage?: boolean;\n /** One validated resume response, including unchanged; never a query re-delivery. */\n resumeSeq?: number;\n dropAnswers?: string[];\n outbox?: { put?: OutboxEntry[]; remove?: string[] };\n /**\n * Byte-cache puts and read touches; they land in the same swap as the rows: one\n * readwrite transaction on IndexedDB, an ordered payload write + state rename with\n * a sweep on open for the Node file carrier.\n */\n bytes?: ByteSwapRequest;\n /** View-once rows viewed now: excluded from every later answer, their bytes never cached. */\n viewed?: RowRef[];\n /** `current` names the grant new intents consume; `null` clears it. */\n grants?: { put?: OutboxGrant[]; current?: string | null; remove?: string[] };\n /** Predicted rows keyed by intent; visible to the twin's local evaluation, never to `answer()` (LLP 1012 \u00A77). */\n overlay?: { put?: Record<string, OverlayRow[]>; remove?: string[] };\n /** The certified programs, replaced whole (one generation is held at a time); custody like the outbox. */\n programs?: Record<string, HeldProgram>;\n /** The facts the swap's envelopes were delivered under; cleared by `resetCoverage`. */\n facts?: CoverageFacts;\n /** A rotation: the facts a refused delivery arrived under; held coverage is superseded until rebuild completion clears it with `null`. */\n superseded?: CoverageFacts | null;\n /**\n * The program's write bounds, replaced whole: what `/api/program` certified each op may\n * mint. Custody like the outbox \u2014 a coverage reset never touches it (LLP 1012 \u00A77).\n */\n bounds?: Record<string, number>;\n}\n\nexport interface RangeStore {\n open(partition: PrincipalPartition): Promise<void>;\n unseal(): Promise<void>;\n seal(): Promise<void>;\n wipe(partition: PrincipalPartition): Promise<void>;\n answer<Result = unknown>(op: string, args: unknown): Promise<HeldAnswer<Result> | undefined>;\n commit(swap: StoreSwap): Promise<void>;\n coverage(): Promise<Coverage>;\n readonly outbox: OutboxStore;\n close?(): Promise<void> | void;\n}\n\nexport interface RangeStoreFactory {\n (): RangeStore;\n readonly carrier?: string;\n}\n\nexport class OfflineStoreFailure extends Error {\n constructor(readonly code: \"E_OFFLINE_CARRIER\" | \"E_OFFLINE_LOCK\", message: string, readonly rewrite?: string) {\n super(message);\n this.name = \"OfflineStoreFailure\";\n }\n}\n\nexport interface PersistedRangeState {\n version: 1;\n sealed: boolean;\n clock: number;\n rows: Record<string, StoredRow>;\n answers: Record<string, StoredAnswer>;\n watermarks: Record<string, WatermarkRecord>;\n outbox: Record<string, OutboxEntry>;\n grants: Record<string, OutboxGrant>;\n currentGrant?: string;\n overlay: Record<string, OverlayRow[]>;\n /** Per committed intent, successful resumes or proven tail advances without its rows. */\n overlayMisses: Record<string, number>;\n /** The commit-time tail snapshot; null after reset until the next drain establishes a new head. */\n overlayWatermarks: Record<string, OverlayWatermark | null>;\n /** Only primary absences and tombstones, scoped to each prediction's ids. */\n overlayNegatives: Record<string, Record<string, { seq: number; source: \"absence\" | \"tombstone\" }>>;\n bounds: Record<string, number>;\n programs: Record<string, HeldProgram>;\n facts?: CoverageFacts;\n superseded?: CoverageFacts;\n negative: Record<string, number>;\n rowSeq: Record<string, number>;\n /** The byte-cache index; payloads live beside the state in the carrier, keyed by `byteKey`. */\n assets: Record<string, ByteCacheEntry>;\n viewed: Record<string, ViewedRecord>;\n}\n\nexport interface RangeStoreBackend {\n readonly carrier: string;\n open(partition: PrincipalPartition): Promise<PersistedRangeState | undefined>;\n /** One carrier transaction: the state, plus the byte payloads to write and the keys to drop. */\n replace(state: PersistedRangeState, bytes: ByteDelta): Promise<void>;\n readBytes?(key: string): Promise<Uint8Array | undefined>;\n wipe(partition: PrincipalPartition): Promise<void>;\n close(): Promise<void> | void;\n}\n\nconst NO_BYTES: ByteDelta = { put: [], remove: [] };\n\nexport function emptyState(): PersistedRangeState {\n return {\n version: 1, sealed: false, clock: 0, rows: {}, answers: {}, watermarks: {}, outbox: {},\n grants: {}, overlay: {}, overlayMisses: {}, overlayWatermarks: {}, overlayNegatives: {}, bounds: {}, programs: {}, negative: {}, rowSeq: {}, assets: {}, viewed: {},\n };\n}\n\nfunction clone<T>(value: T): T {\n return structuredClone(value);\n}\n\nexport function canonicalAnswerKey(op: string, args: unknown): string {\n return `${op}\\u0000${canonical(args === undefined ? args : jsonState(args))}`;\n}\n\nfunction rowKey(ref: RowRef): string {\n return `${ref.table}\\u0000${ref.id}`;\n}\n\nfunction viewedRef(key: string): RowRef {\n const at = key.indexOf(String.fromCharCode(0));\n return { table: key.slice(0, at), id: key.slice(at + 1) };\n}\n\nfunction recordEviction(evictions: Map<string, StoreTombstone>, eviction: StoreTombstone): void {\n const key = rowKey(eviction);\n if ((evictions.get(key)?.seq ?? -1) <= eviction.seq) evictions.set(key, eviction);\n}\n\nexport function rowReference(table: string, id: string): { $row: RowRef } {\n return { $row: { table, id } };\n}\n\nfunction asRowRef(value: unknown): RowRef | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return undefined;\n const marker = (value as { $row?: unknown }).$row;\n return marker !== null && typeof marker === \"object\" && !Array.isArray(marker)\n && Object.keys(marker).sort().join(\",\") === \"id,table\"\n && typeof (marker as RowRef).table === \"string\" && typeof (marker as RowRef).id === \"string\"\n ? { table: (marker as RowRef).table, id: (marker as RowRef).id }\n : undefined;\n}\n\nfunction collectRefs(value: unknown, refs = new Map<string, RowRef>()): RowRef[] {\n const ref = asRowRef(value);\n if (ref) refs.set(rowKey(ref), ref);\n else if (Array.isArray(value)) for (const item of value) collectRefs(item, refs);\n else if (value && typeof value === \"object\") {\n for (const item of Object.values(value as Record<string, unknown>)) collectRefs(item, refs);\n }\n return [...refs.values()];\n}\n\nfunction expand(value: unknown, rows: Record<string, StoredRow>, viewed?: Record<string, unknown>): unknown {\n const ref = asRowRef(value);\n if (ref) return viewed?.[rowKey(ref)] ? null : rows[rowKey(ref)]?.row ?? null;\n if (Array.isArray(value)) return value.map((item) => expand(item, rows, viewed));\n if (!value || typeof value !== \"object\") return value;\n return Object.fromEntries(Object.entries(value as Record<string, unknown>)\n .map(([key, item]) => [key, expand(item, rows, viewed)]));\n}\n\nfunction hiddenRefs(before: unknown, after: unknown, output = new Map<string, RowRef>()): RowRef[] {\n if (after === null || after === undefined) {\n for (const ref of collectRefs(before)) output.set(rowKey(ref), ref);\n return [...output.values()];\n }\n const ref = asRowRef(before);\n if (ref && after === null) output.set(rowKey(ref), ref);\n else if (Array.isArray(before) && Array.isArray(after)) {\n for (let index = 0; index < before.length; index += 1) {\n hiddenRefs(before[index], index < after.length ? after[index] : undefined, output);\n }\n } else if (before && after && typeof before === \"object\" && typeof after === \"object\"\n && !Array.isArray(before) && !Array.isArray(after)) {\n for (const key of Object.keys(before as object)) {\n hiddenRefs(\n (before as Record<string, unknown>)[key],\n Object.prototype.hasOwnProperty.call(after, key) ? (after as Record<string, unknown>)[key] : undefined,\n output,\n );\n }\n }\n return [...output.values()];\n}\n\nfunction restoreRetained(before: unknown, after: unknown, retained: Set<string>): unknown {\n const ref = asRowRef(before);\n if (ref && (after === null || after === undefined) && retained.has(rowKey(ref))) return before;\n if (Array.isArray(before) && Array.isArray(after)) {\n const result = after.map((item, index) => index < before.length\n ? restoreRetained(before[index], item, retained) : item);\n for (let index = after.length; index < before.length; index += 1) {\n if (collectRefs(before[index]).some((item) => retained.has(rowKey(item)))) result.push(clone(before[index]));\n }\n return result;\n }\n if (before && after && typeof before === \"object\" && typeof after === \"object\"\n && !Array.isArray(before) && !Array.isArray(after)) {\n const result = clone(after as Record<string, unknown>);\n for (const key of Object.keys(before as object)) {\n const old = (before as Record<string, unknown>)[key];\n if (Object.prototype.hasOwnProperty.call(result, key)) result[key] = restoreRetained(old, result[key], retained);\n else if (collectRefs(old).some((item) => retained.has(rowKey(item)))) result[key] = clone(old);\n }\n return result;\n }\n if ((after === null || after === undefined)\n && collectRefs(before).some((item) => retained.has(rowKey(item)))) return clone(before);\n return after;\n}\n\nfunction sameRange(left: ReceiptRange, right: ReceiptRange): boolean {\n return left.site === right.site && left.table === right.table && left.index === right.index\n && canonical(left.prefix) === canonical(right.prefix)\n && left.order === right.order\n && canonical(left.after) === canonical(right.after)\n && canonical(left.before) === canonical(right.before)\n && canonical(left.gt) === canonical(right.gt)\n && canonical(left.gte) === canonical(right.gte)\n && canonical(left.lt) === canonical(right.lt)\n && canonical(left.lte) === canonical(right.lte)\n && left.ruleHash === right.ruleHash;\n}\n\nfunction compareValue(left: unknown, right: unknown): number {\n if (left === right) return 0;\n if (typeof left === \"number\" && typeof right === \"number\") return left < right ? -1 : 1;\n if (typeof left === \"string\" && typeof right === \"string\") return left < right ? -1 : 1;\n if (typeof left === \"boolean\" && typeof right === \"boolean\") return left ? 1 : -1;\n const a = canonical(left);\n const b = canonical(right);\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\nfunction compareKey(left: unknown[], right: unknown[]): number {\n for (let index = 0; index < Math.min(left.length, right.length); index += 1) {\n const order = compareValue(left[index], right[index]);\n if (order !== 0) return order;\n }\n return left.length - right.length;\n}\n\nfunction indexKey(schema: OfflineSchema | undefined, range: ReceiptRange, row: StoredRow | undefined): unknown[] | undefined {\n const columns = schema?.tables?.[range.table]?.indexes?.[range.index]?.columns;\n if (!row || !Array.isArray(columns) || !columns.every((item) => typeof item === \"string\")) return undefined;\n const key = columns.map((column) => row.row[column]);\n return key.some((item) => item === undefined) ? undefined : key;\n}\n\nfunction cursorKey(value: unknown, width: number): unknown[] | undefined {\n if (value === null || value === undefined) return undefined;\n if (Array.isArray(value)) return value.length === width ? value : undefined;\n return width === 1 ? [value] : undefined;\n}\n\nfunction insidePrefixBounds(key: unknown[], range: ReceiptRange): boolean {\n if (key.length < range.prefix.length\n || compareKey(key.slice(0, range.prefix.length), range.prefix) !== 0) return false;\n const suffix = key.slice(range.prefix.length);\n const after = cursorKey(range.after, suffix.length);\n const before = cursorKey(range.before, suffix.length);\n if (after && (range.order === \"Asc\" ? compareKey(suffix, after) <= 0 : compareKey(suffix, after) >= 0)) return false;\n if (before && (range.order === \"Asc\" ? compareKey(suffix, before) >= 0 : compareKey(suffix, before) <= 0)) return false;\n const first = suffix[0];\n if (range.gt !== null && range.gt !== undefined && compareValue(first, range.gt) <= 0) return false;\n if (range.gte !== null && range.gte !== undefined && compareValue(first, range.gte) < 0) return false;\n if (range.lt !== null && range.lt !== undefined && compareValue(first, range.lt) >= 0) return false;\n if (range.lte !== null && range.lte !== undefined && compareValue(first, range.lte) > 0) return false;\n return true;\n}\n\nfunction inFreshExtent(\n id: string,\n held: ReceiptRange,\n fresh: ReceiptRange,\n rows: Record<string, StoredRow>,\n schema: OfflineSchema | undefined,\n): boolean {\n const key = indexKey(schema, held, rows[rowKey({ table: held.table, id })]);\n if (!key) return fresh.stop === \"Exhausted\";\n if (!insidePrefixBounds(key, fresh)) return false;\n if (fresh.stop === \"Exhausted\") return true;\n const presentKeys = fresh.rowIds\n .map((rowId) => indexKey(schema, fresh, rows[rowKey({ table: fresh.table, id: rowId })]))\n .filter(Array.isArray) as unknown[][];\n if (presentKeys.length === 0) return false;\n const first = presentKeys.reduce((a, b) => compareKey(a, b) <= 0 ? a : b);\n const last = presentKeys.reduce((a, b) => compareKey(a, b) >= 0 ? a : b);\n return compareKey(key, first) >= 0 && compareKey(key, last) <= 0;\n}\n\n/** One JSON form for warm state and every carrier: omit undefined fields, preserve null. */\nexport function jsonState<T>(value: T): T {\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nfunction normalizeState(value: PersistedRangeState | undefined): PersistedRangeState {\n if (!value) return emptyState();\n value = jsonState(value);\n if (value.version !== 1 || typeof value.rows !== \"object\" || typeof value.answers !== \"object\") {\n throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"range store contains an unsupported format\");\n }\n return {\n ...value,\n watermarks: value.watermarks ?? {},\n outbox: value.outbox ?? {},\n grants: value.grants ?? {},\n overlay: value.overlay ?? {},\n overlayMisses: value.overlayMisses ?? {},\n overlayWatermarks: value.overlayWatermarks ?? {},\n overlayNegatives: value.overlayNegatives ?? {},\n bounds: value.bounds ?? {},\n programs: value.programs ?? {},\n negative: value.negative ?? {},\n rowSeq: value.rowSeq ?? {},\n assets: value.assets ?? {},\n viewed: value.viewed ?? {},\n };\n}\n\n/**\n * The log a settlement's tail request and a resume's `log` both name: the drained\n * query whose watermark was recorded first in this partition \u2014 the first-mounted\n * drain, since a drain records its watermark when it first catches up \u2014 by the\n * store's durable `order`, so the choice survives restarts and re-marks and never\n * follows whichever page moved last (LLP 1012 \u00A77, \u00A78).\n */\nexport function tailWatermark(watermarks: WatermarkRecord[]): WatermarkRecord | undefined {\n return [...watermarks].sort((a, b) =>\n (a.order ?? Number.MAX_SAFE_INTEGER) - (b.order ?? Number.MAX_SAFE_INTEGER)\n || a.updatedAt - b.updatedAt\n || canonicalAnswerKey(a.op, a.args).localeCompare(canonicalAnswerKey(b.op, b.args)))[0];\n}\n\n/** Two post-commit resumes or proven tail advances retire a stranded prediction. */\nconst OVERLAY_PATIENCE = 2;\n\nfunction outboxOrder(entries: Record<string, OutboxEntry>): OutboxEntry[] {\n return Object.values(entries).sort((a, b) =>\n (a.order ?? a.createdAt) - (b.order ?? b.createdAt) || a.createdAt - b.createdAt || (a.intent < b.intent ? -1 : 1));\n}\n\n/** Shared swap engine; carrier subclasses only provide the atomic replace. */\nexport class PersistentRangeStore implements RangeStore {\n private state = emptyState();\n private partition?: PrincipalPartition;\n private tail: Promise<void> = Promise.resolve();\n\n readonly outbox: OutboxStore = {\n all: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(outboxOrder(this.state.outbox));\n }),\n get: async (intent) => this.read(() => {\n this.ensureUnsealed();\n return this.state.outbox[intent] && clone(this.state.outbox[intent]);\n }),\n put: async (entry) => this.commit({ outbox: { put: [entry] } }),\n remove: async (intent) => this.commit({ outbox: { remove: [intent] } }),\n grant: async () => this.read(() => {\n this.ensureUnsealed();\n const current = this.state.currentGrant === undefined ? undefined : this.state.grants[this.state.currentGrant];\n return current && clone(current);\n }),\n grants: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(Object.values(this.state.grants));\n }),\n bounds: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(this.state.bounds);\n }),\n overlay: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(this.state.overlay);\n }),\n programs: async () => this.read(() => {\n this.ensureUnsealed();\n return clone(this.state.programs);\n }),\n };\n\n constructor(private readonly backend: RangeStoreBackend) {}\n\n async open(partition: PrincipalPartition): Promise<void> {\n if (typeof partition !== \"string\" || partition.length === 0) {\n throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"range store partition must be a principal id\");\n }\n await this.enqueue(async () => {\n if (this.partition === partition) return;\n if (this.partition !== undefined && this.partition !== partition) await this.backend.close();\n this.partition = partition;\n this.state = normalizeState(await this.backend.open(partition));\n });\n }\n\n async unseal(): Promise<void> {\n await this.enqueue(async () => {\n this.ensureOpen();\n if (!this.state.sealed) return;\n const next = { ...clone(this.state), sealed: false };\n await this.backend.replace(next, NO_BYTES);\n this.state = next;\n });\n }\n\n async seal(): Promise<void> {\n await this.enqueue(async () => {\n this.ensureOpen();\n const next = { ...clone(this.state), sealed: true };\n await this.backend.replace(next, NO_BYTES);\n this.state = next;\n });\n }\n\n async wipe(partition: PrincipalPartition): Promise<void> {\n await this.enqueue(async () => {\n await this.backend.wipe(partition);\n if (this.partition === partition) {\n this.partition = undefined;\n this.state = emptyState();\n }\n });\n }\n\n async answer<Result = unknown>(op: string, args: unknown): Promise<HeldAnswer<Result> | undefined> {\n return this.read(() => {\n if (this.state.sealed) return undefined;\n const key = canonicalAnswerKey(op, args);\n const stored = this.state.answers[key];\n if (!stored) return undefined;\n const watermark = this.state.watermarks[key];\n const { refs: _refs, order: _order, fingerprint: _fingerprint, cursorArg: _cursorArg, data, ...answer } = clone(stored);\n return {\n ...answer,\n // A viewed view-once row reads as absent: the view was its one delivery (LLP 1012 \u00A79).\n ...(data === undefined ? {} : { data: expand(data, this.state.rows, this.state.viewed) as Result }),\n ...(watermark === undefined ? {} : { caughtUp: true, watermark: watermark.watermark }),\n };\n });\n }\n\n async coverage(): Promise<Coverage> {\n return this.read(() => {\n if (this.state.sealed) return { rows: [], ranges: [], absences: [], verdicts: [], watermarks: [], viewed: [], evicted: [] };\n const ranges = new Map<string, ReceiptRange>();\n const absences = new Map<string, Receipt[\"absences\"][number]>();\n const verdicts = new Map<string, unknown>();\n for (const answer of Object.values(this.state.answers)) {\n for (const range of answer.receipt?.ranges ?? []) {\n ranges.set(`${range.site}\\u0000${canonical(range.prefix)}\\u0000${canonical([\n range.order, range.after, range.before, range.gt, range.gte, range.lt, range.lte,\n ])}`, clone(range));\n }\n for (const absence of answer.receipt?.absences ?? []) absences.set(canonical(absence), clone(absence));\n for (const verdict of answer.receipt?.verdicts ?? []) verdicts.set(canonical(verdict), clone(verdict));\n }\n // A viewed view-once row is absent to the twin: not a row, and a byId absence (LLP 1012 \u00A79).\n const viewed = Object.keys(this.state.viewed).map(viewedRef);\n for (const ref of viewed) {\n const absence: Receipt[\"absences\"][number] = [ref.table, \"byId\", [ref.id]];\n absences.set(canonical(absence), absence);\n }\n let deliveredAt: number | undefined;\n for (const answer of Object.values(this.state.answers)) {\n if (deliveredAt === undefined || answer.deliveredAt > deliveredAt) deliveredAt = answer.deliveredAt;\n }\n return {\n rows: clone(Object.entries(this.state.rows).filter(([key]) => !this.state.viewed[key]).map(([, row]) => row)),\n ranges: [...ranges.values()],\n absences: [...absences.values()],\n verdicts: [...verdicts.values()],\n watermarks: clone(Object.values(this.state.watermarks)),\n viewed,\n evicted: Object.keys(this.state.negative).map(viewedRef),\n ...(this.state.facts === undefined ? {} : { facts: clone(this.state.facts) }),\n ...(this.state.superseded === undefined ? {} : { superseded: clone(this.state.superseded) }),\n ...(deliveredAt === undefined ? {} : { deliveredAt }),\n };\n });\n }\n\n async commit(swap: StoreSwap): Promise<void> {\n await this.enqueue(async () => {\n this.ensureOpen();\n // Byte payloads are not cloned: they can be megabytes and the swap never mutates them.\n const { bytes, ...rest } = swap;\n const delta: ByteDelta = { put: [], remove: [] };\n // Normalize before deriving answer keys/fingerprints, then normalize the state we publish.\n const next = normalizeState(this.applySwap(clone(this.state), { ...jsonState(rest), ...(bytes === undefined ? {} : { bytes }) }, delta));\n await this.backend.replace(next, delta);\n this.state = next;\n });\n }\n\n /** The cached rendition for an asset at a width; nothing when unheld, sealed, or the payload is gone. */\n async readBytes(assetId: string, width: number | null): Promise<{ bytes: Uint8Array; type: string } | undefined> {\n return this.read(async () => {\n if (this.state.sealed) return undefined;\n const key = byteKey(assetId, width);\n const entry = this.state.assets[key];\n if (!entry) return undefined;\n const bytes = await this.backend.readBytes?.(key);\n return bytes && bytes.byteLength === entry.size ? { bytes, type: entry.type } : undefined;\n });\n }\n\n async bytes(): Promise<ByteCacheStatus> {\n return this.read(() => {\n if (this.state.sealed) return { entries: [], totalBytes: 0, viewed: [] };\n const entries = clone(Object.values(this.state.assets));\n return {\n entries,\n totalBytes: entries.reduce((sum, entry) => sum + entry.size, 0),\n viewed: Object.keys(this.state.viewed).map(viewedRef),\n };\n });\n }\n\n /** Held rows whose values carry this asset record: the lease under which its bytes may be cached. */\n async rowsReferencing(assetId: string): Promise<StoredRow[]> {\n return this.read(() => this.state.sealed\n ? []\n : clone(Object.values(this.state.rows).filter((row) => assetIdsIn(row.row).has(assetId))));\n }\n\n /** True while every held row carrying this asset is a viewed view-once row (per row, LLP 1012 \u00A79). */\n async viewedAsset(assetId: string): Promise<boolean> {\n return this.read(() => !this.state.sealed && viewedOnlyAssets(this.state).has(assetId));\n }\n\n /** The viewed view-once rows; a live frame nulls them exactly as a held answer does. */\n async viewedRows(): Promise<RowRef[]> {\n return this.read(() => this.state.sealed ? [] : Object.keys(this.state.viewed).map(viewedRef));\n }\n\n /**\n * LRU read stamps, coalesced per swap: a read stamps the entry in memory and the next\n * swap's `replace` persists it, so a read never rewrites the carrier (LLP 1012 \u00A79).\n */\n async touchBytes(keys: string[]): Promise<void> {\n await this.enqueue(async () => {\n if (this.partition === undefined || this.state.sealed) return;\n for (const key of keys) {\n const entry = this.state.assets[key];\n if (entry) entry.lastRead = ++this.state.clock;\n }\n });\n }\n\n async close(): Promise<void> {\n await this.enqueue(async () => {\n this.partition = undefined;\n this.state = emptyState();\n await this.backend.close();\n });\n }\n\n private applySwap(state: PersistedRangeState, swap: StoreSwap, bytes: ByteDelta): PersistedRangeState {\n if (state.sealed) throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"range store is sealed\");\n if (swap.resetCoverage) {\n state.rows = {};\n // Sequence guards belong to this generation's coverage, just like rows.\n // A query-only successor can deliver the same row at the same data seq.\n state.rowSeq = {};\n state.negative = {};\n state.answers = {};\n state.watermarks = {};\n // These describe coverage, unlike the overlay and its replay entry.\n state.overlayWatermarks = Object.fromEntries(Object.keys(state.overlay).map((intent) => [intent, null]));\n state.overlayMisses = {};\n delete state.facts;\n }\n if (swap.superseded === null) delete state.superseded;\n if (swap.resumeSeq !== undefined && (!Number.isSafeInteger(swap.resumeSeq) || swap.resumeSeq < 0)) {\n throw new TypeError(\"store resume seq must be a non-negative safe integer\");\n }\n if (swap.facts) state.facts = clone(swap.facts);\n if (swap.superseded) state.superseded = clone(swap.superseded);\n const explicitEvictions = new Map<string, StoreTombstone>();\n // Keep provenance distinct from hidden-row and extent evictions. These facts\n // join each matching overlay below, even while its response is still queued.\n const authoritativeNegatives = new Map<string, { seq: number; source: \"absence\" | \"tombstone\" }>();\n const recordNegative = (ref: StoreTombstone, source: \"absence\" | \"tombstone\") => {\n const key = rowKey(ref);\n if ((authoritativeNegatives.get(key)?.seq ?? -1) <= ref.seq) {\n authoritativeNegatives.set(key, { seq: ref.seq, source });\n }\n recordEviction(explicitEvictions, ref);\n };\n const recordAbsences = (answer: Pick<StoredAnswer, \"receipt\" | \"seq\">) => {\n for (const [table, index, key] of answer.receipt?.absences ?? []) {\n if (index !== \"byId\" || key.length !== 1) {\n throw new TypeError(\"store receipts may evict only a primary byId absence\");\n }\n if (typeof key[0] === \"string\") recordNegative({ table, id: key[0], seq: answer.seq }, \"absence\");\n }\n };\n for (const key of swap.dropAnswers ?? []) delete state.answers[key];\n for (const refresh of swap.refreshes ?? []) {\n const answer = state.answers[canonicalAnswerKey(refresh.op, refresh.args)];\n if (!answer || refresh.seq < answer.seq) continue;\n if (answer.validator !== undefined && answer.validator !== refresh.validator) {\n throw new TypeError(`conditional validator changed for ${refresh.op}`);\n }\n if (refresh.seq === answer.seq) continue;\n answer.nextSeq ??= answer.seq;\n answer.seq = refresh.seq;\n answer.validator = refresh.validator;\n answer.deliveredAt = refresh.deliveredAt ?? Date.now();\n answer.order = ++state.clock;\n recordAbsences(answer);\n }\n const before = clone(state.answers);\n const freshRanges: Array<{ range: ReceiptRange; seq: number }> = [];\n for (const ref of swap.tombstones ?? []) {\n recordNegative(ref, \"tombstone\");\n }\n for (const delivery of swap.deliveries ?? []) {\n if (!Number.isSafeInteger(delivery.seq) || delivery.seq < 0) {\n throw new TypeError(\"store delivery seq must be a non-negative safe integer\");\n }\n const key = canonicalAnswerKey(delivery.op, delivery.args);\n const old = before[key];\n const fingerprint = canonical({\n op: delivery.op, args: delivery.args, state: delivery.state, data: delivery.data,\n next: delivery.next, seq: delivery.seq, validator: delivery.validator,\n receipt: delivery.receipt, rows: delivery.rows, reason: delivery.reason, rule: delivery.rule,\n });\n if (old && delivery.seq < old.seq) continue;\n if (old && delivery.seq === old.seq) {\n if (old.fingerprint === fingerprint) continue;\n throw new TypeError(`conflicting deliveries for ${delivery.op} at seq ${delivery.seq}`);\n }\n for (const row of delivery.rows ?? []) {\n if (!row.table || !row.id || !row.row || typeof row.row !== \"object\") {\n throw new TypeError(\"store delivery row is malformed\");\n }\n const storageKey = rowKey(row);\n if ((state.negative[storageKey] ?? -1) >= delivery.seq) {\n recordEviction(explicitEvictions, { table: row.table, id: row.id, seq: state.negative[storageKey]! });\n continue;\n }\n if (state.rowSeq[storageKey] === delivery.seq\n && canonical(state.rows[storageKey]) !== canonical(row)) {\n throw new TypeError(`conflicting row ${row.table}/${row.id} at seq ${delivery.seq}`);\n }\n if ((state.rowSeq[storageKey] ?? -1) > delivery.seq) continue;\n state.rows[storageKey] = clone(row);\n state.rowSeq[storageKey] = delivery.seq;\n }\n let data = clone(delivery.data);\n let answerState = delivery.state;\n let retained = false;\n const hidden = delivery.state === \"denied\" && old\n ? old.refs\n : old ? hiddenRefs(old.data, data) : [];\n const retainedRefs = new Set<string>();\n for (const ref of hidden) {\n if ((swap.retention?.[ref.table] ?? \"until-revoked\") === \"delivered-history\") {\n retainedRefs.add(rowKey(ref));\n retained = true;\n } else recordEviction(explicitEvictions, { ...ref, seq: delivery.seq });\n }\n if (delivery.state === \"denied\" && old && retainedRefs.size > 0) {\n data = clone(old.data);\n answerState = old.state;\n } else if (old && retainedRefs.size > 0) {\n data = restoreRetained(old.data, data, retainedRefs);\n }\n const refs = collectRefs(data);\n for (const range of delivery.receipt?.ranges ?? []) {\n for (const id of [...range.rowIds, ...(range.haloId ? [range.haloId] : [])]) {\n if (!refs.some((ref) => ref.table === range.table && ref.id === id)) refs.push({ table: range.table, id });\n }\n }\n // The pool is the answer's closure: halo and rule-input bodies (the\n // membership a message's read rule probed) are delivered content the\n // twin evaluates over, so an answer keeps every row it was delivered with.\n for (const pooled of delivery.rows ?? []) {\n if (!refs.some((ref) => ref.table === pooled.table && ref.id === pooled.id)) refs.push({ table: pooled.table, id: pooled.id });\n }\n const stored: StoredAnswer = {\n op: delivery.op,\n ...(delivery.cursorArg === undefined ? {} : { cursorArg: delivery.cursorArg }),\n args: clone(delivery.args),\n state: answerState,\n ...(data === undefined ? {} : { data }),\n ...(delivery.next === undefined ? {} : { next: delivery.next }),\n nextSeq: delivery.seq,\n seq: delivery.seq,\n ...(delivery.validator === undefined ? {} : { validator: delivery.validator }),\n ...(delivery.receipt === undefined ? {} : { receipt: clone(delivery.receipt) }),\n deliveredAt: delivery.deliveredAt ?? Date.now(),\n ...(retained ? { retained: true } : {}),\n ...(delivery.reason === undefined ? {} : { reason: delivery.reason }),\n ...(delivery.rule === undefined ? {} : { rule: delivery.rule }),\n refs,\n order: ++state.clock,\n fingerprint,\n };\n state.answers[key] = stored;\n freshRanges.push(...(delivery.receipt?.ranges ?? []).map((range) => ({ range, seq: delivery.seq })));\n recordAbsences(stored);\n }\n\n const heldRanges = Object.values(before).flatMap((answer) => answer.receipt?.ranges ?? []);\n for (const held of heldRanges) {\n const matching = freshRanges.filter(({ range: fresh }) => sameRange(held, fresh));\n if (matching.length === 0) continue;\n const present = new Set(matching.flatMap(({ range: fresh }) => [\n ...fresh.rowIds,\n ...(fresh.haloId ? [fresh.haloId] : []),\n ]));\n for (const id of held.rowIds) {\n if (present.has(id)) continue;\n const seq = matching\n .filter(({ range: fresh }) => inFreshExtent(id, held, fresh, state.rows, swap.schema))\n .reduce((latest, item) => Math.max(latest, item.seq), -1);\n if (seq >= 0) recordEviction(explicitEvictions, { table: held.table, id, seq });\n }\n }\n\n const appliedEvictions = new Set<string>();\n for (const [key, eviction] of explicitEvictions) {\n if ((state.negative[key] ?? -1) > eviction.seq) continue;\n if ((state.rowSeq[key] ?? -1) > eviction.seq) continue;\n state.negative[key] = eviction.seq;\n appliedEvictions.add(key);\n delete state.rows[key];\n delete state.rowSeq[key];\n for (const answer of Object.values(state.answers)) {\n for (const range of answer.receipt?.ranges ?? []) {\n if (range.table !== eviction.table) continue;\n const id = eviction.id;\n if (range.rowIds.includes(id)) {\n range.rowIds = range.rowIds.filter((rowId) => rowId !== id);\n // The page remembers what it lost: an interior eviction leaves a hole\n // the twin must not paper over with \"complete\" (LLP 1012 \u00A76).\n range.evictedIds = [...(range.evictedIds ?? []), id];\n }\n if (range.haloId === id) delete range.haloId;\n }\n if (!answer.refs.some((ref) => rowKey(ref) === key)) continue;\n answer.refs = answer.refs.filter((ref) => rowKey(ref) !== key);\n if (!answer.retained && answer.state !== \"denied\") {\n answer.state = \"partial\";\n answer.reason = \"evicted\";\n delete answer.next;\n }\n }\n }\n\n for (const answer of Object.values(state.answers)) {\n if (!answer.receipt) continue;\n answer.receipt.absences = answer.receipt.absences.filter(([table, index, key]) => {\n const id = index === \"byId\" && key.length === 1 ? key[0] : undefined;\n const storageKey = typeof id === \"string\" ? rowKey({ table, id }) : undefined;\n return storageKey === undefined || (state.rowSeq[storageKey] ?? -1) < 0 || appliedEvictions.has(storageKey);\n });\n }\n\n const referenced = new Set(Object.values(state.answers).flatMap((answer) => answer.refs.map(rowKey)));\n // Every pooled row joins its answer's refs above, so nothing arrives unused;\n // a row leaves here when no answer references it any more \u2014 its answer was\n // dropped, or replaced by a delivery whose closure no longer pools it.\n for (const key of Object.keys(state.rows)) if (!referenced.has(key)) {\n delete state.rows[key];\n delete state.rowSeq[key];\n }\n\n // Bytes join the swap by row lease: whatever left `state.rows` above takes its bytes with it.\n const byteDelta = applyByteSwap(state, swap, leasedAssets(Object.values(state.rows), Object.values(state.answers)));\n bytes.put.push(...byteDelta.put);\n bytes.remove.push(...byteDelta.remove);\n\n const previousTail = tailWatermark(Object.values(state.watermarks));\n if (swap.watermark) {\n const key = canonicalAnswerKey(swap.watermark.op, swap.watermark.args);\n // The order is the store's: first recorded, kept across re-marks (LLP 1012 \u00A77's tail chooser).\n const order = state.watermarks[key]?.order ?? ++state.clock;\n state.watermarks[key] = { ...clone(swap.watermark), order };\n }\n const tail = tailWatermark(Object.values(state.watermarks));\n // The outbox, its grants, its write bounds, and the prediction overlay are\n // custody of unsent work: a coverage reset above never touches them.\n for (const intent of swap.outbox?.remove ?? []) {\n delete state.outbox[intent];\n delete state.overlayMisses[intent];\n delete state.overlay[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n }\n const committedNow = new Set<string>();\n for (const entry of swap.outbox?.put ?? []) {\n if (typeof entry.intent !== \"string\" || entry.intent.length === 0) throw new TypeError(\"outbox entry needs an intent\");\n const previous = state.outbox[entry.intent];\n if (entry.state === \"committed\" && previous?.state !== \"committed\") committedNow.add(entry.intent);\n const order = previous?.order ?? entry.order ?? ++state.clock;\n state.outbox[entry.intent] = { ...clone(entry), order };\n }\n if (swap.bounds) state.bounds = clone(swap.bounds);\n if (swap.programs) state.programs = clone(swap.programs);\n for (const id of swap.grants?.remove ?? []) {\n delete state.grants[id];\n if (state.currentGrant === id) delete state.currentGrant;\n }\n for (const grant of swap.grants?.put ?? []) state.grants[grant.id] = clone(grant);\n if (swap.grants?.current === null) delete state.currentGrant;\n else if (typeof swap.grants?.current === \"string\") {\n if (!state.grants[swap.grants.current]) throw new TypeError(\"current grant must be a held grant\");\n state.currentGrant = swap.grants.current;\n }\n for (const intent of swap.overlay?.remove ?? []) {\n delete state.overlay[intent];\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n }\n for (const [intent, rows] of Object.entries(swap.overlay?.put ?? {})) {\n state.overlay[intent] = clone(rows);\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n }\n // @ref LLP 1012#7-writes-offline \u2014 retire on authoritative row/negative\n // evidence, a non-empty page reached by a post-commit next-cursor chain,\n // or two misses (proven forward marks or successful resumes, once per swap).\n // A reset rebases the snapshot at the new drain's current head; opaque cursor names\n // and positions from the former coverage cannot order the new log.\n const answers = Object.keys(state.overlay).some((intent) => state.outbox[intent]?.state === \"committed\")\n ? Object.values(state.answers) : [];\n const pages = answers.filter((answer) => {\n const nonempty = Array.isArray(answer.data) ? answer.data.length > 0 : collectRefs(answer.data).length > 0;\n return (answer.state === \"complete\" || answer.state === \"capped\") && answer.receipt !== undefined\n && !answer.receipt.ranges.some((range) => (range.evictedIds?.length ?? 0) > 0)\n && nonempty && answer.refs.length > 0 && answer.refs.every((ref) => state.rows[rowKey(ref)] !== undefined);\n });\n const chains = new Map<string, { chain: string[]; reached: Set<string | null | undefined> }>();\n for (const intent of Object.keys(state.overlay)) {\n const entry = state.outbox[intent];\n if (entry === undefined || entry.state === \"rejected\" || entry.state === \"expired\") {\n delete state.overlay[intent];\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n if (entry) delete entry.predicted;\n continue;\n }\n for (const row of state.overlay[intent]!) {\n const key = rowKey(row);\n const evidence = authoritativeNegatives.get(key);\n if (evidence !== undefined && evidence.seq >= (state.overlayNegatives[intent]?.[key]?.seq ?? -1)) {\n (state.overlayNegatives[intent] ??= {})[key] = evidence;\n }\n }\n if (entry.state !== \"committed\") continue;\n if (state.overlayWatermarks[intent] == null && tail !== undefined) {\n const snapshot = committedNow.has(intent) && state.overlayWatermarks[intent] !== null ? previousTail ?? tail : tail;\n state.overlayWatermarks[intent] = {\n op: snapshot.op, args: clone(snapshot.args), cursorArg: snapshot.cursorArg ?? \"c\",\n watermark: snapshot.watermark,\n };\n }\n const committedSeq = (entry.response as { seq?: unknown } | undefined)?.seq;\n if (!Number.isSafeInteger(committedSeq)) {\n delete state.overlay[intent];\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n delete entry.predicted;\n continue;\n }\n const overlay = state.overlay[intent]!;\n const seq = Number(committedSeq);\n // A deletion is confirmed by absence, never by a still-present row.\n const predicted = new Set(overlay.filter((row) => !row.removed).map(rowKey));\n const committedWatermark = state.overlayWatermarks[intent] ?? undefined;\n const chainKey = committedWatermark ? canonical({ op: committedWatermark.op, args: committedWatermark.args,\n cursorArg: committedWatermark.cursorArg, watermark: committedWatermark.watermark, seq }) : \"\";\n if (!chains.has(chainKey)) {\n const chain = committedWatermark ? cursorChain(pages, committedWatermark, seq) : [];\n chains.set(chainKey, { chain, reached: new Set(chain) });\n }\n const { chain, reached } = chains.get(chainKey)!;\n const negative = overlay.some((row) => {\n const evidence = state.overlayNegatives[intent]?.[rowKey(row)];\n return evidence !== undefined && evidence.seq >= seq && (state.rowSeq[rowKey(row)] ?? -1) <= evidence.seq;\n });\n // The closure's pooled halo/rule-input row is authoritative arrival too.\n const arrived = negative || answers.some((answer) => answer.seq >= seq && !answer.retained && answer.state !== \"denied\"\n && answer.refs.some((ref) => predicted.has(rowKey(ref)) && state.rows[rowKey(ref)] !== undefined))\n || (predicted.size > 0 && committedWatermark !== undefined && pages.some((page) => page.seq >= seq\n && reached.has(pagePosition(page, committedWatermark))));\n const advanced = committedWatermark !== undefined && swap.watermark !== undefined\n && tail !== undefined && canonicalAnswerKey(tail.op, tail.args) === canonicalAnswerKey(swap.watermark.op, swap.watermark.args)\n && advanceOverlay(committedWatermark, tail, chain);\n const moved = advanced || (swap.resumeSeq !== undefined && swap.resumeSeq > seq);\n const misses = arrived ? 0 : (state.overlayMisses[intent] ?? 0)\n + (moved && !committedNow.has(intent) ? 1 : 0);\n if (!arrived && misses < OVERLAY_PATIENCE) {\n if (misses > 0) state.overlayMisses[intent] = misses;\n continue;\n }\n delete state.overlay[intent];\n delete state.overlayMisses[intent];\n delete state.overlayWatermarks[intent];\n delete state.overlayNegatives[intent];\n delete entry.predicted;\n }\n return state;\n }\n\n private ensureOpen(): void {\n if (this.partition === undefined) {\n throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", `${this.backend.carrier} range store is not open`);\n }\n }\n\n private ensureUnsealed(): void {\n if (this.state.sealed) throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"range store is sealed\");\n }\n\n private enqueue<T>(action: () => Promise<T>): Promise<T> {\n const run = this.tail.then(action);\n this.tail = run.then(() => undefined, () => undefined);\n return run;\n }\n\n private async read<T>(action: () => T): Promise<T> {\n await this.tail;\n this.ensureOpen();\n return action();\n }\n}\n", "import { emptyState, jsonState, type PersistedRangeState } from \"./range-store.js\";\n\nexport type StateEntry = { key: string; value: unknown };\nexport type StateProjection = Record<\"rows\" | \"answers\" | \"outbox\" | \"meta\", StateEntry[]>;\n\n// @ref LLP 1013#3-the-sqlite-carrier \u2014 one projection for both database carriers;\n// the rest carries future metadata fields without a second list to keep in sync.\nexport function projectState(state: PersistedRangeState): StateProjection {\n // State has the JSON wire form on every carrier: omit undefined object fields,\n // preserve null, and turn undefined array slots into null. Bytes travel separately.\n const { rows = {}, answers = {}, outbox = {}, ...meta } = jsonState(state);\n const entries = (value: object) => Object.entries(value).map(([key, value]) => ({ key, value }));\n return { rows: entries(rows), answers: entries(answers), outbox: entries(outbox), meta: [{ key: \"state\", value: meta }] };\n}\n\nexport function unprojectState(projected: StateProjection): PersistedRangeState | undefined {\n const meta = projected.meta.find(({ key }) => key === \"state\");\n if (!meta && !projected.rows.length && !projected.answers.length && !projected.outbox.length) return undefined;\n const record = (entries: StateEntry[]) => Object.fromEntries(entries.map(({ key, value }) => [key, value]));\n return {\n ...emptyState(),\n ...meta?.value as Omit<PersistedRangeState, \"rows\" | \"answers\" | \"outbox\">,\n rows: record(projected.rows) as PersistedRangeState[\"rows\"],\n answers: record(projected.answers) as PersistedRangeState[\"answers\"],\n outbox: record(projected.outbox) as PersistedRangeState[\"outbox\"],\n };\n}\n\n/** Split only the first separator: a row id may itself contain NUL. */\nexport function encodeStateKey(key: string, tuple: boolean): string {\n const at = tuple ? key.indexOf(\"\\u0000\") : -1;\n return JSON.stringify(at < 0 ? [key] : [key.slice(0, at), key.slice(at + 1)]);\n}\n\nexport function decodeStateKey(key: string): string {\n const parts: unknown = JSON.parse(key);\n if (!Array.isArray(parts) || parts.length < 1 || parts.length > 2 || parts.some((part) => typeof part !== \"string\")) {\n throw new Error(\"invalid sqlite state key\");\n }\n return parts.join(\"\\u0000\");\n}\n", "import {\n OfflineStoreFailure,\n PersistentRangeStore,\n type PersistedRangeState,\n type PrincipalPartition,\n type RangeStoreBackend,\n type RangeStoreFactory,\n} from \"./range-store.js\";\nimport type { ByteDelta } from \"./byte-cache.js\";\nimport { projectState, unprojectState, type StateEntry as Entry } from \"./projection.js\";\n\n// @ref LLP 1012#4-the-range-store \u2014 the carrier holds exactly what `coverage()`\n// reads back: rows, answers (their receipts inside), the outbox, and the meta\n// record. The version-1 `ranges`/`absences`/`verdicts` projections were written\n// and never read; version 3 deletes them so nothing on the device looks\n// authoritative without being the source.\nconst STORE_NAMES = [\"rows\", \"answers\", \"outbox\", \"meta\"] as const;\nconst LEGACY_STORES = [\"ranges\", \"absences\", \"verdicts\"] as const;\n/** Byte payloads are keyed by `byteKey` and changed by delta, never cleared with the state stores. */\nconst BYTES_STORE = \"bytes\";\nconst ALL_STORES = [...STORE_NAMES, BYTES_STORE];\nconst DATABASE_VERSION = 3;\n\ninterface WebLockLike { readonly name?: string }\ninterface WebLocksLike {\n request<T>(\n name: string,\n options: { ifAvailable: true },\n callback: (lock: WebLockLike | null) => Promise<T> | T,\n ): Promise<T>;\n}\n\nexport interface IndexedDbRangeStoreOptions {\n indexedDB?: IDBFactory;\n locks?: WebLocksLike;\n databasePrefix?: string;\n /**\n * Witness barrier: awaited with the next state before its readwrite\n * transaction opens, so a harness can kill the profile between two swaps\n * and prove the carrier lands whole swaps or nothing (LLP 1012 \u00A710).\n */\n beforeReplace?: (state: PersistedRangeState) => void | Promise<void>;\n}\n\nfunction requestResult<T>(request: IDBRequest<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB request failed\"));\n });\n}\n\nfunction transactionDone(transaction: IDBTransaction): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n transaction.oncomplete = () => resolve();\n transaction.onabort = () => reject(transaction.error ?? new Error(\"IndexedDB transaction aborted\"));\n transaction.onerror = () => reject(transaction.error ?? new Error(\"IndexedDB transaction failed\"));\n });\n}\n\nfunction openDatabase(factory: IDBFactory, name: string): Promise<IDBDatabase> {\n return new Promise<IDBDatabase>((resolve, reject) => {\n const request = factory.open(name, DATABASE_VERSION);\n request.onupgradeneeded = () => {\n for (const store of ALL_STORES) {\n if (!request.result.objectStoreNames.contains(store)) request.result.createObjectStore(store, { keyPath: \"key\" });\n }\n for (const store of LEGACY_STORES) {\n if (request.result.objectStoreNames.contains(store)) request.result.deleteObjectStore(store);\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB open failed\"));\n request.onblocked = () => reject(new Error(\"IndexedDB open was blocked\"));\n });\n}\n\nfunction deleteDatabase(factory: IDBFactory, name: string): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n const request = factory.deleteDatabase(name);\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB delete failed\"));\n request.onblocked = () => reject(new Error(\"IndexedDB delete was blocked\"));\n });\n}\n\nclass IndexedDbBackend implements RangeStoreBackend {\n readonly carrier = \"IndexedDB\";\n private database?: IDBDatabase;\n private databaseName?: string;\n private releaseLock?: () => void;\n\n constructor(\n private readonly factory: IDBFactory,\n private readonly locks: WebLocksLike,\n private readonly prefix: string,\n private readonly beforeReplace?: IndexedDbRangeStoreOptions[\"beforeReplace\"],\n ) {}\n\n async open(partition: PrincipalPartition): Promise<PersistedRangeState | undefined> {\n await this.close();\n const databaseName = `${this.prefix}${partition}`;\n await this.acquireLock(partition);\n try {\n const database = await openDatabase(this.factory, databaseName);\n this.database = database;\n this.databaseName = databaseName;\n const transaction = database.transaction(STORE_NAMES as unknown as string[], \"readonly\");\n // Queue every request before awaiting: IndexedDB may auto-commit at the next task.\n const rowsRequest = transaction.objectStore(\"rows\").getAll() as IDBRequest<Entry[]>;\n const answersRequest = transaction.objectStore(\"answers\").getAll() as IDBRequest<Entry[]>;\n const outboxRequest = transaction.objectStore(\"outbox\").getAll() as IDBRequest<Entry[]>;\n const metaRequest = transaction.objectStore(\"meta\").get(\"state\") as IDBRequest<Entry | undefined>;\n const [rows, answers, outbox, meta] = await Promise.all([\n requestResult(rowsRequest), requestResult(answersRequest), requestResult(outboxRequest), requestResult(metaRequest),\n transactionDone(transaction),\n ]);\n return unprojectState({ rows, answers, outbox, meta: meta ? [meta] : [] });\n } catch (error) {\n await this.close();\n if (error instanceof OfflineStoreFailure) throw error;\n throw new OfflineStoreFailure(\n \"E_OFFLINE_CARRIER\",\n `IndexedDB carrier could not open ${databaseName}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n // @ref LLP 1012#4-the-range-store \u2014 one readwrite transaction spans the state\n // stores and the byte payloads, so a row and its bytes leave together or not at all.\n async replace(state: PersistedRangeState, bytes: ByteDelta): Promise<void> {\n const database = this.database;\n if (!database) throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"IndexedDB carrier is not open\");\n // All cloning/projection work is complete before the readwrite transaction opens.\n const projected = projectState(state);\n await this.beforeReplace?.(state);\n const transaction = database.transaction(ALL_STORES, \"readwrite\");\n try {\n for (const name of STORE_NAMES) {\n const store = transaction.objectStore(name);\n store.clear();\n for (const value of projected[name]) store.put(value);\n }\n if (bytes.remove.length > 0 || bytes.put.length > 0) {\n const store = transaction.objectStore(BYTES_STORE);\n for (const key of bytes.remove) store.delete(key);\n for (const item of bytes.put) store.put({ key: item.key, value: item.bytes });\n }\n } catch (error) {\n transaction.abort();\n throw error;\n }\n await transactionDone(transaction);\n }\n\n async readBytes(key: string): Promise<Uint8Array | undefined> {\n const database = this.database;\n if (!database) return undefined;\n const transaction = database.transaction([BYTES_STORE], \"readonly\");\n const request = transaction.objectStore(BYTES_STORE).get(key) as IDBRequest<Entry | undefined>;\n const [entry] = await Promise.all([requestResult(request), transactionDone(transaction)]);\n const value = entry?.value;\n if (value instanceof Uint8Array) return value;\n if (value instanceof ArrayBuffer) return new Uint8Array(value);\n return undefined;\n }\n\n async wipe(partition: PrincipalPartition): Promise<void> {\n const databaseName = `${this.prefix}${partition}`;\n if (this.databaseName === databaseName) await this.close();\n await deleteDatabase(this.factory, databaseName);\n }\n\n async close(): Promise<void> {\n this.database?.close();\n this.database = undefined;\n this.databaseName = undefined;\n this.releaseLock?.();\n this.releaseLock = undefined;\n }\n\n private async acquireLock(partition: PrincipalPartition): Promise<void> {\n let acquiredResolve!: () => void;\n let acquiredReject!: (error: unknown) => void;\n let releaseResolve!: () => void;\n const acquired = new Promise<void>((resolve, reject) => {\n acquiredResolve = resolve;\n acquiredReject = reject;\n });\n const released = new Promise<void>((resolve) => { releaseResolve = resolve; });\n const request = this.locks.request(`snapback2:${partition}`, { ifAvailable: true }, async (lock) => {\n if (!lock) {\n acquiredReject(new OfflineStoreFailure(\n \"E_OFFLINE_LOCK\",\n \"this account is open in another tab\",\n ));\n return;\n }\n this.releaseLock = releaseResolve;\n acquiredResolve();\n await released;\n });\n void request.catch(acquiredReject);\n await acquired;\n }\n}\n\n/** The sole web carrier exported by `snapback2/react`. */\nexport function indexedDbRangeStore(options: IndexedDbRangeStoreOptions = {}): RangeStoreFactory {\n const factory = options.indexedDB ?? globalThis.indexedDB;\n const locks = options.locks ?? (typeof navigator === \"undefined\" ? undefined : navigator.locks);\n if (!factory || !locks || typeof locks.request !== \"function\") {\n const unavailable = (() => new PersistentRangeStore({\n carrier: \"IndexedDB\",\n open: async () => { throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"IndexedDB and Web Locks are required\"); },\n replace: async () => { throw new OfflineStoreFailure(\"E_OFFLINE_CARRIER\", \"IndexedDB is unavailable\"); },\n wipe: async () => undefined,\n close: () => undefined,\n })) as RangeStoreFactory;\n Object.defineProperty(unavailable, \"carrier\", { value: \"IndexedDB\" });\n return unavailable;\n }\n const prefix = options.databasePrefix ?? \"snapback2:\";\n const create = (() => new PersistentRangeStore(new IndexedDbBackend(factory, locks, prefix, options.beforeReplace))) as RangeStoreFactory;\n Object.defineProperty(create, \"carrier\", { value: \"IndexedDB\" });\n return create;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["React", "useEffect", "useMemo", "useRef", "useState", "useSyncExternalStore", "useAssetUrl", "useSnapbackClient", "useSnapbackSnapshot", "isSnapbackRefusal", "snapbackRefusalBrand", "SnapbackRefusal", "envelope", "retryable", "status", "ASSET_ID", "byteKey", "assetId", "width", "rowKey", "ref", "positive", "value", "assetRecordId", "record", "keys", "ASSET_ID", "assetIdsIn", "output", "id", "item", "leasedAssets", "rows", "answers", "leased", "row", "answer", "viewedOnlyAssets", "state", "viewed", "key", "checkedPut", "put", "applyByteSwap", "swap", "delta", "assets", "viewedAssets", "entry", "ceiling", "size", "total", "sum", "victim", "least", "viewedRefusal", "assetId", "SnapbackRefusal", "canonical", "value", "key", "object", "value", "pagePosition", "page", "mark", "cursor", "base", "args", "canonical", "position", "cursorChain", "pages", "committedSeq", "links", "seen", "chain", "next", "advanceOverlay", "tail", "at", "previous", "OfflineStoreFailure", "code", "message", "rewrite", "NO_BYTES", "emptyState", "clone", "value", "canonicalAnswerKey", "op", "args", "canonical", "jsonState", "rowKey", "ref", "viewedRef", "key", "at", "recordEviction", "evictions", "eviction", "asRowRef", "value", "marker", "collectRefs", "refs", "ref", "rowKey", "item", "expand", "rows", "viewed", "key", "hiddenRefs", "before", "after", "output", "index", "restoreRetained", "retained", "result", "clone", "old", "sameRange", "left", "right", "canonical", "compareValue", "a", "b", "compareKey", "order", "indexKey", "schema", "range", "row", "columns", "column", "cursorKey", "width", "insidePrefixBounds", "suffix", "first", "inFreshExtent", "id", "held", "fresh", "presentKeys", "rowId", "last", "jsonState", "normalizeState", "emptyState", "OfflineStoreFailure", "tailWatermark", "watermarks", "canonicalAnswerKey", "OVERLAY_PATIENCE", "outboxOrder", "entries", "PersistentRangeStore", "backend", "intent", "entry", "current", "partition", "next", "NO_BYTES", "op", "args", "stored", "watermark", "_refs", "_order", "_fingerprint", "_cursorArg", "data", "answer", "ranges", "absences", "verdicts", "absence", "verdict", "viewedRef", "deliveredAt", "swap", "bytes", "rest", "delta", "assetId", "byteKey", "sum", "assetIdsIn", "viewedOnlyAssets", "keys", "state", "explicitEvictions", "authoritativeNegatives", "recordNegative", "source", "recordEviction", "recordAbsences", "table", "refresh", "freshRanges", "delivery", "fingerprint", "storageKey", "answerState", "hidden", "retainedRefs", "pooled", "heldRanges", "matching", "present", "seq", "latest", "appliedEvictions", "eviction", "referenced", "byteDelta", "applyByteSwap", "leasedAssets", "previousTail", "tail", "committedNow", "previous", "grant", "answers", "pages", "nonempty", "chains", "evidence", "snapshot", "committedSeq", "overlay", "predicted", "committedWatermark", "chainKey", "chain", "cursorChain", "reached", "arrived", "page", "pagePosition", "moved", "advanceOverlay", "misses", "action", "run", "projectState", "state", "rows", "answers", "outbox", "meta", "jsonState", "entries", "value", "key", "unprojectState", "projected", "record", "emptyState", "STORE_NAMES", "LEGACY_STORES", "BYTES_STORE", "ALL_STORES", "DATABASE_VERSION", "requestResult", "request", "resolve", "reject", "transactionDone", "transaction", "openDatabase", "factory", "name", "store", "deleteDatabase", "IndexedDbBackend", "locks", "prefix", "beforeReplace", "partition", "databaseName", "database", "rowsRequest", "answersRequest", "outboxRequest", "metaRequest", "rows", "answers", "outbox", "meta", "unprojectState", "error", "OfflineStoreFailure", "state", "bytes", "projected", "projectState", "value", "key", "item", "entry", "acquiredResolve", "acquiredReject", "releaseResolve", "acquired", "released", "lock", "indexedDbRangeStore", "options", "unavailable", "PersistentRangeStore", "create", "noSubscription", "noCustody", "useAssetBlob", "url", "client", "useSnapbackClient", "snapshot", "useSnapbackSnapshot", "cache", "custody", "useSyncExternalStore", "viewing", "useRef", "identity", "useMemo", "result", "setResult", "useState", "useEffect", "active", "created", "controller", "blob", "error", "isSnapbackRefusal", "AssetImage", "asset", "width", "height", "style", "props", "element", "setElement", "requestedWidth", "setRequestedWidth", "measured", "setMeasured", "update", "layoutWidth", "fallback", "cssWidth", "ratio", "observer", "entries", "deliveryUrl", "useAssetUrl", "React", "AssetVideo", "controls", "onPlay", "onRefusal", "policy", "setPolicy", "started", "setStarted", "request", "setRequest", "callback", "viewed", "once", "viewedRefusal", "current", "ordinary", "admitted", "carrier", "tokenless", "cacheable", "video", "DevOverlay", "refusal"]
|
|
7
|
+
}
|