@rebon/cli-win32-x64 1.2.0 → 1.4.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.
Files changed (98) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +10 -0
  3. package/README.md +203 -144
  4. package/THIRD_PARTY_NOTICES.txt +1232 -128
  5. package/bin/rebon.js +22 -22
  6. package/lib/windows-managed.js +390 -390
  7. package/package.json +9 -2
  8. package/payload/compose-runtime/package.json +17 -17
  9. package/payload/compose-runtime/payload/compose/shims/dsh-anonymous-user-id.js +10 -10
  10. package/payload/compose-runtime/payload/compose/shims/dsh-credentials.js +13 -13
  11. package/payload/compose-runtime/payload/compose/shims/dsh-launch-environment.js +21 -21
  12. package/payload/compose-runtime/payload/compose/shims/dsh-llm.js +313 -313
  13. package/payload/compose-runtime/payload/compose/shims/dsh-settings.js +43 -43
  14. package/payload/compose-runtime/payload/compose/shims/dsh-tools.js +20 -20
  15. package/payload/compose-runtime/payload/compose/shims/dsh-web.js +10 -10
  16. package/payload/compose-runtime/payload/compose/shims/llm-adapter.js +32 -32
  17. package/payload/compose-runtime/payload/compose/shims/zod-lite.js +49 -49
  18. package/payload/compose-runtime/payload/vendor/cordis/LICENSE +21 -0
  19. package/payload/compose-runtime/payload/vendor/cordis/index.js +1530 -1530
  20. package/payload/compose-runtime/payload/vendor/cosmokit/LICENSE +21 -21
  21. package/payload/compose-runtime/payload/vendor/cosmokit/index.mjs +357 -357
  22. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-agent +21 -21
  23. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-agent-loop +21 -21
  24. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-llm-core +21 -21
  25. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-llm-deepseek +21 -21
  26. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-logger-console +21 -21
  27. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-scope +21 -21
  28. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-session +21 -21
  29. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-system-prompt +21 -21
  30. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-timeout +21 -21
  31. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-timer +21 -21
  32. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-tool-todo +21 -21
  33. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-tool-web +21 -21
  34. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-tools-schema +21 -21
  35. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-turndown +21 -0
  36. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-turndown-plugin-gfm +21 -0
  37. package/payload/compose-runtime/payload/vendor/dsh/LICENSE-web-search-exa +21 -21
  38. package/payload/compose-runtime/payload/vendor/dsh/agent-loop.js +1193 -1193
  39. package/payload/compose-runtime/payload/vendor/dsh/agent.js +714 -714
  40. package/payload/compose-runtime/payload/vendor/dsh/llm-core.js +269 -269
  41. package/payload/compose-runtime/payload/vendor/dsh/llm-deepseek.js +672 -672
  42. package/payload/compose-runtime/payload/vendor/dsh/logger-console.js +83 -83
  43. package/payload/compose-runtime/payload/vendor/dsh/scope.js +287 -287
  44. package/payload/compose-runtime/payload/vendor/dsh/session.js +1668 -1668
  45. package/payload/compose-runtime/payload/vendor/dsh/system-prompt.js +309 -309
  46. package/payload/compose-runtime/payload/vendor/dsh/timeout.js +100 -100
  47. package/payload/compose-runtime/payload/vendor/dsh/timer.js +128 -128
  48. package/payload/compose-runtime/payload/vendor/dsh/tool-todo.js +143 -143
  49. package/payload/compose-runtime/payload/vendor/dsh/tool-web.js +1527 -1527
  50. package/payload/compose-runtime/payload/vendor/dsh/tools-schema.js +849 -849
  51. package/payload/compose-runtime/payload/vendor/dsh/web-search-exa.js +122 -122
  52. package/payload/compose-runtime/payload/vendor/eventsource-parser/LICENSE +21 -21
  53. package/payload/compose-runtime/payload/vendor/eventsource-parser/index.js +177 -177
  54. package/payload/compose-runtime/payload/vendor/eventsource-parser/stream.js +48 -48
  55. package/payload/compose-runtime/payload/vendor/schemastery/LICENSE +21 -0
  56. package/payload/compose-runtime/payload/vendor/schemastery/index.mjs +656 -656
  57. package/payload/compose-runtime/payload-manifests.json +48 -48
  58. package/payload/compose-runtime/src/bridge.mjs +193 -195
  59. package/payload/compose-runtime/src/credentials-runtime.mjs +50 -50
  60. package/payload/compose-runtime/src/eventsource-stream.mjs +48 -48
  61. package/payload/compose-runtime/src/index.mjs +7 -7
  62. package/payload/compose-runtime/src/llm-runtime.mjs +326 -326
  63. package/payload/compose-runtime/src/loader.mjs +78 -78
  64. package/payload/compose-runtime/src/loop-assembly.mjs +237 -237
  65. package/payload/compose-runtime/src/payload.mjs +49 -49
  66. package/payload/compose-runtime/src/plugin.mjs +59 -59
  67. package/payload/compose-runtime/src/realm.mjs +223 -223
  68. package/payload/compose-runtime/src/registry.mjs +191 -191
  69. package/payload/compose-runtime/src/resolve.mjs +115 -115
  70. package/payload/compose-runtime/src/systemprompt-runtime.mjs +67 -67
  71. package/payload/compose-runtime/src/tools-runtime.mjs +239 -239
  72. package/payload/compose-runtime/src/web-runtime.mjs +209 -209
  73. package/payload/plugin-host/package.json +11 -11
  74. package/payload/plugin-host/src/bridge.mjs +64 -64
  75. package/payload/plugin-host/src/cli.mjs +147 -147
  76. package/payload/plugin-host/src/framing.mjs +113 -113
  77. package/payload/plugin-host/src/host.mjs +691 -691
  78. package/payload/plugin-host/src/json.mjs +208 -208
  79. package/payload/plugin-host/src/lifecycle.mjs +114 -114
  80. package/payload/plugin-host/src/loader.mjs +183 -183
  81. package/payload/plugin-host/src/methods.mjs +377 -377
  82. package/payload/plugin-host/src/ownership.mjs +57 -57
  83. package/payload/plugin-host/src/protocol.mjs +129 -129
  84. package/payload/plugin-host/src/sdk.mjs +7 -7
  85. package/payload/rebon-boa-helper.exe +0 -0
  86. package/payload/rebon-browser-mcp.exe +0 -0
  87. package/payload/rebon-computer-use.exe +0 -0
  88. package/payload/rebon-lsp-mcp.exe +0 -0
  89. package/payload/rebon.exe +2 -2
  90. package/payload/sandbox-win.exe +0 -0
  91. package/scripts/postinstall.js +112 -112
  92. package/payload/compose-runtime/payload/compose/credentials-runtime.js +0 -38
  93. package/payload/compose-runtime/payload/compose/llm-runtime.js +0 -330
  94. package/payload/compose-runtime/payload/compose/loop-assembly.js +0 -149
  95. package/payload/compose-runtime/payload/compose/serve-dispatch.js +0 -82
  96. package/payload/compose-runtime/payload/compose/systemprompt-runtime.js +0 -74
  97. package/payload/compose-runtime/payload/compose/tools-runtime.js +0 -228
  98. package/payload/compose-runtime/payload/compose/web-runtime.js +0 -204
