UNPKG

@bitrix24/b24jssdk

Version:

Bitrix24 REST API JavaScript SDK

228 lines (225 loc) • 6.6 kB
/** * @package @bitrix24/b24jssdk * @version 3.0.0 * @copyright (c) 2026 Bitrix24 * @license MIT * @see https://github.com/bitrix24/b24jssdk * @see https://bitrix24.github.io/b24jssdk/ */ 'use strict'; var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); class WireError extends Error { static { __name(this, "WireError"); } name = "WireError"; } const WIRE_VARINT = 0; const WIRE_BYTES = 2; const WIRE_FIXED32 = 5; const WIRE_START_GROUP = 3; const WIRE_END_GROUP = 4; const MAX_GROUP_DEPTH = 64; function tag(fieldNumber, wireType) { return fieldNumber << 3 | wireType; } __name(tag, "tag"); class Writer { static { __name(this, "Writer"); } // A growing `Uint8Array`, not a `number[]`. The array version was measurably // superlinear: each of the four nesting levels copied its child byte by byte // through `push`, and `Uint8Array.from` then copied the lot again — 106 ms for // a 1000-message batch against protobuf.js's 3.4 ms, and 267 ms for a 2 MB // body. Irrelevant for the single-message batches this client usually sends, // and a main-thread stall for the ones it occasionally does. #buffer = new Uint8Array(64); #length = 0; get length() { return this.#length; } #reserve(extra) { const needed = this.#length + extra; if (needed <= this.#buffer.length) { return; } let size = this.#buffer.length * 2; while (size < needed) { size *= 2; } const grown = new Uint8Array(size); grown.set(this.#buffer.subarray(0, this.#length)); this.#buffer = grown; } #push(byte) { this.#reserve(1); this.#buffer[this.#length++] = byte; } varint(value) { let rest = value >>> 0; while (rest > 127) { this.#push(rest & 127 | 128); rest >>>= 7; } this.#push(rest); return this; } fixed32(value) { const v = value >>> 0; this.#reserve(4); this.#buffer[this.#length++] = v & 255; this.#buffer[this.#length++] = v >>> 8 & 255; this.#buffer[this.#length++] = v >>> 16 & 255; this.#buffer[this.#length++] = v >>> 24 & 255; return this; } bytes(value) { this.varint(value.length); this.#reserve(value.length); this.#buffer.set(value, this.#length); this.#length += value.length; return this; } string(value) { return this.bytes(new TextEncoder().encode(value)); } finish() { return this.#buffer.slice(0, this.#length); } } class Reader { static { __name(this, "Reader"); } #view; #pos = 0; constructor(view) { this.#view = view; } get done() { return this.#pos >= this.#view.length; } /** * A varint of up to ten bytes — protobuf's full legal width. * * The ceiling was 35 bits, which made this codec LESS forward-compatible than * the library it replaces: an unknown `uint64` field above 2^35 threw, and * because `extractProtobufMessages` swallows the throw, the whole frame was * dropped where protobuf.js would have skipped the field and carried on. The * symptom would have been "connected, no events". * * Above 2^53 the value is no longer exact. That is acceptable only because * every caller either masks it (`uint32`) or discards it (`skip`); nothing in * this schema is a 64-bit field. */ varint() { let result = 0; let shift = 0; for (; ; ) { if (this.done) { throw new WireError("pull protobuf: truncated varint"); } const byte = this.#view[this.#pos++]; result += (byte & 127) * 2 ** shift; if ((byte & 128) === 0) { return result; } shift += 7; if (shift >= 70) { throw new WireError("pull protobuf: varint longer than ten bytes"); } } } /** * A `uint32` field, truncated the way protobuf.js truncates it. * * Without the mask a wire value of 2^32 read back as 4294967296 where the * library gives 0 — the two codecs disagreeing on a well-formed frame. */ uint32() { return this.varint() >>> 0; } fixed32() { if (this.#pos + 4 > this.#view.length) { throw new WireError("pull protobuf: truncated fixed32"); } const v = this.#view[this.#pos] | this.#view[this.#pos + 1] << 8 | this.#view[this.#pos + 2] << 16 | this.#view[this.#pos + 3] << 24; this.#pos += 4; return v >>> 0; } bytes() { const length = this.varint(); if (this.#pos + length > this.#view.length) { throw new WireError("pull protobuf: length-delimited field runs past the end"); } const out = this.#view.subarray(this.#pos, this.#pos + length); this.#pos += length; return out; } string() { return new TextDecoder().decode(this.bytes()); } /** * Skip a field this codec does not model — the statistics branches, and * anything a future server adds. Unknown fields are ordinary protobuf, not an * error: the vendored library ignored them silently and so must this. * * The throws below are not "give up". `readFields` catches them and stops * reading that message, so a damaged tail costs the fields after it and * nothing else. Throwing is how this reader says "I cannot go further", not * how it reports a failure to its caller — and it is always a `WireError`, * which is the only thing `readFields` catches. */ skip(wireType, depth = 0) { switch (wireType) { case WIRE_VARINT: { this.varint(); break; } case WIRE_BYTES: { this.bytes(); break; } case WIRE_FIXED32: { this.fixed32(); break; } case 1: { if (this.#pos + 8 > this.#view.length) { throw new WireError("pull protobuf: truncated 64-bit field"); } this.#pos += 8; break; } case WIRE_START_GROUP: { this.#skipGroup(depth); break; } default: { throw new WireError(`pull protobuf: unsupported wire type ${wireType}`); } } } #skipGroup(depth) { if (depth >= MAX_GROUP_DEPTH) { throw new WireError("pull protobuf: groups nested too deeply"); } for (; ; ) { const wireType = this.varint() & 7; if (wireType === WIRE_END_GROUP) { return; } this.skip(wireType, depth + 1); } } } exports.Reader = Reader; exports.WIRE_BYTES = WIRE_BYTES; exports.WIRE_FIXED32 = WIRE_FIXED32; exports.WIRE_VARINT = WIRE_VARINT; exports.WireError = WireError; exports.Writer = Writer; exports.tag = tag; //# sourceMappingURL=wire.cjs.map