@volter/world-core 3.0.38 → 3.0.40

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 (179) hide show
  1. package/app-route.cjs +26 -25
  2. package/app-route.d.cts +1 -0
  3. package/dist/app-route.cjs +26 -25
  4. package/dist/app-route.d.cts +1 -0
  5. package/dist/generated/pack-facts.json +409 -352
  6. package/dist/inject.cjs +474 -95
  7. package/dist/network-policy.cjs +110 -13
  8. package/dist/network-policy.d.cts +8 -3
  9. package/dist/src/actions.js +2 -1
  10. package/dist/src/anthropic-wire.d.ts +2 -0
  11. package/dist/src/anthropic-wire.js +5 -0
  12. package/dist/src/attestation.d.ts +6 -0
  13. package/dist/src/attestation.js +27 -0
  14. package/dist/src/bytes.d.ts +3 -0
  15. package/dist/src/bytes.js +17 -0
  16. package/dist/src/changeset.js +2 -1
  17. package/dist/src/clickhouse/sql.js +73 -14
  18. package/dist/src/derived-core.d.ts +210 -32
  19. package/dist/src/derived-core.js +510 -244
  20. package/dist/src/derived-real.d.ts +1 -1
  21. package/dist/src/derived-real.js +704 -93
  22. package/dist/src/derived.d.ts +18 -2
  23. package/dist/src/derived.js +21 -2
  24. package/dist/src/events.d.ts +28 -45
  25. package/dist/src/events.js +40 -58
  26. package/dist/src/exact-json.d.ts +10 -0
  27. package/dist/src/exact-json.js +98 -0
  28. package/dist/src/executor.d.ts +17 -0
  29. package/dist/src/executor.js +91 -30
  30. package/dist/src/file-response.js +1 -1
  31. package/dist/src/form.d.ts +8 -0
  32. package/dist/src/form.js +76 -0
  33. package/dist/src/git/format.d.ts +16 -0
  34. package/dist/src/git/format.js +110 -0
  35. package/dist/src/git/index.d.ts +1 -0
  36. package/dist/src/git/index.js +1 -0
  37. package/dist/src/git/lfs.d.ts +1 -1
  38. package/dist/src/git/lfs.js +4 -3
  39. package/dist/src/graphql-wire.d.ts +6 -0
  40. package/dist/src/graphql-wire.js +6 -3
  41. package/dist/src/grpc-wire.js +2 -1
  42. package/dist/src/head.d.ts +1 -0
  43. package/dist/src/head.js +15 -4
  44. package/dist/src/held-reads.d.ts +6 -0
  45. package/dist/src/held-reads.js +60 -0
  46. package/dist/src/history.js +5 -4
  47. package/dist/src/host-port.d.ts +5 -0
  48. package/dist/src/host-port.js +14 -0
  49. package/dist/src/index.d.ts +11 -3
  50. package/dist/src/index.js +9 -4
  51. package/dist/src/log.js +12 -7
  52. package/dist/src/machines.d.ts +81 -5
  53. package/dist/src/machines.js +125 -9
  54. package/dist/src/managed-database.d.ts +15 -11
  55. package/dist/src/managed-database.js +38 -37
  56. package/dist/src/multipart.d.ts +21 -3
  57. package/dist/src/multipart.js +112 -38
  58. package/dist/src/observe.d.ts +3 -0
  59. package/dist/src/observe.js +6 -2
  60. package/dist/src/openai-wire.d.ts +16 -0
  61. package/dist/src/openai-wire.js +43 -12
  62. package/dist/src/pack-fetch.d.ts +4 -6
  63. package/dist/src/pack-fetch.js +189 -57
  64. package/dist/src/packRegistry.d.ts +7 -1
  65. package/dist/src/packRegistry.js +20 -3
  66. package/dist/src/private-transport.d.ts +1 -0
  67. package/dist/src/private-transport.js +11 -0
  68. package/dist/src/protobuf.js +10 -4
  69. package/dist/src/rateBudget.d.ts +8 -1
  70. package/dist/src/rateBudget.js +1 -0
  71. package/dist/src/redis/engine.d.ts +14 -5
  72. package/dist/src/redis/engine.js +271 -72
  73. package/dist/src/redis/frames.d.ts +17 -0
  74. package/dist/src/redis/frames.js +123 -0
  75. package/dist/src/redis/index.d.ts +6 -0
  76. package/dist/src/redis/index.js +6 -0
  77. package/dist/src/redis/json.d.ts +2 -0
  78. package/dist/src/redis/json.js +14 -0
  79. package/dist/src/redis/lua-libs.d.ts +4 -0
  80. package/dist/src/redis/lua-libs.js +173 -0
  81. package/dist/src/redis/lua.d.ts +1 -0
  82. package/dist/src/redis/lua.js +36 -0
  83. package/dist/src/redis/member-storage.d.ts +5 -0
  84. package/dist/src/redis/member-storage.js +75 -0
  85. package/dist/src/redis/resp2.d.ts +4 -0
  86. package/dist/src/redis/resp2.js +29 -0
  87. package/dist/src/redis/stream.d.ts +14 -0
  88. package/dist/src/redis/stream.js +335 -0
  89. package/dist/src/remote-execute.d.ts +2 -2
  90. package/dist/src/request-body.d.ts +11 -0
  91. package/dist/src/request-body.js +11 -0
  92. package/dist/src/runtime.d.ts +6 -5
  93. package/dist/src/runtime.js +5 -5
  94. package/dist/src/s3/wire.d.ts +4 -4
  95. package/dist/src/s3/wire.js +5 -3
  96. package/dist/src/scenario.d.ts +22 -0
  97. package/dist/src/scenario.js +35 -31
  98. package/dist/src/serve-http.d.ts +2 -1
  99. package/dist/src/serve-http.js +10 -1
  100. package/dist/src/serve.js +7 -4
  101. package/dist/src/signing.d.ts +23 -5
  102. package/dist/src/signing.js +74 -11
  103. package/dist/src/sigv4.d.ts +3 -1
  104. package/dist/src/sigv4.js +4 -2
  105. package/dist/src/smtp.js +2 -1
  106. package/dist/src/sockets.js +8 -3
  107. package/dist/src/state-system.d.ts +3 -0
  108. package/dist/src/storage.js +5 -2
  109. package/dist/src/twin-fetch.d.ts +3 -1
  110. package/dist/src/twin-fetch.js +3 -2
  111. package/dist/src/vendor-call.d.ts +10 -3
  112. package/dist/src/vendor-call.js +58 -14
  113. package/dist/test-fixtures/attestation.SOURCE.md +1 -0
  114. package/dist/test-fixtures/attestation.json +50 -0
  115. package/generated/pack-facts.json +409 -352
  116. package/inject.cjs +474 -95
  117. package/network-policy.cjs +110 -13
  118. package/network-policy.d.cts +8 -3
  119. package/package.json +11 -4
  120. package/src/actions.ts +2 -1
  121. package/src/anthropic-wire.ts +6 -0
  122. package/src/attestation.ts +23 -0
  123. package/src/bytes.ts +21 -0
  124. package/src/changeset.ts +2 -1
  125. package/src/clickhouse/sql.ts +50 -16
  126. package/src/derived-core.ts +573 -249
  127. package/src/derived-real.ts +552 -42
  128. package/src/derived.ts +23 -4
  129. package/src/events.ts +54 -85
  130. package/src/exact-json.ts +71 -0
  131. package/src/executor.ts +86 -27
  132. package/src/file-response.ts +1 -1
  133. package/src/form.ts +66 -0
  134. package/src/git/format.ts +89 -0
  135. package/src/git/index.ts +1 -0
  136. package/src/git/lfs.ts +5 -4
  137. package/src/graphql-wire.ts +8 -3
  138. package/src/grpc-wire.ts +2 -1
  139. package/src/head.ts +15 -5
  140. package/src/held-reads.ts +54 -0
  141. package/src/history.ts +5 -4
  142. package/src/host-port.ts +9 -0
  143. package/src/index.ts +10 -4
  144. package/src/log.ts +11 -7
  145. package/src/machines.ts +135 -13
  146. package/src/managed-database.ts +48 -40
  147. package/src/multipart.ts +110 -35
  148. package/src/observe.ts +6 -3
  149. package/src/openai-wire.ts +45 -14
  150. package/src/pack-fetch.ts +173 -50
  151. package/src/packRegistry.ts +27 -4
  152. package/src/private-transport.ts +8 -0
  153. package/src/protobuf.ts +8 -4
  154. package/src/rateBudget.ts +6 -1
  155. package/src/redis/engine.ts +168 -63
  156. package/src/redis/frames.ts +53 -0
  157. package/src/redis/index.ts +6 -0
  158. package/src/redis/json.ts +13 -0
  159. package/src/redis/lua-libs.ts +62 -0
  160. package/src/redis/lua.ts +20 -0
  161. package/src/redis/member-storage.ts +58 -0
  162. package/src/redis/resp2.ts +25 -0
  163. package/src/redis/stream.ts +102 -0
  164. package/src/remote-execute.ts +2 -2
  165. package/src/request-body.ts +12 -0
  166. package/src/runtime.ts +6 -5
  167. package/src/s3/wire.ts +8 -5
  168. package/src/scenario.ts +34 -13
  169. package/src/serve-http.ts +11 -2
  170. package/src/serve.ts +4 -3
  171. package/src/signing.ts +71 -17
  172. package/src/sigv4.ts +5 -3
  173. package/src/smtp.ts +3 -2
  174. package/src/sockets.ts +8 -3
  175. package/src/state-system.ts +3 -0
  176. package/src/storage.ts +5 -2
  177. package/src/twin-fetch.ts +4 -3
  178. package/src/vendor-call.ts +59 -12
  179. package/test-fixtures/attestation.json +50 -0
