@xpgamesllc/ipcs-be 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +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"]}
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, world } from \"@minecraft/server\";\nimport NetV1, { SendOptions } from \"./v1/net\";\nimport { makeUUID } from \"./utils/uuid\";\n\nexport type { SendOptions };\n\nlet version = 1;\nconst MaxVersion = 1;\nconst MinVersion = 1;\n\nexport function setVersion(v: number) {\n if (v < MinVersion || v > MaxVersion) {\n throw new Error(`IPCS-BE spec version ${v} is not supported`);\n }\n version = v;\n}\n\n/**\n * Send a script event, fragmenting JSON/text payload if needed. Optionally receive a response.\n * @param channel - The script-event channel to send to.\n * @param payload - The payload to send.\n * @param opts - Optional encoding, message ID, and response timeout (`timeoutTicks`, `onTimeout`).\n * @param callback - Optional callback to receive a response. It is dropped after the timeout.\n */\nexport function send(\n channel: string,\n payload: any,\n opts?: SendOptions,\n callback?: (response: any) => void\n): string {\n if (version === 1) {\n return NetV1.send(channel, payload, {\n ...opts,\n // By default, use the most preferred encoding\n encoding: opts?.encoding ?? supportedEncodings[0],\n }, callback);\n }\n throw new Error(`IPCS-BE spec version ${version} is not supported`);\n}\n\n/**\n * Subscribe to reassembled messages on a channel.\n * @param channel - The script-event channel to subscribe to.\n * @param cb - The callback to invoke when a message is received.\n */\nexport function on(\n channel: string,\n cb: (id: string, payload: any, respond?: (resp: any) => void) => void\n): void {\n NetV1.on(channel, cb);\n}\n\n/**\n * Unsubscribe a callback registered with `on`.\n * @param channel - The script-event channel.\n * @param cb - The same callback that was passed to `on`.\n */\nexport function off(\n channel: string,\n cb: (id: string, payload: any, respond?: (resp: any) => void) => void\n): void {\n NetV1.off(channel, cb);\n}\n\n// Register the IPCS-BE script event handler\nNetV1.subscribe();\n\nlet initialized = false;\n\nexport interface InitData {\n /**\n * The pack name.\n */\n packName: string;\n /**\n * The pack author.\n */\n packAuthor: string;\n}\n\ninterface HelloPacket {\n v: number;\n name: string;\n author: string;\n enc: string[];\n encOpts?: Record<string, Record<string, any>>;\n}\n\nexport interface KnownPack {\n name: string;\n author: string;\n}\n\nconst KnownPacks: KnownPack[] = [];\n\n// Encodings supported by all packs ordered from most to least preferred\nlet supportedEncodings: string[] = [\"b64\", \"text\"];\n\n// Channel for the hello packet\nconst HelloChannel = \"ipcs:hello\";\n\nlet worldLoaded = false;\nlet initData: InitData | undefined;\nlet helloId = \"\";\n\nexport function init(data: InitData) {\n if (initialized) {\n throw new Error(\"IPCS-BE is already initialized\");\n }\n initData = data;\n helloId = makeUUID().replace(/-/g, \"\");\n initialized = true;\n // init can come from a before event, where sending is not allowed\n if (worldLoaded) system.run(sendHello);\n}\n\nfunction sendHello() {\n if (!initData) return;\n const packet: HelloPacket = {\n name: initData.packName,\n author: initData.packAuthor,\n // Adjusted according to the library\n v: version,\n enc: [\"text\", \"b64\"],\n };\n // Text is the encoding every pack can read, whatever it supports\n send(HelloChannel, packet, {\n id: helloId,\n encoding: \"text\"\n });\n}\n\nworld.afterEvents.worldLoad.subscribe(() => {\n worldLoaded = true;\n sendHello();\n});\n\non(HelloChannel, (id, payload) => {\n // Handle the hello packet\n if (id === helloId) {\n // Ignore self-sent hello packets\n return;\n }\n const helloPayload = payload as HelloPacket;\n if (helloPayload.v > MaxVersion || helloPayload.v < MinVersion) {\n warn(`Received hello packet with unsupported version ${helloPayload.v}`);\n return;\n }\n if (!helloPayload.name || !helloPayload.author) {\n warn(\"Received hello packet with missing name or author\");\n return;\n }\n if (\n !helloPayload.enc ||\n !Array.isArray(helloPayload.enc) ||\n helloPayload.enc.length === 0\n ) {\n warn(\"Received hello packet with missing or invalid encodings\");\n return;\n }\n // Filter out unsupported encodings\n for (const enc of [...supportedEncodings]) {\n // add exception for text encoding, as it is bare minimum\n if (enc === \"text\") continue;\n if (!helloPayload.enc.includes(enc)) {\n supportedEncodings = supportedEncodings.filter((e) => e !== enc);\n }\n }\n const known = KnownPacks.some((p) => p.name === helloPayload.name && p.author === helloPayload.author);\n if (!known) KnownPacks.push({ name: helloPayload.name, author: helloPayload.author });\n});\n\n/**\n * Get the currently known packs.\n */\nexport function getKnownPacks(): KnownPack[] {\n if (!initialized) {\n throw new Error(\"IPCS-BE is not initialized\");\n }\n return KnownPacks.map((p) => ({ ...p }));\n}\n\nfunction warn(message: string) {\n DEBUG: {\n console.warn(message);\n }\n}\n","import { ScriptEventCommandMessageAfterEvent, 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\nexport interface SendOptions {\r\n encoding?: string;\r\n /** message UUID: 32 hex digits, hyphens allowed, any case */\r\n id?: string;\r\n /** with a callback: stop waiting for the response after this many ticks (default Net.ResponseTimeoutTicks) */\r\n timeoutTicks?: number;\r\n /** with a callback: called once when no response came in time */\r\n onTimeout?: () => void;\r\n}\r\n\r\ninterface FragmentBuffer {\r\n parts: string[];\r\n received: number;\r\n lastIndex?: number;\r\n /** Date.now() of the last fragment */\r\n touched: number;\r\n}\r\n\r\nexport default class Net {\r\n private static listeners = new Map<string, ((id: 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 /** a partial message is dropped when no fragment arrived for this long */\r\n public static BufferTimeoutMs = 10_000;\r\n /** at most this many partial messages are kept; a new one drops the oldest */\r\n public static MaxBuffers = 64;\r\n /** fragment indices at or above this are refused */\r\n public static MaxFragments = 4096;\r\n /** how long send() waits for a response by default (20 ticks = 1 s) */\r\n public static ResponseTimeoutTicks = 200;\r\n /** the engine only passes script events of these namespaces to the script */\r\n private static namespaces = new Set<string>([\"ipcs\"]);\r\n private static handler?: (evt: ScriptEventCommandMessageAfterEvent) => void;\r\n\r\n /** (re)subscribe to script events with the current namespace filter; the old handler works until the new one is in */\r\n public static subscribe(retry = true) {\r\n const signal = system.afterEvents.scriptEventReceive;\r\n const handler = (evt: ScriptEventCommandMessageAfterEvent) => Net.handleScriptEvent(evt.id, evt.message);\r\n try {\r\n signal.subscribe(handler, { namespaces: [...Net.namespaces] });\r\n } catch (e) {\r\n // not allowed in restricted execution (before events), the next tick is fine\r\n if (retry) {\r\n system.run(() => Net.subscribe(false));\r\n return;\r\n }\r\n DEBUG: {\r\n console.warn(`IPCS-BE: could not subscribe to script events: ${e}`);\r\n }\r\n return;\r\n }\r\n if (Net.handler) signal.unsubscribe(Net.handler);\r\n Net.handler = handler;\r\n }\r\n\r\n private static watchNamespace(channel: string) {\r\n const namespace = channel.split(\":\")[0];\r\n if (Net.namespaces.has(namespace)) return;\r\n Net.namespaces.add(namespace);\r\n // before the first subscribe the new namespace is simply part of it\r\n if (Net.handler) Net.subscribe();\r\n }\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?: SendOptions, callback?: (response: any) => void): string {\r\n // b64 carries the id as bytes, so the receiver sees it lowercase\r\n const id = (opts?.id ?? makeUUID()).replace(/-/g, \"\").toLowerCase();\r\n if (!/^[0-9a-f]{32}$/.test(id)) throw new Error(`Invalid message id \"${opts?.id}\": expected a UUID`);\r\n return Net.sendWithId(channel, payload, id, opts, callback);\r\n }\r\n\r\n /** responses reuse the request id as it came, older versions did not check it */\r\n private static sendWithId(channel: string, payload: any, id: string, opts?: SendOptions, callback?: (response: any) => void): string {\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 // subscribe one-time response listener if callback provided\r\n if (callback) {\r\n const respChannel = `ipcs:${id}`;\r\n const wrapper = (id: string, respPayload: any) => {\r\n system.clearRun(timer);\r\n Net.off(respChannel, wrapper as any);\r\n callback(respPayload);\r\n };\r\n Net.on(respChannel, wrapper as any);\r\n const timer = system.runTimeout(() => {\r\n Net.off(respChannel, wrapper as any);\r\n opts?.onTimeout?.();\r\n }, opts?.timeoutTicks ?? Net.ResponseTimeoutTicks);\r\n }\r\n const totalLen = raw.length;\r\n // compute overhead and fragment size to not exceed MAX_CHUNK per envelope\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 if (totalLen + noFragHdr.length + 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 return id;\r\n }\r\n\r\n /** subscribe to reassembled messages on a channel */\r\n public static on(channel: string, cb: (id: string, 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 Net.watchNamespace(channel);\r\n }\r\n\r\n /** unsubscribe a callback from a channel */\r\n public static off(channel: string, cb: (id: string, 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.sendWithId(`ipcs:${id}`, responsePayload, id, { encoding: encodingName });\r\n };\r\n cb(id, payload, respond);\r\n } else if (id) {\r\n cb(id, payload);\r\n } else {\r\n throw new Error(`No ID provided for channel ${channel}`);\r\n }\r\n } catch (e) {\r\n DEBUG: {\r\n console.warn(`IPCS-BE: listener on ${channel} threw: ${e}`);\r\n }\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 // every pack gets every script event, most of them are not for us\r\n if (!Net.listeners.has(channel)) return;\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 (in any order)\r\n if (!Number.isInteger(frag) || frag < 0 || frag >= Net.MaxFragments) return;\r\n const now = Date.now();\r\n Net.dropStale(now);\r\n // a request and its response share the id, so the channel is part of the key\r\n const key = `${channel}|${id}`;\r\n let buf = Net.buffers.get(key);\r\n if (!buf) {\r\n if (Net.buffers.size >= Net.MaxBuffers) Net.dropOldest();\r\n buf = { parts: [], received: 0, touched: now };\r\n Net.buffers.set(key, buf);\r\n }\r\n buf.touched = now;\r\n if (buf.parts[frag] === undefined) {\r\n buf.parts[frag] = body;\r\n buf.received++;\r\n if (last) buf.lastIndex = frag;\r\n }\r\n if (buf.lastIndex !== undefined && buf.received === buf.lastIndex + 1) {\r\n const full = buf.parts.join(\"\");\r\n Net.buffers.delete(key);\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 /** drop partial messages that got no fragment for BufferTimeoutMs */\r\n private static dropStale(now: number) {\r\n for (const [key, buf] of Net.buffers) {\r\n if (now - buf.touched > Net.BufferTimeoutMs) Net.buffers.delete(key);\r\n }\r\n }\r\n\r\n private static dropOldest() {\r\n let oldestKey: string | undefined;\r\n let oldest = Infinity;\r\n for (const [key, buf] of Net.buffers) {\r\n if (buf.touched < oldest) {\r\n oldest = buf.touched;\r\n oldestKey = key;\r\n }\r\n }\r\n if (oldestKey !== undefined) Net.buffers.delete(oldestKey);\r\n }\r\n\r\n /** number of partial messages waiting for fragments */\r\n public static pendingCount(): number {\r\n return Net.buffers.size;\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","id"]}
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { system as system2 } from "@minecraft/server";
2
+ import { system as system2, world } from "@minecraft/server";
3
3
 
