@lunora/wire 1.0.0-alpha.4 → 1.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -57,11 +57,26 @@ declare const encodeWire: (value: unknown, depth?: number) => unknown;
57
57
  /** Inverse of {@link encodeWire}: revive tagged leaves back to their JS values. */
58
58
  declare const decodeWire: (value: unknown, depth?: number) => unknown;
59
59
  /**
60
- * Parse a stored JSON blob back into a document: `JSON.parse`, then
61
- * {@link decodeWire}, then {@link isPlainObject}. Returns `undefined` for
62
- * anything that is not a document — unparseable text, a malformed tag
63
- * (`decodeWire` throws on an over-long bigint or past the nesting cap), or a
64
- * root that decodes to a non-plain object.
60
+ * `JSON.parse` then {@link decodeWire}, skipping the decode when `text` holds
61
+ * no {@link TAG}. `JSON.stringify` writes every tagged frame's tag verbatim,
62
+ * so its absence proves the parsed tree is already the value, and the full
63
+ * rebuild `decodeWire` does would only copy it. A string that merely contains
64
+ * the tag text takes the decode path, which leaves it alone.
65
+ *
66
+ * Text with a `\u` escape always takes the decode path, because JSON allows
67
+ * the tag to be spelled that way (`\u0024` for `$`) and the check would miss it.
68
+ *
69
+ * Keep `decodeWire(JSON.parse(text))` where a peer controls the text: the
70
+ * skipped path also skips {@link MAX_DEPTH}, so a tagless tree nested deeper
71
+ * than 64 levels parses instead of throwing.
72
+ */
73
+ declare const parseWire: (text: string) => unknown;
74
+ /**
75
+ * Parse a stored JSON blob back into a document: {@link parseWire}, then
76
+ * {@link isPlainObject}. Returns `undefined` for anything that is not a document:
77
+ * unparseable text, a malformed tag (`decodeWire` throws on an over-long bigint,
78
+ * or past the nesting cap in tagged text), or a root that decodes to a non-plain
79
+ * object.
65
80
  *
66
81
  * Never throws, because its callers are read paths that must degrade rather
67
82
  * than fail: a display surface shows the row unexpanded, an editor falls back
@@ -92,4 +107,4 @@ declare const encodeArgsOrThrow: (label: string, path: string, args: unknown) =>
92
107
  * `Set`/`URL`/bytes; throws a `TypeError` on values the wire refuses.
93
108
  */
94
109
  declare const stableWireKey: (value: unknown) => string;
95
- export { TAG as WIRE_TAG, decodeDocument, decodeWire, encodeArgsOrThrow, encodeWire, isPlainObject, needsWireEncoding, stableStringify, stableWireKey };
110
+ export { TAG as WIRE_TAG, decodeDocument, decodeWire, encodeArgsOrThrow, encodeWire, isPlainObject, needsWireEncoding, parseWire, stableStringify, stableWireKey };
package/dist/index.d.ts CHANGED
@@ -57,11 +57,26 @@ declare const encodeWire: (value: unknown, depth?: number) => unknown;
57
57
  /** Inverse of {@link encodeWire}: revive tagged leaves back to their JS values. */
58
58
  declare const decodeWire: (value: unknown, depth?: number) => unknown;
59
59
  /**
60
- * Parse a stored JSON blob back into a document: `JSON.parse`, then
61
- * {@link decodeWire}, then {@link isPlainObject}. Returns `undefined` for
62
- * anything that is not a document — unparseable text, a malformed tag
63
- * (`decodeWire` throws on an over-long bigint or past the nesting cap), or a
64
- * root that decodes to a non-plain object.
60
+ * `JSON.parse` then {@link decodeWire}, skipping the decode when `text` holds
61
+ * no {@link TAG}. `JSON.stringify` writes every tagged frame's tag verbatim,
62
+ * so its absence proves the parsed tree is already the value, and the full
63
+ * rebuild `decodeWire` does would only copy it. A string that merely contains
64
+ * the tag text takes the decode path, which leaves it alone.
65
+ *
66
+ * Text with a `\u` escape always takes the decode path, because JSON allows
67
+ * the tag to be spelled that way (`\u0024` for `$`) and the check would miss it.
68
+ *
69
+ * Keep `decodeWire(JSON.parse(text))` where a peer controls the text: the
70
+ * skipped path also skips {@link MAX_DEPTH}, so a tagless tree nested deeper
71
+ * than 64 levels parses instead of throwing.
72
+ */
73
+ declare const parseWire: (text: string) => unknown;
74
+ /**
75
+ * Parse a stored JSON blob back into a document: {@link parseWire}, then
76
+ * {@link isPlainObject}. Returns `undefined` for anything that is not a document:
77
+ * unparseable text, a malformed tag (`decodeWire` throws on an over-long bigint,
78
+ * or past the nesting cap in tagged text), or a root that decodes to a non-plain
79
+ * object.
65
80
  *
66
81
  * Never throws, because its callers are read paths that must degrade rather
67
82
  * than fail: a display surface shows the row unexpanded, an editor falls back
@@ -92,4 +107,4 @@ declare const encodeArgsOrThrow: (label: string, path: string, args: unknown) =>
92
107
  * `Set`/`URL`/bytes; throws a `TypeError` on values the wire refuses.
93
108
  */