@@ -0,0 +1,335 @@
1
+ import { RedisStatus, commandInteger, commandShapeError, globMatch } from "./engine.js";
2
+ import { binaryBytes, binaryText, inlineCommand, readResp, respReply } from "./frames.js";
3
+ export function createRedisStream(options) {
4
+ const sessions = new Set();
5
+ let nextId = 0, commandCount = 0;
6
+ let serial = Promise.resolve();
7
+ const ordered = (f) => { const p = serial.then(f); serial = p.catch(() => { }); return p; };
8
+ const error = (message) => ({ error: message });
9
+ const ok = new RedisStatus('OK');
10
+ const answer = (s, v) => { if (!s.closed)
11
+ s.sink.write(binaryBytes(respReply(v))); };
12
+ const close = (s) => { s.closed = true; if (s.blocked?.timer)
13
+ clearTimeout(s.blocked.timer); sessions.delete(s); };
14
+ const unblock = (s, v) => { if (s.blocked?.timer)
15
+ clearTimeout(s.blocked.timer); s.blocked = undefined; answer(s, v); queueMicrotask(() => { void s.pump?.(); }); };
16
+ const blockRun = async (s, argv) => {
17
+ if (argv[0].toUpperCase() === 'BZPOPMIN') {
18
+ for (const key of argv.slice(1, -1)) {
19
+ const res = (await options.run([['ZPOPMIN', key]], s.database)).items[0];
20
+ if ('error' in res)
21
+ return res;
22
+ if (Array.isArray(res.result) && res.result.length)
23
+ return [key, ...res.result];
24
+ }
25
+ return null;
26
+ }
27
+ throw new Error('the blocking command has no executor');
28
+ };
29
+ const wake = async () => { for (const s of sessions)
30
+ if (s.blocked) {
31
+ const v = await blockRun(s, s.blocked.command);
32
+ if (v !== null)
33
+ unblock(s, v);
34
+ } };
35
+ const command = async (s, argv, executing = false) => {
36
+ if (!argv.length || s.closed)
37
+ return;
38
+ commandCount++;
39
+ const cmd = argv[0].toUpperCase(), a = argv.slice(1);
40
+ const shape = commandShapeError(argv, options.dialect);
41
+ if (shape) {
42
+ if (s.queue)
43
+ s.dirty = true;
44
+ answer(s, error(shape));
45
+ return;
46
+ }
47
+ if (!executing && !s.authenticated && !['AUTH', 'QUIT'].includes(cmd)) {
48
+ answer(s, error('NOAUTH Authentication required.'));
49
+ return;
50
+ }
51
+ if (!executing && s.subscriptions.size + s.patterns.size > 0 && !['SUBSCRIBE', 'PSUBSCRIBE', 'UNSUBSCRIBE', 'PUNSUBSCRIBE', 'PING', 'QUIT'].includes(cmd)) {
52
+ answer(s, error(`ERR Can't execute '${cmd.toLowerCase()}': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context`));
53
+ return;
54
+ }
55
+ if (s.queue && !['EXEC', 'MULTI', 'DISCARD', 'QUIT'].includes(cmd)) {
56
+ s.queue.push(argv);
57
+ answer(s, new RedisStatus('QUEUED'));
58
+ return;
59
+ }
60
+ switch (cmd) {
61
+ // source: https://raw.githubusercontent.com/redis/redis/c9d29f6a918c335bc1778d9f68e521c1bbb36a0f/src/acl.c "Only two or three argument forms are allowed."
62
+ case 'AUTH': {
63
+ if (a.length > 2) {
64
+ answer(s, error("ERR syntax error"));
65
+ return;
66
+ }
67
+ if (!options.password && a.length === 1) {
68
+ answer(s, error('ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?'));
69
+ return;
70
+ }
71
+ if (a.length === 2 && a[0] !== 'default' || options.password && a.at(-1) !== options.password) {
72
+ answer(s, error('WRONGPASS invalid username-password pair or user is disabled.'));
73
+ return;
74
+ }
75
+ s.authenticated = true;
76
+ answer(s, ok);
77
+ return;
78
+ }
79
+ case 'SELECT': {
80
+ let db;
81
+ try {
82
+ db = commandInteger(a[0]);
83
+ }
84
+ catch {
85
+ answer(s, error('ERR value is not an integer or out of range'));
86
+ return;
87
+ }
88
+ if (db < -2147483648 || db > 2147483647) {
89
+ answer(s, error('ERR value is out of range, value must between -2147483648 and 2147483647'));
90
+ return;
91
+ }
92
+ if (db < 0 || db >= options.databases) {
93
+ answer(s, error('ERR DB index is out of range'));
94
+ return;
95
+ }
96
+ s.database = String(db);
97
+ answer(s, ok);
98
+ return;
99
+ }
100
+ case 'CLIENT': {
101
+ const sub = a[0].toUpperCase();
102
+ if (sub === 'SETNAME') {
103
+ if (/[^\x21-\x7e]/.test(a[1] ?? '')) {
104
+ answer(s, error('ERR Client names cannot contain spaces, newlines or special characters.'));
105
+ return;
106
+ }
107
+ s.name = a[1] ?? '';
108
+ answer(s, ok);
109
+ }
110
+ else if (sub === 'SETINFO') {
111
+ if (!['LIB-NAME', 'LIB-VER'].includes(a[1].toUpperCase())) {
112
+ answer(s, error(`ERR Unrecognized option '${a[1]}'`));
113
+ return;
114
+ }
115
+ if (/[^\x21-\x7e]/.test(a[2])) {
116
+ answer(s, error(`ERR ${a[1]} cannot contain spaces, newlines or special characters.`));
117
+ return;
118
+ }
119
+ s.lib[a[1].toUpperCase()] = a[2];
120
+ answer(s, ok);
121
+ }
122
+ else if (sub === 'LIST') {
123
+ let clients = [...sessions];
124
+ // source: https://raw.githubusercontent.com/redis/redis/c9d29f6a918c335bc1778d9f68e521c1bbb36a0f/src/networking.c "Invalid client ID"
125
+ if (a[1]?.toUpperCase() === 'ID' && a.length > 2) {
126
+ let ids;
127
+ try {
128
+ ids = a.slice(2).map((raw) => commandInteger(raw, 'ERR Invalid client ID'));
129
+ }
130
+ catch (e) {
131
+ answer(s, error(e.message));
132
+ return;
133
+ }
134
+ clients = ids.flatMap((id) => [...sessions].filter((x) => x.id === id));
135
+ }
136
+ else if (a[1]?.toUpperCase() === 'TYPE' && a.length === 3) {
137
+ const type = a[2].toLowerCase();
138
+ if (!['normal', 'pubsub', 'master', 'replica'].includes(type)) {
139
+ answer(s, error(`ERR Unknown client type '${a[2]}'`));
140
+ return;
141
+ }
142
+ clients = clients.filter((x) => type === (x.subscriptions.size + x.patterns.size ? 'pubsub' : 'normal'));
143
+ }
144
+ else if (a.length !== 1) {
145
+ answer(s, error('ERR syntax error'));
146
+ return;
147
+ }
148
+ answer(s, clients.map((x) => `id=${x.id} addr=127.0.0.1:0 name=${x.name} db=${x.database} flags=${x.subscriptions.size + x.patterns.size ? 'P' : 'N'} lib-name=${x.lib['LIB-NAME'] ?? ''} lib-ver=${x.lib['LIB-VER'] ?? ''}\n`).join(''));
149
+ }
150
+ else
151
+ answer(s, error(options.dialect.unknownCommand(argv)));
152
+ return;
153
+ }
154
+ // source: https://raw.githubusercontent.com/redis/redis/c9d29f6a918c335bc1778d9f68e521c1bbb36a0f/src/server.c "It works in a different way if the client is in"
155
+ case 'PING':
156
+ if (a.length > 1) {
157
+ answer(s, error("ERR wrong number of arguments for 'ping' command"));
158
+ return;
159
+ }
160
+ answer(s, s.subscriptions.size + s.patterns.size ? ['pong', a[0] ?? ''] : a.length ? a[0] : new RedisStatus('PONG'));
161
+ return;
162
+ case 'INFO': {
163
+ const blocks = { server: `# Server\r\nredis_version:${options.version}\r\nredis_mode:standalone\r\n`, clients: `# Clients\r\nconnected_clients:${sessions.size}\r\nblocked_clients:${[...sessions].filter((x) => x.blocked).length}\r\n`, memory: `# Memory\r\nmaxmemory:0\r\nmaxmemory_policy:noeviction\r\n`, stats: `# Stats\r\ntotal_connections_received:${nextId}\r\ntotal_commands_processed:${commandCount}\r\n`, persistence: '# Persistence\r\nloading:0\r\n' };
164
+ answer(s, a.length && !['ALL', 'DEFAULT'].includes(a[0].toUpperCase()) ? a.map((x) => blocks[x.toLowerCase()] ?? '').join('') : Object.values(blocks).join('\r\n'));
165
+ return;
166
+ }
167
+ case 'MULTI':
168
+ if (s.queue)
169
+ answer(s, error('ERR MULTI calls can not be nested'));
170
+ else {
171
+ s.queue = [];
172
+ s.dirty = false;
173
+ answer(s, ok);
174
+ }
175
+ return;
176
+ case 'DISCARD':
177
+ if (!s.queue)
178
+ answer(s, error('ERR DISCARD without MULTI'));
179
+ else {
180
+ s.queue = null;
181
+ s.dirty = false;
182
+ answer(s, ok);
183
+ }
184
+ return;
185
+ case 'EXEC': {
186
+ if (!s.queue) {
187
+ answer(s, error('ERR EXEC without MULTI'));
188
+ return;
189
+ }
190
+ const q = s.queue;
191
+ s.queue = null;
192
+ if (s.dirty) {
193
+ s.dirty = false;
194
+ answer(s, error('EXECABORT Transaction discarded because of previous errors.'));
195
+ return;
196
+ } // source: https://raw.githubusercontent.com/redis/redis/c9d29f6a918c335bc1778d9f68e521c1bbb36a0f/src/multi.c "Exec all the queued commands"
197
+ // Redis writes the queue length before dispatch; pub/sub may write multiple acknowledgement frames.
198
+ s.sink.write(binaryBytes(`*${q.length}\r\n`));
199
+ for (const queued of q)
200
+ await command(s, queued, true);
201
+ await wake();
202
+ return;
203
+ }
204
+ case 'QUIT':
205
+ answer(s, ok);
206
+ close(s);
207
+ s.sink.end();
208
+ return;
209
+ case 'SUBSCRIBE':
210
+ case 'PSUBSCRIBE':
211
+ case 'UNSUBSCRIBE':
212
+ case 'PUNSUBSCRIBE': {
213
+ const target = cmd.includes('PSUB') || cmd.includes('PUNSUB') ? s.patterns : s.subscriptions;
214
+ const removing = cmd.includes('UNSUB');
215
+ const names = a.length ? a : [...target];
216
+ for (const name of names.length ? names : [null]) {
217
+ if (name !== null) {
218
+ if (removing)
219
+ target.delete(name);
220
+ else
221
+ target.add(name);
222
+ }
223
+ answer(s, [cmd.toLowerCase(), name, s.subscriptions.size + s.patterns.size]);
224
+ }
225
+ return;
226
+ }
227
+ case 'PUBLISH': {
228
+ let count = 0;
229
+ for (const target of sessions) {
230
+ if (target.subscriptions.has(a[0])) {
231
+ answer(target, ['message', a[0], a[1]]);
232
+ count++;
233
+ }
234
+ for (const pattern of target.patterns)
235
+ if (globMatch(pattern, a[0])) {
236
+ answer(target, ['pmessage', pattern, a[0], a[1]]);
237
+ count++;
238
+ }
239
+ }
240
+ answer(s, count);
241
+ return;
242
+ }
243
+ case 'BZPOPMIN': {
244
+ // source: https://raw.githubusercontent.com/redis/redis/c9d29f6a918c335bc1778d9f68e521c1bbb36a0f/src/timeout.c "timeout is negative"
245
+ const raw = a.at(-1);
246
+ const infinite = /^[+-]?inf(?:inity)?$/i.test(raw);
247
+ if (raw !== raw.trim() || raw === '' || !infinite && !/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?$/i.test(raw)) {
248
+ answer(s, error('ERR timeout is not a float or out of range'));
249
+ return;
250
+ }
251
+ const millis = (infinite ? raw.startsWith('-') ? -Infinity : Infinity : Number(raw)) * 1000;
252
+ if (millis > 9223372036854775807) {
253
+ answer(s, error('ERR timeout is out of range'));
254
+ return;
255
+ }
256
+ const timeout = Math.ceil(millis);
257
+ if (!Number.isFinite(timeout) || timeout < 0) {
258
+ answer(s, error('ERR timeout is negative'));
259
+ return;
260
+ }
261
+ const v = await blockRun(s, argv);
262
+ if (v !== null) {
263
+ answer(s, v);
264
+ return;
265
+ }
266
+ // source: https://raw.githubusercontent.com/redis/redis/c9d29f6a918c335bc1778d9f68e521c1bbb36a0f/src/multi.c "we do not want to allow blocking commands inside multi"
267
+ if (executing) {
268
+ answer(s, null);
269
+ return;
270
+ }
271
+ const initial = await options.run([], s.database);
272
+ s.blocked = { command: argv, deadline: timeout === 0 ? Infinity : (initial.instant ?? 0) + timeout };
273
+ const poll = () => { if (!s.blocked || s.closed)
274
+ return; s.blocked.timer = setTimeout(() => { void ordered(async () => { if (!s.blocked)
275
+ return; const now = await options.run([], s.database); if ((now.instant ?? 0) >= s.blocked.deadline)
276
+ unblock(s, null);
277
+ else
278
+ poll(); }); }, 50); };
279
+ poll();
280
+ return;
281
+ }
282
+ default: {
283
+ const res = await options.run([argv], s.database);
284
+ const item = res.items[0];
285
+ answer(s, 'error' in item ? item : item.result);
286
+ if (res.wrote && !executing)
287
+ await wake();
288
+ }
289
+ }
290
+ };
291
+ return (sink) => {
292
+ const s = { id: ++nextId, name: '', lib: {}, database: '0', authenticated: !options.password, queue: null, dirty: false, subscriptions: new Set(), patterns: new Set(), sink, closed: false };
293
+ sessions.add(s);
294
+ let buffer = '', chain = Promise.resolve();
295
+ const pending = [];
296
+ const pump = async () => { while (pending.length && !s.blocked && !s.closed)
297
+ await ordered(() => command(s, pending.shift())); };
298
+ s.pump = pump;
299
+ return {
300
+ data(chunk) { if (s.closed)
301
+ return; buffer += binaryText(chunk); try {
302
+ while (buffer.length) {
303
+ let argv;
304
+ let end;
305
+ if (buffer[0] === '*') {
306
+ const f = readResp(buffer);
307
+ if (!f)
308
+ break;
309
+ if (!Array.isArray(f.value) || f.value.some((x) => typeof x !== 'string'))
310
+ throw new Error('Protocol error: expected bulk string');
311
+ argv = f.value;
312
+ end = f.end;
313
+ }
314
+ else {
315
+ const at = buffer.indexOf('\r\n');
316
+ if (at < 0)
317
+ break;
318
+ argv = inlineCommand(buffer.slice(0, at));
319
+ end = at + 2;
320
+ }
321
+ buffer = buffer.slice(end);
322
+ pending.push(argv);
323
+ }
324
+ chain = chain.then(pump);
325
+ }
326
+ catch (e) {
327
+ answer(s, error(`ERR ${e.message}`));
328
+ close(s);
329
+ sink.end();
330
+ } },
331
+ settled: () => chain,
332
+ close: () => close(s),
333
+ };
334
+ };
335
+ }
@@ -1,4 +1,6 @@
1
1
  export type RemoteExecuteRequest = {
2
+ /** The lane of a vendor of lanes that sends the call: the descriptor's `lanes` strategy picks its own by it. */
3
+ lane?: string;
2
4
  method: string;
3
5
  path: string;
4
6
  headers?: Record<string, string>;
@@ -16,8 +18,6 @@ export type RemoteExecuteRequest = {
16
18
  * that its upload calls carry instead of the API token), on the root's own origin: it is sent as the request's
17
19
  * Authorization and the sealed credential does not go with it. */
18
20
  issued?: string;
19
- /** the lane of a vendor of lanes the request is (its strategy, when its lanes authenticate apart) */
20
- lane?: string;
21
21
  };
