@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
@@ -1,6 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  const WORLD_NETWORK_POLICY_ENV = 'VOLTER_WORLD_NETWORK_POLICY';
4
+ /** Reads only: an `egress` grant admits these; any other method needs `writes`. */
5
+ const READ_METHODS = Object.freeze(['GET', 'HEAD', 'OPTIONS']);
6
+ /** The public build-artifact origins a build-phase World reads without listing them (architecture, "Reads are granted generously"). */
7
+ const PUBLIC_BUILD_READS = Object.freeze([
8
+ 'https://binaries.prisma.sh', 'https://fonts.googleapis.com', 'https://fonts.gstatic.com',
9
+ 'https://index.crates.io', 'https://registry.npmjs.org', 'https://static.crates.io',
10
+ ]);
4
11
 
5
12
  function object(value, keys, label) {
6
13
  if (!value || typeof value !== 'object' || Array.isArray(value)
@@ -10,17 +17,37 @@ function object(value, keys, label) {
10
17
  return value;
11
18
  }
12
19
 
20
+ // Decode once, then resolve dot segments. Separators must have been literal on the wire.
21
+ function normalizedPath(path) {
22
+ if (/\\|%2f|%5c/i.test(path)) return null;
23
+ let decoded;
24
+ try { decoded = decodeURIComponent(path); } catch { return null; }
25
+ if (/[\\\x00-\x1f\x7f]/.test(decoded) || /%[0-9a-f]{2}/i.test(decoded)) return null;
26
+ const parts = [];
27
+ for (const segment of decoded.split('/')) {
28
+ if (segment === '.') continue;
29
+ if (segment === '..') { if (parts.length > 1) parts.pop(); }
30
+ else parts.push(segment);
31
+ }
32
+ let result = parts.join('/');
33
+ if (!result.startsWith('/')) result = '/' + result;
34
+ if ((decoded.endsWith('/.') || decoded.endsWith('/..')) && !result.endsWith('/')) result += '/';
35
+ return result;
36
+ }
37
+
13
38
  function origins(value) {
14
- if (!Array.isArray(value) || value.length > 256) throw new Error('World network egress must be an array of at most 256 exact HTTPS origins');
39
+ if (!Array.isArray(value) || value.length > 256) throw new Error('World network egress must be an array of at most 256 exact HTTPS origins, exact paths or trailing-slash subtrees');
15
40
  const normalized = value.map(origin => {
16
41
  if (typeof origin !== 'string' || origin.length > 2048) throw new Error('World network egress origins must be strings');
17
42
  let url;
18
43
  try { url = new URL(origin); } catch { throw new Error(`Invalid World network origin: ${origin}`); }
19
- if (url.protocol !== 'https:' || url.origin !== origin || url.username || url.password
44
+ const canonical = url.pathname === '/' ? url.origin : url.origin + url.pathname;
45
+ if (url.protocol !== 'https:' || url.port === '0' || canonical !== origin || url.username || url.password || url.search || url.hash
46
+ || /[\\*]/.test(origin) || normalizedPath(url.pathname) === null
20
47
  || !/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/.test(url.hostname)
21
48
  || url.hostname.split('.').some(label => !label || label.length > 63 || label.startsWith('-') || label.endsWith('-'))
22
49
  || /^[\d.]+$/.test(url.hostname) || url.hostname === 'localhost' || url.hostname.endsWith('.localhost')) {
23
- throw new Error(`World network requires an exact canonical HTTPS origin: ${origin}`);
50
+ throw new Error(`World network requires an exact canonical HTTPS origin, path or subtree: ${origin}`);
24
51
  }
25
52
  return origin;
26
53
  });
@@ -28,19 +55,32 @@ function origins(value) {
28
55
  }
29
56
 
30
57
  function normalizeWorldNetwork(value) {
31
- const network = object(value, ['egress'], 'World network');
32
- return Object.freeze({ egress: origins(network.egress) });
58
+ const network = object(value, ['egress', 'writes', 'phase', 'passthrough', 'publicReads'], 'World network');
59
+ const egress = origins(network.egress);
60
+ const writes = origins(network.writes ?? []);
61
+ const phase = network.phase ?? 'runtime';
62
+ if (phase !== 'build' && phase !== 'runtime') throw new Error('World network phase must be build or runtime');
63
+ if (network.publicReads !== undefined && typeof network.publicReads !== 'boolean') throw new Error('World network publicReads must be a boolean');
64
+ const publicReads = phase === 'build' && network.publicReads !== false;
65
+ const passthrough = origins(network.passthrough ?? []);
66
+ if (passthrough.length && phase !== 'build') throw new Error('World TLS passthrough requires phase: build');
67
+ for (const origin of passthrough) {
68
+ if (origin !== new URL(origin).origin || !egress.includes(origin)) throw new Error(`TLS passthrough requires an exact-origin egress grant: ${origin}`);
69
+ // an opaque tunnel cannot show its method, so it cannot carry a write
70
+ if (writes.some(grant => new URL(grant).origin === origin)) throw new Error(`TLS passthrough cannot carry a write grant: ${origin}`);
71
+ }
72
+ return Object.freeze({ egress, writes, phase, passthrough, publicReads });
33
73
  }
34
74
 
35
75
  function createWorldNetworkPolicy(world, network) {
36
76
  if (typeof world !== 'string' || !world || world.length > 256) throw new Error('World network policy requires its World identity');
37
- return Object.freeze({ version: 1, world, egress: normalizeWorldNetwork(network).egress });
77
+ return Object.freeze({ version: 1, world, ...normalizeWorldNetwork(network) });
38
78
  }
39
79
 
40
80
  function parseWorldNetworkPolicy(value) {
41
- const policy = object(value, ['version', 'world', 'egress'], 'World network policy');
81
+ const policy = object(value, ['version', 'world', 'egress', 'writes', 'phase', 'passthrough', 'publicReads'], 'World network policy');
42
82
  if (policy.version !== 1) throw new Error('Unsupported World network policy version');
43
- return createWorldNetworkPolicy(policy.world, { egress: policy.egress });
83
+ return createWorldNetworkPolicy(policy.world, { egress: policy.egress, writes: policy.writes, phase: policy.phase, passthrough: policy.passthrough, publicReads: policy.publicReads });
44
84
  }
45
85
 
46
86
  function worldNetworkPolicyFromEnv(env) {
@@ -52,10 +92,67 @@ function worldNetworkPolicyFromEnv(env) {
52
92
  return policy;
53
93
  }
54
94
 
55
- function allowsWorldNetworkEgress(policy, value) {
95
+ function destination(value, originOnly = false) {
96
+ if (/\\/.test(String(value).split(/[?#]/, 1)[0])) return null;
97
+ let url;
98
+ try { url = new URL(String(value)); } catch { return null; }
99
+ const path = normalizedPath(url.pathname);
100
+ return url.protocol === 'https:' && url.port !== '0' && !url.username && !url.password && (path !== null || originOnly) ? { url, path } : null;
101
+ }
102
+
103
+ function containsGrant(broad, narrow) {
104
+ const a = destination(broad); const b = destination(narrow);
105
+ if (!a || !b || a.url.origin !== b.url.origin) return false;
106
+ if (broad === a.url.origin) return true;
107
+ if (narrow === b.url.origin) return false;
108
+ return a.path.endsWith('/') ? b.path.startsWith(a.path) : !b.path.endsWith('/') && b.path === a.path;
109
+ }
110
+
111
+ function granted(grants, to) {
112
+ return grants.some(grant => {
113
+ const allowed = destination(grant);
114
+ return allowed && to.url.origin === allowed.url.origin && (grant === allowed.url.origin
115
+ || (to.path !== null && (allowed.path.endsWith('/') ? to.path.startsWith(allowed.path) : to.path === allowed.path)));
116
+ });
117
+ }
118
+
119
+ /** Whether `method` to `value` is allowed: reads by `egress`, `writes` or the build phase's public reads; writes only by `writes`. */
120
+ function allowsWorldNetworkEgress(policy, value, method = 'GET') {
121
+ const to = destination(value, true);
122
+ if (!to) return false;
123
+ if (granted(policy.writes ?? [], to)) return true;
124
+ if (!READ_METHODS.includes(String(method).toUpperCase())) return false;
125
+ return granted(policy.egress, to) || (policy.phase === 'build' && policy.publicReads === true && PUBLIC_BUILD_READS.includes(to.url.origin));
126
+ }
127
+
128
+ function worldNetworkUsesPassthrough(policy, value) {
129
+ const to = destination(value, true);
130
+ if (!to || policy.phase !== 'build') return false;
131
+ // public build artifacts tunnel unopened: native clients (Turbopack's next/font on macOS) trust only the OS store
132
+ if (policy.publicReads === true && PUBLIC_BUILD_READS.includes(to.url.origin) && !granted(policy.writes ?? [], to)) return true;
133
+ return policy.passthrough?.includes(to.url.origin) === true && policy.egress.includes(to.url.origin);
134
+ }
135
+
136
+ /** This authority must be mediated per request; CONNECT is only a path to the inspector. */
137
+ function worldNetworkNeedsPathInspection(policy, value) {
56
138
  let url;
57
139
  try { url = new URL(String(value)); } catch { return false; }
58
- return url.protocol === 'https:' && !url.username && !url.password && policy.egress.includes(url.origin);
140
+ return url.protocol === 'https:' && !worldNetworkUsesPassthrough(policy, url)
141
+ && ([...policy.egress, ...(policy.writes ?? [])].some(grant => new URL(grant).origin === url.origin)
142
+ || (policy.phase === 'build' && policy.publicReads === true && PUBLIC_BUILD_READS.includes(url.origin)));
143
+ }
144
+
145
+ /** Parent ceilings keep the narrower path and cannot create opaque transport permission. */
146
+ function intersectWorldNetwork(own, ceiling) {
147
+ const left = normalizeWorldNetwork(own); const right = normalizeWorldNetwork(ceiling);
148
+ const meet = (a, b) => [...new Set(a.flatMap(x => b.flatMap(y => containsGrant(y, x) ? [x] : containsGrant(x, y) ? [y] : [])))].sort();
149
+ const egress = meet(left.egress, right.egress);
150
+ const writes = meet(left.writes, right.writes);
151
+ const passthrough = left.phase === 'build' && right.phase === 'build'
152
+ ? left.passthrough.filter(origin => right.passthrough.includes(origin) && egress.includes(origin)) : [];
153
+ // public reads are permission too: only a build ceiling that reads them passes them on
154
+ const publicReads = left.publicReads && right.publicReads;
155
+ return normalizeWorldNetwork({ egress, writes, phase: left.phase, passthrough, publicReads });
59
156
  }
60
157
 
61
158
  /** Loopback and private addresses stay inside the machine a World runs on: never refused. */
@@ -80,15 +177,15 @@ function isWorldInternalHost(hostname) {
80
177
  * injector does not attach to. Internal addresses pass; strict egress refuses everything else; a
81
178
  * published network policy refuses what it does not list. An unreadable policy refuses.
82
179
  */
83
- function worldEgressRefusal(value, env = process.env) {
180
+ function worldEgressRefusal(value, env = process.env, method = 'GET') {
84
181
  let url;
85
182
  try { url = new URL(String(value)); } catch { return `unparseable destination ${String(value)}`; }
86
183
  if (isWorldInternalHost(url.hostname)) return null;
87
184
  if (env.VOLTER_TWIN_STRICT_EGRESS === '1' || env.VOLTER_TWIN_STRICT_EGRESS === 'true') return `sealed World refuses untwinned host ${url.hostname}`;
88
185
  let policy;
89
186
  try { policy = worldNetworkPolicyFromEnv(env); } catch (error) { return `World network policy unreadable (${error.message}); refusing ${url.hostname}`; }
90
- if (policy !== undefined && !allowsWorldNetworkEgress(policy, url)) return `World network policy does not allow ${url.origin}`;
187
+ if (policy !== undefined && !allowsWorldNetworkEgress(policy, url, method)) return `World network policy does not allow ${String(method).toUpperCase()} ${url.origin}`;
91
188
  return null;
92
189
  }
93
190
 
94
- module.exports = { isWorldInternalHost, worldEgressRefusal, WORLD_NETWORK_POLICY_ENV, normalizeWorldNetwork, createWorldNetworkPolicy, parseWorldNetworkPolicy, worldNetworkPolicyFromEnv, allowsWorldNetworkEgress };
191
+ module.exports = { PUBLIC_BUILD_READS, READ_METHODS, intersectWorldNetwork, worldNetworkNeedsPathInspection, worldNetworkUsesPassthrough, isWorldInternalHost, worldEgressRefusal, WORLD_NETWORK_POLICY_ENV, normalizeWorldNetwork, createWorldNetworkPolicy, parseWorldNetworkPolicy, worldNetworkPolicyFromEnv, allowsWorldNetworkEgress };
@@ -1,10 +1,15 @@
1
- export interface WorldNetwork { readonly egress: readonly string[] }
1
+ export interface WorldNetwork { readonly egress: readonly string[]; readonly writes?: readonly string[]; readonly phase?: 'build' | 'runtime'; readonly passthrough?: readonly string[]; readonly publicReads?: boolean }
2
2
  export interface WorldNetworkPolicy extends WorldNetwork { readonly version: 1; readonly world: string }
3
3
  export const WORLD_NETWORK_POLICY_ENV: 'VOLTER_WORLD_NETWORK_POLICY';
4
4
  export function normalizeWorldNetwork(value: unknown): WorldNetwork;
5
5
  export function createWorldNetworkPolicy(world: string, network: WorldNetwork): WorldNetworkPolicy;
6
6
  export function parseWorldNetworkPolicy(value: unknown): WorldNetworkPolicy;
7
7
  export function worldNetworkPolicyFromEnv(env: Readonly<Record<string, string | undefined>>): WorldNetworkPolicy | undefined;
8
- export function allowsWorldNetworkEgress(policy: WorldNetworkPolicy, value: string | URL): boolean;
8
+ export const READ_METHODS: readonly string[];
9
+ export const PUBLIC_BUILD_READS: readonly string[];
10
+ export function allowsWorldNetworkEgress(policy: WorldNetworkPolicy, value: string | URL, method?: string): boolean;
9
11
  export function isWorldInternalHost(hostname: string): boolean;
10
- export function worldEgressRefusal(value: string | URL, env?: Readonly<Record<string, string | undefined>>): string | null;
12
+ export function worldEgressRefusal(value: string | URL, env?: Readonly<Record<string, string | undefined>>, method?: string): string | null;
13
+ export function worldNetworkNeedsPathInspection(policy: WorldNetworkPolicy, value: string | URL): boolean;
14
+ export function worldNetworkUsesPassthrough(policy: WorldNetworkPolicy, value: string | URL): boolean;
15
+ export function intersectWorldNetwork(own: WorldNetwork, ceiling: WorldNetwork): WorldNetwork;
@@ -1,3 +1,4 @@
1
+ import { parseExactJson } from "./exact-json.js";
1
2
  // Transaction/action log (scorecard R18) — the semantic correction that separates
2
3
  // OBSERVED facts from LOCAL transaction commits.
3
4
  //
@@ -297,7 +298,7 @@ export function listActions(service, root) {
297
298
  return getActiveWorldStore()
298
299
  .readLines(path)
299
300
  .filter((line) => line.trim())
300
- .map((line) => JSON.parse(line));
301
+ .map((line) => parseExactJson(line));
301
302
  }
302
303
  const META = new Set(['id', 'type', 'updatedAt']);
303
304
  function projectedField(resource, field) {
@@ -36,4 +36,6 @@ export declare function messageSSE(m: Row, extra?: Row, options?: {
36
36
  ping?: boolean;
37
37
  completeToolInput?: boolean;
38
38
  }): string;
39
+ /** An admitted Messages generation failure is an error SSE event, or the native JSON envelope. */
40
+ export declare function messageFailure(error: Row, stream: boolean, requestId?: string): Row | string;
39
41
  export {};
@@ -134,3 +134,8 @@ export function messageSSE(m, extra = {}, options = {}) {
134
134
  send('message_stop', { ...extra });
135
135
  return events.join('');
136
136
  }
137
+ /** An admitted Messages generation failure is an error SSE event, or the native JSON envelope. */
138
+ export function messageFailure(error, stream, requestId) {
139
+ const data = { type: 'error', error, ...(stream ? {} : { request_id: requestId ?? null }) };
140
+ return stream ? `event: error\ndata: ${JSON.stringify(data)}\n\n` : data;
141
+ }
@@ -0,0 +1,6 @@
1
+ /** Verify simulated keyless attestations using the World's certificate and transparency roots.
2
+ * World certificate authorities do not run CT; signing time must still be authenticated by a log witness. */
3
+ export declare function verifyAttestationBundle(bundle: unknown, trust: {
4
+ certificates: readonly string[];
5
+ logKeys: readonly string[];
6
+ }): Promise<void>;
@@ -0,0 +1,27 @@
1
+ // Offline bundle verification against explicit World trust anchors. No network or persistent TUF state.
2
+ import { certificateOf, digest, publicKeyOf } from "./signing.js";
3
+ /** Verify simulated keyless attestations using the World's certificate and transparency roots.
4
+ * World certificate authorities do not run CT; signing time must still be authenticated by a log witness. */
5
+ export async function verifyAttestationBundle(bundle, trust) {
6
+ if (!trust.certificates.length || !trust.logKeys.length)
7
+ throw new Error('Attestation trust anchors are required');
8
+ // B1: protocol libraries are supplied by the pack and load only when the wire is used.
9
+ const [{ bundleFromJSON }, { TrustedRoot }, { toSignedEntity, toTrustMaterial, Verifier }] = await Promise.all([import('@sigstore/bundle'), import('@sigstore/protobuf-specs'), import('@sigstore/verify')]);
10
+ const root = TrustedRoot.fromJSON({ mediaType: 'application/vnd.dev.sigstore.trustedroot+json;version=0.1',
11
+ certificateAuthorities: trust.certificates.map((pem) => {
12
+ const cert = certificateOf(pem);
13
+ if (!cert)
14
+ throw new Error('Invalid attestation certificate root');
15
+ return { certChain: { certificates: [{ rawBytes: Buffer.from(cert.der).toString('base64') }] }, validFor: { start: cert.notBefore, end: cert.notAfter } };
16
+ }),
17
+ tlogs: trust.logKeys.map((pem) => {
18
+ const key = publicKeyOf(pem);
19
+ return {
20
+ hashAlgorithm: 'SHA2_256', logId: { keyId: Buffer.from(digest('sha256', key.der), 'hex').toString('base64') },
21
+ publicKey: { rawBytes: Buffer.from(key.der).toString('base64'), keyDetails: 'PUBLIC_KEY_DETAILS_UNSPECIFIED' },
22
+ };
23
+ }), ctlogs: [], timestampAuthorities: [],
24
+ });
25
+ const entity = toSignedEntity(bundleFromJSON(bundle));
26
+ new Verifier(toTrustMaterial(root), { tlogThreshold: 1, ctlogThreshold: 0 }).verify(entity);
27
+ }
@@ -1,5 +1,8 @@
1
1
  /** The bytes of a gzip member (a SARIF upload, a tarball's contents, a gzipped request body). */
2
2
  export declare function gunzip(bytes: Uint8Array): Promise<Uint8Array>;
3
+ /** Compressed HTTP REQUESTS only: async decoding stops at maxOutputLength during inflation.
4
+ * Return the decoder's own buffer; the request consumes it as a stream without copying it again. */
5
+ export declare function decompress(bytes: Uint8Array, coding: 'gzip' | 'deflate' | 'br' | 'zstd', limit?: number): Promise<Uint8Array>;
3
6
  /** Bytes as a gzip member. */
4
7
  export declare function gzip(bytes: Uint8Array): Promise<Uint8Array>;
5
8
  /** Bytes as a zlib (deflate) member: git's object and pack framing. Reading one back is git/inflate.ts, which also
package/dist/src/bytes.js CHANGED
@@ -4,6 +4,7 @@
4
4
  // `bun -e "typeof CompressionStream"` prints `undefined`), and a local World is served by Bun, so there the builtin is
5
5
  // reached the way the kernel reaches every builtin: `process.getBuiltinModule`, at call time, never at import (the seam
6
6
  // serve-http.ts's `nodeBuiltin` uses).
7
+ import { DEFAULT_MAX_DECODED_REQUEST_BODY_SIZE, RequestBodyTooLargeError } from "./request-body.js";
7
8
  function zlib(what) {
8
9
  const get = globalThis.process?.getBuiltinModule;
9
10
  if (typeof get !== 'function')
@@ -20,6 +21,22 @@ export async function gunzip(bytes) {
20
21
  return streamed(bytes, new DecompressionStream('gzip'));
21
22
  return new Uint8Array(zlib('gunzip').gunzipSync(bytes));
22
23
  }
24
+ /** Compressed HTTP REQUESTS only: async decoding stops at maxOutputLength during inflation.
25
+ * Return the decoder's own buffer; the request consumes it as a stream without copying it again. */
26
+ export async function decompress(bytes, coding, limit = DEFAULT_MAX_DECODED_REQUEST_BODY_SIZE) {
27
+ const builtin = zlib('decompress');
28
+ const decode = { gzip: builtin.gunzip, deflate: builtin.inflate, br: builtin.brotliDecompress, zstd: builtin.zstdDecompress }[coding];
29
+ return new Promise((resolve, reject) => {
30
+ decode(bytes, { maxOutputLength: limit }, (error, body) => {
31
+ if (error)
32
+ reject(error.code === 'ERR_BUFFER_TOO_LARGE' ? new RequestBodyTooLargeError() : error);
33
+ else if (body.byteLength > limit)
34
+ reject(new RequestBodyTooLargeError());
35
+ else
36
+ resolve(body);
37
+ });
38
+ });
39
+ }
23
40
  /** Bytes as a gzip member. */
24
41
  export async function gzip(bytes) {
25
42
  if (typeof CompressionStream === 'function')
@@ -1,3 +1,4 @@
1
+ import { parseExactJson } from "./exact-json.js";
1
2
  import { resolveReferences } from "./references.js";
2
3
  import { withHistoryLocks } from "./ancestry.js";
3
4
  import { captureParentHistory, historyChanges, historyEntries, historyPrefix, readHistoryView } from "./history.js";
@@ -268,7 +269,7 @@ export function parseVerifierExpression(expression, id) {
268
269
  let value;
269
270
  if (raw) {
270
271
  try {
271
- value = JSON.parse(raw);
272
+ value = parseExactJson(raw);
272
273
  }
273
274
  catch {
274
275
  value = raw;
@@ -1,3 +1,4 @@
1
+ import { parseExactJson } from "../exact-json.js";
1
2
  // The kernel's ClickHouse® SQL engine — deterministic, over rows a pack supplies (Tinybird's Data Sources and pipe nodes,
2
3
  // PostHog's events and persons).
3
4
  //
@@ -1442,6 +1443,7 @@ function fnType(e, scope, seen, lambdaTypes) {
1442
1443
  case 'decodeurlformcomponent':
1443
1444
  case 'encodeurlcomponent':
1444
1445
  case 'decodeurlcomponent':
1446
+ case 'extract':
1445
1447
  case 'extracturlparameter':
1446
1448
  case 'jsonextractstring':
1447
1449
  case 'jsonextractraw':
@@ -1543,10 +1545,14 @@ function fnType(e, scope, seen, lambdaTypes) {
1543
1545
  case 'tosecond':
1544
1546
  case 'todayofweek': return 'UInt8';
1545
1547
  case 'todatetime64':
1546
- case 'todatetime64orzero': {
1548
+ case 'todatetime64orzero':
1549
+ case 'parsedatetime64besteffort':
1550
+ case 'parsedatetime64besteffortornull':
1551
+ case 'parsedatetime64besteffortorzero': {
1547
1552
  const scale = e.args[1]?.k === 'lit' ? Number(e.args[1].v) : 3;
1548
1553
  const tz = e.args[2]?.k === 'lit' ? String(e.args[2].v) : undefined;
1549
- return tz ? `DateTime64(${scale}, '${tz}')` : `DateTime64(${scale})`;
1554
+ const type = tz ? `DateTime64(${scale}, '${tz}')` : `DateTime64(${scale})`;
1555
+ return name.endsWith('ornull') ? `Nullable(${type})` : type;
1550
1556
  }
1551
1557
  case 'todatetime':
1552
1558
  case 'now':
@@ -1560,7 +1566,8 @@ function fnType(e, scope, seen, lambdaTypes) {
1560
1566
  case 'parsedatetimebesteffortornull': {
1561
1567
  const tzArg = name === 'now' ? a0 : e.args[1];
1562
1568
  const tz = tzArg?.k === 'lit' ? String(tzArg.v) : undefined;
1563
- return tz ? `DateTime('${tz}')` : 'DateTime';
1569
+ const type = tz ? `DateTime('${tz}')` : 'DateTime';
1570
+ return name.endsWith('ornull') ? `Nullable(${type})` : type;
1564
1571
  }
1565
1572
  case 'now64': return 'DateTime64(3)';
1566
1573
  case 'todate':
@@ -2167,7 +2174,7 @@ function jsonPathValue(json, keys) {
2167
2174
  let cur;
2168
2175
  if (typeof json === 'string') {
2169
2176
  try {
2170
- cur = JSON.parse(json);
2177
+ cur = parseExactJson(json, (digits) => BigInt(digits));
2171
2178
  }
2172
2179
  catch {
2173
2180
  return undefined;
@@ -2518,6 +2525,23 @@ function evalFunction(e, env) {
2518
2525
  const pad = fill.repeat(Math.ceil((n - s.length) / Math.max(1, fill.length))).slice(0, n - s.length);
2519
2526
  return name === 'leftpad' ? pad + s : s + pad;
2520
2527
  }
2528
+ // ClickHouse string-search-functions#extract: first capturing group, otherwise the whole first match.
2529
+ case 'extract': {
2530
+ argc(2);
2531
+ const haystack = A(0), pattern = A(1);
2532
+ if (haystack === null || pattern === null)
2533
+ return null;
2534
+ if (typeof haystack !== 'string' || typeof pattern !== 'string')
2535
+ return fail('Illegal type of argument of function extract: expected String');
2536
+ let match;
2537
+ try {
2538
+ match = new RegExp(valueToText(pattern)).exec(valueToText(haystack));
2539
+ }
2540
+ catch {
2541
+ return fail('Cannot compile re2: ' + valueToText(pattern));
2542
+ }
2543
+ return match ? (match.length > 1 ? match[1] ?? '' : match[0]) : '';
2544
+ }
2521
2545
  case 'match': {
2522
2546
  argc(2);
2523
2547
  const s = A(0);
@@ -2667,15 +2691,17 @@ function evalFunction(e, env) {
2667
2691
  if (j === null)
2668
2692
  return null;
2669
2693
  const keys = e.args.slice(1).map((_, i) => A(i + 1));
2670
- const v = jsonPathValue(typeof j === 'string' ? j : JSON.stringify(j), keys);
2694
+ const v = jsonPathValue(typeof j === 'string' ? j : stringifyJson(j), keys);
2671
2695
  if (name === 'jsonhas')
2672
2696
  return v === undefined ? 0 : 1;
2673
2697
  if (name === 'jsonextractstring')
2674
2698
  return typeof v === 'string' ? v : '';
2675
2699
  if (name === 'jsonextractraw')
2676
- return v === undefined ? '' : JSON.stringify(v);
2700
+ return v === undefined ? '' : stringifyJson(v);
2677
2701
  if (name === 'jsonextractbool')
2678
2702
  return v === true ? 1 : 0;
2703
+ if (typeof v === 'bigint')
2704
+ return name === 'jsonextractint' ? normInt(v) : Number(v);
2679
2705
  if (typeof v === 'number')
2680
2706
  return name === 'jsonextractint' ? Math.trunc(v) : v;
2681
2707
  if (typeof v === 'boolean')
@@ -2739,7 +2765,7 @@ function evalFunction(e, env) {
2739
2765
  case 'abs': {
2740
2766
  argc(1);
2741
2767
  const v = A(0);
2742
- return v === null ? null : Math.abs(asNumber(v));
2768
+ return v === null ? null : typeof v === 'bigint' ? normInt(v < 0n ? -v : v) : Math.abs(asNumber(v));
2743
2769
  }
2744
2770
  case 'intdiv': {
2745
2771
  argc(2);
@@ -2747,6 +2773,12 @@ function evalFunction(e, env) {
2747
2773
  const b = A(1);
2748
2774
  if (a === null || b === null)
2749
2775
  return null;
2776
+ if (isExactInt(a) && isExactInt(b)) {
2777
+ const divisor = toBigInt(b);
2778
+ if (divisor === 0n)
2779
+ fail('Division by zero');
2780
+ return normInt(toBigInt(a) / divisor);
2781
+ }
2750
2782
  if (asNumber(b) === 0)
2751
2783
  fail('Division by zero');
2752
2784
  return Math.trunc(asNumber(a) / asNumber(b));
@@ -2791,7 +2823,6 @@ function evalFunction(e, env) {
2791
2823
  }
2792
2824
  case 'todatetime':
2793
2825
  case 'parsedatetimebesteffort':
2794
- case 'parsedatetime64besteffort':
2795
2826
  case 'parsedatetimebesteffortornull': {
2796
2827
  argc(1, 2);
2797
2828
  const v = A(0);
@@ -2806,7 +2837,30 @@ function evalFunction(e, env) {
2806
2837
  return null;
2807
2838
  }
2808
2839
  }
2809
- return castDateTime(v, name === 'parsedatetime64besteffort' ? 3 : 0, tz);
2840
+ return castDateTime(v, 0, tz);
2841
+ }
2842
+ // https://clickhouse.com/docs/en/sql-reference/functions/type-conversion-functions#parseDateTime64BestEffort
2843
+ case 'parsedatetime64besteffort':
2844
+ case 'parsedatetime64besteffortornull':
2845
+ case 'parsedatetime64besteffortorzero': {
2846
+ argc(1, 3);
2847
+ const v = A(0);
2848
+ if (v === null)
2849
+ return null;
2850
+ if (typeof v !== 'string')
2851
+ fail('Illegal type of argument of function ' + e.name + ': expected String');
2852
+ const scale = e.args.length > 1 ? asNumber(A(1)) : 3;
2853
+ const tz = e.args.length > 2 ? tzArg(e, 2, env) : undefined;
2854
+ try {
2855
+ return castDateTime(v, scale, tz);
2856
+ }
2857
+ catch (error) {
2858
+ if (name === 'parsedatetime64besteffortornull')
2859
+ return null;
2860
+ if (name === 'parsedatetime64besteffortorzero')
2861
+ return new DT(0, scale, tz);
2862
+ throw error;
2863
+ }
2810
2864
  }
2811
2865
  case 'todatetime64':
2812
2866
  case 'todatetime64orzero': {
@@ -3214,7 +3268,7 @@ function evalFunction(e, env) {
3214
3268
  const arr = A(0);
3215
3269
  if (arr === null)
3216
3270
  return null;
3217
- return name === 'arraysum' ? arr.reduce((s, x) => s + (asNumber(x) ?? 0), 0) : arr.filter((x) => truth(x) === true).length;
3271
+ return name === 'arraysum' ? sumArray(arr) : arr.filter((x) => truth(x) === true).length;
3218
3272
  }
3219
3273
  return fail(`${e.name}: first argument must be a lambda`);
3220
3274
  }
@@ -3232,7 +3286,7 @@ function evalFunction(e, env) {
3232
3286
  if (name === 'arrayall')
3233
3287
  return results.every((r) => truth(r) === true) ? 1 : 0;
3234
3288
  if (name === 'arraysum')
3235
- return results.reduce((s, x) => s + (asNumber(x) ?? 0), 0);
3289
+ return sumArray(results);
3236
3290
  const i = results.findIndex((r) => truth(r) === true);
3237
3291
  return i < 0 ? arrayAt(arrays[0], 0) : arrays[0][i];
3238
3292
  }
@@ -3249,6 +3303,11 @@ function evalFunction(e, env) {
3249
3303
  return fail(`Unknown function ${e.name}`);
3250
3304
  }
3251
3305
  }
3306
+ function sumArray(values) {
3307
+ const held = values.filter((value) => value !== null && value !== undefined);
3308
+ return held.every(isExactInt) ? normInt(held.reduce((sum, value) => sum + toBigInt(value), 0n))
3309
+ : held.reduce((sum, value) => sum + (asNumber(value) ?? 0), 0);
3310
+ }
3252
3311
  function roundHalfEven(x) {
3253
3312
  const r = Math.round(x);
3254
3313
  return Math.abs(x % 1) === 0.5 && r % 2 !== 0 ? r - 1 : r;
@@ -3498,13 +3557,13 @@ const SCALAR_FUNCTIONS = new Set([
3498
3557
  'arraypushback', 'arraypushfront', 'arrayreverse', 'arrayreversesort', 'arrayslice', 'arraysort', 'arraystringconcat', 'arraysum',
3499
3558
  'assumenotnull', 'base64decode', 'base64encode', 'ceil', 'ceiling', 'char_length', 'coalesce', 'concat', 'cutquerystring', 'date_bin',
3500
3559
  'date_diff', 'datediff', 'decodeurlcomponent', 'decodeurlformcomponent', 'divide', 'domain', 'domainwithoutwww', 'empty',
3501
- 'encodeurlcomponent', 'encodeurlformcomponent', 'endswith', 'equals', 'extracturlparameter', 'extracturlparameternames', 'floor', 'formatdatetime',
3560
+ 'encodeurlcomponent', 'encodeurlformcomponent', 'endswith', 'equals', 'extract', 'extracturlparameter', 'extracturlparameternames', 'floor', 'formatdatetime',
3502
3561
  'mapcontains', 'mapcontainskey', 'mapfilter', 'mapkeys', 'mapvalues',
3503
3562
  'fromunixtimestamp', 'fromunixtimestamp64micro', 'fromunixtimestamp64milli', 'fromunixtimestamp64nano', 'greatest', 'has', 'hasall',
3504
3563
  'hasany', 'hex', 'identity', 'if', 'ifnull', 'indexof', 'intdiv', 'isnotnull', 'isnull', 'jsonextractbool', 'jsonextractfloat',
3505
3564
  'jsonextractint', 'jsonextractraw', 'jsonextractstring', 'jsonhas', 'lcase', 'least', 'leftpad', 'length', 'lengthutf8', 'locate',
3506
3565
  'lower', 'lowerutf8', 'ltrim', 'match', 'materialize', 'mid', 'minus', 'modulo', 'multiif', 'multiply', 'notempty', 'notequals', 'now',
3507
- 'now64', 'nullif', 'parsedatetime64besteffort', 'parsedatetimebesteffort', 'parsedatetimebesteffortornull', 'path', 'plus',
3566
+ 'now64', 'nullif', 'parsedatetime64besteffort', 'parsedatetime64besteffortornull', 'parsedatetime64besteffortorzero', 'parsedatetimebesteffort', 'parsedatetimebesteffortornull', 'path', 'plus',
3508
3567
  'position', 'pow', 'power', 'range', 'replace', 'replaceall', 'replaceone', 'replaceregexpall', 'replaceregexpone', 'reverse',
3509
3568
  'rightpad', 'round', 'rtrim', 'splitbychar', 'splitbystring', 'sqrt', 'startswith', 'substr', 'substring', 'subtractdays',
3510
3569
  'subtracthours', 'subtractminutes', 'subtractmonths', 'subtractseconds', 'subtractweeks', 'subtractyears', 'time_bucket',
@@ -3521,7 +3580,7 @@ const INTERVAL_FUNCTIONS = new Set(['millisecond', 'second', 'minute', 'hour', '
3521
3580
  const STRING_FUNCTIONS = new Set([
3522
3581
  'tostring', 'concat', 'replace', 'replaceall', 'replaceone', 'replaceregexpall', 'replaceregexpone', 'lower', 'upper', 'lowerutf8',
3523
3582
  'upperutf8', 'substring', 'substr', 'trim', 'trimboth', 'trimleft', 'trimright', 'encodeurlformcomponent', 'decodeurlformcomponent',
3524
- 'encodeurlcomponent', 'decodeurlcomponent', 'extracturlparameter', 'jsonextractstring', 'jsonextractraw', 'formatdatetime', 'domain',
3583
+ 'encodeurlcomponent', 'decodeurlcomponent', 'extract', 'extracturlparameter', 'jsonextractstring', 'jsonextractraw', 'formatdatetime', 'domain',
3525
3584
  'domainwithoutwww', 'path', 'cutquerystring', 'leftpad', 'rightpad', 'base64encode', 'base64decode', 'hex', 'totypename',
3526
3585
  ]);
3527
3586
  export function isKnownFunction(name) {