4
4
  // src/v1/net.ts
5
5
  import { system } from "@minecraft/server";
@@ -367,6 +367,45 @@ var Net = class _Net {
367
367
  static buffers = /* @__PURE__ */ new Map();
368
368
  static encoders = /* @__PURE__ */ new Map();
369
369
  static DefaultEncoding = "text";
370
+ /** a partial message is dropped when no fragment arrived for this long */
371
+ static BufferTimeoutMs = 1e4;
372
+ /** at most this many partial messages are kept; a new one drops the oldest */
373
+ static MaxBuffers = 64;
374
+ /** fragment indices at or above this are refused */
375
+ static MaxFragments = 4096;
376
+ /** how long send() waits for a response by default (20 ticks = 1 s) */
377
+ static ResponseTimeoutTicks = 200;
378
+ /** the engine only passes script events of these namespaces to the script */
379
+ static namespaces = /* @__PURE__ */ new Set(["ipcs"]);
380
+ static handler;
381
+ /** (re)subscribe to script events with the current namespace filter; the old handler works until the new one is in */
382
+ static subscribe(retry = true) {
383
+ const signal = system.afterEvents.scriptEventReceive;
384
+ const handler = (evt) => _Net.handleScriptEvent(evt.id, evt.message);
385
+ try {
386
+ signal.subscribe(handler, { namespaces: [..._Net.namespaces] });
387
+ } catch (e) {
388
+ if (retry) {
389
+ system.run(() => _Net.subscribe(false));
390
+ return;
391
+ }
392
+ DEBUG: {
393
+ console.warn(`IPCS-BE: could not subscribe to script events: ${e}`);
394
+ }
395
+ return;
396
+ }
397
+ if (_Net.handler)
398
+ signal.unsubscribe(_Net.handler);
399
+ _Net.handler = handler;
400
+ }
401
+ static watchNamespace(channel) {
402
+ const namespace = channel.split(":")[0];
403
+ if (_Net.namespaces.has(namespace))
404
+ return;
405
+ _Net.namespaces.add(namespace);
406
+ if (_Net.handler)
407
+ _Net.subscribe();
408
+ }
370
409
  /**
371
410
  * Register a new encoder implementation by its unique name.
372
411
  */
@@ -375,32 +414,37 @@ var Net = class _Net {
375
414
  }
376
415
  /** fire a script event, fragmenting JSON/text payload if needed. Optionally receive a response. */
377
416
  static send(channel, payload, opts, callback) {
417
+ const id = (opts?.id ?? makeUUID()).replace(/-/g, "").toLowerCase();
418
+ if (!/^[0-9a-f]{32}$/.test(id))
419
+ throw new Error(`Invalid message id "${opts?.id}": expected a UUID`);
420
+ return _Net.sendWithId(channel, payload, id, opts, callback);
421
+ }
422
+ /** responses reuse the request id as it came, older versions did not check it */
423
+ static sendWithId(channel, payload, id, opts, callback) {
378
424
  const encodingName = opts?.encoding ?? _Net.DefaultEncoding;
379
425
  const encoder = _Net.encoders.get(encodingName);
380
426
  if (!encoder)
381
427
  throw new Error(`Unknown encoder: ${encodingName}`);
382
428
  const raw = encoder.encode(payload);
383
- const id = (opts?.id ?? makeUUID()).replace(/-/g, "");
384
429
  if (callback) {
385
430
  const respChannel = `ipcs:${id}`;
386
- const wrapper = (respPayload) => {
387
- try {
388
- callback(respPayload);
389
- } finally {
390
- _Net.off(respChannel, wrapper);
391
- }
431
+ const wrapper = (id2, respPayload) => {
432
+ system.clearRun(timer);
433
+ _Net.off(respChannel, wrapper);
434
+ callback(respPayload);
392
435
  };
393
436
  _Net.on(respChannel, wrapper);
437
+ const timer = system.runTimeout(() => {
438
+ _Net.off(respChannel, wrapper);
439
+ opts?.onTimeout?.();
440
+ }, opts?.timeoutTicks ?? _Net.ResponseTimeoutTicks);
394
441
  }
395
442
  const totalLen = raw.length;
396
- const metaPart = `${SPEC_VERSION}|${encodingName}`;
397
443
  let chunks = [];
398
444
  const meta = { version: SPEC_VERSION, encoding: encodingName };
399
445
  const metaLength = getEnvelopeLength(meta);
400
446
  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) {
447
+ if (totalLen + noFragHdr.length + metaLength <= MAX_CHUNK) {
404
448
  chunks = [[noFragHdr, raw]];
405
449
  } else {
406
450
  let i = 0;
@@ -428,12 +472,14 @@ var Net = class _Net {
428
472
  system.sendScriptEvent(channel, envelope);
429
473
  }
430
474
  }
475
+ return id;
431
476
  }
432
477
  /** subscribe to reassembled messages on a channel */
433
478
  static on(channel, cb) {
434
479
  const arr = _Net.listeners.get(channel) ?? [];
435
480
  arr.push(cb);
436
481
  _Net.listeners.set(channel, arr);
482
+ _Net.watchNamespace(channel);
437
483
  }
438
484
  /** unsubscribe a callback from a channel */
439
485
  static off(channel, cb) {
@@ -455,18 +501,25 @@ var Net = class _Net {
455
501
  try {
456
502
  if (id && !channel.startsWith("ipcs:")) {
457
503
  const respond = (responsePayload) => {
458
- _Net.send(`ipcs:${id}`, responsePayload, { encoding: encodingName, id });
504
+ _Net.sendWithId(`ipcs:${id}`, responsePayload, id, { encoding: encodingName });
459
505
  };
460
- cb(payload, respond);
506
+ cb(id, payload, respond);
507
+ } else if (id) {
508
+ cb(id, payload);
461
509
  } else {
462
- cb(payload);
510
+ throw new Error(`No ID provided for channel ${channel}`);
511
+ }
512
+ } catch (e) {
513
+ DEBUG: {
514
+ console.warn(`IPCS-BE: listener on ${channel} threw: ${e}`);
463
515
  }
464
- } catch {
465
516
  }
466
517
  }
467
518
  }
468
519
  /** internal dispatcher: parse envelope, reassemble if needed, then fire user-cb */
469
520
  static handleScriptEvent(channel, raw) {
521
+ if (!_Net.listeners.has(channel))
522
+ return;
470
523
  const [metaPart, rest] = raw.split(RS, 2);
471
524
  if (!rest)
472
525
  return;
@@ -489,29 +542,56 @@ var Net = class _Net {
489
542
  _Net.dispatch(channel, payload, id, encodingName);
490
543
  return;
491
544
  }
492
- let buf = _Net.buffers.get(id);
545
+ if (!Number.isInteger(frag) || frag < 0 || frag >= _Net.MaxFragments)
546
+ return;
547
+ const now = Date.now();
548
+ _Net.dropStale(now);
549
+ const key = `${channel}|${id}`;
550
+ let buf = _Net.buffers.get(key);
493
551
  if (!buf) {
494
- buf = { parts: [] };
495
- _Net.buffers.set(id, buf);
552
+ if (_Net.buffers.size >= _Net.MaxBuffers)
553
+ _Net.dropOldest();
554
+ buf = { parts: [], received: 0, touched: now };
555
+ _Net.buffers.set(key, buf);
496
556
  }
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) {
557
+ buf.touched = now;
558
+ if (buf.parts[frag] === void 0) {
559
+ buf.parts[frag] = body;
560
+ buf.received++;
561
+ if (last)
504
562
  buf.lastIndex = frag;
505
- }
506
563
  }
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);
564
+ if (buf.lastIndex !== void 0 && buf.received === buf.lastIndex + 1) {
565
+ const full = buf.parts.join("");
566
+ _Net.buffers.delete(key);
510
567
  const payload = encoder.decode(full);
511
568
  if (payload !== null)
512
569
  _Net.dispatch(channel, payload, id, encodingName);
513
570
  }
514
571
  }