22
22
  export type RemoteExecuteResponse = {
23
23
  status: number;
@@ -0,0 +1,11 @@
1
+ /** Compressed-request output only: Node's plain requests remain uncapped; Bun retains its own plain-body limit.
2
+ * The default is Bun's existing largest plain body (128 MiB), so both runtimes decode the same.
3
+ * Source: bun-types/serve.d.ts, ServeOptions.maxRequestBodySize (@default 1024 * 1024 * 128),
4
+ * https://github.com/oven-sh/bun/blob/main/packages/bun-types/serve.d.ts .
5
+ * A pack's descriptor.maxRequestBodySize overrides decoded output as it does Bun's plain-body limit. */
6
+ export declare const DEFAULT_MAX_DECODED_REQUEST_BODY_SIZE: number;
7
+ export declare class RequestBodyTooLargeError extends Error {
8
+ constructor();
9
+ }
10
+ export declare const oversizedBody: () => Response;
11
+ export declare const decodedBodyLimit: (declared?: number) => number;
@@ -0,0 +1,11 @@
1
+ /** Compressed-request output only: Node's plain requests remain uncapped; Bun retains its own plain-body limit.
2
+ * The default is Bun's existing largest plain body (128 MiB), so both runtimes decode the same.
3
+ * Source: bun-types/serve.d.ts, ServeOptions.maxRequestBodySize (@default 1024 * 1024 * 128),
4
+ * https://github.com/oven-sh/bun/blob/main/packages/bun-types/serve.d.ts .
5
+ * A pack's descriptor.maxRequestBodySize overrides decoded output as it does Bun's plain-body limit. */
6
+ export const DEFAULT_MAX_DECODED_REQUEST_BODY_SIZE = 128 * 1024 * 1024;
7
+ export class RequestBodyTooLargeError extends Error {
8
+ constructor() { super('Payload Too Large'); this.name = 'RequestBodyTooLargeError'; }
9
+ }
10
+ export const oversizedBody = () => new Response('Payload Too Large', { status: 413 });
11
+ export const decodedBodyLimit = (declared) => declared ?? DEFAULT_MAX_DECODED_REQUEST_BODY_SIZE;
@@ -11,7 +11,7 @@ export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTracepar
11
11
  export type { Traceparent } from './trace-context.js';
12
12
  export type { DerivedCall, DerivedCoreOutcome, DerivedFetch, DerivedFetchOptions, DerivedHandler, DerivedOperation, DerivedOwner, DerivedSurface, BoardFrame } from './derived.js';
13
13
  export { authRefusal, bindSemantics, coreFor, crossCutting, flagOf, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from './derived-core.js';
14
- export { deliverEvents, fillEnvelope, signEvent, signEventAll, verifyEvent } from './events.js';
14
+ export { deliverEvents, fillEnvelope, setDeliveryObserver, signEvent, signEventAll, verifyEvent } from './events.js';
15
15
  export { equalSecrets, hmac, jwks, jwtDecode, jwtSign, jwtVerify, keyId, lettersFrom, md5, sha256, SIGNING_ALGORITHMS, uuidFrom } from './signing.js';
16
16
  export type { HandlerCrypto, Jwk, Jwks, JwtVerdict, SigningKey } from './signing.js';
17
17
  export type { EventDelivery, EventRender, EventScheme, EventsDecl, EventTransport, EventWrite } from './events.js';
@@ -69,14 +69,14 @@ export { observeResource, observeResources, collectObservations, foldObservation
69
69
  export type { ObservedResource, ObserveReport, Observation } from './observe.js';
70
70
  export { readTreeMap, readParentTreeMap, treeStamp, treeChangesSince, originEntries, appendOriginEntry, originLogPath, isUrlParent, parentPosition, positionAt, splitsBatch, assertBatchBoundary } from './log.js';
71
71
  export { referenceField, registerReferences, packReferences, resolveReferences, type ReferenceDeclaration } from './references.js';
72
- export { serveHttp, serveStream, nodeBuiltin, WORLD_BOOT_PATH, type HttpServer, type ServeHttpOptions, type HttpHandler } from './serve-http.js';
72
+ export { serveHttp, serveStream, connectWebSocket, nodeBuiltin, WORLD_BOOT_PATH, type HttpServer, type ServeHttpOptions, type HttpHandler } from './serve-http.js';
73
73
  export { fileResponse, contentTypeOf } from './file-response.js';
74
74
  export { bundleClient, filePathOf } from './client-bundle.js';
75
75
  export { brandTokensResponse } from './brand-tokens.js';
76
- export { multipartBoundary, multipartParts, type MultipartPart } from './multipart.js';
76
+ export { multipartBoundary, multipartParts, multipartEnvelope, inferMultipartBoundary, multipartDelimiterPattern, type MultipartPart, type MultipartFramedPart, type MultipartEnvelope } from './multipart.js';
77
77
  export { corsHeaders, withCors, type CorsDecl } from './cors.js';
78
- export { vendorFetch, VendorUnreachableError } from './vendor-call.js';
79
- export { closeManagedDatabases, EngineDatabaseError, EngineUnavailableError, managedDatabase, quoteIdent, useDatabaseDriver, WORLD_CLOCK_SETTING, worldClockSql, type DatabaseDriver } from './managed-database.js';
78
+ export { setInProcessTwins, vendorFetch, VendorUnreachableError, type InProcessTwin } from './vendor-call.js';
79
+ export { closeManagedDatabases, databaseSession, EngineDatabaseError, EngineUnavailableError, managedDatabase, quoteIdent, useDatabaseDriver, type DatabaseDriver, type DatabaseSession } from './managed-database.js';
80
80
  export type { Batch as EngineBatch, ManagedDatabase, Statement as EngineStatement, StatementResult as EngineStatementResult } from './managed-database.js';
81
81
  export { readResourceBlob, readResourceBlobRange, removeResourceBlob, resourceBlobSize, resourceChain, writeResourceBlob } from './resource-blob.js';
82
82
  export { assertStateRemovable, checkParent, stateGeneration, withAncestryLock, withHistoryLock, withHistoryLocks, withStateLock, withStateRemoval } from './ancestry.js';
@@ -84,4 +84,5 @@ export { captureHistory, captureParentHistory, historyChanges, historyAtInstant,
84
84
  export type { HistoryView, HistoryLayout, HistoryReference, HistoryOrigin } from './history.js';
85
85
  export { foldHistory } from './log.js';
86
86
  export { volterHome } from './volter-home.js';
87
+ export type { MachinePool, MachineSpec, MachineProcess, MachineStatus, MachineFiles, MachineFileStat, GuestImage, LightPoolOptions } from './machines.js';
87
88
  export { boardFrameKey } from './board-keys.js';
@@ -17,7 +17,7 @@ export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runA
17
17
  export { compileSurface, createDerivedFetch, matchOperation } from "./derived.js";
18
18
  export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from "./trace-context.js";
19
19
  export { authRefusal, bindSemantics, coreFor, crossCutting, flagOf, derivedRequestScopes, observeTransitions, resourcesOfType as twinResourcesOfType, semanticsContext, stateOf, transitionFor, parseBracketForm, readParams, render as renderDerived, serveCore, sse, vendorError } from "./derived-core.js";
20
- export { deliverEvents, fillEnvelope, signEvent, signEventAll, verifyEvent } from "./events.js";
20
+ export { deliverEvents, fillEnvelope, setDeliveryObserver, signEvent, signEventAll, verifyEvent } from "./events.js";
21
21
  export { equalSecrets, hmac, jwks, jwtDecode, jwtSign, jwtVerify, keyId, lettersFrom, md5, sha256, SIGNING_ALGORITHMS, uuidFrom } from "./signing.js";
22
22
  export { emitTwinEvent, eventSubscriptionMatches, listEmittable, runEmitCli } from "./emit.js";
23
23
  // The vendor-agnostic CLIENT-SIDE RATE BUDGET — the fail-closed backstop a pack's guarded client
@@ -88,16 +88,16 @@ export { observeResource, observeResources, collectObservations, foldObservation
88
88
  export { readTreeMap, readParentTreeMap, treeStamp, treeChangesSince, originEntries, appendOriginEntry, originLogPath, isUrlParent, parentPosition, positionAt, splitsBatch, assertBatchBoundary } from "./log.js";
89
89
  export { referenceField, registerReferences, packReferences, resolveReferences } from "./references.js";
90
90
  // the HTTP server seam: the one place the serve path meets the runtime (Bun or Node)
91
- export { serveHttp, serveStream, nodeBuiltin, WORLD_BOOT_PATH } from "./serve-http.js";
91
+ export { serveHttp, serveStream, connectWebSocket, nodeBuiltin, WORLD_BOOT_PATH } from "./serve-http.js";
92
92
  // two runtime-neutral helpers for a serve path: a file as a Response, a page's client bundle
93
93
  export { fileResponse, contentTypeOf } from "./file-response.js";
94
94
  export { bundleClient, filePathOf } from "./client-bundle.js";
95
95
  // the brand's tokens and faces for a Volter page (the console, the site, the UI kit), fetched at build
96
96
  export { brandTokensResponse } from "./brand-tokens.js";
97
- export { multipartBoundary, multipartParts } from "./multipart.js";
97
+ export { multipartBoundary, multipartParts, multipartEnvelope, inferMultipartBoundary, multipartDelimiterPattern } from "./multipart.js";
98
98
  export { corsHeaders, withCors } from "./cors.js";
99
- export { vendorFetch, VendorUnreachableError } from "./vendor-call.js";
100
- export { closeManagedDatabases, EngineDatabaseError, EngineUnavailableError, managedDatabase, quoteIdent, useDatabaseDriver, WORLD_CLOCK_SETTING, worldClockSql } from "./managed-database.js";
99
+ export { setInProcessTwins, vendorFetch, VendorUnreachableError } from "./vendor-call.js";
100
+ export { closeManagedDatabases, databaseSession, EngineDatabaseError, EngineUnavailableError, managedDatabase, quoteIdent, useDatabaseDriver } from "./managed-database.js";
101
101
  export { readResourceBlob, readResourceBlobRange, removeResourceBlob, resourceBlobSize, resourceChain, writeResourceBlob } from "./resource-blob.js";
102
102
  export { assertStateRemovable, checkParent, stateGeneration, withAncestryLock, withHistoryLock, withHistoryLocks, withStateLock, withStateRemoval } from "./ancestry.js";
103
103
  export { captureHistory, captureParentHistory, historyChanges, historyAtInstant, historyDigest, historyEntries, historyLength, historyPrefix, inheritedHistory, originHead, publishOriginHistory, readHistoryView } from "./history.js";
@@ -14,7 +14,7 @@ export type CorsRule = {
14
14
  allowedMethods: string[];
15
15
  allowedHeaders: string[];
16
16
  exposeHeaders: string[];
17
- maxAgeSeconds?: number;
17
+ maxAgeSeconds?: number | string;
18
18
  };
19
19
  export declare function parseCors(xml: string): CorsRule[];
20
20
  export declare function corsXml(rules: CorsRule[]): string;
@@ -34,11 +34,11 @@ export type LifecycleRule = {
34
34
  prefix: string;
35
35
  prefixOnRule?: boolean;
36
36
  noPrefix?: boolean;
37
- expireDays?: number;
37
+ expireDays?: number | string;
38
38
  expireDate?: string;
39
- abortMultipartDays?: number;
39
+ abortMultipartDays?: number | string;
40
40
  transitions?: Array<{
41
- days?: number;
41
+ days?: number | string;
42
42
  date?: string;
43
43
  storageClass: string;
44
44
  }>;
@@ -1,3 +1,4 @@
1
+ import { exactInteger } from "../exact-json.js";
1
2
  // S3'S WIRE — the XML bodies S3 answers and reads, a bucket's CORS and lifecycle documents, a delete batch, an object's
2
3
  // ETag, and a request's body kept as its bytes (docs/contributing/architecture.md, "Other wires": S3's wire is a kernel
3
4
  // library, as Redis's command core is). Every vendor that speaks S3's API speaks this wire: AWS S3 itself, Cloudflare
@@ -5,6 +6,7 @@
5
6
  // what they refuse, what they implement) is each pack's own. Moved here from the cloudflare pack's R2 lane, which had it
6
7
  // ported from the aws pack's S3 code; a pack may import neither (B4). Importing this module does nothing.
7
8
  import { createHash } from 'node:crypto';
9
+ const wireInteger = (text) => /^[+-]?\d+$/.test(text) ? exactInteger(text) : Number(text);
8
10
  // ── XML ──────────────────────────────────────────────────────────────────────────────────────
9
11
  const DECL = '<?xml version="1.0" encoding="UTF-8"?>';
10
12
  const NS = 'http://s3.amazonaws.com/doc/2006-03-01/';
@@ -36,7 +38,7 @@ export function parseCors(xml) {
36
38
  const b = m[1];
37
39
  const id = oneOf(b, 'ID');
38
40
  const age = oneOf(b, 'MaxAgeSeconds');
39
- return { ...(id ? { id } : {}), allowedOrigins: allOf(b, 'AllowedOrigin'), allowedMethods: allOf(b, 'AllowedMethod'), allowedHeaders: allOf(b, 'AllowedHeader'), exposeHeaders: allOf(b, 'ExposeHeader'), ...(age ? { maxAgeSeconds: Number(age) } : {}) };
41
+ return { ...(id ? { id } : {}), allowedOrigins: allOf(b, 'AllowedOrigin'), allowedMethods: allOf(b, 'AllowedMethod'), allowedHeaders: allOf(b, 'AllowedHeader'), exposeHeaders: allOf(b, 'ExposeHeader'), ...(age ? { maxAgeSeconds: wireInteger(age) } : {}) };
40
42
  });
41
43
  }
42
44
  export function corsXml(rules) {
@@ -83,11 +85,11 @@ export function parseLifecycle(xml) {
83
85
  const transitions = [...b.matchAll(/<Transition>([\s\S]*?)<\/Transition>/g)].map((x) => {
84
86
  const d = oneOf(x[1], 'Days');
85
87
  const on = oneOf(x[1], 'Date');
86
- return { ...(d !== undefined ? { days: Number(d) } : {}), ...(on !== undefined ? { date: on } : {}), storageClass: oneOf(x[1], 'StorageClass') ?? '' };
88
+ return { ...(d !== undefined ? { days: wireInteger(d) } : {}), ...(on !== undefined ? { date: on } : {}), storageClass: oneOf(x[1], 'StorageClass') ?? '' };
87
89
  });
88
90
  return {
89
91
  id: oneOf(b, 'ID') ?? '', enabled: (oneOf(b, 'Status') ?? 'Enabled') === 'Enabled', prefix: oneOf(b, 'Prefix') ?? '', ...(/<Filter>/.test(b) ? {} : /<Prefix>/.test(b) ? { prefixOnRule: true } : { noPrefix: true }),
90
- ...(days ? { expireDays: Number(days) } : {}), ...(date ? { expireDate: date } : {}), ...(after ? { abortMultipartDays: Number(after) } : {}), ...(transitions.length ? { transitions } : {}),
92
+ ...(days ? { expireDays: wireInteger(days) } : {}), ...(date ? { expireDate: date } : {}), ...(after ? { abortMultipartDays: wireInteger(after) } : {}), ...(transitions.length ? { transitions } : {}),
91
93
  };
92
94
  });
93
95
  }
@@ -36,6 +36,8 @@ export type PackScenarioAdapter<Req> = {
36
36
  scopeKey?: (req: Req) => string;
37
37
  /** The VENDOR'S error envelope for a `status` fault — a 429 from this vendor looks like this
38
38
  * vendor's 429. Omitted → the kernel's envelope `{ error: { message, type: "twin_fault" } }`. */
39
+ /** Opt-in scope check for post-admission model generation failures; absent rejects them. */
40
+ validateGenerationFault?: (fault: ScenarioGenerationFault, handler: ScenarioHandler) => string | null;
39
41
  renderFault?: (fault: ScenarioStatusFault, req: Req) => {
40
42
  body: unknown;
41
43
  headers?: Record<string, string>;
@@ -49,6 +51,7 @@ export type PackScenarioAdapter<Req> = {
49
51
  * status — answer this HTTP status instead of serving: a 4xx/5xx the vendor's own envelope
50
52
  * (the pack's adapter renders it; a kernel envelope when it declares none), with
51
53
  * `Retry-After` when `retryAfterSeconds` is set;
54
+ * generation — opt-in post-admission compute failure, carried to the handler for its SDK error wire;
52
55
  * drop — never answer: the request hangs until the client's own timeout ends it (what an
53
56
  * outage looks like from the client; a TCP reset is not something a fetch can do),
54
57
  * released after `holdMs` (default 300 000) so a socket is not held forever. */
@@ -60,10 +63,23 @@ export type ScenarioFault = {
60
63
  status: number;
61
64
  retryAfterSeconds?: number;
62
65
  message?: string;
66
+ errorType?: string;
67
+ metadata?: Record<string, unknown>;
68
+ } | {
69
+ kind: "generation";
70
+ status: number;
71
+ message: string;
72
+ errorType: string;
73
+ metadata?: Record<string, unknown>;
74
+ partialText?: string;
75
+ event?: string;
63
76
  } | {
64
77
  kind: "drop";
65
78
  holdMs?: number;
66
79
  };
80
+ export type ScenarioGenerationFault = Extract<ScenarioFault, {
81
+ kind: "generation";
82
+ }>;
67
83
  export type ScenarioStatusFault = Extract<ScenarioFault, {
68
84
  kind: "status";
69
85
  }>;
@@ -186,7 +202,13 @@ export declare function statefulTwinManifest(input: {
186
202
  twinOf: string;
187
203
  stores: string;
188
204
  identity?: string;
205
+ behavior?: string;
189
206
  notes?: string;
207
+ doors?: ReadonlyArray<{
208
+ method: string;
209
+ path: string;
210
+ note?: string;
211
+ }>;
190
212
  }): Record<string, unknown>;
191
213
  /** The GET /twin manifest — the discovery door's body. Education ships INSIDE the twin:
192
214
  * in-world agents have no repos or skills, only HTTP. */