@xpgamesllc/ipcs-be 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/LICENSE +674 -0
- package/README.md +11 -0
- package/dist/index.d.mts +20 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +572 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +545 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/v1/net.ts","../src/v1/encoding/encoding.ts","../src/v1/envelope.ts","../src/utils/uuid.ts","../src/v1/encoding/TextPacketEncoder.ts","../src/utils/base64.ts","../src/v1/encoding/Base64PacketEncoder.ts"],"sourcesContent":["import { system } from \"@minecraft/server\";\r\nimport NetV1 from \"./v1/net\";\r\n\r\nlet version = 1;\r\nconst MaxVersion = 1;\r\nconst MinVersion = 1;\r\n\r\nexport function setVersion(v: number) {\r\n if (version < MinVersion || version > MaxVersion) {\r\n throw new Error(`IPCS-BE spec version ${version} is not supported`);\r\n }\r\n version = v;\r\n}\r\n\r\n/**\r\n * Send a script event, fragmenting JSON/text payload if needed. Optionally receive a response.\r\n * @param channel - The script-event channel to send to.\r\n * @param payload - The payload to send.\r\n * @param opts - Optional encoding and message ID.\r\n * @param callback - Optional callback to receive a response.\r\n */\r\nexport function send(\r\n channel: string,\r\n payload: any,\r\n opts?: { encoding?: string; id?: string },\r\n callback?: (response: any) => void\r\n): void {\r\n if (version === 1) {\r\n NetV1.send(channel, payload, opts, callback);\r\n }\r\n}\r\n\r\n/**\r\n * Subscribe to reassembled messages on a channel.\r\n * @param channel - The script-event channel to subscribe to.\r\n * @param cb - The callback to invoke when a message is received.\r\n */\r\nexport function on(\r\n channel: string,\r\n cb: (payload: any, respond?: (resp: any) => void) => void\r\n): void {\r\n NetV1.on(channel, cb);\r\n}\r\n\r\nsystem.afterEvents.scriptEventReceive.subscribe((evt) => {\r\n NetV1.handleScriptEvent(evt.id, evt.message);\r\n});\r\n","import { system } from \"@minecraft/server\";\r\nimport { IEncoder, SPEC_VERSION, MAX_CHUNK } from \"./encoding/encoding\";\r\nimport { buildEnvelope, MetaHeader, EncHeader, RS, ETX, getEnvelopeLength } from \"./envelope\";\r\nimport { makeUUID } from \"../utils/uuid\";\r\nimport { TextPacketEncoder } from \"./encoding/TextPacketEncoder\";\r\nimport { Base64PacketEncoder } from \"./encoding/Base64PacketEncoder\";\r\n\r\ninterface FragmentBuffer {\r\n parts: {body: string, frag: number, last: boolean}[];\r\n lastIndex?: number;\r\n}\r\n\r\nexport default class Net {\r\n private static listeners = new Map<string, ((payload: any, respond?: (resp: any) => void) => void)[]>();\r\n private static buffers = new Map<string, FragmentBuffer>();\r\n private static encoders = new Map<string, IEncoder>();\r\n private static readonly DefaultEncoding = \"text\";\r\n\r\n /**\r\n * Register a new encoder implementation by its unique name.\r\n */\r\n public static registerEncoder(encoder: IEncoder) {\r\n this.encoders.set(encoder.encoding, encoder);\r\n }\r\n\r\n /** fire a script event, fragmenting JSON/text payload if needed. Optionally receive a response. */\r\n public static send(channel: string, payload: any, opts?: { encoding?: string; id?: string }, callback?: (response: any) => void): void {\r\n const encodingName = opts?.encoding ?? Net.DefaultEncoding;\r\n const encoder = Net.encoders.get(encodingName);\r\n if (!encoder) throw new Error(`Unknown encoder: ${encodingName}`);\r\n const raw = encoder.encode(payload);\r\n const id = (opts?.id ?? makeUUID()).replace(/-/g, \"\");\r\n // subscribe one-time response listener if callback provided\r\n if (callback) {\r\n const respChannel = `ipcs:${id}`;\r\n const wrapper = (respPayload: any) => { try { callback(respPayload); } finally { Net.off(respChannel, wrapper as any); } };\r\n Net.on(respChannel, wrapper as any);\r\n }\r\n const totalLen = raw.length;\r\n // compute overhead and fragment size to not exceed MAX_CHUNK per envelope\r\n const metaPart = `${SPEC_VERSION}|${encodingName}`;\r\n let chunks: string[][] = [];\r\n // estimate header length without fragmentation\r\n const meta: MetaHeader = { version: SPEC_VERSION, encoding: encodingName };\r\n const metaLength = getEnvelopeLength(meta);\r\n const noFragHdr = encoder.encodeHeader({ id });\r\n const noFragHdrLen = noFragHdr.length;\r\n const noFragOverhead = metaPart.length + RS.length + ETX.length + noFragHdrLen;\r\n if (totalLen + noFragOverhead + metaLength <= MAX_CHUNK) {\r\n // fits without fragmentation\r\n chunks = [[noFragHdr, raw]];\r\n } else {\r\n let i = 0;\r\n let remaining = totalLen;\r\n let written = 0;\r\n while (remaining > 0) {\r\n // Calculate header length for fragment i\r\n const hdr = encoder.encodeHeader({ id, frag: i, last: 0 } as any);\r\n const hdrLen = hdr.length;\r\n // Fit as much as possible into a single envelope\r\n const chunkSize = Math.min(MAX_CHUNK - hdrLen - metaLength, remaining);\r\n chunks.push([hdr, raw.slice(written, written + chunkSize)]);\r\n remaining -= chunkSize;\r\n written += chunkSize;\r\n i++;\r\n }\r\n }\r\n // total fragments count\r\n // send each fragment envelope\r\n if (chunks.length === 1) {\r\n const hdrString = chunks[0][0];\r\n const envelope = buildEnvelope(meta, hdrString, chunks[0][1]);\r\n system.sendScriptEvent(channel, envelope);\r\n } else {\r\n for (let i = 0; i < chunks.length; i++) {\r\n const encHdr: EncHeader = { id, frag: i, last: i === chunks.length - 1 };\r\n const hdrString = encHdr.last ? encoder.encodeHeader(encHdr) : chunks[i][0];\r\n const envelope = buildEnvelope(meta, hdrString, chunks[i][1]);\r\n system.sendScriptEvent(channel, envelope);\r\n }\r\n }\r\n }\r\n\r\n /** subscribe to reassembled messages on a channel */\r\n public static on(channel: string, cb: (payload: any, respond?: (resp: any) => void) => void): void {\r\n const arr = Net.listeners.get(channel) ?? [];\r\n arr.push(cb);\r\n Net.listeners.set(channel, arr);\r\n }\r\n\r\n /** unsubscribe a callback from a channel */\r\n public static off(channel: string, cb: (payload: any, respond?: (resp: any) => void) => void): void {\r\n const arr = this.listeners.get(channel);\r\n if (!arr) return;\r\n const filtered = arr.filter(fn => fn !== cb);\r\n if (filtered.length) this.listeners.set(channel, filtered);\r\n else this.listeners.delete(channel);\r\n }\r\n\r\n /** invoke all cbs registered on this channel, providing optional respond function */\r\n private static dispatch(channel: string, payload: any, id?: string, encodingName?: string) {\r\n const arr = Net.listeners.get(channel);\r\n if (!arr) return;\r\n for (const cb of arr) {\r\n try {\r\n // provide respond function only for request listeners (non-ipcs channels)\r\n if (id && !channel.startsWith('ipcs:')) {\r\n const respond = (responsePayload: any) => {\r\n Net.send(`ipcs:${id}`, responsePayload, { encoding: encodingName, id });\r\n };\r\n (cb as any)(payload, respond);\r\n } else {\r\n (cb as any)(payload);\r\n }\r\n } catch {\r\n /* swallow errors */\r\n }\r\n }\r\n }\r\n\r\n /** internal dispatcher: parse envelope, reassemble if needed, then fire user-cb */\r\n public static handleScriptEvent(channel: string, raw: string): void {\r\n // split meta and rest\r\n const [metaPart, rest] = raw.split(RS, 2);\r\n if (!rest) return;\r\n // split enc header and payload\r\n const [encPart, body] = rest.split(ETX, 2);\r\n if (body === undefined) return;\r\n // parse meta header\r\n const [verStr, encodingName] = metaPart.split(\"|\");\r\n if (parseInt(verStr, 10) !== SPEC_VERSION) return;\r\n const encoder = Net.encoders.get(encodingName);\r\n if (!encoder) return;\r\n // parse enc header\r\n const header = encoder.decodeHeader(encPart);\r\n if (!header) return;\r\n const { id, frag, last } = header;\r\n // single-part\r\n if (frag === undefined || last === undefined) {\r\n const payload = encoder.decode(body);\r\n if (payload !== null) Net.dispatch(channel, payload, id, encodingName);\r\n return;\r\n }\r\n // fragmented: buffer until all arrive\r\n let buf = Net.buffers.get(id);\r\n if (!buf) {\r\n buf = { parts: [] };\r\n Net.buffers.set(id, buf);\r\n }\r\n if (frag !== undefined && buf.parts[frag] === undefined) {\r\n buf.parts[frag] = {\r\n body,\r\n frag: header.frag!,\r\n last: header.last!,\r\n };\r\n if (header.last!) {\r\n buf.lastIndex = frag;\r\n }\r\n }\r\n if (buf.lastIndex !== undefined && buf.parts.length === (buf.lastIndex + 1) && buf.parts.sort((a, b) => a.frag - b.frag)[buf.lastIndex].frag === buf.lastIndex) {\r\n const full = buf.parts.map(p => p.body).join(\"\");\r\n Net.buffers.delete(id);\r\n const payload = encoder.decode(full);\r\n if (payload !== null) Net.dispatch(channel, payload, id, encodingName);\r\n }\r\n }\r\n}\r\n\r\n// register built-in encoders\r\nNet.registerEncoder(new TextPacketEncoder());\r\nNet.registerEncoder(new Base64PacketEncoder());","import { EncHeader } from \"../envelope\";\r\n\r\nexport const MAX_CHUNK = 2047;\r\nexport const SPEC_VERSION = 1;\r\n\r\n/**\r\n * Encoder interface for IPCS-BE payloads.\r\n */\r\nexport interface IEncoder {\r\n /** Unique encoding name (e.g. 'text', 'b64', 'struct'). */\r\n encoding: string;\r\n /**\r\n * Split and serialize payload into header chunks.\r\n * @param payload Data to send\r\n * @param opts.id Optional message UUID\r\n * @returns Encoded payload\r\n */\r\n encode(payload: Record<string, any>): string;\r\n\r\n /**\r\n * Serialize a single header into a string.\r\n * @param header Header to serialize\r\n * @returns String representation of header\r\n */\r\n encodeHeader(header: EncHeader): string;\r\n\r\n /**\r\n * Parse a payload string into decoded payload.\r\n * @param raw Raw body extracted from envelope\r\n * @returns Parsed data or null if not applicable\r\n */\r\n decode(raw: string): Record<string, any> | null;\r\n\r\n /**\r\n * Parse a header string into metadata.\r\n * @param raw Raw header extracted from envelope\r\n * @returns Parsed data or null if not applicable\r\n */\r\n decodeHeader(raw: string): EncHeader | null;\r\n}\r\n","/** Meta header fields */\r\nexport interface MetaHeader {\r\n version: number;\r\n encoding: string;\r\n}\r\n\r\n/** Encoding-specific header fields */\r\nexport interface EncHeader {\r\n id: string;\r\n frag?: number;\r\n last?: boolean;\r\n}\r\n\r\n/**\r\n * Record Separator and End-of-Text constants\r\n */\r\nexport const RS = \"\\u001e\";\r\nexport const ETX = \"\\u0003\";\r\n\r\n/**\r\n * Build an IPCS-BE envelope string: <meta>RS<enc>ETX<payload>\r\n */\r\nexport function buildEnvelope(meta: MetaHeader, enc: string, chunk: string): string {\r\n const metaPart = `${meta.version}|${meta.encoding}`;\r\n return `${metaPart}${RS}${enc}${ETX}${chunk}`;\r\n}\r\n\r\nexport function getEnvelopeLength(meta: MetaHeader): number {\r\n const metaPart = `${meta.version}|${meta.encoding}`;\r\n return `${metaPart}${RS}${ETX}`.length;\r\n}","export function makeUUID(): string {\r\n return \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, (c) => {\r\n const r = (Math.random() * 16) | 0;\r\n const v = c === \"x\" ? r : (r & 0x3) | 0x8;\r\n return v.toString(16);\r\n });\r\n}\r\n\r\n/**\r\n * Converts a UUID string (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) into a 16-byte Uint8Array.\r\n * @param uuid A valid UUID string.\r\n * @throws If the input is not a 36-char UUID.\r\n */\r\nexport function uuidToBytes(uuid: string): Uint8Array {\r\n const hex = uuid.replace(/-/g, '');\r\n if (hex.length !== 32) {\r\n throw new Error(`Invalid UUID: expected 36 chars with hyphens, got \"${uuid}\"`);\r\n }\r\n\r\n const bytes = new Uint8Array(16);\r\n for (let i = 0; i < 16; i++) {\r\n bytes[i] = parseInt(hex.substr(i * 2, 2), 16);\r\n }\r\n return bytes;\r\n}\r\n\r\n/**\r\n * Converts a 16-byte Uint8Array back into a UUID string.\r\n * @param bytes A Uint8Array of length 16.\r\n * @throws If the input array is not exactly 16 bytes.\r\n */\r\nexport function bytesToUuid(bytes: Uint8Array): string {\r\n if (bytes.length !== 16) {\r\n throw new Error(`Invalid byte array: expected length 16, got ${bytes.length}`);\r\n }\r\n\r\n // Convert each byte to hex, pad single-digit with leading zero\r\n const hex: string[] = Array.from(bytes, b => b.toString(16).padStart(2, '0'));\r\n\r\n return hex.join('');\r\n}","import { EncHeader } from \"../envelope\";\r\nimport { IEncoder } from \"./encoding\";\r\n\r\n/**\r\n * Text encoding implementation for IPCS-BE (UTF-16 JSON).\r\n */\r\nexport class TextPacketEncoder implements IEncoder {\r\n encoding = \"text\";\r\n\r\n encode(payload: Record<string, any>): string {\r\n return JSON.stringify(payload);\r\n }\r\n\r\n encodeHeader(header: EncHeader): string {\r\n const parts: string[] = [header.id];\r\n if (header.frag !== undefined && header.last !== undefined) {\r\n parts.push(header.frag.toString(), (header.last ? 1 : 0).toString());\r\n }\r\n return parts.join(\"|\");\r\n }\r\n\r\n decode(raw: string): Record<string, any> | null {\r\n try {\r\n return JSON.parse(raw);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n decodeHeader(raw: string): EncHeader | null {\r\n const parts = raw.split(\"|\");\r\n const id = parts[0];\r\n const header: EncHeader = { id };\r\n if (parts.length === 3) {\r\n const frag = parseInt(parts[1], 10);\r\n const last = parseInt(parts[2], 10);\r\n if (isNaN(frag) || isNaN(last)) return null;\r\n header.frag = frag;\r\n header.last = last === 1;\r\n } else if (parts.length !== 1) {\r\n return null;\r\n }\r\n return header;\r\n }\r\n}","export default class Base64 {\r\n private static readonly _alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\r\n private static readonly _pad = \"=\";\r\n\r\n /* UTF-8 encode/decode helpers for ES2023-only environments */\r\n public static utf8Encode(str: string): Uint8Array {\r\n const bytes: number[] = [];\r\n for (const ch of str) {\r\n const cp = ch.codePointAt(0)!;\r\n if (cp <= 0x7F) {\r\n bytes.push(cp);\r\n } else if (cp <= 0x7FF) {\r\n bytes.push(0xC0 | (cp >> 6), 0x80 | (cp & 0x3F));\r\n } else if (cp <= 0xFFFF) {\r\n bytes.push(\r\n 0xE0 | (cp >> 12),\r\n 0x80 | ((cp >> 6) & 0x3F),\r\n 0x80 | (cp & 0x3F)\r\n );\r\n } else {\r\n bytes.push(\r\n 0xF0 | (cp >> 18),\r\n 0x80 | ((cp >> 12) & 0x3F),\r\n 0x80 | ((cp >> 6) & 0x3F),\r\n 0x80 | (cp & 0x3F)\r\n );\r\n }\r\n }\r\n return new Uint8Array(bytes);\r\n }\r\n\r\n public static utf8Decode(bytes: Uint8Array): string {\r\n let str = \"\";\r\n for (let i = 0; i < bytes.length; ) {\r\n const b1 = bytes[i++];\r\n if (b1 < 0x80) {\r\n str += String.fromCodePoint(b1);\r\n } else if (b1 < 0xE0) {\r\n const b2 = bytes[i++];\r\n str += String.fromCodePoint(((b1 & 0x1F) << 6) | (b2 & 0x3F));\r\n } else if (b1 < 0xF0) {\r\n const b2 = bytes[i++], b3 = bytes[i++];\r\n str += String.fromCodePoint(\r\n ((b1 & 0x0F) << 12) |\r\n ((b2 & 0x3F) << 6) |\r\n (b3 & 0x3F)\r\n );\r\n } else {\r\n const b2 = bytes[i++], b3 = bytes[i++], b4 = bytes[i++];\r\n str += String.fromCodePoint(\r\n ((b1 & 0x07) << 18) |\r\n ((b2 & 0x3F) << 12) |\r\n ((b3 & 0x3F) << 6) |\r\n (b4 & 0x3F)\r\n );\r\n }\r\n }\r\n return str;\r\n }\r\n\r\n /* ------------------------------------------------------------------ */\r\n /* Low-level byte-wise codec */\r\n /* ------------------------------------------------------------------ */\r\n\r\n /** Encode raw bytes (Uint8Array) -> Base-64 text. */\r\n public static encodeBytes(bytes: Uint8Array): string {\r\n let out = \"\";\r\n let i = 0;\r\n while (i < bytes.length) {\r\n const b1 = bytes[i++] ?? NaN;\r\n const b2 = bytes[i++] ?? NaN;\r\n const b3 = bytes[i++] ?? NaN;\r\n\r\n const enc1 = b1 >> 2;\r\n const enc2 = ((b1 & 0x03) << 4) | (b2 >> 4);\r\n const enc3 = isNaN(b2) ? 64 : (((b2 & 0x0F) << 2) | (b3 >> 6));\r\n const enc4 = isNaN(b3) ? 64 : (b3 & 0x3F);\r\n\r\n out += Base64._alphabet.charAt(enc1);\r\n out += Base64._alphabet.charAt(enc2);\r\n out += enc3 === 64 ? Base64._pad : Base64._alphabet.charAt(enc3);\r\n out += enc4 === 64 ? Base64._pad : Base64._alphabet.charAt(enc4);\r\n }\r\n return out;\r\n }\r\n\r\n /** Decode Base-64 text -> raw bytes (Uint8Array). */\r\n public static decodeToBytes(base64: string): Uint8Array {\r\n // Remove whitespace & non-alphabet chars\r\n base64 = base64.replace(/[^A-Za-z0-9+/=]/g, \"\");\r\n const byteLen = (base64.length / 4) * 3 - (base64.endsWith(\"==\") ? 2 : base64.endsWith(\"=\") ? 1 : 0);\r\n const bytes = new Uint8Array(byteLen);\r\n let byteIdx = 0, i = 0;\r\n while (i < base64.length) {\r\n const enc1 = Base64._alphabet.indexOf(base64.charAt(i++));\r\n const enc2 = Base64._alphabet.indexOf(base64.charAt(i++));\r\n const enc3 = Base64._alphabet.indexOf(base64.charAt(i++));\r\n const enc4 = Base64._alphabet.indexOf(base64.charAt(i++));\r\n\r\n const b1 = (enc1 << 2) | (enc2 >> 4);\r\n const b2 = ((enc2 & 0x0F) << 4) | (enc3 >> 2);\r\n const b3 = ((enc3 & 0x03) << 6) | enc4;\r\n\r\n bytes[byteIdx++] = b1;\r\n if (enc3 !== 64 && byteIdx < byteLen) bytes[byteIdx++] = b2;\r\n if (enc4 !== 64 && byteIdx < byteLen) bytes[byteIdx++] = b3;\r\n }\r\n return bytes;\r\n }\r\n\r\n /* ------------------------------------------------------------------ */\r\n /* Convenience wrappers for regular JS strings (UTF-8) */\r\n /* ------------------------------------------------------------------ */\r\n\r\n /** Encode a JS string to Base-64 using UTF-8. */\r\n public static encode(str: string): string {\r\n const bytes = Base64.utf8Encode(str);\r\n return Base64.encodeBytes(bytes);\r\n }\r\n\r\n /** Decode Base-64 to a JS string using UTF-8. */\r\n public static decode(base64: string): string {\r\n const bytes = Base64.decodeToBytes(base64);\r\n return Base64.utf8Decode(bytes);\r\n }\r\n\r\n /* ------------------------------------------------------------------ */\r\n /* Helper factories */\r\n /* ------------------------------------------------------------------ */\r\n\r\n public static createOutputStream(): Base64OutputStream {\r\n return new Base64OutputStream();\r\n }\r\n public static createInputStream(encoded: string): Base64InputStream {\r\n return new Base64InputStream(encoded);\r\n }\r\n}\r\n\r\n/* ===================================================================== */\r\n/* Streaming writer */\r\n/* ===================================================================== */\r\nexport class Base64OutputStream {\r\n private readonly _buf: number[] = [];\r\n public get length(): number { return this._buf.length; }\r\n\r\n public writeBytes(arr: Uint8Array): void {\r\n for (let i = 0; i < arr.length; i++) {\r\n this.writeByte(arr[i]);\r\n }\r\n }\r\n\r\n /* ---------- range-checked primitives ---------- */\r\n public writeByte(v: number): void {\r\n if (!Number.isInteger(v) || v < 0 || v > 0xFF) throw new RangeError(\"byte 0-255\");\r\n this._buf.push(v);\r\n }\r\n public writeShort(v: number): void {\r\n if (!Number.isInteger(v) || v < 0 || v > 0xFFFF) throw new RangeError(\"short 0-65535\");\r\n this.writeByte((v >>> 8) & 0xFF); this.writeByte(v & 0xFF);\r\n }\r\n public writeInt(v: number): void {\r\n if (!Number.isInteger(v) || v < 0 || v > 0xFFFFFFFF) throw new RangeError(\"int 0-4294967295\");\r\n this.writeByte((v >>> 24) & 0xFF); this.writeByte((v >>> 16) & 0xFF); this.writeByte((v >>> 8) & 0xFF); this.writeByte(v & 0xFF);\r\n }\r\n\r\n /* ---------- IEEE-754 ---------- */\r\n public writeFloat(v: number): void {\r\n const dv = new DataView(new ArrayBuffer(4));\r\n dv.setFloat32(0, v, false);\r\n for (let i = 0; i < 4; i++) this.writeByte(dv.getUint8(i));\r\n }\r\n public writeDouble(v: number): void {\r\n const dv = new DataView(new ArrayBuffer(8));\r\n dv.setFloat64(0, v, false);\r\n for (let i = 0; i < 8; i++) this.writeByte(dv.getUint8(i));\r\n }\r\n\r\n /* ---------- strings ---------- */\r\n public writeUTF(str: string): void {\r\n const bytes = Base64.utf8Encode(str);\r\n this.writeShort(bytes.length);\r\n for (const b of bytes) this.writeByte(b);\r\n }\r\n\r\n /** Finalize & return Base-64. */\r\n public toString(): string {\r\n return Base64.encodeBytes(Uint8Array.from(this._buf));\r\n }\r\n}\r\n\r\n/* ===================================================================== */\r\n/* Streaming reader */\r\n/* ===================================================================== */\r\nexport class Base64InputStream {\r\n private readonly _bytes: Uint8Array;\r\n private _pos = 0;\r\n constructor(encoded: string) {\r\n this._bytes = Base64.decodeToBytes(encoded);\r\n }\r\n private _need(n: number) { if (this._pos + n > this._bytes.length) throw new RangeError(\"EOF\"); }\r\n\r\n public readBytes(n: number): Uint8Array {\r\n const arr = new Uint8Array(n);\r\n for (let i = 0; i < n; i++) {\r\n arr[i] = this.readByte();\r\n }\r\n return arr;\r\n }\r\n public readByte(): number { this._need(1); return this._bytes[this._pos++]; }\r\n public readShort(): number { return (this.readByte() << 8) | this.readByte(); }\r\n public readInt(): number { return (this.readByte() << 24) | (this.readByte() << 16) | (this.readByte() << 8) | this.readByte(); }\r\n public readFloat(): number {\r\n this._need(4); const dv = new DataView(this._bytes.buffer, this._bytes.byteOffset + this._pos, 4);\r\n const v = dv.getFloat32(0, false); this._pos += 4; return v; }\r\n public readDouble(): number {\r\n this._need(8); const dv = new DataView(this._bytes.buffer, this._bytes.byteOffset + this._pos, 8);\r\n const v = dv.getFloat64(0, false); this._pos += 8; return v; }\r\n public readUTF(): string {\r\n const len = this.readShort(); this._need(len);\r\n const slice = this._bytes.subarray(this._pos, this._pos + len);\r\n this._pos += len; \r\n return Base64.utf8Decode(slice);\r\n }\r\n public get remaining(): number { return this._bytes.length - this._pos; }\r\n}","import Base64, { Base64InputStream, Base64OutputStream } from \"../../utils/base64\";\r\nimport { bytesToUuid, uuidToBytes } from \"../../utils/uuid\";\r\nimport { EncHeader } from \"../envelope\";\r\nimport { IEncoder } from \"./encoding\";\r\n\r\n\r\nexport class Base64PacketEncoder implements IEncoder {\r\n // encoding name for Base64 transport\r\n encoding = \"b64\";\r\n\r\n encode(payload: Record<string, any>): string {\r\n // JSON stringify and then Base64 encode\r\n const json = JSON.stringify(payload);\r\n return Base64.encode(json);\r\n }\r\n\r\n encodeHeader(header: EncHeader): string {\r\n const { id, frag, last } = header;\r\n // build binary header\r\n const out = new Base64OutputStream();\r\n // write 16-byte UUID (hex without hyphens)\r\n out.writeBytes(uuidToBytes(id));\r\n // flags: bit0 = fragmented, bit1 = extra (none for b64)\r\n let flags = 0;\r\n if (last !== undefined) flags |= 0x01;\r\n out.writeByte(flags);\r\n // optionally write fragment indices\r\n if (flags & 0x01) {\r\n out.writeShort(frag!);\r\n out.writeByte(last ? 1 : 0);\r\n }\r\n return out.toString();\r\n }\r\n\r\n decode(raw: string): Record<string, any> | null {\r\n try {\r\n const json = Base64.decode(raw);\r\n return JSON.parse(json);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n decodeHeader(raw: string): EncHeader | null {\r\n try {\r\n const inp = new Base64InputStream(raw);\r\n // read 16-byte UUID\r\n const bytes = inp.readBytes(16);\r\n const id = bytesToUuid(bytes);\r\n const flags = inp.readByte();\r\n const header: EncHeader = { id };\r\n if (flags & 0x01) {\r\n header.frag = inp.readShort();\r\n header.last = inp.readByte() === 1;\r\n }\r\n return header;\r\n } catch {\r\n return null;\r\n }\r\n }\r\n}"],"mappings":"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","names":["import_server"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,545 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { system as system2 } from "@minecraft/server";
|
|
3
|
+
|
|
4
|
+
// src/v1/net.ts
|
|
5
|
+
import { system } from "@minecraft/server";
|
|
6
|
+
|
|
7
|
+
// src/v1/encoding/encoding.ts
|
|
8
|
+
var MAX_CHUNK = 2047;
|
|
9
|
+
var SPEC_VERSION = 1;
|
|
10
|
+
|
|
11
|
+
// src/v1/envelope.ts
|
|
12
|
+
var RS = "";
|
|
13
|
+
var ETX = "";
|
|
14
|
+
function buildEnvelope(meta, enc, chunk) {
|
|
15
|
+
const metaPart = `${meta.version}|${meta.encoding}`;
|
|
16
|
+
return `${metaPart}${RS}${enc}${ETX}${chunk}`;
|
|
17
|
+
}
|
|
18
|
+
function getEnvelopeLength(meta) {
|
|
19
|
+
const metaPart = `${meta.version}|${meta.encoding}`;
|
|
20
|
+
return `${metaPart}${RS}${ETX}`.length;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/utils/uuid.ts
|
|
24
|
+
function makeUUID() {
|
|
25
|
+
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
26
|
+
const r = Math.random() * 16 | 0;
|
|
27
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
28
|
+
return v.toString(16);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function uuidToBytes(uuid) {
|
|
32
|
+
const hex = uuid.replace(/-/g, "");
|
|
33
|
+
if (hex.length !== 32) {
|
|
34
|
+
throw new Error(`Invalid UUID: expected 36 chars with hyphens, got "${uuid}"`);
|
|
35
|
+
}
|
|
36
|
+
const bytes = new Uint8Array(16);
|
|
37
|
+
for (let i = 0; i < 16; i++) {
|
|
38
|
+
bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
|
|
39
|
+
}
|
|
40
|
+
return bytes;
|
|
41
|
+
}
|
|
42
|
+
function bytesToUuid(bytes) {
|
|
43
|
+
if (bytes.length !== 16) {
|
|
44
|
+
throw new Error(`Invalid byte array: expected length 16, got ${bytes.length}`);
|
|
45
|
+
}
|
|
46
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
|
|
47
|
+
return hex.join("");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/v1/encoding/TextPacketEncoder.ts
|
|
51
|
+
var TextPacketEncoder = class {
|
|
52
|
+
encoding = "text";
|
|
53
|
+
encode(payload) {
|
|
54
|
+
return JSON.stringify(payload);
|
|
55
|
+
}
|
|
56
|
+
encodeHeader(header) {
|
|
57
|
+
const parts = [header.id];
|
|
58
|
+
if (header.frag !== void 0 && header.last !== void 0) {
|
|
59
|
+
parts.push(header.frag.toString(), (header.last ? 1 : 0).toString());
|
|
60
|
+
}
|
|
61
|
+
return parts.join("|");
|
|
62
|
+
}
|
|
63
|
+
decode(raw) {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(raw);
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
decodeHeader(raw) {
|
|
71
|
+
const parts = raw.split("|");
|
|
72
|
+
const id = parts[0];
|
|
73
|
+
const header = { id };
|
|
74
|
+
if (parts.length === 3) {
|
|
75
|
+
const frag = parseInt(parts[1], 10);
|
|
76
|
+
const last = parseInt(parts[2], 10);
|
|
77
|
+
if (isNaN(frag) || isNaN(last))
|
|
78
|
+
return null;
|
|
79
|
+
header.frag = frag;
|
|
80
|
+
header.last = last === 1;
|
|
81
|
+
} else if (parts.length !== 1) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
return header;
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/utils/base64.ts
|
|
89
|
+
var Base64 = class _Base64 {
|
|
90
|
+
static _alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
91
|
+
static _pad = "=";
|
|
92
|
+
/* UTF-8 encode/decode helpers for ES2023-only environments */
|
|
93
|
+
static utf8Encode(str) {
|
|
94
|
+
const bytes = [];
|
|
95
|
+
for (const ch of str) {
|
|
96
|
+
const cp = ch.codePointAt(0);
|
|
97
|
+
if (cp <= 127) {
|
|
98
|
+
bytes.push(cp);
|
|
99
|
+
} else if (cp <= 2047) {
|
|
100
|
+
bytes.push(192 | cp >> 6, 128 | cp & 63);
|
|
101
|
+
} else if (cp <= 65535) {
|
|
102
|
+
bytes.push(
|
|
103
|
+
224 | cp >> 12,
|
|
104
|
+
128 | cp >> 6 & 63,
|
|
105
|
+
128 | cp & 63
|
|
106
|
+
);
|
|
107
|
+
} else {
|
|
108
|
+
bytes.push(
|
|
109
|
+
240 | cp >> 18,
|
|
110
|
+
128 | cp >> 12 & 63,
|
|
111
|
+
128 | cp >> 6 & 63,
|
|
112
|
+
128 | cp & 63
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return new Uint8Array(bytes);
|
|
117
|
+
}
|
|
118
|
+
static utf8Decode(bytes) {
|
|
119
|
+
let str = "";
|
|
120
|
+
for (let i = 0; i < bytes.length; ) {
|
|
121
|
+
const b1 = bytes[i++];
|
|
122
|
+
if (b1 < 128) {
|
|
123
|
+
str += String.fromCodePoint(b1);
|
|
124
|
+
} else if (b1 < 224) {
|
|
125
|
+
const b2 = bytes[i++];
|
|
126
|
+
str += String.fromCodePoint((b1 & 31) << 6 | b2 & 63);
|
|
127
|
+
} else if (b1 < 240) {
|
|
128
|
+
const b2 = bytes[i++], b3 = bytes[i++];
|
|
129
|
+
str += String.fromCodePoint(
|
|
130
|
+
(b1 & 15) << 12 | (b2 & 63) << 6 | b3 & 63
|
|
131
|
+
);
|
|
132
|
+
} else {
|
|
133
|
+
const b2 = bytes[i++], b3 = bytes[i++], b4 = bytes[i++];
|
|
134
|
+
str += String.fromCodePoint(
|
|
135
|
+
(b1 & 7) << 18 | (b2 & 63) << 12 | (b3 & 63) << 6 | b4 & 63
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return str;
|
|
140
|
+
}
|
|
141
|
+
/* ------------------------------------------------------------------ */
|
|
142
|
+
/* Low-level byte-wise codec */
|
|
143
|
+
/* ------------------------------------------------------------------ */
|
|
144
|
+
/** Encode raw bytes (Uint8Array) -> Base-64 text. */
|
|
145
|
+
static encodeBytes(bytes) {
|
|
146
|
+
let out = "";
|
|
147
|
+
let i = 0;
|
|
148
|
+
while (i < bytes.length) {
|
|
149
|
+
const b1 = bytes[i++] ?? NaN;
|
|
150
|
+
const b2 = bytes[i++] ?? NaN;
|
|
151
|
+
const b3 = bytes[i++] ?? NaN;
|
|
152
|
+
const enc1 = b1 >> 2;
|
|
153
|
+
const enc2 = (b1 & 3) << 4 | b2 >> 4;
|
|
154
|
+
const enc3 = isNaN(b2) ? 64 : (b2 & 15) << 2 | b3 >> 6;
|
|
155
|
+
const enc4 = isNaN(b3) ? 64 : b3 & 63;
|
|
156
|
+
out += _Base64._alphabet.charAt(enc1);
|
|
157
|
+
out += _Base64._alphabet.charAt(enc2);
|
|
158
|
+
out += enc3 === 64 ? _Base64._pad : _Base64._alphabet.charAt(enc3);
|
|
159
|
+
out += enc4 === 64 ? _Base64._pad : _Base64._alphabet.charAt(enc4);
|
|
160
|
+
}
|
|
161
|
+
return out;
|
|
162
|
+
}
|
|
163
|
+
/** Decode Base-64 text -> raw bytes (Uint8Array). */
|
|
164
|
+
static decodeToBytes(base64) {
|
|
165
|
+
base64 = base64.replace(/[^A-Za-z0-9+/=]/g, "");
|
|
166
|
+
const byteLen = base64.length / 4 * 3 - (base64.endsWith("==") ? 2 : base64.endsWith("=") ? 1 : 0);
|
|
167
|
+
const bytes = new Uint8Array(byteLen);
|
|
168
|
+
let byteIdx = 0, i = 0;
|
|
169
|
+
while (i < base64.length) {
|
|
170
|
+
const enc1 = _Base64._alphabet.indexOf(base64.charAt(i++));
|
|
171
|
+
const enc2 = _Base64._alphabet.indexOf(base64.charAt(i++));
|
|
172
|
+
const enc3 = _Base64._alphabet.indexOf(base64.charAt(i++));
|
|
173
|
+
const enc4 = _Base64._alphabet.indexOf(base64.charAt(i++));
|
|
174
|
+
const b1 = enc1 << 2 | enc2 >> 4;
|
|
175
|
+
const b2 = (enc2 & 15) << 4 | enc3 >> 2;
|
|
176
|
+
const b3 = (enc3 & 3) << 6 | enc4;
|
|
177
|
+
bytes[byteIdx++] = b1;
|
|
178
|
+
if (enc3 !== 64 && byteIdx < byteLen)
|
|
179
|
+
bytes[byteIdx++] = b2;
|
|
180
|
+
if (enc4 !== 64 && byteIdx < byteLen)
|
|
181
|
+
bytes[byteIdx++] = b3;
|
|
182
|
+
}
|
|
183
|
+
return bytes;
|
|
184
|
+
}
|
|
185
|
+
/* ------------------------------------------------------------------ */
|
|
186
|
+
/* Convenience wrappers for regular JS strings (UTF-8) */
|
|
187
|
+
/* ------------------------------------------------------------------ */
|
|
188
|
+
/** Encode a JS string to Base-64 using UTF-8. */
|
|
189
|
+
static encode(str) {
|
|
190
|
+
const bytes = _Base64.utf8Encode(str);
|
|
191
|
+
return _Base64.encodeBytes(bytes);
|
|
192
|
+
}
|
|
193
|
+
/** Decode Base-64 to a JS string using UTF-8. */
|
|
194
|
+
static decode(base64) {
|
|
195
|
+
const bytes = _Base64.decodeToBytes(base64);
|
|
196
|
+
return _Base64.utf8Decode(bytes);
|
|
197
|
+
}
|
|
198
|
+
/* ------------------------------------------------------------------ */
|
|
199
|
+
/* Helper factories */
|
|
200
|
+
/* ------------------------------------------------------------------ */
|
|
201
|
+
static createOutputStream() {
|
|
202
|
+
return new Base64OutputStream();
|
|
203
|
+
}
|
|
204
|
+
static createInputStream(encoded) {
|
|
205
|
+
return new Base64InputStream(encoded);
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
var Base64OutputStream = class {
|
|
209
|
+
_buf = [];
|
|
210
|
+
get length() {
|
|
211
|
+
return this._buf.length;
|
|
212
|
+
}
|
|
213
|
+
writeBytes(arr) {
|
|
214
|
+
for (let i = 0; i < arr.length; i++) {
|
|
215
|
+
this.writeByte(arr[i]);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/* ---------- range-checked primitives ---------- */
|
|
219
|
+
writeByte(v) {
|
|
220
|
+
if (!Number.isInteger(v) || v < 0 || v > 255)
|
|
221
|
+
throw new RangeError("byte 0-255");
|
|
222
|
+
this._buf.push(v);
|
|
223
|
+
}
|
|
224
|
+
writeShort(v) {
|
|
225
|
+
if (!Number.isInteger(v) || v < 0 || v > 65535)
|
|
226
|
+
throw new RangeError("short 0-65535");
|
|
227
|
+
this.writeByte(v >>> 8 & 255);
|
|
228
|
+
this.writeByte(v & 255);
|
|
229
|
+
}
|
|
230
|
+
writeInt(v) {
|
|
231
|
+
if (!Number.isInteger(v) || v < 0 || v > 4294967295)
|
|
232
|
+
throw new RangeError("int 0-4294967295");
|
|
233
|
+
this.writeByte(v >>> 24 & 255);
|
|
234
|
+
this.writeByte(v >>> 16 & 255);
|
|
235
|
+
this.writeByte(v >>> 8 & 255);
|
|
236
|
+
this.writeByte(v & 255);
|
|
237
|
+
}
|
|
238
|
+
/* ---------- IEEE-754 ---------- */
|
|
239
|
+
writeFloat(v) {
|
|
240
|
+
const dv = new DataView(new ArrayBuffer(4));
|
|
241
|
+
dv.setFloat32(0, v, false);
|
|
242
|
+
for (let i = 0; i < 4; i++)
|
|
243
|
+
this.writeByte(dv.getUint8(i));
|
|
244
|
+
}
|
|
245
|
+
writeDouble(v) {
|
|
246
|
+
const dv = new DataView(new ArrayBuffer(8));
|
|
247
|
+
dv.setFloat64(0, v, false);
|
|
248
|
+
for (let i = 0; i < 8; i++)
|
|
249
|
+
this.writeByte(dv.getUint8(i));
|
|
250
|
+
}
|
|
251
|
+
/* ---------- strings ---------- */
|
|
252
|
+
writeUTF(str) {
|
|
253
|
+
const bytes = Base64.utf8Encode(str);
|
|
254
|
+
this.writeShort(bytes.length);
|
|
255
|
+
for (const b of bytes)
|
|
256
|
+
this.writeByte(b);
|
|
257
|
+
}
|
|
258
|
+
/** Finalize & return Base-64. */
|
|
259
|
+
toString() {
|
|
260
|
+
return Base64.encodeBytes(Uint8Array.from(this._buf));
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
var Base64InputStream = class {
|
|
264
|
+
_bytes;
|
|
265
|
+
_pos = 0;
|
|
266
|
+
constructor(encoded) {
|
|
267
|
+
this._bytes = Base64.decodeToBytes(encoded);
|
|
268
|
+
}
|
|
269
|
+
_need(n) {
|
|
270
|
+
if (this._pos + n > this._bytes.length)
|
|
271
|
+
throw new RangeError("EOF");
|
|
272
|
+
}
|
|
273
|
+
readBytes(n) {
|
|
274
|
+
const arr = new Uint8Array(n);
|
|
275
|
+
for (let i = 0; i < n; i++) {
|
|
276
|
+
arr[i] = this.readByte();
|
|
277
|
+
}
|
|
278
|
+
return arr;
|
|
279
|
+
}
|
|
280
|
+
readByte() {
|
|
281
|
+
this._need(1);
|
|
282
|
+
return this._bytes[this._pos++];
|
|
283
|
+
}
|
|
284
|
+
readShort() {
|
|
285
|
+
return this.readByte() << 8 | this.readByte();
|
|
286
|
+
}
|
|
287
|
+
readInt() {
|
|
288
|
+
return this.readByte() << 24 | this.readByte() << 16 | this.readByte() << 8 | this.readByte();
|
|
289
|
+
}
|
|
290
|
+
readFloat() {
|
|
291
|
+
this._need(4);
|
|
292
|
+
const dv = new DataView(this._bytes.buffer, this._bytes.byteOffset + this._pos, 4);
|
|
293
|
+
const v = dv.getFloat32(0, false);
|
|
294
|
+
this._pos += 4;
|
|
295
|
+
return v;
|
|
296
|
+
}
|
|
297
|
+
readDouble() {
|
|
298
|
+
this._need(8);
|
|
299
|
+
const dv = new DataView(this._bytes.buffer, this._bytes.byteOffset + this._pos, 8);
|
|
300
|
+
const v = dv.getFloat64(0, false);
|
|
301
|
+
this._pos += 8;
|
|
302
|
+
return v;
|
|
303
|
+
}
|
|
304
|
+
readUTF() {
|
|
305
|
+
const len = this.readShort();
|
|
306
|
+
this._need(len);
|
|
307
|
+
const slice = this._bytes.subarray(this._pos, this._pos + len);
|
|
308
|
+
this._pos += len;
|
|
309
|
+
return Base64.utf8Decode(slice);
|
|
310
|
+
}
|
|
311
|
+
get remaining() {
|
|
312
|
+
return this._bytes.length - this._pos;
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
// src/v1/encoding/Base64PacketEncoder.ts
|
|
317
|
+
var Base64PacketEncoder = class {
|
|
318
|
+
// encoding name for Base64 transport
|
|
319
|
+
encoding = "b64";
|
|
320
|
+
encode(payload) {
|
|
321
|
+
const json = JSON.stringify(payload);
|
|
322
|
+
return Base64.encode(json);
|
|
323
|
+
}
|
|
324
|
+
encodeHeader(header) {
|
|
325
|
+
const { id, frag, last } = header;
|
|
326
|
+
const out = new Base64OutputStream();
|
|
327
|
+
out.writeBytes(uuidToBytes(id));
|
|
328
|
+
let flags = 0;
|
|
329
|
+
if (last !== void 0)
|
|
330
|
+
flags |= 1;
|
|
331
|
+
out.writeByte(flags);
|
|
332
|
+
if (flags & 1) {
|
|
333
|
+
out.writeShort(frag);
|
|
334
|
+
out.writeByte(last ? 1 : 0);
|
|
335
|
+
}
|
|
336
|
+
return out.toString();
|
|
337
|
+
}
|
|
338
|
+
decode(raw) {
|
|
339
|
+
try {
|
|
340
|
+
const json = Base64.decode(raw);
|
|
341
|
+
return JSON.parse(json);
|
|
342
|
+
} catch {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
decodeHeader(raw) {
|
|
347
|
+
try {
|
|
348
|
+
const inp = new Base64InputStream(raw);
|
|
349
|
+
const bytes = inp.readBytes(16);
|
|
350
|
+
const id = bytesToUuid(bytes);
|
|
351
|
+
const flags = inp.readByte();
|
|
352
|
+
const header = { id };
|
|
353
|
+
if (flags & 1) {
|
|
354
|
+
header.frag = inp.readShort();
|
|
355
|
+
header.last = inp.readByte() === 1;
|
|
356
|
+
}
|
|
357
|
+
return header;
|
|
358
|
+
} catch {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
// src/v1/net.ts
|
|
365
|
+
var Net = class _Net {
|
|
366
|
+
static listeners = /* @__PURE__ */ new Map();
|
|
367
|
+
static buffers = /* @__PURE__ */ new Map();
|
|
368
|
+
static encoders = /* @__PURE__ */ new Map();
|
|
369
|
+
static DefaultEncoding = "text";
|
|
370
|
+
/**
|
|
371
|
+
* Register a new encoder implementation by its unique name.
|
|
372
|
+
*/
|
|
373
|
+
static registerEncoder(encoder) {
|
|
374
|
+
this.encoders.set(encoder.encoding, encoder);
|
|
375
|
+
}
|
|
376
|
+
/** fire a script event, fragmenting JSON/text payload if needed. Optionally receive a response. */
|
|
377
|
+
static send(channel, payload, opts, callback) {
|
|
378
|
+
const encodingName = opts?.encoding ?? _Net.DefaultEncoding;
|
|
379
|
+
const encoder = _Net.encoders.get(encodingName);
|
|
380
|
+
if (!encoder)
|
|
381
|
+
throw new Error(`Unknown encoder: ${encodingName}`);
|
|
382
|
+
const raw = encoder.encode(payload);
|
|
383
|
+
const id = (opts?.id ?? makeUUID()).replace(/-/g, "");
|
|
384
|
+
if (callback) {
|
|
385
|
+
const respChannel = `ipcs:${id}`;
|
|
386
|
+
const wrapper = (respPayload) => {
|
|
387
|
+
try {
|
|
388
|
+
callback(respPayload);
|
|
389
|
+
} finally {
|
|
390
|
+
_Net.off(respChannel, wrapper);
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
_Net.on(respChannel, wrapper);
|
|
394
|
+
}
|
|
395
|
+
const totalLen = raw.length;
|
|
396
|
+
const metaPart = `${SPEC_VERSION}|${encodingName}`;
|
|
397
|
+
let chunks = [];
|
|
398
|
+
const meta = { version: SPEC_VERSION, encoding: encodingName };
|
|
399
|
+
const metaLength = getEnvelopeLength(meta);
|
|
400
|
+
const noFragHdr = encoder.encodeHeader({ id });
|
|
401
|
+
const noFragHdrLen = noFragHdr.length;
|
|
402
|
+
const noFragOverhead = metaPart.length + RS.length + ETX.length + noFragHdrLen;
|
|
403
|
+
if (totalLen + noFragOverhead + metaLength <= MAX_CHUNK) {
|
|
404
|
+
chunks = [[noFragHdr, raw]];
|
|
405
|
+
} else {
|
|
406
|
+
let i = 0;
|
|
407
|
+
let remaining = totalLen;
|
|
408
|
+
let written = 0;
|
|
409
|
+
while (remaining > 0) {
|
|
410
|
+
const hdr = encoder.encodeHeader({ id, frag: i, last: 0 });
|
|
411
|
+
const hdrLen = hdr.length;
|
|
412
|
+
const chunkSize = Math.min(MAX_CHUNK - hdrLen - metaLength, remaining);
|
|
413
|
+
chunks.push([hdr, raw.slice(written, written + chunkSize)]);
|
|
414
|
+
remaining -= chunkSize;
|
|
415
|
+
written += chunkSize;
|
|
416
|
+
i++;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (chunks.length === 1) {
|
|
420
|
+
const hdrString = chunks[0][0];
|
|
421
|
+
const envelope = buildEnvelope(meta, hdrString, chunks[0][1]);
|
|
422
|
+
system.sendScriptEvent(channel, envelope);
|
|
423
|
+
} else {
|
|
424
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
425
|
+
const encHdr = { id, frag: i, last: i === chunks.length - 1 };
|
|
426
|
+
const hdrString = encHdr.last ? encoder.encodeHeader(encHdr) : chunks[i][0];
|
|
427
|
+
const envelope = buildEnvelope(meta, hdrString, chunks[i][1]);
|
|
428
|
+
system.sendScriptEvent(channel, envelope);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
/** subscribe to reassembled messages on a channel */
|
|
433
|
+
static on(channel, cb) {
|
|
434
|
+
const arr = _Net.listeners.get(channel) ?? [];
|
|
435
|
+
arr.push(cb);
|
|
436
|
+
_Net.listeners.set(channel, arr);
|
|
437
|
+
}
|
|
438
|
+
/** unsubscribe a callback from a channel */
|
|
439
|
+
static off(channel, cb) {
|
|
440
|
+
const arr = this.listeners.get(channel);
|
|
441
|
+
if (!arr)
|
|
442
|
+
return;
|
|
443
|
+
const filtered = arr.filter((fn) => fn !== cb);
|
|
444
|
+
if (filtered.length)
|
|
445
|
+
this.listeners.set(channel, filtered);
|
|
446
|
+
else
|
|
447
|
+
this.listeners.delete(channel);
|
|
448
|
+
}
|
|
449
|
+
/** invoke all cbs registered on this channel, providing optional respond function */
|
|
450
|
+
static dispatch(channel, payload, id, encodingName) {
|
|
451
|
+
const arr = _Net.listeners.get(channel);
|
|
452
|
+
if (!arr)
|
|
453
|
+
return;
|
|
454
|
+
for (const cb of arr) {
|
|
455
|
+
try {
|
|
456
|
+
if (id && !channel.startsWith("ipcs:")) {
|
|
457
|
+
const respond = (responsePayload) => {
|
|
458
|
+
_Net.send(`ipcs:${id}`, responsePayload, { encoding: encodingName, id });
|
|
459
|
+
};
|
|
460
|
+
cb(payload, respond);
|
|
461
|
+
} else {
|
|
462
|
+
cb(payload);
|
|
463
|
+
}
|
|
464
|
+
} catch {
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/** internal dispatcher: parse envelope, reassemble if needed, then fire user-cb */
|
|
469
|
+
static handleScriptEvent(channel, raw) {
|
|
470
|
+
const [metaPart, rest] = raw.split(RS, 2);
|
|
471
|
+
if (!rest)
|
|
472
|
+
return;
|
|
473
|
+
const [encPart, body] = rest.split(ETX, 2);
|
|
474
|
+
if (body === void 0)
|
|
475
|
+
return;
|
|
476
|
+
const [verStr, encodingName] = metaPart.split("|");
|
|
477
|
+
if (parseInt(verStr, 10) !== SPEC_VERSION)
|
|
478
|
+
return;
|
|
479
|
+
const encoder = _Net.encoders.get(encodingName);
|
|
480
|
+
if (!encoder)
|
|
481
|
+
return;
|
|
482
|
+
const header = encoder.decodeHeader(encPart);
|
|
483
|
+
if (!header)
|
|
484
|
+
return;
|
|
485
|
+
const { id, frag, last } = header;
|
|
486
|
+
if (frag === void 0 || last === void 0) {
|
|
487
|
+
const payload = encoder.decode(body);
|
|
488
|
+
if (payload !== null)
|
|
489
|
+
_Net.dispatch(channel, payload, id, encodingName);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
let buf = _Net.buffers.get(id);
|
|
493
|
+
if (!buf) {
|
|
494
|
+
buf = { parts: [] };
|
|
495
|
+
_Net.buffers.set(id, buf);
|
|
496
|
+
}
|
|
497
|
+
if (frag !== void 0 && buf.parts[frag] === void 0) {
|
|
498
|
+
buf.parts[frag] = {
|
|
499
|
+
body,
|
|
500
|
+
frag: header.frag,
|
|
501
|
+
last: header.last
|
|
502
|
+
};
|
|
503
|
+
if (header.last) {
|
|
504
|
+
buf.lastIndex = frag;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
if (buf.lastIndex !== void 0 && buf.parts.length === buf.lastIndex + 1 && buf.parts.sort((a, b) => a.frag - b.frag)[buf.lastIndex].frag === buf.lastIndex) {
|
|
508
|
+
const full = buf.parts.map((p) => p.body).join("");
|
|
509
|
+
_Net.buffers.delete(id);
|
|
510
|
+
const payload = encoder.decode(full);
|
|
511
|
+
if (payload !== null)
|
|
512
|
+
_Net.dispatch(channel, payload, id, encodingName);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
Net.registerEncoder(new TextPacketEncoder());
|
|
517
|
+
Net.registerEncoder(new Base64PacketEncoder());
|
|
518
|
+
|
|
519
|
+
// src/index.ts
|
|
520
|
+
var version = 1;
|
|
521
|
+
var MaxVersion = 1;
|
|
522
|
+
var MinVersion = 1;
|
|
523
|
+
function setVersion(v) {
|
|
524
|
+
if (version < MinVersion || version > MaxVersion) {
|
|
525
|
+
throw new Error(`IPCS-BE spec version ${version} is not supported`);
|
|
526
|
+
}
|
|
527
|
+
version = v;
|
|
528
|
+
}
|
|
529
|
+
function send(channel, payload, opts, callback) {
|
|
530
|
+
if (version === 1) {
|
|
531
|
+
Net.send(channel, payload, opts, callback);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
function on(channel, cb) {
|
|
535
|
+
Net.on(channel, cb);
|
|
536
|
+
}
|
|
537
|
+
system2.afterEvents.scriptEventReceive.subscribe((evt) => {
|
|
538
|
+
Net.handleScriptEvent(evt.id, evt.message);
|
|
539
|
+
});
|
|
540
|
+
export {
|
|
541
|
+
on,
|
|
542
|
+
send,
|
|
543
|
+
setVersion
|
|
544
|
+
};
|
|
545
|
+
//# sourceMappingURL=index.mjs.map
|