94
109
  declare const stableWireKey: (value: unknown) => string;
95
- export { TAG as WIRE_TAG, decodeDocument, decodeWire, encodeArgsOrThrow, encodeWire, isPlainObject, needsWireEncoding, stableStringify, stableWireKey };
110
+ export { TAG as WIRE_TAG, decodeDocument, decodeWire, encodeArgsOrThrow, encodeWire, isPlainObject, needsWireEncoding, parseWire, stableStringify, stableWireKey };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{default as o}from"./packem_shared/stableStringify-B25OZXVT.mjs";import{WIRE_TAG as d,decodeDocument as i,decodeWire as n,encodeArgsOrThrow as a,encodeWire as c,needsWireEncoding as f}from"./packem_shared/WIRE_TAG-MKcNwZg1.mjs";import{default as l}from"./packem_shared/stableWireKey-CSfZL7E7.mjs";import{isPlainObject as W}from"./packem_shared/isPlainObject-UM7p1XXO.mjs";export{d as WIRE_TAG,i as decodeDocument,n as decodeWire,a as encodeArgsOrThrow,c as encodeWire,W as isPlainObject,f as needsWireEncoding,o as stableStringify,l as stableWireKey};
1
+ import{default as o}from"./packem_shared/stableStringify-B25OZXVT.mjs";import{WIRE_TAG as d,decodeDocument as i,decodeWire as a,encodeArgsOrThrow as n,encodeWire as s,needsWireEncoding as c,parseWire as f}from"./packem_shared/WIRE_TAG-BeHtJ6HC.mjs";import{default as l}from"./packem_shared/stableWireKey-PtuMDxhZ.mjs";import{isPlainObject as p}from"./packem_shared/isPlainObject-UM7p1XXO.mjs";export{d as WIRE_TAG,i as decodeDocument,a as decodeWire,n as encodeArgsOrThrow,s as encodeWire,p as isPlainObject,c as needsWireEncoding,f as parseWire,o as stableStringify,l as stableWireKey};
@@ -1 +1 @@
1
- import{isPlainObject as b}from"./isPlainObject-UM7p1XXO.mjs";const f=r=>{let e="";for(let n=0;n<r.length;n+=32768)e+=String.fromCharCode(...r.subarray(n,n+32768));return btoa(e)},h=r=>{const e=atob(r),t=new Uint8Array(e.length);for(let n=0;n<e.length;n+=1)t[n]=e.codePointAt(n)??0;return t},i="$lunora.wire$",s=64,d=1024,A="__proto__",O=/^-?\d+$/,p={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},w={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},g=(r,e,t)=>{e===A?Object.defineProperty(r,e,{configurable:!0,enumerable:!0,value:t,writable:!0}):r[e]=t},T=(r,e)=>{for(let t=0;t<r.length;t+=1){const n=Object.getOwnPropertyDescriptor(r,t);if(n!==void 0&&(!("value"in n)||n.value===void 0||e(n.value)))return!0}return!1},m=(r,e=0)=>{if(e>s)return!0;const t=typeof r;return r===null||t==="string"||t==="boolean"?!1:t==="number"?!Number.isFinite(r):t!=="object"||"toJSON"in r?!0:Array.isArray(r)?r.length>0&&r[0]===i?!0:T(r,n=>m(n,e+1)):!b(r)||Object.hasOwn(r,A)?!0:Object.keys(r).some(n=>{const o=Object.getOwnPropertyDescriptor(r,n);return o===void 0||!("value"in o)||o.value!==void 0&&m(o.value,e+1)})},j=r=>{const e=r.toString();if(e.length>d)throw new RangeError(`wire-codec: over-long bigint (max ${String(d)} digits)`);return[i,"bigint",e]},R=r=>Number.isNaN(r)?[i,"nan"]:r===1/0?[i,"inf"]:r===-1/0?[i,"-inf"]:r,S=(r,e)=>{const t=e(Object.fromEntries(Object.keys(r).map(c=>[c,r[c]]))),n=r,o=[i,"error",String(n.name),String(n.message),t];return r.cause!==void 0&&o.push(e(r.cause)),o},U=r=>{const e=r.constructor.name,t=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);return e==="Uint8Array"?[i,"bytes",f(t)]:[i,"bytes",f(t),e]},I=(r,e)=>r instanceof Date?[i,"date",e(r.getTime())]:r instanceof Error?S(r,e):r instanceof URL?[i,"url",r.href]:r instanceof Map?[i,"map",[...r.entries()].map(([t,n])=>[e(t),e(n)])]:r instanceof Set?[i,"set",[...r].map(t=>e(t))]:r instanceof ArrayBuffer?[i,"bytes",f(new Uint8Array(r)),"ArrayBuffer"]:ArrayBuffer.isView(r)?U(r):void 0,N=(r,e)=>{const t=r.map(n=>y(n,e));return t.length>0&&t[0]===i?[i,"arr",t]:t},B=(r,e)=>{const t={};for(const n of Object.keys(r)){const o=r[n];o!==void 0&&g(t,n,y(o,e))}return t},y=(r,e=0)=>{if(e>s)throw new RangeError(`wire-codec: value nesting exceeds the ${String(s)}-level limit`);if(r===void 0)return[i,"undefined"];if(r===null)return r;if(typeof r=="bigint")return j(r);if(typeof r=="number")return R(r);if(typeof r!="object")return r;if(Array.isArray(r))return N(r,e+1);if(b(r))return B(r,e+1);const t=I(r,o=>y(o,e+1));if(t!==void 0)return t;const n=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${n} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)},_=r=>{const e=r[2];if(typeof e!="string"||e.length>d||!O.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${String(d)} digits)`);return BigInt(e)},P=(r,e)=>{const t=e(r[2]);if(typeof t!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(t)},$=(r,e)=>{const t=r[2];return new Map(t.map(n=>{if(!Array.isArray(n)||n.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[e(n[0]),e(n[1])]}))},D=r=>{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(e)},k=(r,e)=>{const t=r[2],n=r[3];if(typeof t!="string"||typeof n!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const o=(Object.hasOwn(w,t)?w[t]:void 0)??Error,c=new o(n);c.name!==t&&Object.defineProperty(c,"name",{configurable:!0,value:t,writable:!0});const a=e(r[4]);if(a===null||typeof a!="object"||Array.isArray(a))throw new TypeError("wire-codec: malformed error — props must be an object");for(const[l,E]of Object.entries(a))g(c,l,E);return r.length>5&&Object.defineProperty(c,"cause",{configurable:!0,value:e(r[5]),writable:!0}),c},C=r=>{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const t=h(e);if(f(t)!==e)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const n=r[3]??"Uint8Array";if(n==="ArrayBuffer")return t.buffer.byteLength===t.byteLength?t.buffer:new Uint8Array(t).buffer;const o=Object.hasOwn(p,n)?p[n]:void 0;return o?new o(new Uint8Array(t).buffer):t},L=(r,e)=>{switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(n=>e(n));case"bigint":return _(r);case"bytes":return C(r);case"date":return P(r,e);case"error":return k(r,e);case"inf":return 1/0;case"map":return $(r,e);case"nan":return Number.NaN;case"set":return new Set(r[2].map(n=>e(n)));case"undefined":return;case"url":return D(r);default:return r.map(n=>e(n))}},M=(r,e)=>{const t={};for(const n of Object.keys(r))g(t,n,u(r[n],e));return t},u=(r,e=0)=>{if(e>s)throw new RangeError(`wire-codec: value nesting exceeds the ${String(s)}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){const t=r;return t[0]===i?L(t,n=>u(n,e+1)):t.map(n=>u(n,e+1))}return M(r,e+1)},G=r=>{try{const e=u(JSON.parse(r));return b(e)?e:void 0}catch{return}},W=(r,e,t)=>{try{return y(t)}catch(n){throw new TypeError(`${r}: cannot encode args for '${e}' — ${n instanceof Error?n.message:String(n)}`,n instanceof Error?{cause:n}:void 0)}};export{i as WIRE_TAG,G as decodeDocument,u as decodeWire,W as encodeArgsOrThrow,y as encodeWire,b as isPlainObject,m as needsWireEncoding};
1
+ import{isPlainObject as b}from"./isPlainObject-UM7p1XXO.mjs";const f=r=>{let e="";for(let n=0;n<r.length;n+=32768)e+=String.fromCharCode(...r.subarray(n,n+32768));return btoa(e)},h=r=>{const e=atob(r),t=new Uint8Array(e.length);for(let n=0;n<e.length;n+=1)t[n]=e.codePointAt(n)??0;return t},o="$lunora.wire$",s=64,d=1024,l="__proto__",O=/^-?\d+$/,p={BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int8Array,Int16Array,Int32Array,Uint8Array,Uint8ClampedArray,Uint16Array,Uint32Array},w={Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError},g=(r,e,t)=>{e===l?Object.defineProperty(r,e,{configurable:!0,enumerable:!0,value:t,writable:!0}):r[e]=t},T=(r,e)=>{for(let t=0;t<r.length;t+=1){const n=Object.getOwnPropertyDescriptor(r,t);if(n!==void 0&&(!("value"in n)||n.value===void 0||e(n.value)))return!0}return!1},m=(r,e=0)=>{if(e>s)return!0;const t=typeof r;return r===null||t==="string"||t==="boolean"?!1:t==="number"?!Number.isFinite(r):t!=="object"||"toJSON"in r?!0:Array.isArray(r)?r.length>0&&r[0]===o?!0:T(r,n=>m(n,e+1)):!b(r)||Object.hasOwn(r,l)?!0:Object.keys(r).some(n=>{const i=Object.getOwnPropertyDescriptor(r,n);return i===void 0||!("value"in i)||i.value!==void 0&&m(i.value,e+1)})},j=r=>{const e=r.toString();if(e.length>d)throw new RangeError(`wire-codec: over-long bigint (max ${String(d)} digits)`);return[o,"bigint",e]},S=r=>Number.isNaN(r)?[o,"nan"]:r===1/0?[o,"inf"]:r===-1/0?[o,"-inf"]:r,R=(r,e)=>{const t=e(Object.fromEntries(Object.keys(r).map(c=>[c,r[c]]))),n=r,i=[o,"error",String(n.name),String(n.message),t];return r.cause!==void 0&&i.push(e(r.cause)),i},U=r=>{const e=r.constructor.name,t=new Uint8Array(r.buffer,r.byteOffset,r.byteLength);return e==="Uint8Array"?[o,"bytes",f(t)]:[o,"bytes",f(t),e]},I=(r,e)=>r instanceof Date?[o,"date",e(r.getTime())]:r instanceof Error?R(r,e):r instanceof URL?[o,"url",r.href]:r instanceof Map?[o,"map",[...r.entries()].map(([t,n])=>[e(t),e(n)])]:r instanceof Set?[o,"set",[...r].map(t=>e(t))]:r instanceof ArrayBuffer?[o,"bytes",f(new Uint8Array(r)),"ArrayBuffer"]:ArrayBuffer.isView(r)?U(r):void 0,N=(r,e)=>{const t=r.map(n=>y(n,e));return t.length>0&&t[0]===o?[o,"arr",t]:t},B=(r,e)=>{const t={};for(const n of Object.keys(r)){const i=r[n];i!==void 0&&g(t,n,y(i,e))}return t},y=(r,e=0)=>{if(e>s)throw new RangeError(`wire-codec: value nesting exceeds the ${String(s)}-level limit`);if(r===void 0)return[o,"undefined"];if(r===null)return r;if(typeof r=="bigint")return j(r);if(typeof r=="number")return S(r);if(typeof r!="object")return r;if(Array.isArray(r))return N(r,e+1);if(b(r))return B(r,e+1);const t=I(r,i=>y(i,e+1));if(t!==void 0)return t;const n=r.constructor?.name??"value";throw new TypeError(`wire-codec: cannot encode a ${n} over the Lunora wire — only plain objects, arrays, and the supported built-ins (Date, Error, URL, Map, Set, ArrayBuffer/typed arrays, bigint) round-trip`)},_=r=>{const e=r[2];if(typeof e!="string"||e.length>d||!O.test(e))throw new RangeError(`wire-codec: invalid or over-long bigint (max ${String(d)} digits)`);return BigInt(e)},P=(r,e)=>{const t=e(r[2]);if(typeof t!="number")throw new TypeError("wire-codec: malformed date — epoch must be a number");return new Date(t)},$=(r,e)=>{const t=r[2];return new Map(t.map(n=>{if(!Array.isArray(n)||n.length!==2)throw new TypeError("wire-codec: malformed map entry — expected a [key, value] pair");return[e(n[0]),e(n[1])]}))},D=r=>{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed url — href must be a string");return new URL(e)},k=(r,e)=>{const t=r[2],n=r[3];if(typeof t!="string"||typeof n!="string")throw new TypeError("wire-codec: malformed error — name and message must be strings");const i=(Object.hasOwn(w,t)?w[t]:void 0)??Error,c=new i(n);c.name!==t&&Object.defineProperty(c,"name",{configurable:!0,value:t,writable:!0});const a=e(r[4]);if(a===null||typeof a!="object"||Array.isArray(a))throw new TypeError("wire-codec: malformed error — props must be an object");for(const[A,E]of Object.entries(a))g(c,A,E);return r.length>5&&Object.defineProperty(c,"cause",{configurable:!0,value:e(r[5]),writable:!0}),c},C=r=>{const e=r[2];if(typeof e!="string")throw new TypeError("wire-codec: malformed bytes — payload must be a base64 string");const t=h(e);if(f(t)!==e)throw new TypeError("wire-codec: malformed bytes — payload must be canonical padded base64");const n=r[3]??"Uint8Array";if(n==="ArrayBuffer")return t.buffer.byteLength===t.byteLength?t.buffer:new Uint8Array(t).buffer;const i=Object.hasOwn(p,n)?p[n]:void 0;return i?new i(new Uint8Array(t).buffer):t},L=(r,e)=>{switch(r[1]){case"-inf":return-1/0;case"arr":return r[2].map(n=>e(n));case"bigint":return _(r);case"bytes":return C(r);case"date":return P(r,e);case"error":return k(r,e);case"inf":return 1/0;case"map":return $(r,e);case"nan":return Number.NaN;case"set":return new Set(r[2].map(n=>e(n)));case"undefined":return;case"url":return D(r);default:return r.map(n=>e(n))}},M=(r,e)=>{const t={};for(const n of Object.keys(r))g(t,n,u(r[n],e));return t},u=(r,e=0)=>{if(e>s)throw new RangeError(`wire-codec: value nesting exceeds the ${String(s)}-level limit`);if(r===null||typeof r!="object")return r;if(Array.isArray(r)){const t=r;return t[0]===o?L(t,n=>u(n,e+1)):t.map(n=>u(n,e+1))}return M(r,e+1)},F=r=>{const e=JSON.parse(r);return r.includes(o)||r.includes(String.raw`\u`)?u(e):e},W=r=>{try{const e=F(r);return b(e)?e:void 0}catch{return}},Y=(r,e,t)=>{try{return y(t)}catch(n){throw new TypeError(`${r}: cannot encode args for '${e}' — ${n instanceof Error?n.message:String(n)}`,n instanceof Error?{cause:n}:void 0)}};export{o as WIRE_TAG,W as decodeDocument,u as decodeWire,Y as encodeArgsOrThrow,y as encodeWire,b as isPlainObject,m as needsWireEncoding,F as parseWire};
@@ -1 +1 @@
1
- import r from"./stableStringify-B25OZXVT.mjs";import{encodeWire as t}from"./WIRE_TAG-MKcNwZg1.mjs";import"./isPlainObject-UM7p1XXO.mjs";const a=e=>r(t(e));export{a as default};
1
+ import r from"./stableStringify-B25OZXVT.mjs";import{encodeWire as t}from"./WIRE_TAG-BeHtJ6HC.mjs";import"./isPlainObject-UM7p1XXO.mjs";const a=e=>r(t(e));export{a as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/wire",
3
- "version": "1.0.0-alpha.4",
3
+ "version": "1.0.0-alpha.5",
4
4
  "description": "Wire codec and stable keys shared by every Lunora tier",
5
5
  "keywords": [
6
6
  "cloudflare",