@private.me/xbind 3.0.0 → 3.0.2
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 +55 -7
- package/dist-standalone/_deps/mldsa-wasm/dist/mldsa.js +1920 -1
- package/dist-standalone/_deps/shared/cjs/errors.js +729 -1
- package/dist-standalone/_deps/shared/cjs/index.js +463 -1
- package/dist-standalone/_deps/shared/cjs/types.js +315 -1
- package/dist-standalone/_deps/shared/errors.js +244 -1
- package/dist-standalone/_deps/shared/index.js +72 -1
- package/dist-standalone/_deps/shared/types.js +86 -1
- package/dist-standalone/_deps/ux-helpers/cjs/errors.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/index.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/pagination.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/progress.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/search.js +1 -1
- package/dist-standalone/_deps/ux-helpers/cjs/types.js +1 -1
- package/dist-standalone/_deps/ux-helpers/errors.js +1 -1
- package/dist-standalone/_deps/ux-helpers/index.js +1 -1
- package/dist-standalone/_deps/ux-helpers/pagination.js +1 -1
- package/dist-standalone/_deps/ux-helpers/progress.js +1 -1
- package/dist-standalone/_deps/ux-helpers/search.js +1 -1
- package/dist-standalone/_deps/xchange/auto-accept.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/auto-accept.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/errors.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/index.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/invite-client.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/lazy-init.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/trust-integration.js +1 -1
- package/dist-standalone/_deps/xchange/cjs/xchange.js +1 -1
- package/dist-standalone/_deps/xchange/errors.js +1 -1
- package/dist-standalone/_deps/xchange/index.js +1 -1
- package/dist-standalone/_deps/xchange/invite-client.js +1 -1
- package/dist-standalone/_deps/xchange/lazy-init.js +1 -1
- package/dist-standalone/_deps/xchange/trust-integration.js +1 -1
- package/dist-standalone/_deps/xchange/xchange.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/discovery.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/errors.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/index.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/registry.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/schema.js +1 -1
- package/dist-standalone/_deps/xregistry/cjs/types.js +1 -1
- package/dist-standalone/_deps/xregistry/discovery.js +1 -1
- package/dist-standalone/_deps/xregistry/errors.js +1 -1
- package/dist-standalone/_deps/xregistry/index.js +1 -1
- package/dist-standalone/_deps/xregistry/registry.js +1 -1
- package/dist-standalone/_deps/xregistry/schema.js +1 -1
- package/dist-standalone/_deps/xregistry/types.js +1 -1
- package/dist-standalone/agent-call.js +659 -1
- package/dist-standalone/agent-sdk.js +328 -1
- package/dist-standalone/agent.js +1800 -1
- package/dist-standalone/approval.js +193 -1
- package/dist-standalone/async-iterators.js +382 -1
- package/dist-standalone/auth.js +219 -1
- package/dist-standalone/auto-accept.js +229 -1
- package/dist-standalone/backup-config.js +201 -1
- package/dist-standalone/backup.js +326 -1
- package/dist-standalone/batch-operations.js +388 -1
- package/dist-standalone/cancellation.js +477 -1
- package/dist-standalone/checkpoint.js +186 -1
- package/dist-standalone/circuit-breaker.js +468 -1
- package/dist-standalone/cjs/agent-call.js +701 -1
- package/dist-standalone/cjs/agent-sdk.js +332 -1
- package/dist-standalone/cjs/agent.js +1837 -1
- package/dist-standalone/cjs/approval.js +199 -1
- package/dist-standalone/cjs/async-iterators.js +392 -1
- package/dist-standalone/cjs/auth.js +225 -1
- package/dist-standalone/cjs/auto-accept.js +233 -1
- package/dist-standalone/cjs/backup-config.js +207 -1
- package/dist-standalone/cjs/backup.js +330 -1
- package/dist-standalone/cjs/batch-operations.js +397 -1
- package/dist-standalone/cjs/cancellation.js +490 -1
- package/dist-standalone/cjs/checkpoint.js +193 -1
- package/dist-standalone/cjs/circuit-breaker.js +476 -1
- package/dist-standalone/cjs/cli/init.js +492 -1
- package/dist-standalone/cjs/config-validation.js +522 -1
- package/dist-standalone/cjs/connect.js +312 -1
- package/dist-standalone/cjs/connection-pool.js +506 -1
- package/dist-standalone/cjs/correlation-id.js +339 -1
- package/dist-standalone/cjs/crypto-utils.js +176 -1
- package/dist-standalone/cjs/debug-mode.js +534 -1
- package/dist-standalone/cjs/did-document.js +101 -1
- package/dist-standalone/cjs/did-privateme.js +130 -1
- package/dist-standalone/cjs/did-web.js +201 -1
- package/dist-standalone/cjs/discovery.js +462 -1
- package/dist-standalone/cjs/dual-mode.js +251 -1
- package/dist-standalone/cjs/email-templates.js +313 -1
- package/dist-standalone/cjs/email-transport.js +239 -1
- package/dist-standalone/cjs/envelope.js +538 -1
- package/dist-standalone/cjs/errors.js +913 -1
- package/dist-standalone/cjs/event-emitter.js +461 -1
- package/dist-standalone/cjs/gateway-state.js +55 -1
- package/dist-standalone/cjs/gateway-transport.js +120 -1
- package/dist-standalone/cjs/graceful-degradation.js +403 -1
- package/dist-standalone/cjs/guardrails.js +223 -1
- package/dist-standalone/cjs/health-check.js +336 -1
- package/dist-standalone/cjs/http-compat.js +272 -1
- package/dist-standalone/cjs/http-status-map.js +571 -1
- package/dist-standalone/cjs/identity.js +645 -1
- package/dist-standalone/cjs/index.js +406 -1
- package/dist-standalone/cjs/invitation.js +421 -1
- package/dist-standalone/cjs/invite.js +328 -1
- package/dist-standalone/cjs/key-agreement.js +335 -1
- package/dist-standalone/cjs/lazy-init.js +300 -1
- package/dist-standalone/cjs/logger.js +291 -1
- package/dist-standalone/cjs/mdns-discovery.js +202 -1
- package/dist-standalone/cjs/nonce-store.js +80 -1
- package/dist-standalone/cjs/pairing-manager.js +223 -1
- package/dist-standalone/cjs/plugin-system.js +264 -1
- package/dist-standalone/cjs/plugins/logging.js +168 -1
- package/dist-standalone/cjs/plugins/metrics.js +181 -1
- package/dist-standalone/cjs/plugins/validation.js +302 -1
- package/dist-standalone/cjs/policy.js +320 -1
- package/dist-standalone/cjs/progress-callbacks.js +583 -1
- package/dist-standalone/cjs/redis-nonce-store.js +76 -1
- package/dist-standalone/cjs/registry-middleware.js +50 -1
- package/dist-standalone/cjs/retry-strategies.js +544 -1
- package/dist-standalone/cjs/retry-transport.js +102 -1
- package/dist-standalone/cjs/runtime/browser.js +533 -1
- package/dist-standalone/cjs/runtime/edge.js +526 -1
- package/dist-standalone/cjs/runtime/react-native.js +394 -1
- package/dist-standalone/cjs/security-policy.js +245 -1
- package/dist-standalone/cjs/serialization.js +1040 -1
- package/dist-standalone/cjs/split-channel.js +225 -1
- package/dist-standalone/cjs/subscription-proof.js +230 -1
- package/dist-standalone/cjs/succession.js +148 -1
- package/dist-standalone/cjs/timeouts.js +412 -1
- package/dist-standalone/cjs/trace-context.js +424 -1
- package/dist-standalone/cjs/trace-spans.js +495 -1
- package/dist-standalone/cjs/transport.js +63 -1
- package/dist-standalone/cjs/trust-registry.js +991 -1
- package/dist-standalone/cjs/types/error-response.js +56 -1
- package/dist-standalone/cjs/vault-auth.js +178 -1
- package/dist-standalone/cjs/vault-store-loader.js +194 -1
- package/dist-standalone/cjs/verify.js +25 -1
- package/dist-standalone/cjs/version-info.js +543 -1
- package/dist-standalone/cjs/xfetch.js +340 -1
- package/dist-standalone/cli/init.js +455 -1
- package/dist-standalone/cli/setup.js +514 -1
- package/dist-standalone/cli/types.js +27 -1
- package/dist-standalone/cli/xbind.js +148 -1
- package/dist-standalone/config-validation.js +513 -1
- package/dist-standalone/connect.js +274 -1
- package/dist-standalone/connection-pool.js +500 -1
- package/dist-standalone/correlation-id.js +326 -1
- package/dist-standalone/crypto-utils.js +157 -1
- package/dist-standalone/debug-mode.js +510 -1
- package/dist-standalone/did-document.js +96 -1
- package/dist-standalone/did-privateme.js +121 -1
- package/dist-standalone/did-web.js +196 -1
- package/dist-standalone/discovery.js +458 -1
- package/dist-standalone/dual-mode.js +247 -1
- package/dist-standalone/email-templates.js +309 -1
- package/dist-standalone/email-transport.js +232 -1
- package/dist-standalone/envelope.js +525 -1
- package/dist-standalone/errors.js +896 -1
- package/dist-standalone/event-emitter.js +456 -1
- package/dist-standalone/gateway-state.js +51 -1
- package/dist-standalone/gateway-transport.js +116 -1
- package/dist-standalone/graceful-degradation.js +396 -1
- package/dist-standalone/guardrails.js +216 -1
- package/dist-standalone/health-check.js +332 -1
- package/dist-standalone/http-compat.js +267 -1
- package/dist-standalone/http-status-map.js +561 -1
- package/dist-standalone/identity.js +619 -1
- package/dist-standalone/index.js +78 -1
- package/dist-standalone/invitation.js +415 -1
- package/dist-standalone/invite.js +324 -1
- package/dist-standalone/key-agreement.js +325 -1
- package/dist-standalone/lazy-init.js +295 -1
- package/dist-standalone/logger.js +285 -1
- package/dist-standalone/mdns-discovery.js +195 -1
- package/dist-standalone/nonce-store.js +76 -1
- package/dist-standalone/pairing-manager.js +219 -1
- package/dist-standalone/plugin-system.js +257 -1
- package/dist-standalone/plugins/logging.d.ts +84 -0
- package/dist-standalone/plugins/logging.js +163 -0
- package/dist-standalone/plugins/metrics.d.ts +111 -0
- package/dist-standalone/plugins/metrics.js +176 -0
- package/dist-standalone/plugins/validation.d.ts +104 -0
- package/dist-standalone/plugins/validation.js +297 -0
- package/dist-standalone/policy.js +315 -1
- package/dist-standalone/progress-callbacks.js +576 -1
- package/dist-standalone/redis-nonce-store.js +72 -1
- package/dist-standalone/registry-middleware.js +47 -1
- package/dist-standalone/retry-strategies.js +534 -1
- package/dist-standalone/retry-transport.js +98 -1
- package/dist-standalone/runtime/browser.d.ts +311 -0
- package/dist-standalone/runtime/browser.js +516 -0
- package/dist-standalone/runtime/edge.d.ts +282 -0
- package/dist-standalone/runtime/edge.js +511 -0
- package/dist-standalone/runtime/react-native.d.ts +157 -0
- package/dist-standalone/runtime/react-native.js +383 -0
- package/dist-standalone/security-policy.js +239 -1
- package/dist-standalone/serialization.js +1031 -1
- package/dist-standalone/split-channel.js +219 -1
- package/dist-standalone/subscription-proof.js +224 -1
- package/dist-standalone/succession.js +142 -1
- package/dist-standalone/timeouts.js +398 -1
- package/dist-standalone/trace-context.js +414 -1
- package/dist-standalone/trace-spans.js +488 -1
- package/dist-standalone/transport.js +59 -1
- package/dist-standalone/trust-registry.js +950 -1
- package/dist-standalone/types/error-response.d.ts +209 -0
- package/dist-standalone/types/error-response.js +52 -0
- package/dist-standalone/vault-auth.js +174 -1
- package/dist-standalone/vault-store-loader.js +187 -1
- package/dist-standalone/verify.js +16 -1
- package/dist-standalone/version-info.js +530 -1
- package/dist-standalone/xfetch.js +335 -1
- package/package.json +4 -10
- package/share1.dat +0 -0
- package/dist-standalone/_deps/mldsa-wasm/LICENSE +0 -24
- package/dist-standalone/_deps/mldsa-wasm/package.json +0 -46
- package/dist-standalone/_deps/shared/cjs/package.json +0 -1
- package/dist-standalone/_deps/ux-helpers/cjs/package.json +0 -1
- package/dist-standalone/_deps/xchange/cjs/package.json +0 -1
- package/dist-standalone/_deps/xregistry/cjs/package.json +0 -1
- package/dist-standalone/cjs/package.json +0 -3
- package/dist-standalone/package.json +0 -10
|
@@ -1 +1,1040 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.serialize=serialize,exports.deserialize=deserialize,exports.detectFormat=detectFormat,exports.negotiateFormat=negotiateFormat,exports.compareFormats=compareFormats,exports.getContentType=getContentType,exports.parseContentType=parseContentType;const shared_1=require("../_deps/shared/index.js");class JSONSerializer{format="json";contentType="application/json";serialize(e,t){try{const r=t?.pretty?JSON.stringify(e,null,2):JSON.stringify(e);return(0,shared_1.ok)((new TextEncoder).encode(r))}catch(e){return(0,shared_1.err)({code:"SERIALIZATION_FAILED",reason:e instanceof Error?e.message:String(e),format:"json"})}}deserialize(e){try{const t=(new TextDecoder).decode(e);return(0,shared_1.ok)(JSON.parse(t))}catch(e){return(0,shared_1.err)({code:"DESERIALIZATION_FAILED",reason:e instanceof Error?e.message:String(e)})}}detect(e){if(0===e.length)return!1;const t=e[0];if(void 0===t)return!1;if(123===t||91===t||34===t)return!0;if(32===t||9===t||10===t||13===t)for(let t=1;t<Math.min(e.length,10);t++){const r=e[t];if(void 0===r)return!1;if(123===r||91===r||34===r)return!0;if(32!==r&&9!==r&&10!==r&&13!==r)return!1}return!1}}class MessagePackSerializer{format="msgpack";contentType="application/msgpack";serialize(e,t){try{return(0,shared_1.ok)(this.encode(e))}catch(e){return(0,shared_1.err)({code:"SERIALIZATION_FAILED",reason:e instanceof Error?e.message:String(e),format:"msgpack"})}}deserialize(e){try{return(0,shared_1.ok)(this.decode(e))}catch(e){return(0,shared_1.err)({code:"DESERIALIZATION_FAILED",reason:e instanceof Error?e.message:String(e)})}}detect(e){if(0===e.length)return!1;const t=e[0];if(void 0===t)return!1;if(t>=224&&t<=255&&e.length<2)return!1;try{const t={offset:0};return this.decodeValue(e,t),!0}catch{return!1}}encode(e){const t=[];this.encodeValue(e,t);const r=t.reduce((e,t)=>e+t.length,0),n=new Uint8Array(r);let s=0;for(const e of t)n.set(e,s),s+=e.length;return n}encodeValue(e,t){if(null==e)t.push(new Uint8Array([192]));else if("boolean"==typeof e)t.push(new Uint8Array([e?195:194]));else if("number"==typeof e)this.encodeNumber(e,t);else if("string"==typeof e)this.encodeString(e,t);else if(e instanceof Uint8Array)this.encodeBinary(e,t);else if(Array.isArray(e))this.encodeArray(e,t);else{if("object"!=typeof e)throw new Error("Unsupported type: "+typeof e);this.encodeObject(e,t)}}encodeNumber(e,t){if(Number.isInteger(e))if(e>=0&&e<=127)t.push(new Uint8Array([e]));else if(e>=-32&&e<0)t.push(new Uint8Array([224|31&e]));else if(e>=0&&e<=255)t.push(new Uint8Array([204,e]));else if(e>=0&&e<=65535)t.push(new Uint8Array([205,e>>8,255&e]));else if(e>=0&&e<=4294967295){const r=new Uint8Array(5);r[0]=206,new DataView(r.buffer).setUint32(1,e,!1),t.push(r)}else{const r=new Uint8Array(9);r[0]=203,new DataView(r.buffer).setFloat64(1,e,!1),t.push(r)}else{const r=new Uint8Array(9);r[0]=203,new DataView(r.buffer).setFloat64(1,e,!1),t.push(r)}}encodeString(e,t){const r=(new TextEncoder).encode(e),n=r.length;if(n<=31)t.push(new Uint8Array([160|n]));else if(n<=255)t.push(new Uint8Array([217,n]));else if(n<=65535)t.push(new Uint8Array([218,n>>8,255&n]));else{const e=new Uint8Array(5);e[0]=219,new DataView(e.buffer).setUint32(1,n,!1),t.push(e)}t.push(r)}encodeBinary(e,t){const r=e.length;if(r<=255)t.push(new Uint8Array([196,r]));else if(r<=65535)t.push(new Uint8Array([197,r>>8,255&r]));else{const e=new Uint8Array(5);e[0]=198,new DataView(e.buffer).setUint32(1,r,!1),t.push(e)}t.push(e)}encodeArray(e,t){const r=e.length;if(r<=15)t.push(new Uint8Array([144|r]));else if(r<=65535)t.push(new Uint8Array([220,r>>8,255&r]));else{const e=new Uint8Array(5);e[0]=221,new DataView(e.buffer).setUint32(1,r,!1),t.push(e)}for(const r of e)this.encodeValue(r,t)}encodeObject(e,t){const r=Object.keys(e),n=r.length;if(n<=15)t.push(new Uint8Array([128|n]));else if(n<=65535)t.push(new Uint8Array([222,n>>8,255&n]));else{const e=new Uint8Array(5);e[0]=223,new DataView(e.buffer).setUint32(1,n,!1),t.push(e)}for(const n of r)this.encodeValue(n,t),this.encodeValue(e[n],t)}decode(e){return this.decodeValue(e,{offset:0})}decodeValue(e,t){if(t.offset>=e.length)throw new Error("Unexpected end of data");const r=e[t.offset++];if(void 0===r)throw new Error("Unexpected end of data");if(r<=127)return r;if(r>=128&&r<=143){const n=15&r;return this.decodeMap(e,t,n)}if(r>=144&&r<=159){const n=15&r;return this.decodeArray(e,t,n)}if(r>=160&&r<=191){const n=31&r;return this.decodeString(e,t,n)}if(r>=224)return(31&r)-32;switch(r){case 192:return null;case 194:return!1;case 195:return!0;case 196:{const r=e[t.offset++];if(void 0===r)throw new Error("Unexpected end of data");return this.decodeBinary(e,t,r)}case 197:return this.decodeBinary(e,t,this.readUint16(e,t));case 198:return this.decodeBinary(e,t,this.readUint32(e,t));case 202:return this.readFloat32(e,t);case 203:return this.readFloat64(e,t);case 204:{const r=e[t.offset++];if(void 0===r)throw new Error("Unexpected end of data");return r}case 205:return this.readUint16(e,t);case 206:return this.readUint32(e,t);case 208:return this.readInt8(e,t);case 209:return this.readInt16(e,t);case 210:return this.readInt32(e,t);case 217:{const r=e[t.offset++];if(void 0===r)throw new Error("Unexpected end of data");return this.decodeString(e,t,r)}case 218:return this.decodeString(e,t,this.readUint16(e,t));case 219:return this.decodeString(e,t,this.readUint32(e,t));case 220:return this.decodeArray(e,t,this.readUint16(e,t));case 221:return this.decodeArray(e,t,this.readUint32(e,t));case 222:return this.decodeMap(e,t,this.readUint16(e,t));case 223:return this.decodeMap(e,t,this.readUint32(e,t));default:throw new Error(`Unknown MessagePack type: 0x${r.toString(16)}`)}}decodeString(e,t,r){const n=e.slice(t.offset,t.offset+r);return t.offset+=r,(new TextDecoder).decode(n)}decodeBinary(e,t,r){const n=e.slice(t.offset,t.offset+r);return t.offset+=r,n}decodeArray(e,t,r){const n=[];for(let s=0;s<r;s++)n.push(this.decodeValue(e,t));return n}decodeMap(e,t,r){const n={};for(let s=0;s<r;s++){const r=this.decodeValue(e,t),s=this.decodeValue(e,t);n[String(r)]=s}return n}readUint16(e,t){const r=new DataView(e.buffer,e.byteOffset).getUint16(t.offset,!1);return t.offset+=2,r}readUint32(e,t){const r=new DataView(e.buffer,e.byteOffset).getUint32(t.offset,!1);return t.offset+=4,r}readInt8(e,t){if(t.offset>=e.length)throw new Error("Unexpected end of data");const r=new DataView(e.buffer,e.byteOffset).getInt8(t.offset);return t.offset+=1,r}readInt16(e,t){const r=new DataView(e.buffer,e.byteOffset).getInt16(t.offset,!1);return t.offset+=2,r}readInt32(e,t){const r=new DataView(e.buffer,e.byteOffset).getInt32(t.offset,!1);return t.offset+=4,r}readFloat32(e,t){const r=new DataView(e.buffer,e.byteOffset).getFloat32(t.offset,!1);return t.offset+=4,r}readFloat64(e,t){const r=new DataView(e.buffer,e.byteOffset).getFloat64(t.offset,!1);return t.offset+=8,r}}class CBORSerializer{format="cbor";contentType="application/cbor";serialize(e,t){try{return(0,shared_1.ok)(this.encode(e))}catch(e){return(0,shared_1.err)({code:"SERIALIZATION_FAILED",reason:e instanceof Error?e.message:String(e),format:"cbor"})}}deserialize(e){try{return(0,shared_1.ok)(this.decode(e))}catch(e){return(0,shared_1.err)({code:"DESERIALIZATION_FAILED",reason:e instanceof Error?e.message:String(e)})}}detect(e){if(0===e.length)return!1;e[0];try{const t={offset:0};return this.decodeValue(e,t),!0}catch{return!1}}encode(e){const t=[];this.encodeValue(e,t);const r=t.reduce((e,t)=>e+t.length,0),n=new Uint8Array(r);let s=0;for(const e of t)n.set(e,s),s+=e.length;return n}encodeValue(e,t){if(null==e)t.push(new Uint8Array([246]));else if("boolean"==typeof e)t.push(new Uint8Array([e?245:244]));else if("number"==typeof e)this.encodeNumber(e,t);else if("string"==typeof e)this.encodeString(e,t);else if(e instanceof Uint8Array)this.encodeBinary(e,t);else if(Array.isArray(e))this.encodeArray(e,t);else{if("object"!=typeof e)throw new Error("Unsupported type: "+typeof e);this.encodeObject(e,t)}}encodeNumber(e,t){if(Number.isInteger(e))if(e>=0)if(e<=23)t.push(new Uint8Array([e]));else if(e<=255)t.push(new Uint8Array([24,e]));else if(e<=65535)t.push(new Uint8Array([25,e>>8,255&e]));else if(e<=4294967295){const r=new Uint8Array(5);r[0]=26,new DataView(r.buffer).setUint32(1,e,!1),t.push(r)}else{const r=new Uint8Array(9);r[0]=251,new DataView(r.buffer).setFloat64(1,e,!1),t.push(r)}else{const r=-1-e;if(r<=23)t.push(new Uint8Array([32|r]));else if(r<=255)t.push(new Uint8Array([56,r]));else if(r<=65535)t.push(new Uint8Array([57,r>>8,255&r]));else{const e=new Uint8Array(5);e[0]=58,new DataView(e.buffer).setUint32(1,r,!1),t.push(e)}}else{const r=new Uint8Array(9);r[0]=251,new DataView(r.buffer).setFloat64(1,e,!1),t.push(r)}}encodeString(e,t){const r=(new TextEncoder).encode(e),n=r.length;if(n<=23)t.push(new Uint8Array([96|n]));else if(n<=255)t.push(new Uint8Array([120,n]));else if(n<=65535)t.push(new Uint8Array([121,n>>8,255&n]));else{const e=new Uint8Array(5);e[0]=122,new DataView(e.buffer).setUint32(1,n,!1),t.push(e)}t.push(r)}encodeBinary(e,t){const r=e.length;if(r<=23)t.push(new Uint8Array([64|r]));else if(r<=255)t.push(new Uint8Array([88,r]));else if(r<=65535)t.push(new Uint8Array([89,r>>8,255&r]));else{const e=new Uint8Array(5);e[0]=90,new DataView(e.buffer).setUint32(1,r,!1),t.push(e)}t.push(e)}encodeArray(e,t){const r=e.length;if(r<=23)t.push(new Uint8Array([128|r]));else if(r<=255)t.push(new Uint8Array([152,r]));else if(r<=65535)t.push(new Uint8Array([153,r>>8,255&r]));else{const e=new Uint8Array(5);e[0]=154,new DataView(e.buffer).setUint32(1,r,!1),t.push(e)}for(const r of e)this.encodeValue(r,t)}encodeObject(e,t){const r=Object.keys(e),n=r.length;if(n<=23)t.push(new Uint8Array([160|n]));else if(n<=255)t.push(new Uint8Array([184,n]));else if(n<=65535)t.push(new Uint8Array([185,n>>8,255&n]));else{const e=new Uint8Array(5);e[0]=186,new DataView(e.buffer).setUint32(1,n,!1),t.push(e)}for(const n of r)this.encodeValue(n,t),this.encodeValue(e[n],t)}decode(e){return this.decodeValue(e,{offset:0})}decodeValue(e,t){if(t.offset>=e.length)throw new Error("Unexpected end of data");const r=e[t.offset++];if(void 0===r)throw new Error("Unexpected end of data");const n=r>>5&7,s=31&r;switch(n){case 0:return this.decodeInteger(e,t,s);case 1:return-1-this.decodeInteger(e,t,s);case 2:return this.decodeBinary(e,t,s);case 3:return this.decodeString(e,t,s);case 4:return this.decodeArray(e,t,s);case 5:return this.decodeMap(e,t,s);case 7:return this.decodeSpecial(e,t,s);default:throw new Error(`Unsupported CBOR major type: ${n}`)}}decodeInteger(e,t,r){if(r<=23)return r;if(24===r){const r=e[t.offset++];if(void 0===r)throw new Error("Unexpected end of data");return r}if(25===r)return this.readUint16(e,t);if(26===r)return this.readUint32(e,t);throw new Error("Unsupported integer size")}decodeString(e,t,r){let n;n=r<=23?r:this.decodeInteger(e,t,r);const s=e.slice(t.offset,t.offset+n);return t.offset+=n,(new TextDecoder).decode(s)}decodeBinary(e,t,r){let n;n=r<=23?r:this.decodeInteger(e,t,r);const s=e.slice(t.offset,t.offset+n);return t.offset+=n,s}decodeArray(e,t,r){let n;n=r<=23?r:this.decodeInteger(e,t,r);const s=[];for(let r=0;r<n;r++)s.push(this.decodeValue(e,t));return s}decodeMap(e,t,r){let n;n=r<=23?r:this.decodeInteger(e,t,r);const s={};for(let r=0;r<n;r++){const r=this.decodeValue(e,t),n=this.decodeValue(e,t);s[String(r)]=n}return s}decodeSpecial(e,t,r){switch(r){case 20:return!1;case 21:return!0;case 22:return null;case 23:return;case 27:return this.readFloat64(e,t);default:throw new Error(`Unsupported CBOR special: ${r}`)}}readUint16(e,t){const r=new DataView(e.buffer,e.byteOffset).getUint16(t.offset,!1);return t.offset+=2,r}readUint32(e,t){const r=new DataView(e.buffer,e.byteOffset).getUint32(t.offset,!1);return t.offset+=4,r}readFloat64(e,t){const r=new DataView(e.buffer,e.byteOffset).getFloat64(t.offset,!1);return t.offset+=8,r}}const serializers=new Map([["json",new JSONSerializer],["cbor",new CBORSerializer],["msgpack",new MessagePackSerializer]]);function serialize(e,t={}){const r=t.format??"json",n=serializers.get(r);if(!n)return(0,shared_1.err)({code:"UNSUPPORTED_FORMAT",format:r});const s=t.collectMetrics?performance.now():0,o=n.serialize(e,t);if(!o.ok)return o;const i=t.collectMetrics?{serializeDuration:performance.now()-s,size:o.value.length,format:r,timestamp:Date.now()}:void 0;return(0,shared_1.ok)({data:o.value,format:r,size:o.value.length,contentType:n.contentType,metrics:i})}function deserialize(e,t={}){const r=t.collectMetrics?performance.now():0;let n,s;if(t.format){if(n=t.format,s=serializers.get(n),!s)return(0,shared_1.err)({code:"UNSUPPORTED_FORMAT",format:n})}else{const t=detectFormat(e);if(!t.ok)return t;if(n=t.value,s=serializers.get(n),!s)return(0,shared_1.err)({code:"UNSUPPORTED_FORMAT",format:n})}const o=s.deserialize(e);if(!o.ok)return o;const i=t.collectMetrics?{serializeDuration:performance.now()-r,size:e.length,format:n,timestamp:Date.now()}:void 0;return(0,shared_1.ok)({value:o.value,format:n,metrics:i})}function detectFormat(e){const t=serializers.get("json");if(t?.detect(e))return(0,shared_1.ok)("json");if(0===e.length)return(0,shared_1.err)({code:"FORMAT_DETECTION_FAILED",reason:"Empty data"});const r=serializers.get("cbor");if(r?.detect(e))return(0,shared_1.ok)("cbor");const n=serializers.get("msgpack");return n?.detect(e)?(0,shared_1.ok)("msgpack"):(0,shared_1.err)({code:"FORMAT_DETECTION_FAILED",reason:"No serializer recognized the data format"})}function negotiateFormat(e,t){for(const r of e)if(t.includes(r))return(0,shared_1.ok)(r);return(0,shared_1.err)({code:"UNSUPPORTED_FORMAT",format:`No common format (client: ${e.join(",")}, server: ${t.join(",")})`})}function compareFormats(e,t=["json","msgpack","cbor"]){const r=[];for(const n of t){const t=serialize(e,{format:n,collectMetrics:!0});if(!t.ok)return t;r.push({format:n,size:t.value.size,duration:t.value.metrics?.serializeDuration??0})}return(0,shared_1.ok)(r)}function getContentType(e){const t=serializers.get(e);return t?.contentType??"application/octet-stream"}function parseContentType(e){const t=e.toLowerCase().split(";")[0]?.trim()??"";for(const e of serializers.values())if(e.contentType===t)return e.format}
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Alternative Serialization Formats (API-14)
|
|
4
|
+
*
|
|
5
|
+
* Pluggable serialization system supporting JSON, MessagePack, and CBOR.
|
|
6
|
+
* Provides format negotiation, backward compatibility, and performance benchmarks.
|
|
7
|
+
*
|
|
8
|
+
* @module serialization
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.serialize = serialize;
|
|
12
|
+
exports.deserialize = deserialize;
|
|
13
|
+
exports.detectFormat = detectFormat;
|
|
14
|
+
exports.negotiateFormat = negotiateFormat;
|
|
15
|
+
exports.compareFormats = compareFormats;
|
|
16
|
+
exports.getContentType = getContentType;
|
|
17
|
+
exports.parseContentType = parseContentType;
|
|
18
|
+
const shared_1 = require("../_deps/shared/index.js");
|
|
19
|
+
/* ── JSON Serializer ── */
|
|
20
|
+
class JSONSerializer {
|
|
21
|
+
format = 'json';
|
|
22
|
+
contentType = 'application/json';
|
|
23
|
+
serialize(value, options) {
|
|
24
|
+
try {
|
|
25
|
+
const json = options?.pretty
|
|
26
|
+
? JSON.stringify(value, null, 2)
|
|
27
|
+
: JSON.stringify(value);
|
|
28
|
+
return (0, shared_1.ok)(new TextEncoder().encode(json));
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return (0, shared_1.err)({
|
|
32
|
+
code: 'SERIALIZATION_FAILED',
|
|
33
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
34
|
+
format: 'json',
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
deserialize(data) {
|
|
39
|
+
try {
|
|
40
|
+
const text = new TextDecoder().decode(data);
|
|
41
|
+
return (0, shared_1.ok)(JSON.parse(text));
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return (0, shared_1.err)({
|
|
45
|
+
code: 'DESERIALIZATION_FAILED',
|
|
46
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
detect(data) {
|
|
51
|
+
if (data.length === 0)
|
|
52
|
+
return false;
|
|
53
|
+
// JSON starts with { [ " or whitespace + one of those
|
|
54
|
+
const first = data[0];
|
|
55
|
+
if (first === undefined)
|
|
56
|
+
return false;
|
|
57
|
+
if (first === 0x7B || first === 0x5B || first === 0x22)
|
|
58
|
+
return true; // { [ "
|
|
59
|
+
if (first === 0x20 || first === 0x09 || first === 0x0A || first === 0x0D) {
|
|
60
|
+
// Whitespace - scan for first non-whitespace
|
|
61
|
+
for (let i = 1; i < Math.min(data.length, 10); i++) {
|
|
62
|
+
const byte = data[i];
|
|
63
|
+
if (byte === undefined)
|
|
64
|
+
return false;
|
|
65
|
+
if (byte === 0x7B || byte === 0x5B || byte === 0x22)
|
|
66
|
+
return true;
|
|
67
|
+
if (byte !== 0x20 && byte !== 0x09 && byte !== 0x0A && byte !== 0x0D)
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/* ── MessagePack Serializer ── */
|
|
75
|
+
class MessagePackSerializer {
|
|
76
|
+
format = 'msgpack';
|
|
77
|
+
contentType = 'application/msgpack';
|
|
78
|
+
serialize(value, _options) {
|
|
79
|
+
try {
|
|
80
|
+
return (0, shared_1.ok)(this.encode(value));
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
return (0, shared_1.err)({
|
|
84
|
+
code: 'SERIALIZATION_FAILED',
|
|
85
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
86
|
+
format: 'msgpack',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
deserialize(data) {
|
|
91
|
+
try {
|
|
92
|
+
return (0, shared_1.ok)(this.decode(data));
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
return (0, shared_1.err)({
|
|
96
|
+
code: 'DESERIALIZATION_FAILED',
|
|
97
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
detect(data) {
|
|
102
|
+
if (data.length === 0)
|
|
103
|
+
return false;
|
|
104
|
+
const first = data[0];
|
|
105
|
+
if (first === undefined)
|
|
106
|
+
return false;
|
|
107
|
+
// MessagePack format markers
|
|
108
|
+
// fixmap: 0x80-0x8F, fixarray: 0x90-0x9F, fixstr: 0xA0-0xBF
|
|
109
|
+
// nil: 0xC0, false: 0xC2, true: 0xC3
|
|
110
|
+
// bin8/16/32: 0xC4-0xC6, ext8/16/32: 0xC7-0xC9
|
|
111
|
+
// float32/64: 0xCA-0xCB, uint8/16/32/64: 0xCC-0xCF
|
|
112
|
+
// int8/16/32/64: 0xD0-0xD3, fixext1/2/4/8/16: 0xD4-0xD8
|
|
113
|
+
// str8/16/32: 0xD9-0xDB, array16/32: 0xDC-0xDD, map16/32: 0xDE-0xDF
|
|
114
|
+
// Reject invalid patterns that would cause decode errors
|
|
115
|
+
if (first >= 0xE0 && first <= 0xFF) {
|
|
116
|
+
// Negative fixint: valid only for single-byte integers
|
|
117
|
+
// But we need more data to validate structure
|
|
118
|
+
if (data.length < 2)
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
// Try to validate structure
|
|
122
|
+
try {
|
|
123
|
+
const state = { offset: 0 };
|
|
124
|
+
this.decodeValue(data, state);
|
|
125
|
+
return true; // Successfully decoded
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return false; // Decode failed
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Minimal MessagePack encoder (subset implementation)
|
|
132
|
+
encode(value) {
|
|
133
|
+
const chunks = [];
|
|
134
|
+
this.encodeValue(value, chunks);
|
|
135
|
+
// Concatenate chunks
|
|
136
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
137
|
+
const result = new Uint8Array(totalLength);
|
|
138
|
+
let offset = 0;
|
|
139
|
+
for (const chunk of chunks) {
|
|
140
|
+
result.set(chunk, offset);
|
|
141
|
+
offset += chunk.length;
|
|
142
|
+
}
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
encodeValue(value, chunks) {
|
|
146
|
+
if (value === null || value === undefined) {
|
|
147
|
+
chunks.push(new Uint8Array([0xC0])); // nil
|
|
148
|
+
}
|
|
149
|
+
else if (typeof value === 'boolean') {
|
|
150
|
+
chunks.push(new Uint8Array([value ? 0xC3 : 0xC2])); // true/false
|
|
151
|
+
}
|
|
152
|
+
else if (typeof value === 'number') {
|
|
153
|
+
this.encodeNumber(value, chunks);
|
|
154
|
+
}
|
|
155
|
+
else if (typeof value === 'string') {
|
|
156
|
+
this.encodeString(value, chunks);
|
|
157
|
+
}
|
|
158
|
+
else if (value instanceof Uint8Array) {
|
|
159
|
+
this.encodeBinary(value, chunks);
|
|
160
|
+
}
|
|
161
|
+
else if (Array.isArray(value)) {
|
|
162
|
+
this.encodeArray(value, chunks);
|
|
163
|
+
}
|
|
164
|
+
else if (typeof value === 'object') {
|
|
165
|
+
this.encodeObject(value, chunks);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
throw new Error(`Unsupported type: ${typeof value}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
encodeNumber(value, chunks) {
|
|
172
|
+
if (Number.isInteger(value)) {
|
|
173
|
+
if (value >= 0 && value <= 127) {
|
|
174
|
+
chunks.push(new Uint8Array([value])); // positive fixint
|
|
175
|
+
}
|
|
176
|
+
else if (value >= -32 && value < 0) {
|
|
177
|
+
chunks.push(new Uint8Array([0xE0 | (value & 0x1F)])); // negative fixint
|
|
178
|
+
}
|
|
179
|
+
else if (value >= 0 && value <= 0xFF) {
|
|
180
|
+
chunks.push(new Uint8Array([0xCC, value])); // uint8
|
|
181
|
+
}
|
|
182
|
+
else if (value >= 0 && value <= 0xFFFF) {
|
|
183
|
+
chunks.push(new Uint8Array([0xCD, value >> 8, value & 0xFF])); // uint16
|
|
184
|
+
}
|
|
185
|
+
else if (value >= 0 && value <= 0xFFFFFFFF) {
|
|
186
|
+
const bytes = new Uint8Array(5);
|
|
187
|
+
bytes[0] = 0xCE;
|
|
188
|
+
new DataView(bytes.buffer).setUint32(1, value, false);
|
|
189
|
+
chunks.push(bytes);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// Use float64 for large integers or negative integers
|
|
193
|
+
const bytes = new Uint8Array(9);
|
|
194
|
+
bytes[0] = 0xCB;
|
|
195
|
+
new DataView(bytes.buffer).setFloat64(1, value, false);
|
|
196
|
+
chunks.push(bytes);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
// Float
|
|
201
|
+
const bytes = new Uint8Array(9);
|
|
202
|
+
bytes[0] = 0xCB; // float64
|
|
203
|
+
new DataView(bytes.buffer).setFloat64(1, value, false);
|
|
204
|
+
chunks.push(bytes);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
encodeString(value, chunks) {
|
|
208
|
+
const utf8 = new TextEncoder().encode(value);
|
|
209
|
+
const len = utf8.length;
|
|
210
|
+
if (len <= 31) {
|
|
211
|
+
chunks.push(new Uint8Array([0xA0 | len])); // fixstr
|
|
212
|
+
}
|
|
213
|
+
else if (len <= 0xFF) {
|
|
214
|
+
chunks.push(new Uint8Array([0xD9, len])); // str8
|
|
215
|
+
}
|
|
216
|
+
else if (len <= 0xFFFF) {
|
|
217
|
+
chunks.push(new Uint8Array([0xDA, len >> 8, len & 0xFF])); // str16
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
const header = new Uint8Array(5);
|
|
221
|
+
header[0] = 0xDB;
|
|
222
|
+
new DataView(header.buffer).setUint32(1, len, false);
|
|
223
|
+
chunks.push(header);
|
|
224
|
+
}
|
|
225
|
+
chunks.push(utf8);
|
|
226
|
+
}
|
|
227
|
+
encodeBinary(value, chunks) {
|
|
228
|
+
const len = value.length;
|
|
229
|
+
if (len <= 0xFF) {
|
|
230
|
+
chunks.push(new Uint8Array([0xC4, len])); // bin8
|
|
231
|
+
}
|
|
232
|
+
else if (len <= 0xFFFF) {
|
|
233
|
+
chunks.push(new Uint8Array([0xC5, len >> 8, len & 0xFF])); // bin16
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
const header = new Uint8Array(5);
|
|
237
|
+
header[0] = 0xC6;
|
|
238
|
+
new DataView(header.buffer).setUint32(1, len, false);
|
|
239
|
+
chunks.push(header);
|
|
240
|
+
}
|
|
241
|
+
chunks.push(value);
|
|
242
|
+
}
|
|
243
|
+
encodeArray(value, chunks) {
|
|
244
|
+
const len = value.length;
|
|
245
|
+
if (len <= 15) {
|
|
246
|
+
chunks.push(new Uint8Array([0x90 | len])); // fixarray
|
|
247
|
+
}
|
|
248
|
+
else if (len <= 0xFFFF) {
|
|
249
|
+
chunks.push(new Uint8Array([0xDC, len >> 8, len & 0xFF])); // array16
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const header = new Uint8Array(5);
|
|
253
|
+
header[0] = 0xDD;
|
|
254
|
+
new DataView(header.buffer).setUint32(1, len, false);
|
|
255
|
+
chunks.push(header);
|
|
256
|
+
}
|
|
257
|
+
for (const item of value) {
|
|
258
|
+
this.encodeValue(item, chunks);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
encodeObject(value, chunks) {
|
|
262
|
+
const keys = Object.keys(value);
|
|
263
|
+
const len = keys.length;
|
|
264
|
+
if (len <= 15) {
|
|
265
|
+
chunks.push(new Uint8Array([0x80 | len])); // fixmap
|
|
266
|
+
}
|
|
267
|
+
else if (len <= 0xFFFF) {
|
|
268
|
+
chunks.push(new Uint8Array([0xDE, len >> 8, len & 0xFF])); // map16
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
const header = new Uint8Array(5);
|
|
272
|
+
header[0] = 0xDF;
|
|
273
|
+
new DataView(header.buffer).setUint32(1, len, false);
|
|
274
|
+
chunks.push(header);
|
|
275
|
+
}
|
|
276
|
+
for (const key of keys) {
|
|
277
|
+
this.encodeValue(key, chunks);
|
|
278
|
+
this.encodeValue(value[key], chunks);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
// Minimal MessagePack decoder (subset implementation)
|
|
282
|
+
decode(data) {
|
|
283
|
+
const state = { offset: 0 };
|
|
284
|
+
return this.decodeValue(data, state);
|
|
285
|
+
}
|
|
286
|
+
decodeValue(data, state) {
|
|
287
|
+
if (state.offset >= data.length) {
|
|
288
|
+
throw new Error('Unexpected end of data');
|
|
289
|
+
}
|
|
290
|
+
const byte = data[state.offset++];
|
|
291
|
+
if (byte === undefined) {
|
|
292
|
+
throw new Error('Unexpected end of data');
|
|
293
|
+
}
|
|
294
|
+
// Positive fixint (0x00 - 0x7F)
|
|
295
|
+
if (byte <= 0x7F)
|
|
296
|
+
return byte;
|
|
297
|
+
// Fixmap (0x80 - 0x8F)
|
|
298
|
+
if (byte >= 0x80 && byte <= 0x8F) {
|
|
299
|
+
const len = byte & 0x0F;
|
|
300
|
+
return this.decodeMap(data, state, len);
|
|
301
|
+
}
|
|
302
|
+
// Fixarray (0x90 - 0x9F)
|
|
303
|
+
if (byte >= 0x90 && byte <= 0x9F) {
|
|
304
|
+
const len = byte & 0x0F;
|
|
305
|
+
return this.decodeArray(data, state, len);
|
|
306
|
+
}
|
|
307
|
+
// Fixstr (0xA0 - 0xBF)
|
|
308
|
+
if (byte >= 0xA0 && byte <= 0xBF) {
|
|
309
|
+
const len = byte & 0x1F;
|
|
310
|
+
return this.decodeString(data, state, len);
|
|
311
|
+
}
|
|
312
|
+
// Negative fixint (0xE0 - 0xFF)
|
|
313
|
+
if (byte >= 0xE0)
|
|
314
|
+
return (byte & 0x1F) - 32;
|
|
315
|
+
// Other types
|
|
316
|
+
switch (byte) {
|
|
317
|
+
case 0xC0: return null; // nil
|
|
318
|
+
case 0xC2: return false;
|
|
319
|
+
case 0xC3: return true;
|
|
320
|
+
case 0xC4: { // bin8
|
|
321
|
+
const len = data[state.offset++];
|
|
322
|
+
if (len === undefined)
|
|
323
|
+
throw new Error('Unexpected end of data');
|
|
324
|
+
return this.decodeBinary(data, state, len);
|
|
325
|
+
}
|
|
326
|
+
case 0xC5: return this.decodeBinary(data, state, this.readUint16(data, state)); // bin16
|
|
327
|
+
case 0xC6: return this.decodeBinary(data, state, this.readUint32(data, state)); // bin32
|
|
328
|
+
case 0xCA: return this.readFloat32(data, state);
|
|
329
|
+
case 0xCB: return this.readFloat64(data, state);
|
|
330
|
+
case 0xCC: { // uint8
|
|
331
|
+
const value = data[state.offset++];
|
|
332
|
+
if (value === undefined)
|
|
333
|
+
throw new Error('Unexpected end of data');
|
|
334
|
+
return value;
|
|
335
|
+
}
|
|
336
|
+
case 0xCD: return this.readUint16(data, state); // uint16
|
|
337
|
+
case 0xCE: return this.readUint32(data, state); // uint32
|
|
338
|
+
case 0xD0: return this.readInt8(data, state); // int8
|
|
339
|
+
case 0xD1: return this.readInt16(data, state); // int16
|
|
340
|
+
case 0xD2: return this.readInt32(data, state); // int32
|
|
341
|
+
case 0xD9: { // str8
|
|
342
|
+
const len = data[state.offset++];
|
|
343
|
+
if (len === undefined)
|
|
344
|
+
throw new Error('Unexpected end of data');
|
|
345
|
+
return this.decodeString(data, state, len);
|
|
346
|
+
}
|
|
347
|
+
case 0xDA: return this.decodeString(data, state, this.readUint16(data, state)); // str16
|
|
348
|
+
case 0xDB: return this.decodeString(data, state, this.readUint32(data, state)); // str32
|
|
349
|
+
case 0xDC: return this.decodeArray(data, state, this.readUint16(data, state)); // array16
|
|
350
|
+
case 0xDD: return this.decodeArray(data, state, this.readUint32(data, state)); // array32
|
|
351
|
+
case 0xDE: return this.decodeMap(data, state, this.readUint16(data, state)); // map16
|
|
352
|
+
case 0xDF: return this.decodeMap(data, state, this.readUint32(data, state)); // map32
|
|
353
|
+
default:
|
|
354
|
+
throw new Error(`Unknown MessagePack type: 0x${byte.toString(16)}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
decodeString(data, state, len) {
|
|
358
|
+
const bytes = data.slice(state.offset, state.offset + len);
|
|
359
|
+
state.offset += len;
|
|
360
|
+
return new TextDecoder().decode(bytes);
|
|
361
|
+
}
|
|
362
|
+
decodeBinary(data, state, len) {
|
|
363
|
+
const bytes = data.slice(state.offset, state.offset + len);
|
|
364
|
+
state.offset += len;
|
|
365
|
+
return bytes;
|
|
366
|
+
}
|
|
367
|
+
decodeArray(data, state, len) {
|
|
368
|
+
const result = [];
|
|
369
|
+
for (let i = 0; i < len; i++) {
|
|
370
|
+
result.push(this.decodeValue(data, state));
|
|
371
|
+
}
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
decodeMap(data, state, len) {
|
|
375
|
+
const result = {};
|
|
376
|
+
for (let i = 0; i < len; i++) {
|
|
377
|
+
const key = this.decodeValue(data, state);
|
|
378
|
+
const value = this.decodeValue(data, state);
|
|
379
|
+
result[String(key)] = value;
|
|
380
|
+
}
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
383
|
+
readUint16(data, state) {
|
|
384
|
+
const value = new DataView(data.buffer, data.byteOffset).getUint16(state.offset, false);
|
|
385
|
+
state.offset += 2;
|
|
386
|
+
return value;
|
|
387
|
+
}
|
|
388
|
+
readUint32(data, state) {
|
|
389
|
+
const value = new DataView(data.buffer, data.byteOffset).getUint32(state.offset, false);
|
|
390
|
+
state.offset += 4;
|
|
391
|
+
return value;
|
|
392
|
+
}
|
|
393
|
+
readInt8(data, state) {
|
|
394
|
+
if (state.offset >= data.length)
|
|
395
|
+
throw new Error('Unexpected end of data');
|
|
396
|
+
const value = new DataView(data.buffer, data.byteOffset).getInt8(state.offset);
|
|
397
|
+
state.offset += 1;
|
|
398
|
+
return value;
|
|
399
|
+
}
|
|
400
|
+
readInt16(data, state) {
|
|
401
|
+
const value = new DataView(data.buffer, data.byteOffset).getInt16(state.offset, false);
|
|
402
|
+
state.offset += 2;
|
|
403
|
+
return value;
|
|
404
|
+
}
|
|
405
|
+
readInt32(data, state) {
|
|
406
|
+
const value = new DataView(data.buffer, data.byteOffset).getInt32(state.offset, false);
|
|
407
|
+
state.offset += 4;
|
|
408
|
+
return value;
|
|
409
|
+
}
|
|
410
|
+
readFloat32(data, state) {
|
|
411
|
+
const value = new DataView(data.buffer, data.byteOffset).getFloat32(state.offset, false);
|
|
412
|
+
state.offset += 4;
|
|
413
|
+
return value;
|
|
414
|
+
}
|
|
415
|
+
readFloat64(data, state) {
|
|
416
|
+
const value = new DataView(data.buffer, data.byteOffset).getFloat64(state.offset, false);
|
|
417
|
+
state.offset += 8;
|
|
418
|
+
return value;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/* ── CBOR Serializer ── */
|
|
422
|
+
class CBORSerializer {
|
|
423
|
+
format = 'cbor';
|
|
424
|
+
contentType = 'application/cbor';
|
|
425
|
+
serialize(value, _options) {
|
|
426
|
+
try {
|
|
427
|
+
return (0, shared_1.ok)(this.encode(value));
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
return (0, shared_1.err)({
|
|
431
|
+
code: 'SERIALIZATION_FAILED',
|
|
432
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
433
|
+
format: 'cbor',
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
deserialize(data) {
|
|
438
|
+
try {
|
|
439
|
+
return (0, shared_1.ok)(this.decode(data));
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
return (0, shared_1.err)({
|
|
443
|
+
code: 'DESERIALIZATION_FAILED',
|
|
444
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
detect(data) {
|
|
449
|
+
if (data.length === 0)
|
|
450
|
+
return false;
|
|
451
|
+
const first = data[0];
|
|
452
|
+
// CBOR major types:
|
|
453
|
+
// 0: unsigned integer (0x00-0x1B)
|
|
454
|
+
// 1: negative integer (0x20-0x3B)
|
|
455
|
+
// 2: byte string (0x40-0x5B)
|
|
456
|
+
// 3: text string (0x60-0x7B)
|
|
457
|
+
// 4: array (0x80-0x9B)
|
|
458
|
+
// 5: map (0xA0-0xBB)
|
|
459
|
+
// 6: tag (0xC0-0xDB)
|
|
460
|
+
// 7: float/special (0xE0-0xFB, 0xF4-0xF7 for false/true/null/undefined)
|
|
461
|
+
// Try to validate structure
|
|
462
|
+
try {
|
|
463
|
+
const state = { offset: 0 };
|
|
464
|
+
this.decodeValue(data, state);
|
|
465
|
+
return true; // Successfully decoded
|
|
466
|
+
}
|
|
467
|
+
catch {
|
|
468
|
+
return false; // Decode failed
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
// Minimal CBOR encoder (subset implementation)
|
|
472
|
+
encode(value) {
|
|
473
|
+
const chunks = [];
|
|
474
|
+
this.encodeValue(value, chunks);
|
|
475
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
476
|
+
const result = new Uint8Array(totalLength);
|
|
477
|
+
let offset = 0;
|
|
478
|
+
for (const chunk of chunks) {
|
|
479
|
+
result.set(chunk, offset);
|
|
480
|
+
offset += chunk.length;
|
|
481
|
+
}
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
encodeValue(value, chunks) {
|
|
485
|
+
if (value === null || value === undefined) {
|
|
486
|
+
chunks.push(new Uint8Array([0xF6])); // null
|
|
487
|
+
}
|
|
488
|
+
else if (typeof value === 'boolean') {
|
|
489
|
+
chunks.push(new Uint8Array([value ? 0xF5 : 0xF4])); // true/false
|
|
490
|
+
}
|
|
491
|
+
else if (typeof value === 'number') {
|
|
492
|
+
this.encodeNumber(value, chunks);
|
|
493
|
+
}
|
|
494
|
+
else if (typeof value === 'string') {
|
|
495
|
+
this.encodeString(value, chunks);
|
|
496
|
+
}
|
|
497
|
+
else if (value instanceof Uint8Array) {
|
|
498
|
+
this.encodeBinary(value, chunks);
|
|
499
|
+
}
|
|
500
|
+
else if (Array.isArray(value)) {
|
|
501
|
+
this.encodeArray(value, chunks);
|
|
502
|
+
}
|
|
503
|
+
else if (typeof value === 'object') {
|
|
504
|
+
this.encodeObject(value, chunks);
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
throw new Error(`Unsupported type: ${typeof value}`);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
encodeNumber(value, chunks) {
|
|
511
|
+
if (Number.isInteger(value)) {
|
|
512
|
+
if (value >= 0) {
|
|
513
|
+
if (value <= 23) {
|
|
514
|
+
chunks.push(new Uint8Array([value])); // 0-23 direct
|
|
515
|
+
}
|
|
516
|
+
else if (value <= 0xFF) {
|
|
517
|
+
chunks.push(new Uint8Array([0x18, value])); // uint8
|
|
518
|
+
}
|
|
519
|
+
else if (value <= 0xFFFF) {
|
|
520
|
+
chunks.push(new Uint8Array([0x19, value >> 8, value & 0xFF])); // uint16
|
|
521
|
+
}
|
|
522
|
+
else if (value <= 0xFFFFFFFF) {
|
|
523
|
+
const bytes = new Uint8Array(5);
|
|
524
|
+
bytes[0] = 0x1A;
|
|
525
|
+
new DataView(bytes.buffer).setUint32(1, value, false);
|
|
526
|
+
chunks.push(bytes);
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
// Large integer as float64
|
|
530
|
+
const bytes = new Uint8Array(9);
|
|
531
|
+
bytes[0] = 0xFB;
|
|
532
|
+
new DataView(bytes.buffer).setFloat64(1, value, false);
|
|
533
|
+
chunks.push(bytes);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
// Negative integer
|
|
538
|
+
const absMinusOne = -1 - value;
|
|
539
|
+
if (absMinusOne <= 23) {
|
|
540
|
+
chunks.push(new Uint8Array([0x20 | absMinusOne]));
|
|
541
|
+
}
|
|
542
|
+
else if (absMinusOne <= 0xFF) {
|
|
543
|
+
chunks.push(new Uint8Array([0x38, absMinusOne]));
|
|
544
|
+
}
|
|
545
|
+
else if (absMinusOne <= 0xFFFF) {
|
|
546
|
+
chunks.push(new Uint8Array([0x39, absMinusOne >> 8, absMinusOne & 0xFF]));
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
const bytes = new Uint8Array(5);
|
|
550
|
+
bytes[0] = 0x3A;
|
|
551
|
+
new DataView(bytes.buffer).setUint32(1, absMinusOne, false);
|
|
552
|
+
chunks.push(bytes);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
// Float
|
|
558
|
+
const bytes = new Uint8Array(9);
|
|
559
|
+
bytes[0] = 0xFB; // float64
|
|
560
|
+
new DataView(bytes.buffer).setFloat64(1, value, false);
|
|
561
|
+
chunks.push(bytes);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
encodeString(value, chunks) {
|
|
565
|
+
const utf8 = new TextEncoder().encode(value);
|
|
566
|
+
const len = utf8.length;
|
|
567
|
+
if (len <= 23) {
|
|
568
|
+
chunks.push(new Uint8Array([0x60 | len])); // text string 0-23
|
|
569
|
+
}
|
|
570
|
+
else if (len <= 0xFF) {
|
|
571
|
+
chunks.push(new Uint8Array([0x78, len])); // text string uint8
|
|
572
|
+
}
|
|
573
|
+
else if (len <= 0xFFFF) {
|
|
574
|
+
chunks.push(new Uint8Array([0x79, len >> 8, len & 0xFF])); // text string uint16
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
const header = new Uint8Array(5);
|
|
578
|
+
header[0] = 0x7A;
|
|
579
|
+
new DataView(header.buffer).setUint32(1, len, false);
|
|
580
|
+
chunks.push(header);
|
|
581
|
+
}
|
|
582
|
+
chunks.push(utf8);
|
|
583
|
+
}
|
|
584
|
+
encodeBinary(value, chunks) {
|
|
585
|
+
const len = value.length;
|
|
586
|
+
if (len <= 23) {
|
|
587
|
+
chunks.push(new Uint8Array([0x40 | len])); // byte string 0-23
|
|
588
|
+
}
|
|
589
|
+
else if (len <= 0xFF) {
|
|
590
|
+
chunks.push(new Uint8Array([0x58, len])); // byte string uint8
|
|
591
|
+
}
|
|
592
|
+
else if (len <= 0xFFFF) {
|
|
593
|
+
chunks.push(new Uint8Array([0x59, len >> 8, len & 0xFF])); // byte string uint16
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
const header = new Uint8Array(5);
|
|
597
|
+
header[0] = 0x5A;
|
|
598
|
+
new DataView(header.buffer).setUint32(1, len, false);
|
|
599
|
+
chunks.push(header);
|
|
600
|
+
}
|
|
601
|
+
chunks.push(value);
|
|
602
|
+
}
|
|
603
|
+
encodeArray(value, chunks) {
|
|
604
|
+
const len = value.length;
|
|
605
|
+
if (len <= 23) {
|
|
606
|
+
chunks.push(new Uint8Array([0x80 | len])); // array 0-23
|
|
607
|
+
}
|
|
608
|
+
else if (len <= 0xFF) {
|
|
609
|
+
chunks.push(new Uint8Array([0x98, len])); // array uint8
|
|
610
|
+
}
|
|
611
|
+
else if (len <= 0xFFFF) {
|
|
612
|
+
chunks.push(new Uint8Array([0x99, len >> 8, len & 0xFF])); // array uint16
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
const header = new Uint8Array(5);
|
|
616
|
+
header[0] = 0x9A;
|
|
617
|
+
new DataView(header.buffer).setUint32(1, len, false);
|
|
618
|
+
chunks.push(header);
|
|
619
|
+
}
|
|
620
|
+
for (const item of value) {
|
|
621
|
+
this.encodeValue(item, chunks);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
encodeObject(value, chunks) {
|
|
625
|
+
const keys = Object.keys(value);
|
|
626
|
+
const len = keys.length;
|
|
627
|
+
if (len <= 23) {
|
|
628
|
+
chunks.push(new Uint8Array([0xA0 | len])); // map 0-23
|
|
629
|
+
}
|
|
630
|
+
else if (len <= 0xFF) {
|
|
631
|
+
chunks.push(new Uint8Array([0xB8, len])); // map uint8
|
|
632
|
+
}
|
|
633
|
+
else if (len <= 0xFFFF) {
|
|
634
|
+
chunks.push(new Uint8Array([0xB9, len >> 8, len & 0xFF])); // map uint16
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
const header = new Uint8Array(5);
|
|
638
|
+
header[0] = 0xBA;
|
|
639
|
+
new DataView(header.buffer).setUint32(1, len, false);
|
|
640
|
+
chunks.push(header);
|
|
641
|
+
}
|
|
642
|
+
for (const key of keys) {
|
|
643
|
+
this.encodeValue(key, chunks);
|
|
644
|
+
this.encodeValue(value[key], chunks);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
// Minimal CBOR decoder
|
|
648
|
+
decode(data) {
|
|
649
|
+
const state = { offset: 0 };
|
|
650
|
+
return this.decodeValue(data, state);
|
|
651
|
+
}
|
|
652
|
+
decodeValue(data, state) {
|
|
653
|
+
if (state.offset >= data.length) {
|
|
654
|
+
throw new Error('Unexpected end of data');
|
|
655
|
+
}
|
|
656
|
+
const byte = data[state.offset++];
|
|
657
|
+
if (byte === undefined) {
|
|
658
|
+
throw new Error('Unexpected end of data');
|
|
659
|
+
}
|
|
660
|
+
const majorType = (byte >> 5) & 0x07;
|
|
661
|
+
const additionalInfo = byte & 0x1F;
|
|
662
|
+
switch (majorType) {
|
|
663
|
+
case 0: // unsigned integer
|
|
664
|
+
return this.decodeInteger(data, state, additionalInfo);
|
|
665
|
+
case 1: // negative integer
|
|
666
|
+
return -1 - this.decodeInteger(data, state, additionalInfo);
|
|
667
|
+
case 2: // byte string
|
|
668
|
+
return this.decodeBinary(data, state, additionalInfo);
|
|
669
|
+
case 3: // text string
|
|
670
|
+
return this.decodeString(data, state, additionalInfo);
|
|
671
|
+
case 4: // array
|
|
672
|
+
return this.decodeArray(data, state, additionalInfo);
|
|
673
|
+
case 5: // map
|
|
674
|
+
return this.decodeMap(data, state, additionalInfo);
|
|
675
|
+
case 7: // float/special
|
|
676
|
+
return this.decodeSpecial(data, state, additionalInfo);
|
|
677
|
+
default:
|
|
678
|
+
throw new Error(`Unsupported CBOR major type: ${majorType}`);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
decodeInteger(data, state, additionalInfo) {
|
|
682
|
+
if (additionalInfo <= 23) {
|
|
683
|
+
return additionalInfo;
|
|
684
|
+
}
|
|
685
|
+
else if (additionalInfo === 24) {
|
|
686
|
+
const value = data[state.offset++];
|
|
687
|
+
if (value === undefined)
|
|
688
|
+
throw new Error('Unexpected end of data');
|
|
689
|
+
return value;
|
|
690
|
+
}
|
|
691
|
+
else if (additionalInfo === 25) {
|
|
692
|
+
return this.readUint16(data, state);
|
|
693
|
+
}
|
|
694
|
+
else if (additionalInfo === 26) {
|
|
695
|
+
return this.readUint32(data, state);
|
|
696
|
+
}
|
|
697
|
+
else {
|
|
698
|
+
throw new Error('Unsupported integer size');
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
decodeString(data, state, additionalInfo) {
|
|
702
|
+
let len;
|
|
703
|
+
if (additionalInfo <= 23) {
|
|
704
|
+
len = additionalInfo;
|
|
705
|
+
}
|
|
706
|
+
else {
|
|
707
|
+
len = this.decodeInteger(data, state, additionalInfo);
|
|
708
|
+
}
|
|
709
|
+
const bytes = data.slice(state.offset, state.offset + len);
|
|
710
|
+
state.offset += len;
|
|
711
|
+
return new TextDecoder().decode(bytes);
|
|
712
|
+
}
|
|
713
|
+
decodeBinary(data, state, additionalInfo) {
|
|
714
|
+
let len;
|
|
715
|
+
if (additionalInfo <= 23) {
|
|
716
|
+
len = additionalInfo;
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
len = this.decodeInteger(data, state, additionalInfo);
|
|
720
|
+
}
|
|
721
|
+
const bytes = data.slice(state.offset, state.offset + len);
|
|
722
|
+
state.offset += len;
|
|
723
|
+
return bytes;
|
|
724
|
+
}
|
|
725
|
+
decodeArray(data, state, additionalInfo) {
|
|
726
|
+
let len;
|
|
727
|
+
if (additionalInfo <= 23) {
|
|
728
|
+
len = additionalInfo;
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
len = this.decodeInteger(data, state, additionalInfo);
|
|
732
|
+
}
|
|
733
|
+
const result = [];
|
|
734
|
+
for (let i = 0; i < len; i++) {
|
|
735
|
+
result.push(this.decodeValue(data, state));
|
|
736
|
+
}
|
|
737
|
+
return result;
|
|
738
|
+
}
|
|
739
|
+
decodeMap(data, state, additionalInfo) {
|
|
740
|
+
let len;
|
|
741
|
+
if (additionalInfo <= 23) {
|
|
742
|
+
len = additionalInfo;
|
|
743
|
+
}
|
|
744
|
+
else {
|
|
745
|
+
len = this.decodeInteger(data, state, additionalInfo);
|
|
746
|
+
}
|
|
747
|
+
const result = {};
|
|
748
|
+
for (let i = 0; i < len; i++) {
|
|
749
|
+
const key = this.decodeValue(data, state);
|
|
750
|
+
const value = this.decodeValue(data, state);
|
|
751
|
+
result[String(key)] = value;
|
|
752
|
+
}
|
|
753
|
+
return result;
|
|
754
|
+
}
|
|
755
|
+
decodeSpecial(data, state, additionalInfo) {
|
|
756
|
+
switch (additionalInfo) {
|
|
757
|
+
case 20: return false;
|
|
758
|
+
case 21: return true;
|
|
759
|
+
case 22: return null;
|
|
760
|
+
case 23: return undefined;
|
|
761
|
+
case 27: { // float64
|
|
762
|
+
return this.readFloat64(data, state);
|
|
763
|
+
}
|
|
764
|
+
default:
|
|
765
|
+
throw new Error(`Unsupported CBOR special: ${additionalInfo}`);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
readUint16(data, state) {
|
|
769
|
+
const value = new DataView(data.buffer, data.byteOffset).getUint16(state.offset, false);
|
|
770
|
+
state.offset += 2;
|
|
771
|
+
return value;
|
|
772
|
+
}
|
|
773
|
+
readUint32(data, state) {
|
|
774
|
+
const value = new DataView(data.buffer, data.byteOffset).getUint32(state.offset, false);
|
|
775
|
+
state.offset += 4;
|
|
776
|
+
return value;
|
|
777
|
+
}
|
|
778
|
+
readFloat64(data, state) {
|
|
779
|
+
const value = new DataView(data.buffer, data.byteOffset).getFloat64(state.offset, false);
|
|
780
|
+
state.offset += 8;
|
|
781
|
+
return value;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
/* ── Serializer Registry ── */
|
|
785
|
+
// Order matters for format detection: JSON (most specific), CBOR, MessagePack
|
|
786
|
+
const serializers = new Map([
|
|
787
|
+
['json', new JSONSerializer()],
|
|
788
|
+
['cbor', new CBORSerializer()],
|
|
789
|
+
['msgpack', new MessagePackSerializer()],
|
|
790
|
+
]);
|
|
791
|
+
/* ── Public API ── */
|
|
792
|
+
/**
|
|
793
|
+
* Serialize a value using the specified format.
|
|
794
|
+
*
|
|
795
|
+
* @param value - Value to serialize
|
|
796
|
+
* @param options - Serialization options
|
|
797
|
+
* @returns Serialized data with metadata
|
|
798
|
+
*
|
|
799
|
+
* @example
|
|
800
|
+
* ```typescript
|
|
801
|
+
* const data = { message: 'Hello', timestamp: Date.now() };
|
|
802
|
+
*
|
|
803
|
+
* // JSON (default, human-readable)
|
|
804
|
+
* const json = serialize(data);
|
|
805
|
+
*
|
|
806
|
+
* // MessagePack (compact binary)
|
|
807
|
+
* const msgpack = serialize(data, { format: 'msgpack' });
|
|
808
|
+
*
|
|
809
|
+
* // CBOR (standard binary)
|
|
810
|
+
* const cbor = serialize(data, { format: 'cbor' });
|
|
811
|
+
*
|
|
812
|
+
* console.log('JSON:', json.value.size, 'bytes');
|
|
813
|
+
* console.log('MessagePack:', msgpack.value.size, 'bytes');
|
|
814
|
+
* console.log('CBOR:', cbor.value.size, 'bytes');
|
|
815
|
+
* ```
|
|
816
|
+
*/
|
|
817
|
+
function serialize(value, options = {}) {
|
|
818
|
+
const format = options.format ?? 'json';
|
|
819
|
+
const serializer = serializers.get(format);
|
|
820
|
+
if (!serializer) {
|
|
821
|
+
return (0, shared_1.err)({ code: 'UNSUPPORTED_FORMAT', format });
|
|
822
|
+
}
|
|
823
|
+
const startTime = options.collectMetrics ? performance.now() : 0;
|
|
824
|
+
const result = serializer.serialize(value, options);
|
|
825
|
+
if (!result.ok)
|
|
826
|
+
return result;
|
|
827
|
+
const metrics = options.collectMetrics ? {
|
|
828
|
+
serializeDuration: performance.now() - startTime,
|
|
829
|
+
size: result.value.length,
|
|
830
|
+
format,
|
|
831
|
+
timestamp: Date.now(),
|
|
832
|
+
} : undefined;
|
|
833
|
+
return (0, shared_1.ok)({
|
|
834
|
+
data: result.value,
|
|
835
|
+
format,
|
|
836
|
+
size: result.value.length,
|
|
837
|
+
contentType: serializer.contentType,
|
|
838
|
+
metrics,
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Deserialize bytes using format auto-detection or explicit format.
|
|
843
|
+
*
|
|
844
|
+
* @param data - Serialized bytes
|
|
845
|
+
* @param options - Deserialization options
|
|
846
|
+
* @returns Deserialized value with format metadata
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* ```typescript
|
|
850
|
+
* // Auto-detect format
|
|
851
|
+
* const result = deserialize(bytes);
|
|
852
|
+
* if (result.ok) {
|
|
853
|
+
* console.log('Format:', result.value.format);
|
|
854
|
+
* console.log('Data:', result.value.value);
|
|
855
|
+
* }
|
|
856
|
+
*
|
|
857
|
+
* // Explicit format (faster, skips detection)
|
|
858
|
+
* const json = deserialize(bytes, { format: 'json' });
|
|
859
|
+
* ```
|
|
860
|
+
*/
|
|
861
|
+
function deserialize(data, options = {}) {
|
|
862
|
+
const startTime = options.collectMetrics ? performance.now() : 0;
|
|
863
|
+
let format;
|
|
864
|
+
let serializer;
|
|
865
|
+
if (options.format) {
|
|
866
|
+
// Explicit format
|
|
867
|
+
format = options.format;
|
|
868
|
+
serializer = serializers.get(format);
|
|
869
|
+
if (!serializer) {
|
|
870
|
+
return (0, shared_1.err)({ code: 'UNSUPPORTED_FORMAT', format });
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
else {
|
|
874
|
+
// Auto-detect format
|
|
875
|
+
const detected = detectFormat(data);
|
|
876
|
+
if (!detected.ok)
|
|
877
|
+
return detected;
|
|
878
|
+
format = detected.value;
|
|
879
|
+
serializer = serializers.get(format);
|
|
880
|
+
if (!serializer) {
|
|
881
|
+
return (0, shared_1.err)({ code: 'UNSUPPORTED_FORMAT', format });
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
const result = serializer.deserialize(data);
|
|
885
|
+
if (!result.ok)
|
|
886
|
+
return result;
|
|
887
|
+
const metrics = options.collectMetrics ? {
|
|
888
|
+
serializeDuration: performance.now() - startTime,
|
|
889
|
+
size: data.length,
|
|
890
|
+
format,
|
|
891
|
+
timestamp: Date.now(),
|
|
892
|
+
} : undefined;
|
|
893
|
+
return (0, shared_1.ok)({
|
|
894
|
+
value: result.value,
|
|
895
|
+
format,
|
|
896
|
+
metrics,
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Detect serialization format from bytes.
|
|
901
|
+
*
|
|
902
|
+
* @param data - Serialized bytes
|
|
903
|
+
* @returns Detected format
|
|
904
|
+
*
|
|
905
|
+
* @example
|
|
906
|
+
* ```typescript
|
|
907
|
+
* const format = detectFormat(bytes);
|
|
908
|
+
* if (format.ok) {
|
|
909
|
+
* console.log('Detected format:', format.value); // 'json' | 'msgpack' | 'cbor'
|
|
910
|
+
* }
|
|
911
|
+
* ```
|
|
912
|
+
*/
|
|
913
|
+
function detectFormat(data) {
|
|
914
|
+
// Try JSON first (most specific - must start with { [ " or whitespace + those)
|
|
915
|
+
const jsonSerializer = serializers.get('json');
|
|
916
|
+
if (jsonSerializer?.detect(data)) {
|
|
917
|
+
return (0, shared_1.ok)('json');
|
|
918
|
+
}
|
|
919
|
+
if (data.length === 0) {
|
|
920
|
+
return (0, shared_1.err)({
|
|
921
|
+
code: 'FORMAT_DETECTION_FAILED',
|
|
922
|
+
reason: 'Empty data',
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
// CBOR and MessagePack have overlapping byte ranges
|
|
926
|
+
// Both formats can successfully decode data but with different interpretations
|
|
927
|
+
// Priority: Try CBOR first, then MessagePack
|
|
928
|
+
// This matches the serializers Map insertion order
|
|
929
|
+
const cborSerializer = serializers.get('cbor');
|
|
930
|
+
if (cborSerializer?.detect(data)) {
|
|
931
|
+
return (0, shared_1.ok)('cbor');
|
|
932
|
+
}
|
|
933
|
+
const msgpackSerializer = serializers.get('msgpack');
|
|
934
|
+
if (msgpackSerializer?.detect(data)) {
|
|
935
|
+
return (0, shared_1.ok)('msgpack');
|
|
936
|
+
}
|
|
937
|
+
return (0, shared_1.err)({
|
|
938
|
+
code: 'FORMAT_DETECTION_FAILED',
|
|
939
|
+
reason: 'No serializer recognized the data format',
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Negotiate format between client and server.
|
|
944
|
+
*
|
|
945
|
+
* @param clientFormats - Formats accepted by client (in preference order)
|
|
946
|
+
* @param serverFormats - Formats supported by server
|
|
947
|
+
* @returns Best matching format
|
|
948
|
+
*
|
|
949
|
+
* @example
|
|
950
|
+
* ```typescript
|
|
951
|
+
* const client = ['msgpack', 'cbor', 'json'];
|
|
952
|
+
* const server = ['json', 'cbor'];
|
|
953
|
+
* const format = negotiateFormat(client, server);
|
|
954
|
+
* console.log(format.value); // 'cbor' (first match)
|
|
955
|
+
* ```
|
|
956
|
+
*/
|
|
957
|
+
function negotiateFormat(clientFormats, serverFormats) {
|
|
958
|
+
for (const format of clientFormats) {
|
|
959
|
+
if (serverFormats.includes(format)) {
|
|
960
|
+
return (0, shared_1.ok)(format);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return (0, shared_1.err)({
|
|
964
|
+
code: 'UNSUPPORTED_FORMAT',
|
|
965
|
+
format: `No common format (client: ${clientFormats.join(',')}, server: ${serverFormats.join(',')})`,
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
/**
|
|
969
|
+
* Compare serialization performance across formats.
|
|
970
|
+
*
|
|
971
|
+
* @param value - Value to benchmark
|
|
972
|
+
* @param formats - Formats to compare
|
|
973
|
+
* @returns Performance comparison
|
|
974
|
+
*
|
|
975
|
+
* @example
|
|
976
|
+
* ```typescript
|
|
977
|
+
* const data = { message: 'Hello', items: [1, 2, 3, 4, 5] };
|
|
978
|
+
* const comparison = compareFormats(data);
|
|
979
|
+
*
|
|
980
|
+
* if (comparison.ok) {
|
|
981
|
+
* for (const result of comparison.value) {
|
|
982
|
+
* console.log(`${result.format}: ${result.size} bytes, ${result.duration}ms`);
|
|
983
|
+
* }
|
|
984
|
+
* }
|
|
985
|
+
* ```
|
|
986
|
+
*/
|
|
987
|
+
function compareFormats(value, formats = ['json', 'msgpack', 'cbor']) {
|
|
988
|
+
const results = [];
|
|
989
|
+
for (const format of formats) {
|
|
990
|
+
const result = serialize(value, { format, collectMetrics: true });
|
|
991
|
+
if (!result.ok)
|
|
992
|
+
return result;
|
|
993
|
+
results.push({
|
|
994
|
+
format,
|
|
995
|
+
size: result.value.size,
|
|
996
|
+
duration: result.value.metrics?.serializeDuration ?? 0,
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
return (0, shared_1.ok)(results);
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Get Content-Type header for a serialization format.
|
|
1003
|
+
*
|
|
1004
|
+
* @param format - Serialization format
|
|
1005
|
+
* @returns Content-Type header value
|
|
1006
|
+
*
|
|
1007
|
+
* @example
|
|
1008
|
+
* ```typescript
|
|
1009
|
+
* const contentType = getContentType('msgpack');
|
|
1010
|
+
* console.log(contentType); // 'application/msgpack'
|
|
1011
|
+
* ```
|
|
1012
|
+
*/
|
|
1013
|
+
function getContentType(format) {
|
|
1014
|
+
const serializer = serializers.get(format);
|
|
1015
|
+
return serializer?.contentType ?? 'application/octet-stream';
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Parse Content-Type header to serialization format.
|
|
1019
|
+
*
|
|
1020
|
+
* @param contentType - Content-Type header value
|
|
1021
|
+
* @returns Serialization format or undefined
|
|
1022
|
+
*
|
|
1023
|
+
* @example
|
|
1024
|
+
* ```typescript
|
|
1025
|
+
* const format = parseContentType('application/json');
|
|
1026
|
+
* console.log(format); // 'json'
|
|
1027
|
+
*
|
|
1028
|
+
* const format2 = parseContentType('application/msgpack');
|
|
1029
|
+
* console.log(format2); // 'msgpack'
|
|
1030
|
+
* ```
|
|
1031
|
+
*/
|
|
1032
|
+
function parseContentType(contentType) {
|
|
1033
|
+
const normalized = contentType.toLowerCase().split(';')[0]?.trim() ?? '';
|
|
1034
|
+
for (const serializer of serializers.values()) {
|
|
1035
|
+
if (serializer.contentType === normalized) {
|
|
1036
|
+
return serializer.format;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return undefined;
|
|
1040
|
+
}
|