UNPKG

@strapi/data-transfer

Version:

Data transfer capabilities for Strapi

68 lines (65 loc) 3.3 kB
'use strict'; /** * Shared `JSON.stringify` replacer for data-transfer WebSocket frames (push and pull). * * Default `JSON.stringify` uses `Buffer.toJSON()` → `{ type: 'Buffer', data: [n,n,...] }`, which * allocates a large array on the peer during `JSON.parse`. Encode binary values as compact base64 strings instead. * * Note: Node runs `Buffer.prototype.toJSON` before the replacer sees a `Buffer` property, so the * replacer receives `{ type: 'Buffer', data: [...] }` unless the value is already a string (see * `createTransferAssetStreamChunk` in `transfer-asset-chunk.ts`). */ const replacerForTransferWebSocket = (_key, value)=>{ /** `JSON.stringify` throws on bigint; upload metadata or ORM fields may surface as BigInt. */ if (typeof value === 'bigint') { return value.toString(); } if (Buffer.isBuffer(value)) { return value.toString('base64'); } if (value instanceof Uint8Array) { const { buffer, byteOffset, byteLength } = value; if (buffer == null) { throw new TypeError('Invalid Uint8Array in transfer payload (missing underlying ArrayBuffer); cannot encode for WebSocket'); } return Buffer.from(buffer, byteOffset, byteLength).toString('base64'); } if (ArrayBuffer.isView(value) && !(value instanceof DataView)) { const v = value; const { buffer, byteOffset, byteLength } = v; if (buffer == null) { throw new TypeError('Invalid typed array in transfer payload (missing underlying ArrayBuffer); cannot encode for WebSocket'); } return Buffer.from(buffer, byteOffset, byteLength).toString('base64'); } return value; }; /** * `JSON.stringify` invokes an own enumerable `toJSON` on the root value before replacers run. If that * method returns `undefined`, the whole `JSON.stringify` result is `undefined`, and `ws.send(undefined)` * throws ("The first argument must be of type string or an instance of Buffer... Received undefined"). * Spreading transfer messages (`{ ...message, uuid }`) can copy an enumerable `toJSON` from user / ORM * objects onto the wire payload — strip it on the root object we control. */ function stripRootToJSONMethod(payload) { if (typeof payload.toJSON === 'function') { delete payload.toJSON; } } /** * Serialize a transfer WebSocket envelope. Never returns `undefined` (unlike raw `JSON.stringify`). */ function stringifyTransferWebSocketPayload(payload) { stripRootToJSONMethod(payload); let s; try { s = JSON.stringify(payload, replacerForTransferWebSocket); } catch (err) { const message = err instanceof Error ? err.message : String(err); throw new TypeError(`Transfer WebSocket payload could not be serialized to JSON: ${message}`); } if (typeof s !== 'string') { throw new TypeError('Transfer WebSocket payload could not be serialized to JSON (result was undefined). Check for Symbol or other non-JSON values on the root payload.'); } return s; } exports.replacerForTransferWebSocket = replacerForTransferWebSocket; exports.stringifyTransferWebSocketPayload = stringifyTransferWebSocketPayload; exports.stripRootToJSONMethod = stripRootToJSONMethod; //# sourceMappingURL=transfer-websocket-json.js.map