@@ -1,208 +1,208 @@
1
- import { ProtocolError, RawJsonNumber, validateEnvelope } from './protocol.mjs';
2
-
3
- class RawNumber {
4
- constructor(raw) { this.raw = raw; Object.freeze(this); }
5
- }
6
-
7
- class JsonParser {
8
- constructor(text) { this.text = text; this.index = 0; }
9
- parse() {
10
- this.#space();
11
- const value = this.#value('envelope');
12
- this.#space();
13
- if (this.index !== this.text.length) this.#error('trailing_json', 'trailing data after JSON value');
14
- return value;
15
- }
16
- #value(role = 'value') {
17
- const c = this.text[this.index];
18
- if (c === '{') return this.#object(role);
19
- if (c === '[') return this.#array();
20
- if (c === '"') return this.#string();
21
- if (c === 't') return this.#literal('true', true);
22
- if (c === 'f') return this.#literal('false', false);
23
- if (c === 'n') return this.#literal('null', null);
24
- if (c === '-' || (c >= '0' && c <= '9')) return this.#number();
25
- this.#error('malformed_json', 'expected a JSON value');
26
- }
27
- #object(role) {
28
- this.index++;
29
- const object = Object.create(null);
30
- const keys = new Set();
31
- this.#space();
32
- if (this.text[this.index] === '}') { this.index++; return object; }
33
- for (;;) {
34
- if (this.text[this.index] !== '"') this.#error('malformed_json', 'object key must be a string');
35
- const key = this.#string();
36
- this.#space();
37
- if (this.text[this.index++] !== ':') this.#error('malformed_json', 'expected colon after object key');
38
- this.#space();
39
- const childRole = role === 'envelope' && key === 'message' ? 'message' : 'value';
40
- const value = this.#value(childRole);
41
- if ((role === 'envelope' || role === 'message') && keys.has(key)) {
42
- this.#error('duplicate_field', `duplicate field in ${role}`);
43
- }
44
- keys.add(key);
45
- object[key] = value; // serde_json::Value uses the last value for opaque object duplicates.
46
- this.#space();
47
- const delimiter = this.text[this.index++];
48
- if (delimiter === '}') return object;
49
- if (delimiter !== ',') this.#error('malformed_json', 'expected comma or object end');
50
- this.#space();
51
- }
52
- }
53
- #array() {
54
- this.index++;
55
- const array = [];
56
- this.#space();
57
- if (this.text[this.index] === ']') { this.index++; return array; }
58
- for (;;) {
59
- array.push(this.#value());
60
- this.#space();
61
- const delimiter = this.text[this.index++];
62
- if (delimiter === ']') return array;
63
- if (delimiter !== ',') this.#error('malformed_json', 'expected comma or array end');
64
- this.#space();
65
- }
66
- }
67
- #string() {
68
- this.index++;
69
- let result = '';
70
- for (;;) {
71
- if (this.index >= this.text.length) this.#error('malformed_json', 'unterminated JSON string');
72
- const c = this.text[this.index++];
73
- if (c === '"') return result;
74
- if (c === '\\') {
75
- if (this.index >= this.text.length) this.#error('malformed_json', 'unterminated JSON escape');
76
- const escape = this.text[this.index++];
77
- const simple = { '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t' }[escape];
78
- if (simple !== undefined) { result += simple; continue; }
79
- if (escape !== 'u') this.#error('malformed_json', 'invalid JSON escape');
80
- const first = this.#hexUnit();
81
- if (first >= 0xd800 && first <= 0xdbff) {
82
- if (this.text.slice(this.index, this.index + 2) !== '\\u') this.#error('invalid_surrogate', 'lone high surrogate in JSON string');
83
- this.index += 2;
84
- const second = this.#hexUnit();
85
- if (second < 0xdc00 || second > 0xdfff) this.#error('invalid_surrogate', 'invalid surrogate pair in JSON string');
86
- result += String.fromCodePoint(0x10000 + ((first - 0xd800) << 10) + second - 0xdc00);
87
- } else if (first >= 0xdc00 && first <= 0xdfff) {
88
- this.#error('invalid_surrogate', 'lone low surrogate in JSON string');
89
- } else result += String.fromCharCode(first);
90
- continue;
91
- }
92
- const unit = c.charCodeAt(0);
93
- if (unit < 0x20) this.#error('malformed_json', 'unescaped control character in JSON string');
94
- // The text is UTF-16, so a raw character outside the BMP (an emoji, as
95
- // serde_json writes it unescaped) is two units here: a high surrogate
96
- // followed by a low one. Only a half without its partner is invalid.
97
- if (unit >= 0xd800 && unit <= 0xdbff) {
98
- const next = this.text.charCodeAt(this.index);
99
- if (next >= 0xdc00 && next <= 0xdfff) {
100
- result += c + this.text[this.index++];
101
- continue;
102
- }
103
- this.#error('invalid_surrogate', 'lone surrogate in JSON string');
104
- }
105
- if (unit >= 0xdc00 && unit <= 0xdfff) this.#error('invalid_surrogate', 'lone surrogate in JSON string');
106
- result += c;
107
- }
108
- }
109
- #hexUnit() {
110
- const token = this.text.slice(this.index, this.index + 4);
111
- if (!/^[0-9a-fA-F]{4}$/.test(token)) this.#error('malformed_json', 'invalid unicode escape');
112
- this.index += 4;
113
- return Number.parseInt(token, 16);
114
- }
115
- #number() {
116
- const start = this.index;
117
- if (this.text[this.index] === '-') this.index++;
118
- if (this.text[this.index] === '0') this.index++;
119
- else {
120
- if (this.text[this.index] < '1' || this.text[this.index] > '9') this.#error('malformed_json', 'invalid JSON number');
121
- while (this.text[this.index] >= '0' && this.text[this.index] <= '9') this.index++;
122
- }
123
- if (this.text[this.index] === '.') {
124
- this.index++;
125
- const fraction = this.index;
126
- while (this.text[this.index] >= '0' && this.text[this.index] <= '9') this.index++;
127
- if (fraction === this.index) this.#error('malformed_json', 'fraction requires digits');
128
- }
129
- if (this.text[this.index] === 'e' || this.text[this.index] === 'E') {
130
- this.index++;
131
- if (this.text[this.index] === '+' || this.text[this.index] === '-') this.index++;
132
- const exponent = this.index;
133
- while (this.text[this.index] >= '0' && this.text[this.index] <= '9') this.index++;
134
- if (exponent === this.index) this.#error('malformed_json', 'exponent requires digits');
135
- }
136
- return new RawNumber(this.text.slice(start, this.index));
137
- }
138
- #literal(token, value) {
139
- if (this.text.slice(this.index, this.index + token.length) !== token) this.#error('malformed_json', 'invalid JSON literal');
140
- this.index += token.length;
141
- return value;
142
- }
143
- #space() { while (' \t\r\n'.includes(this.text[this.index] ?? '\0')) this.index++; }
144
- #error(code, message) { throw new ProtocolError(code, message); }
145
- }
146
-
147
- function exponentValue(raw) {
148
- const marker = Math.max(raw.indexOf('e'), raw.indexOf('E'));
149
- if (marker < 0) return 0;
150
- let value = raw.slice(marker + 1);
151
- let sign = 1;
152
- if (value[0] === '+' || value[0] === '-') { if (value[0] === '-') sign = -1; value = value.slice(1); }
153
- value = value.replace(/^0+/, '') || '0';
154
- if (value.length > 9) return sign * Infinity;
155
- return sign * Number(value);
156
- }
157
-
158
- export function parseSafeIntegerToken(raw, field) {
159
- const negative = raw[0] === '-';
160
- const unsigned = negative ? raw.slice(1) : raw;
161
- const marker = Math.max(unsigned.indexOf('e'), unsigned.indexOf('E'));
162
- const mantissa = marker < 0 ? unsigned : unsigned.slice(0, marker);
163
- const dot = mantissa.indexOf('.');
164
- const fractionLength = dot < 0 ? 0 : mantissa.length - dot - 1;
165
- let digits = (dot < 0 ? mantissa : mantissa.slice(0, dot) + mantissa.slice(dot + 1)).replace(/^0+/, '');
166
- if (!digits) return 0;
167
- if (negative) throw new ProtocolError('unsafe_integer', `${field} must be a safe non-negative integer`);
168
- const scale = exponentValue(unsigned) - fractionLength;
169
- if (!Number.isFinite(scale)) throw new ProtocolError('unsafe_integer', `${field} must be a safe non-negative integer`);
170
- if (scale < 0) {
171
- const remove = -scale;
172
- if (remove > digits.length || !digits.endsWith('0'.repeat(remove))) throw new ProtocolError('unsafe_integer', `${field} must be an exact integer`);
173
- digits = digits.slice(0, digits.length - remove).replace(/^0+/, '') || '0';
174
- } else {
175
- if (digits.length + scale > 16) throw new ProtocolError('unsafe_integer', `${field} must be a safe non-negative integer`);
176
- digits += '0'.repeat(scale);
177
- }
178
- if (digits.length > 16 || (digits.length === 16 && digits > '9007199254740991')) {
179
- throw new ProtocolError('unsafe_integer', `${field} must be a safe non-negative integer`);
180
- }
181
- return Number(digits);
182
- }
183
-
184
- function materialize(value) {
185
- if (value instanceof RawNumber) {
186
- const number = Number(value.raw);
187
- if (/^-?(?:0|[1-9][0-9]*)$/.test(value.raw) && Number.isSafeInteger(number)) return Object.is(number, -0) ? 0 : number;
188
- return new RawJsonNumber(value.raw);
189
- }
190
- if (Array.isArray(value)) return value.map(materialize);
191
- if (value && typeof value === 'object') for (const key of Object.keys(value)) value[key] = materialize(value[key]);
192
- return value;
193
- }
194
-
195
- export function parseEnvelopeJson(text) {
196
- const value = new JsonParser(text).parse();
197
- if (!value || value instanceof RawNumber || Array.isArray(value) || typeof value !== 'object') throw new ProtocolError('wrong_shape', 'envelope must be an object');
198
- if (!(value.protocol_version instanceof RawNumber) || value.protocol_version.raw !== '1') {
199
- throw new ProtocolError('bad_version', 'protocol_version must be integer token 1');
200
- }
201
- value.protocol_version = 1;
202
- for (const field of ['host_epoch', 'scope_generation']) {
203
- if (!(value[field] instanceof RawNumber)) throw new ProtocolError('unsafe_integer', `${field} must be a JSON number`);
204
- value[field] = parseSafeIntegerToken(value[field].raw, field);
205
- }
206
- value.message = materialize(value.message);
207
- return validateEnvelope(value);
208
- }
1
+ import { ProtocolError, RawJsonNumber, validateEnvelope } from './protocol.mjs';
2
+
3
+ class RawNumber {
4
+ constructor(raw) { this.raw = raw; Object.freeze(this); }
5
+ }
6
+
7
+ class JsonParser {
8
+ constructor(text) { this.text = text; this.index = 0; }
9
+ parse() {
10
+ this.#space();
11
+ const value = this.#value('envelope');
12
+ this.#space();
13
+ if (this.index !== this.text.length) this.#error('trailing_json', 'trailing data after JSON value');
14
+ return value;
15
+ }
16
+ #value(role = 'value') {
17
+ const c = this.text[this.index];
18
+ if (c === '{') return this.#object(role);
19
+ if (c === '[') return this.#array();
20
+ if (c === '"') return this.#string();
21
+ if (c === 't') return this.#literal('true', true);
22
+ if (c === 'f') return this.#literal('false', false);
23
+ if (c === 'n') return this.#literal('null', null);
24
+ if (c === '-' || (c >= '0' && c <= '9')) return this.#number();
25
+ this.#error('malformed_json', 'expected a JSON value');
26
+ }
27
+ #object(role) {
28
+ this.index++;
29
+ const object = Object.create(null);
30
+ const keys = new Set();
31
+ this.#space();
32
+ if (this.text[this.index] === '}') { this.index++; return object; }
33
+ for (;;) {
34
+ if (this.text[this.index] !== '"') this.#error('malformed_json', 'object key must be a string');
35
+ const key = this.#string();
36
+ this.#space();
37
+ if (this.text[this.index++] !== ':') this.#error('malformed_json', 'expected colon after object key');
38
+ this.#space();
39
+ const childRole = role === 'envelope' && key === 'message' ? 'message' : 'value';
40
+ const value = this.#value(childRole);
41
+ if ((role === 'envelope' || role === 'message') && keys.has(key)) {
42
+ this.#error('duplicate_field', `duplicate field in ${role}`);
43
+ }
44
+ keys.add(key);
45
+ object[key] = value; // serde_json::Value uses the last value for opaque object duplicates.
46
+ this.#space();
47
+ const delimiter = this.text[this.index++];
48
+ if (delimiter === '}') return object;
49
+ if (delimiter !== ',') this.#error('malformed_json', 'expected comma or object end');
50
+ this.#space();
51
+ }
52
+ }
53
+ #array() {
54
+ this.index++;
55
+ const array = [];
56
+ this.#space();
57
+ if (this.text[this.index] === ']') { this.index++; return array; }
58
+ for (;;) {
59
+ array.push(this.#value());
60
+ this.#space();
61
+ const delimiter = this.text[this.index++];
62
+ if (delimiter === ']') return array;
63
+ if (delimiter !== ',') this.#error('malformed_json', 'expected comma or array end');
64
+ this.#space();
65
+ }
66
+ }
67
+ #string() {
68
+ this.index++;
69
+ let result = '';
70
+ for (;;) {
71
+ if (this.index >= this.text.length) this.#error('malformed_json', 'unterminated JSON string');
72
+ const c = this.text[this.index++];
73
+ if (c === '"') return result;
74
+ if (c === '\\') {
75
+ if (this.index >= this.text.length) this.#error('malformed_json', 'unterminated JSON escape');
76
+ const escape = this.text[this.index++];
77
+ const simple = { '"': '"', '\\': '\\', '/': '/', b: '\b', f: '\f', n: '\n', r: '\r', t: '\t' }[escape];
78
+ if (simple !== undefined) { result += simple; continue; }
79
+ if (escape !== 'u') this.#error('malformed_json', 'invalid JSON escape');
80
+ const first = this.#hexUnit();
81
+ if (first >= 0xd800 && first <= 0xdbff) {
82
+ if (this.text.slice(this.index, this.index + 2) !== '\\u') this.#error('invalid_surrogate', 'lone high surrogate in JSON string');
83
+ this.index += 2;
84
+ const second = this.#hexUnit();
85
+ if (second < 0xdc00 || second > 0xdfff) this.#error('invalid_surrogate', 'invalid surrogate pair in JSON string');
86
+ result += String.fromCodePoint(0x10000 + ((first - 0xd800) << 10) + second - 0xdc00);
87
+ } else if (first >= 0xdc00 && first <= 0xdfff) {
88
+ this.#error('invalid_surrogate', 'lone low surrogate in JSON string');
89
+ } else result += String.fromCharCode(first);
90
+ continue;
91
+ }
92
+ const unit = c.charCodeAt(0);
93
+ if (unit < 0x20) this.#error('malformed_json', 'unescaped control character in JSON string');
94
+ // The text is UTF-16, so a raw character outside the BMP (an emoji, as
95
+ // serde_json writes it unescaped) is two units here: a high surrogate
96
+ // followed by a low one. Only a half without its partner is invalid.
97
+ if (unit >= 0xd800 && unit <= 0xdbff) {
98
+ const next = this.text.charCodeAt(this.index);
99
+ if (next >= 0xdc00 && next <= 0xdfff) {
100
+ result += c + this.text[this.index++];
101
+ continue;
102
+ }
103
+ this.#error('invalid_surrogate', 'lone surrogate in JSON string');
104
+ }
105
+ if (unit >= 0xdc00 && unit <= 0xdfff) this.#error('invalid_surrogate', 'lone surrogate in JSON string');
106
+ result += c;
107
+ }
108
+ }
109
+ #hexUnit() {
110
+ const token = this.text.slice(this.index, this.index + 4);
111
+ if (!/^[0-9a-fA-F]{4}$/.test(token)) this.#error('malformed_json', 'invalid unicode escape');
112
+ this.index += 4;
113
+ return Number.parseInt(token, 16);
114
+ }
115
+ #number() {
116
+ const start = this.index;
117
+ if (this.text[this.index] === '-') this.index++;
118
+ if (this.text[this.index] === '0') this.index++;
119
+ else {
120
+ if (this.text[this.index] < '1' || this.text[this.index] > '9') this.#error('malformed_json', 'invalid JSON number');
121
+ while (this.text[this.index] >= '0' && this.text[this.index] <= '9') this.index++;
122
+ }
123
+ if (this.text[this.index] === '.') {
124
+ this.index++;
125
+ const fraction = this.index;
126
+ while (this.text[this.index] >= '0' && this.text[this.index] <= '9') this.index++;
127
+ if (fraction === this.index) this.#error('malformed_json', 'fraction requires digits');
128
+ }
129
+ if (this.text[this.index] === 'e' || this.text[this.index] === 'E') {
130
+ this.index++;
131
+ if (this.text[this.index] === '+' || this.text[this.index] === '-') this.index++;
132
+ const exponent = this.index;
133
+ while (this.text[this.index] >= '0' && this.text[this.index] <= '9') this.index++;
134
+ if (exponent === this.index) this.#error('malformed_json', 'exponent requires digits');
135
+ }
136
+ return new RawNumber(this.text.slice(start, this.index));
137
+ }
138
+ #literal(token, value) {
139
+ if (this.text.slice(this.index, this.index + token.length) !== token) this.#error('malformed_json', 'invalid JSON literal');
140
+ this.index += token.length;
141
+ return value;
142
+ }
143
+ #space() { while (' \t\r\n'.includes(this.text[this.index] ?? '\0')) this.index++; }
144
+ #error(code, message) { throw new ProtocolError(code, message); }
145
+ }
146
+
147
+ function exponentValue(raw) {
148
+ const marker = Math.max(raw.indexOf('e'), raw.indexOf('E'));
149
+ if (marker < 0) return 0;
150
+ let value = raw.slice(marker + 1);
151
+ let sign = 1;
152
+ if (value[0] === '+' || value[0] === '-') { if (value[0] === '-') sign = -1; value = value.slice(1); }
153
+ value = value.replace(/^0+/, '') || '0';
154
+ if (value.length > 9) return sign * Infinity;
155
+ return sign * Number(value);
156
+ }
157
+
158
+ export function parseSafeIntegerToken(raw, field) {
159
+ const negative = raw[0] === '-';
160
+ const unsigned = negative ? raw.slice(1) : raw;
161
+ const marker = Math.max(unsigned.indexOf('e'), unsigned.indexOf('E'));
162
+ const mantissa = marker < 0 ? unsigned : unsigned.slice(0, marker);
163
+ const dot = mantissa.indexOf('.');
164
+ const fractionLength = dot < 0 ? 0 : mantissa.length - dot - 1;
165
+ let digits = (dot < 0 ? mantissa : mantissa.slice(0, dot) + mantissa.slice(dot + 1)).replace(/^0+/, '');
166
+ if (!digits) return 0;
167
+ if (negative) throw new ProtocolError('unsafe_integer', `${field} must be a safe non-negative integer`);
168
+ const scale = exponentValue(unsigned) - fractionLength;
169
+ if (!Number.isFinite(scale)) throw new ProtocolError('unsafe_integer', `${field} must be a safe non-negative integer`);
170
+ if (scale < 0) {
171
+ const remove = -scale;
172
+ if (remove > digits.length || !digits.endsWith('0'.repeat(remove))) throw new ProtocolError('unsafe_integer', `${field} must be an exact integer`);
173
+ digits = digits.slice(0, digits.length - remove).replace(/^0+/, '') || '0';
174
+ } else {
175
+ if (digits.length + scale > 16) throw new ProtocolError('unsafe_integer', `${field} must be a safe non-negative integer`);
176
+ digits += '0'.repeat(scale);
177
+ }
178
+ if (digits.length > 16 || (digits.length === 16 && digits > '9007199254740991')) {
179
+ throw new ProtocolError('unsafe_integer', `${field} must be a safe non-negative integer`);
180
+ }
181
+ return Number(digits);
182
+ }
183
+
184
+ function materialize(value) {
185
+ if (value instanceof RawNumber) {
186
+ const number = Number(value.raw);
187
+ if (/^-?(?:0|[1-9][0-9]*)$/.test(value.raw) && Number.isSafeInteger(number)) return Object.is(number, -0) ? 0 : number;
188
+ return new RawJsonNumber(value.raw);
189
+ }
190
+ if (Array.isArray(value)) return value.map(materialize);
191
+ if (value && typeof value === 'object') for (const key of Object.keys(value)) value[key] = materialize(value[key]);
192
+ return value;
193
+ }
194
+
195
+ export function parseEnvelopeJson(text) {
196
+ const value = new JsonParser(text).parse();
197
+ if (!value || value instanceof RawNumber || Array.isArray(value) || typeof value !== 'object') throw new ProtocolError('wrong_shape', 'envelope must be an object');
198
+ if (!(value.protocol_version instanceof RawNumber) || value.protocol_version.raw !== '1') {
199
+ throw new ProtocolError('bad_version', 'protocol_version must be integer token 1');
200
+ }
201
+ value.protocol_version = 1;
202
+ for (const field of ['host_epoch', 'scope_generation']) {
203
+ if (!(value[field] instanceof RawNumber)) throw new ProtocolError('unsafe_integer', `${field} must be a JSON number`);
204
+ value[field] = parseSafeIntegerToken(value[field].raw, field);
205
+ }
206
+ value.message = materialize(value.message);
207
+ return validateEnvelope(value);
208
+ }