572
+ /** drop partial messages that got no fragment for BufferTimeoutMs */
573
+ static dropStale(now) {
574
+ for (const [key, buf] of _Net.buffers) {
575
+ if (now - buf.touched > _Net.BufferTimeoutMs)
576
+ _Net.buffers.delete(key);
577
+ }
578
+ }
579
+ static dropOldest() {
580
+ let oldestKey;
581
+ let oldest = Infinity;
582
+ for (const [key, buf] of _Net.buffers) {
583
+ if (buf.touched < oldest) {
584
+ oldest = buf.touched;
585
+ oldestKey = key;
586
+ }
587
+ }
588
+ if (oldestKey !== void 0)
589
+ _Net.buffers.delete(oldestKey);
590
+ }
591
+ /** number of partial messages waiting for fragments */
592
+ static pendingCount() {
593
+ return _Net.buffers.size;
594
+ }
515
595
  };
516
596
  Net.registerEncoder(new TextPacketEncoder());
517
597
  Net.registerEncoder(new Base64PacketEncoder());
@@ -521,23 +601,107 @@ var version = 1;
521
601
  var MaxVersion = 1;
522
602
  var MinVersion = 1;
523
603
  function setVersion(v) {
524
- if (version < MinVersion || version > MaxVersion) {
525
- throw new Error(`IPCS-BE spec version ${version} is not supported`);
604
+ if (v < MinVersion || v > MaxVersion) {
605
+ throw new Error(`IPCS-BE spec version ${v} is not supported`);
526
606
  }
527
607
  version = v;
528
608
  }
529
609
  function send(channel, payload, opts, callback) {
530
610
  if (version === 1) {
531
- Net.send(channel, payload, opts, callback);
611
+ return Net.send(channel, payload, {
612
+ ...opts,
613
+ // By default, use the most preferred encoding
614
+ encoding: opts?.encoding ?? supportedEncodings[0]
615
+ }, callback);
532
616
  }
617
+ throw new Error(`IPCS-BE spec version ${version} is not supported`);
533
618
  }
534
619
  function on(channel, cb) {
535
620
  Net.on(channel, cb);
536
621
  }
537
- system2.afterEvents.scriptEventReceive.subscribe((evt) => {
538
- Net.handleScriptEvent(evt.id, evt.message);
622
+ function off(channel, cb) {
623
+ Net.off(channel, cb);
624
+ }
625
+ Net.subscribe();
626
+ var initialized = false;
627
+ var KnownPacks = [];
628
+ var supportedEncodings = ["b64", "text"];
629
+ var HelloChannel = "ipcs:hello";
630
+ var worldLoaded = false;
631
+ var initData;
632
+ var helloId = "";
633
+ function init(data) {
634
+ if (initialized) {
635
+ throw new Error("IPCS-BE is already initialized");
636
+ }
637
+ initData = data;
638
+ helloId = makeUUID().replace(/-/g, "");
639
+ initialized = true;
640
+ if (worldLoaded)
641
+ system2.run(sendHello);
642
+ }
643
+ function sendHello() {
644
+ if (!initData)
645
+ return;
646
+ const packet = {
647
+ name: initData.packName,
648
+ author: initData.packAuthor,
649
+ // Adjusted according to the library
650
+ v: version,
651
+ enc: ["text", "b64"]
652
+ };
653
+ send(HelloChannel, packet, {
654
+ id: helloId,
655
+ encoding: "text"
656
+ });
657
+ }
658
+ world.afterEvents.worldLoad.subscribe(() => {
659
+ worldLoaded = true;
660
+ sendHello();
661
+ });
662
+ on(HelloChannel, (id, payload) => {
663
+ if (id === helloId) {
664
+ return;
665
+ }
666
+ const helloPayload = payload;
667
+ if (helloPayload.v > MaxVersion || helloPayload.v < MinVersion) {
668
+ warn(`Received hello packet with unsupported version ${helloPayload.v}`);
669
+ return;
670
+ }
671
+ if (!helloPayload.name || !helloPayload.author) {
672
+ warn("Received hello packet with missing name or author");
673
+ return;
674
+ }
675
+ if (!helloPayload.enc || !Array.isArray(helloPayload.enc) || helloPayload.enc.length === 0) {
676
+ warn("Received hello packet with missing or invalid encodings");
677
+ return;
678
+ }
679
+ for (const enc of [...supportedEncodings]) {
680
+ if (enc === "text")
681
+ continue;
682
+ if (!helloPayload.enc.includes(enc)) {
683
+ supportedEncodings = supportedEncodings.filter((e) => e !== enc);
684
+ }
685
+ }
686
+ const known = KnownPacks.some((p) => p.name === helloPayload.name && p.author === helloPayload.author);
687
+ if (!known)
688
+ KnownPacks.push({ name: helloPayload.name, author: helloPayload.author });
539
689
  });
690
+ function getKnownPacks() {
691
+ if (!initialized) {
692
+ throw new Error("IPCS-BE is not initialized");
693
+ }
694
+ return KnownPacks.map((p) => ({ ...p }));
695
+ }
696
+ function warn(message) {
697
+ DEBUG: {
698
+ console.warn(message);
699
+ }
700
+ }
540
701
  export {
702
+ getKnownPacks,
703
+ init,
704
+ off,
541
705
  on,
542
706
  send,
543
707
  setVersion