toiljs 0.0.116 → 0.0.118

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 (337) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +16 -7
  3. package/build/backend/.tsbuildinfo +1 -1
  4. package/build/cli/.tsbuildinfo +1 -1
  5. package/build/cli/index.js +2375 -258
  6. package/build/client/.tsbuildinfo +1 -1
  7. package/build/client/auth.d.ts +3 -0
  8. package/build/client/auth.js +19 -10
  9. package/build/client/dev/devtools.js +1 -1
  10. package/build/client/dev/error-overlay.js +1 -1
  11. package/build/client/index.d.ts +1 -1
  12. package/build/client/index.js +1 -1
  13. package/build/client/navigation/navigation.js +28 -3
  14. package/build/client/routing/Router.js +5 -2
  15. package/build/client/routing/mount.js +1 -1
  16. package/build/compiler/.tsbuildinfo +1 -1
  17. package/build/compiler/auth-emails.js +7 -3
  18. package/build/compiler/emails.js +1 -1
  19. package/build/compiler/index.d.ts +1 -0
  20. package/build/compiler/index.js +26 -5
  21. package/build/compiler/pages.js +2 -3
  22. package/build/compiler/prerender.d.ts +3 -8
  23. package/build/compiler/prerender.js +88 -127
  24. package/build/compiler/ssg.js +3 -4
  25. package/build/compiler/template-build.js +3 -4
  26. package/build/compiler/toil-docs.generated.js +8 -7
  27. package/build/compiler/vite.js +4 -6
  28. package/build/devserver/.tsbuildinfo +1 -1
  29. package/build/devserver/db/database.js +7 -3
  30. package/build/devserver/db/types.js +1 -1
  31. package/build/devserver/production.js +4 -3
  32. package/build/devserver/runtime/crypto.d.ts +1 -1
  33. package/build/io/.tsbuildinfo +1 -1
  34. package/build/logger/.tsbuildinfo +1 -1
  35. package/build/shared/.tsbuildinfo +1 -1
  36. package/examples/basic/client/routes/analytics.tsx +7 -5
  37. package/examples/basic/client/routes/pq.tsx +2 -1
  38. package/examples/basic/server/tsconfig.json +1 -3
  39. package/package.json +45 -44
  40. package/presets/no-uint8array-tostring.js +120 -153
  41. package/presets/oxlint.d.ts +5 -0
  42. package/presets/oxlint.js +224 -0
  43. package/server/auth/AuthController.ts +53 -14
  44. package/server/auth/FactorSettings.ts +41 -0
  45. package/server/auth/SessionEpochs.ts +58 -0
  46. package/server/auth/SessionRevocations.ts +13 -0
  47. package/server/globals/auth.ts +27 -2
  48. package/server/runtime/tsconfig.json +1 -3
  49. package/tsconfig.json +2 -11
  50. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  51. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
  52. package/.github/ISSUE_TEMPLATE/config.yml +0 -8
  53. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  54. package/.github/PULL_REQUEST_TEMPLATE.md +0 -43
  55. package/.github/changelog-config.json +0 -45
  56. package/.github/dependabot.yml +0 -27
  57. package/.github/workflows/ci.yml +0 -222
  58. package/.vscode/settings.json +0 -10
  59. package/docs/README.md +0 -107
  60. package/docs/auth/README.md +0 -104
  61. package/docs/auth/configuration.md +0 -105
  62. package/docs/auth/emails.md +0 -92
  63. package/docs/auth/extending.md +0 -202
  64. package/docs/auth/how-it-works.md +0 -138
  65. package/docs/auth/usage.md +0 -188
  66. package/docs/backend/README.md +0 -143
  67. package/docs/backend/data.md +0 -351
  68. package/docs/backend/rest.md +0 -402
  69. package/docs/backend/rpc.md +0 -226
  70. package/docs/background/README.md +0 -114
  71. package/docs/background/daemons.md +0 -276
  72. package/docs/background/derive.md +0 -179
  73. package/docs/cli/README.md +0 -379
  74. package/docs/concepts/ai-guide.md +0 -132
  75. package/docs/concepts/config.md +0 -416
  76. package/docs/concepts/decorators.md +0 -127
  77. package/docs/concepts/security.md +0 -108
  78. package/docs/concepts/tiers.md +0 -166
  79. package/docs/concepts/types.md +0 -216
  80. package/docs/database/README.md +0 -143
  81. package/docs/database/capacity.md +0 -350
  82. package/docs/database/counters.md +0 -174
  83. package/docs/database/documents.md +0 -277
  84. package/docs/database/events.md +0 -307
  85. package/docs/database/membership.md +0 -246
  86. package/docs/database/setup.md +0 -155
  87. package/docs/database/unique.md +0 -216
  88. package/docs/database/views.md +0 -246
  89. package/docs/frontend/README.md +0 -104
  90. package/docs/frontend/components.md +0 -286
  91. package/docs/frontend/data-fetching.md +0 -260
  92. package/docs/frontend/images.md +0 -148
  93. package/docs/frontend/metadata.md +0 -344
  94. package/docs/frontend/navigation.md +0 -296
  95. package/docs/frontend/rendering.md +0 -236
  96. package/docs/frontend/routing.md +0 -346
  97. package/docs/frontend/scripts.md +0 -118
  98. package/docs/frontend/search.md +0 -191
  99. package/docs/frontend/styling.md +0 -147
  100. package/docs/frontend/toil-global.md +0 -216
  101. package/docs/getting-started/README.md +0 -81
  102. package/docs/getting-started/create-project.md +0 -131
  103. package/docs/getting-started/deploy.md +0 -101
  104. package/docs/getting-started/first-app.md +0 -215
  105. package/docs/getting-started/installation.md +0 -124
  106. package/docs/getting-started/migrating.md +0 -125
  107. package/docs/getting-started/project-structure.md +0 -163
  108. package/docs/introduction/README.md +0 -66
  109. package/docs/introduction/design-principles.md +0 -81
  110. package/docs/introduction/distributed.md +0 -91
  111. package/docs/introduction/how-it-works.md +0 -121
  112. package/docs/introduction/hyperscale.md +0 -70
  113. package/docs/introduction/modern-stack.md +0 -85
  114. package/docs/introduction/vs-other-frameworks.md +0 -64
  115. package/docs/introduction/why-toil.md +0 -99
  116. package/docs/llms.txt +0 -95
  117. package/docs/realtime/README.md +0 -102
  118. package/docs/realtime/channels.md +0 -211
  119. package/docs/realtime/streams.md +0 -369
  120. package/docs/services/README.md +0 -60
  121. package/docs/services/analytics.md +0 -279
  122. package/docs/services/caching.md +0 -175
  123. package/docs/services/cookies.md +0 -235
  124. package/docs/services/crypto.md +0 -209
  125. package/docs/services/email.md +0 -289
  126. package/docs/services/environment.md +0 -141
  127. package/docs/services/ratelimit.md +0 -174
  128. package/docs/services/time.md +0 -85
  129. package/eslint.config.js +0 -57
  130. package/examples/basic/client/routes/docs/[...slug].tsx +0 -12
  131. package/presets/eslint.js +0 -88
  132. package/src/backend/index.ts +0 -204
  133. package/src/cli/configure.ts +0 -363
  134. package/src/cli/create.ts +0 -924
  135. package/src/cli/db.ts +0 -158
  136. package/src/cli/diagnostics.ts +0 -665
  137. package/src/cli/doctor.ts +0 -982
  138. package/src/cli/features.ts +0 -170
  139. package/src/cli/index.ts +0 -326
  140. package/src/cli/notify.ts +0 -120
  141. package/src/cli/proc.ts +0 -56
  142. package/src/cli/ui.ts +0 -169
  143. package/src/cli/update.ts +0 -248
  144. package/src/cli/updates.ts +0 -92
  145. package/src/cli/validate.ts +0 -31
  146. package/src/cli/version-check.ts +0 -125
  147. package/src/client/auth.ts +0 -869
  148. package/src/client/channel/channel.ts +0 -146
  149. package/src/client/components/Form.tsx +0 -65
  150. package/src/client/components/Image.tsx +0 -160
  151. package/src/client/components/Script.tsx +0 -113
  152. package/src/client/components/Slot.tsx +0 -21
  153. package/src/client/dev/devtools.tsx +0 -1089
  154. package/src/client/dev/error-overlay.tsx +0 -225
  155. package/src/client/errors.ts +0 -11
  156. package/src/client/head/head.ts +0 -182
  157. package/src/client/head/metadata.ts +0 -110
  158. package/src/client/index.ts +0 -130
  159. package/src/client/navigation/Link.tsx +0 -108
  160. package/src/client/navigation/NavLink.tsx +0 -86
  161. package/src/client/navigation/navigation.ts +0 -235
  162. package/src/client/navigation/prefetch.ts +0 -169
  163. package/src/client/navigation/scroll.ts +0 -53
  164. package/src/client/routing/Router.tsx +0 -216
  165. package/src/client/routing/action.ts +0 -122
  166. package/src/client/routing/error-boundary.tsx +0 -43
  167. package/src/client/routing/hooks.ts +0 -140
  168. package/src/client/routing/lazy.ts +0 -77
  169. package/src/client/routing/loader.ts +0 -381
  170. package/src/client/routing/match.ts +0 -47
  171. package/src/client/routing/mount.tsx +0 -90
  172. package/src/client/routing/params-context.ts +0 -10
  173. package/src/client/routing/slot-context.ts +0 -7
  174. package/src/client/rpc.ts +0 -97
  175. package/src/client/search/search.ts +0 -189
  176. package/src/client/search/use-page-search.ts +0 -73
  177. package/src/client/ssr/markers.tsx +0 -172
  178. package/src/client/stream/client.ts +0 -237
  179. package/src/client/types.ts +0 -73
  180. package/src/compiler/auth-emails.ts +0 -312
  181. package/src/compiler/config.ts +0 -369
  182. package/src/compiler/docs.ts +0 -127
  183. package/src/compiler/email-preview.ts +0 -314
  184. package/src/compiler/emails.ts +0 -404
  185. package/src/compiler/fonts.ts +0 -89
  186. package/src/compiler/generate.ts +0 -471
  187. package/src/compiler/image-blur.ts +0 -42
  188. package/src/compiler/image-report.ts +0 -88
  189. package/src/compiler/index.ts +0 -1362
  190. package/src/compiler/pages.ts +0 -49
  191. package/src/compiler/plugin.ts +0 -391
  192. package/src/compiler/prerender.ts +0 -263
  193. package/src/compiler/routes.ts +0 -170
  194. package/src/compiler/seo.ts +0 -415
  195. package/src/compiler/sri.ts +0 -144
  196. package/src/compiler/ssg.ts +0 -177
  197. package/src/compiler/ssr-codegen.ts +0 -85
  198. package/src/compiler/template-build.ts +0 -676
  199. package/src/compiler/template.ts +0 -262
  200. package/src/compiler/toil-docs.generated.ts +0 -77
  201. package/src/compiler/vite.ts +0 -245
  202. package/src/devserver/analytics/index.ts +0 -317
  203. package/src/devserver/config/dotenv.ts +0 -102
  204. package/src/devserver/config/env.ts +0 -30
  205. package/src/devserver/config/ratelimit.ts +0 -123
  206. package/src/devserver/daemon/catalog.ts +0 -120
  207. package/src/devserver/daemon/cron.ts +0 -87
  208. package/src/devserver/daemon/host.ts +0 -134
  209. package/src/devserver/daemon/index.ts +0 -369
  210. package/src/devserver/daemon/runtime.ts +0 -48
  211. package/src/devserver/db/catalog.ts +0 -109
  212. package/src/devserver/db/database.ts +0 -1834
  213. package/src/devserver/db/derives.ts +0 -121
  214. package/src/devserver/db/index.ts +0 -20
  215. package/src/devserver/db/routeKinds.ts +0 -191
  216. package/src/devserver/db/types.ts +0 -168
  217. package/src/devserver/email/caps.ts +0 -0
  218. package/src/devserver/email/config.ts +0 -141
  219. package/src/devserver/email/console.ts +0 -348
  220. package/src/devserver/email/index.ts +0 -155
  221. package/src/devserver/email/providers.ts +0 -131
  222. package/src/devserver/email/status.ts +0 -23
  223. package/src/devserver/email/validate.ts +0 -37
  224. package/src/devserver/email/wire.ts +0 -55
  225. package/src/devserver/http/cache.ts +0 -0
  226. package/src/devserver/http/envelope.ts +0 -157
  227. package/src/devserver/http/proxy.ts +0 -172
  228. package/src/devserver/http/runtime.ts +0 -387
  229. package/src/devserver/index.ts +0 -43
  230. package/src/devserver/production-ipc.ts +0 -63
  231. package/src/devserver/production-worker.ts +0 -83
  232. package/src/devserver/production.ts +0 -718
  233. package/src/devserver/runtime/crypto.ts +0 -587
  234. package/src/devserver/runtime/host.ts +0 -427
  235. package/src/devserver/runtime/module.ts +0 -442
  236. package/src/devserver/server.ts +0 -251
  237. package/src/devserver/ssr.ts +0 -208
  238. package/src/devserver/stream/catalog.ts +0 -106
  239. package/src/devserver/stream/host.ts +0 -42
  240. package/src/devserver/stream/index.ts +0 -301
  241. package/src/devserver/stream/manager.ts +0 -167
  242. package/src/devserver/stream/router.ts +0 -101
  243. package/src/devserver/stream/wire.ts +0 -58
  244. package/src/devserver/stream/ws.ts +0 -78
  245. package/src/devserver/wasm/sections.ts +0 -59
  246. package/src/devserver/wasm/surface.ts +0 -115
  247. package/src/io/FastMap.ts +0 -151
  248. package/src/io/FastSet.ts +0 -113
  249. package/src/io/codec.ts +0 -362
  250. package/src/io/index.ts +0 -10
  251. package/src/io/lengths.ts +0 -14
  252. package/src/io/types.ts +0 -19
  253. package/src/logger/index.ts +0 -22
  254. package/src/shared/index.ts +0 -46
  255. package/test/analytics-dev.test.ts +0 -113
  256. package/test/assembly/aspect-shim.ts +0 -33
  257. package/test/assembly/cookie.spec.ts +0 -303
  258. package/test/assembly/example.spec.ts +0 -22
  259. package/test/assembly/ssr.spec.ts +0 -95
  260. package/test/assembly.test.ts +0 -59
  261. package/test/auth-emails.test.ts +0 -118
  262. package/test/built-ssr.test.ts +0 -148
  263. package/test/channel.test.ts +0 -21
  264. package/test/config-host-port.test.ts +0 -59
  265. package/test/configure.test.ts +0 -94
  266. package/test/daemon-build.test.ts +0 -278
  267. package/test/daemon-catalog.test.ts +0 -349
  268. package/test/daemon-emulation.test.ts +0 -256
  269. package/test/db.test.ts +0 -0
  270. package/test/devserver-database.test.ts +0 -1102
  271. package/test/devserver-email.test.ts +0 -306
  272. package/test/devserver-pqauth.test.ts +0 -93
  273. package/test/devserver-secrets.test.ts +0 -63
  274. package/test/devserver.test.ts +0 -259
  275. package/test/doctor.test.ts +0 -298
  276. package/test/dom/Image.test.tsx +0 -144
  277. package/test/dom/Link.test.tsx +0 -67
  278. package/test/dom/NavLink.test.tsx +0 -37
  279. package/test/dom/Script.test.tsx +0 -48
  280. package/test/dom/action.test.tsx +0 -146
  281. package/test/dom/error-overlay.test.tsx +0 -44
  282. package/test/dom/loader.test.tsx +0 -121
  283. package/test/dom/navigation.test.ts +0 -59
  284. package/test/dom/revalidate.test.tsx +0 -38
  285. package/test/dom/route-head.test.tsx +0 -56
  286. package/test/dom/router-loading.test.tsx +0 -44
  287. package/test/dom/scroll.test.ts +0 -56
  288. package/test/dom/slot.test.tsx +0 -131
  289. package/test/dom/use-metadata.test.tsx +0 -58
  290. package/test/dom/view-transitions.test.tsx +0 -53
  291. package/test/dynamic-routing.test.ts +0 -132
  292. package/test/email-console.test.ts +0 -86
  293. package/test/email-preview.test.ts +0 -73
  294. package/test/emails.test.ts +0 -58
  295. package/test/errors.test.ts +0 -21
  296. package/test/example-guestbook.test.ts +0 -123
  297. package/test/features.test.ts +0 -149
  298. package/test/fixtures/bignum-wire/spec.ts +0 -25
  299. package/test/fixtures/daemon-app.ts +0 -65
  300. package/test/fixtures/stream-echo.ts +0 -26
  301. package/test/fixtures/stream-gate.ts +0 -28
  302. package/test/fixtures/stream-trap.ts +0 -18
  303. package/test/fixtures/stream-typed.ts +0 -41
  304. package/test/fonts.test.ts +0 -28
  305. package/test/global-setup.ts +0 -17
  306. package/test/head.test.ts +0 -42
  307. package/test/image-blur.test.ts +0 -50
  308. package/test/io.test.ts +0 -117
  309. package/test/metadata.test.ts +0 -40
  310. package/test/navlink.test.ts +0 -28
  311. package/test/pages.test.ts +0 -105
  312. package/test/placeholder.test.ts +0 -9
  313. package/test/pqauth-e2e.test.ts +0 -216
  314. package/test/pqauth-email.test.ts +0 -801
  315. package/test/prerender.test.ts +0 -116
  316. package/test/prettier-plugin.test.ts +0 -46
  317. package/test/routes.test.ts +0 -76
  318. package/test/rpc-bignum-wire.test.ts +0 -164
  319. package/test/rpc-dispatch.test.ts +0 -132
  320. package/test/rpc-kinds.test.ts +0 -18
  321. package/test/rpc.test.ts +0 -66
  322. package/test/search.test.ts +0 -114
  323. package/test/seo.test.ts +0 -175
  324. package/test/slot-layouts.test.ts +0 -69
  325. package/test/sri.test.ts +0 -129
  326. package/test/ssg.test.ts +0 -36
  327. package/test/ssr-hydration.test.tsx +0 -122
  328. package/test/ssr-render.test.ts +0 -197
  329. package/test/ssr-template.test.tsx +0 -482
  330. package/test/stream-emulation.test.ts +0 -479
  331. package/test/ui.test.ts +0 -40
  332. package/test/update.test.ts +0 -58
  333. package/test/validate.test.ts +0 -42
  334. package/test/version-check.test.ts +0 -130
  335. package/tests/data-parity/generated-parity.ts +0 -99
  336. package/tests/data-parity/parity.ts +0 -80
  337. package/tests/data-parity/spec.ts +0 -46
@@ -1,587 +0,0 @@
1
- /**
2
- * Dev-server mock of the `env.crypto.*` host functions, mirroring the
3
- * production edge (`toil-backend/src/wasm/host/import_functions/crypto`) and the
4
- * toilscript std ABI (`std/assembly/crypto/algorithms.ts`). Backed by Node's
5
- * `crypto`. The dev server intentionally skips the edge's metering, so these
6
- * charge nothing; results must still be byte-identical to the edge for the
7
- * common algorithms.
8
- *
9
- * Variable-length results use the same two-step pull as the edge: the op
10
- * returns the length and stashes the bytes; the guest then calls `take_result`.
11
- *
12
- * Dev-only limitations: raw-format import of asymmetric keys (EC/Ed25519/
13
- * X25519) returns the "unsupported" code (-3) here because Node can't import a
14
- * bare key without DER; use pkcs8/spki in the dev server. The production edge
15
- * supports raw too. These are catchable guest-side errors, never crashes.
16
- */
17
-
18
- import * as nodeCrypto from 'node:crypto';
19
-
20
- import { ml_dsa44 } from '@dacely/noble-post-quantum/ml-dsa.js';
21
- import { ml_kem768 } from '@dacely/noble-post-quantum/ml-kem.js';
22
- import { ristretto255_oprf } from '@noble/curves/ed25519.js';
23
-
24
- import type { MemoryRef } from './host.js';
25
-
26
- // --- ABI id tables (must match the std + Rust backend) ----------------------
27
- const ALG = {
28
- SHA1: 1,
29
- SHA256: 2,
30
- SHA384: 3,
31
- SHA512: 4,
32
- SHA3_256: 5,
33
- SHA3_384: 6,
34
- SHA3_512: 7,
35
- AES_GCM: 10,
36
- AES_CBC: 11,
37
- AES_CTR: 12,
38
- AES_KW: 13,
39
- HMAC: 20,
40
- ECDSA: 32,
41
- ED25519: 33,
42
- ECDH: 50,
43
- X25519: 51,
44
- HKDF: 52,
45
- PBKDF2: 53,
46
- } as const;
47
- const FMT = { RAW: 0, PKCS8: 1, SPKI: 2, JWK: 3 } as const;
48
-
49
- // Recoverable error codes (negative returns).
50
- const ERR_GENERIC = -1;
51
- const ERR_UNSUPPORTED = -3;
52
- const ERR_INVALID_PARAMS = -4;
53
- const ERR_OPERATION_FAILED = -5;
54
- const ERR_NOT_EXTRACTABLE = -7;
55
-
56
- const MAX_OUTPUT = 1024 * 1024;
57
-
58
- interface KeyEntry {
59
- /** Raw bytes for symmetric/MAC/KDF keys. */
60
- raw: Buffer | null;
61
- /** Node KeyObject for asymmetric keys. */
62
- keyObject: nodeCrypto.KeyObject | null;
63
- alg: number;
64
- hash: number;
65
- extractable: boolean;
66
- isPrivate: boolean;
67
- }
68
-
69
- export interface CryptoState {
70
- keys: Map<number, KeyEntry>;
71
- nextHandle: number;
72
- lastResult: Buffer | null;
73
- }
74
-
75
- export function freshCryptoState(): CryptoState {
76
- return { keys: new Map(), nextHandle: 1, lastResult: null };
77
- }
78
-
79
- function memBuf(ref: MemoryRef): Buffer {
80
- if (!ref.memory) throw new Error('crypto host import called before memory was bound');
81
- return Buffer.from(ref.memory.buffer);
82
- }
83
-
84
- function readBytes(ref: MemoryRef, ptr: number, len: number): Buffer {
85
- const m = memBuf(ref);
86
- if (ptr < 0 || len < 0 || ptr + len > m.length)
87
- throw new Error(`crypto read out of bounds: ptr=${String(ptr)} len=${String(len)}`);
88
- // Copy out so later writes/grows can't alias the input.
89
- return Buffer.from(m.subarray(ptr, ptr + len));
90
- }
91
-
92
- function writeBytes(ref: MemoryRef, ptr: number, bytes: Buffer | Uint8Array): void {
93
- const m = memBuf(ref);
94
- if (ptr < 0 || ptr + bytes.length > m.length)
95
- throw new Error(
96
- `crypto write out of bounds: ptr=${String(ptr)} len=${String(bytes.length)}`,
97
- );
98
- m.set(bytes, ptr);
99
- }
100
-
101
- /** Little-endian reader over a packed params buffer (mirrors the Rust ParamReader). */
102
- class ParamReader {
103
- private pos = 0;
104
- constructor(private readonly buf: Buffer) {}
105
-
106
- readI32(): number {
107
- this.need(4);
108
- const v = this.buf.readInt32LE(this.pos);
109
- this.pos += 4;
110
- return v;
111
- }
112
-
113
- readU32(): number {
114
- this.need(4);
115
- const v = this.buf.readUInt32LE(this.pos);
116
- this.pos += 4;
117
- return v;
118
- }
119
-
120
- readBlob(): Buffer {
121
- const n = this.readU32();
122
- this.need(n);
123
- const s = Buffer.from(this.buf.subarray(this.pos, this.pos + n));
124
- this.pos += n;
125
- return s;
126
- }
127
-
128
- /** Bounds-check before a read so a malformed buffer throws a controlled
129
- * error (trap-equivalent, caught by the dispatcher) rather than a raw
130
- * Node RangeError. */
131
- private need(n: number): void {
132
- if (n < 0 || this.pos + n > this.buf.length)
133
- throw new Error('crypto: malformed params buffer (truncated)');
134
- }
135
- }
136
-
137
- function hashName(id: number): string {
138
- switch (id) {
139
- case ALG.SHA1:
140
- return 'sha1';
141
- case ALG.SHA256:
142
- return 'sha256';
143
- case ALG.SHA384:
144
- return 'sha384';
145
- case ALG.SHA512:
146
- return 'sha512';
147
- case ALG.SHA3_256:
148
- return 'sha3-256';
149
- case ALG.SHA3_384:
150
- return 'sha3-384';
151
- case ALG.SHA3_512:
152
- return 'sha3-512';
153
- default:
154
- throw new Error(`crypto: bad hash id ${String(id)}`);
155
- }
156
- }
157
-
158
- function stash(state: CryptoState, bytes: Buffer): number {
159
- state.lastResult = bytes;
160
- return bytes.length;
161
- }
162
-
163
- /**
164
- * Build the `env.crypto.*` import functions. `state.crypto` holds the per-
165
- * dispatch keystore + result scratch.
166
- */
167
- export function buildCryptoImports(
168
- ref: MemoryRef,
169
- cs: CryptoState,
170
- ): Record<string, (...args: number[]) => number | void> {
171
- return {
172
- 'crypto.fill_random': (outPtr: number, len: number): void => {
173
- if (len < 0 || len > MAX_OUTPUT) throw new Error('crypto.fill_random: bad length');
174
- writeBytes(ref, outPtr, nodeCrypto.randomBytes(len));
175
- },
176
-
177
- 'crypto.random_uuid': (outPtr: number): void => {
178
- writeBytes(ref, outPtr, nodeCrypto.randomBytes(16));
179
- },
180
-
181
- 'crypto.take_result': (outPtr: number, outLen: number): number => {
182
- const r = cs.lastResult;
183
- if (!r || r.length !== outLen) throw new Error('crypto.take_result: length mismatch');
184
- writeBytes(ref, outPtr, r);
185
- cs.lastResult = null;
186
- return r.length;
187
- },
188
-
189
- 'crypto.digest': (alg: number, dataPtr: number, dataLen: number): number => {
190
- const data = readBytes(ref, dataPtr, dataLen);
191
- try {
192
- return stash(cs, nodeCrypto.createHash(hashName(alg)).update(data).digest());
193
- } catch {
194
- return ERR_UNSUPPORTED;
195
- }
196
- },
197
-
198
- 'crypto.import_key': (
199
- format: number,
200
- keyPtr: number,
201
- keyLen: number,
202
- paramsPtr: number,
203
- paramsLen: number,
204
- extractable: number,
205
- _usages: number,
206
- ): number => {
207
- const key = readBytes(ref, keyPtr, keyLen);
208
- const pr = new ParamReader(readBytes(ref, paramsPtr, paramsLen));
209
- const alg = pr.readI32();
210
- const hash = pr.readI32();
211
- return importKey(cs, format, alg, hash, pr, key, extractable !== 0);
212
- },
213
-
214
- 'crypto.export_key': (format: number, handle: number): number => {
215
- const e = cs.keys.get(handle);
216
- if (!e) throw new Error('crypto.export_key: invalid handle');
217
- if (!e.extractable) return ERR_NOT_EXTRACTABLE;
218
- try {
219
- if (e.raw && format === FMT.RAW) return stash(cs, e.raw);
220
- if (e.keyObject) {
221
- if (format === FMT.PKCS8 && e.isPrivate)
222
- return stash(
223
- cs,
224
- e.keyObject.export({ format: 'der', type: 'pkcs8' }) as Buffer,
225
- );
226
- if (format === FMT.SPKI && !e.isPrivate)
227
- return stash(
228
- cs,
229
- e.keyObject.export({ format: 'der', type: 'spki' }) as Buffer,
230
- );
231
- }
232
- return ERR_UNSUPPORTED;
233
- } catch {
234
- return ERR_OPERATION_FAILED;
235
- }
236
- },
237
-
238
- 'crypto.encrypt': (h: number, pp: number, pl: number, dp: number, dl: number): number =>
239
- aesOp(cs, ref, true, h, pp, pl, dp, dl),
240
- 'crypto.decrypt': (h: number, pp: number, pl: number, dp: number, dl: number): number =>
241
- aesOp(cs, ref, false, h, pp, pl, dp, dl),
242
-
243
- 'crypto.sign': (h: number, pp: number, pl: number, dp: number, dl: number): number =>
244
- signOp(cs, ref, h, pp, pl, dp, dl),
245
-
246
- 'crypto.verify': (
247
- h: number,
248
- pp: number,
249
- pl: number,
250
- sp: number,
251
- sl: number,
252
- dp: number,
253
- dl: number,
254
- ): number => verifyOp(cs, ref, h, pp, pl, sp, sl, dp, dl),
255
-
256
- 'crypto.derive_bits': (h: number, pp: number, pl: number, lengthBits: number): number =>
257
- deriveBitsOp(cs, ref, h, pp, pl, lengthBits),
258
-
259
- // ML-DSA-44 (FIPS 204) verify for the auth primitive. Mirrors the edge
260
- // host (`mldsa_verify_import.rs`): same size asserts, 1/0/neg result.
261
- // Backed by the same noble lib the client signs with, so dev == prod.
262
- 'crypto.mldsa_verify': (
263
- pkPtr: number,
264
- pkLen: number,
265
- msgPtr: number,
266
- msgLen: number,
267
- sigPtr: number,
268
- sigLen: number,
269
- ctxPtr: number,
270
- ctxLen: number,
271
- ): number => {
272
- if (pkLen !== 1312 || sigLen !== 2420 || ctxLen > 255) return -4;
273
- try {
274
- const pk = new Uint8Array(readBytes(ref, pkPtr, pkLen));
275
- const msg = new Uint8Array(readBytes(ref, msgPtr, msgLen));
276
- const sig = new Uint8Array(readBytes(ref, sigPtr, sigLen));
277
- const ctx = new Uint8Array(readBytes(ref, ctxPtr, ctxLen));
278
- return ml_dsa44.verify(sig, msg, pk, { context: ctx }) ? 1 : 0;
279
- } catch {
280
- return -1;
281
- }
282
- },
283
-
284
- // ML-KEM-768 (FIPS 203) decapsulation for the mutual-auth + session-key
285
- // layer. Mirrors the edge host (`mlkem_decapsulate_import.rs` / fips203):
286
- // recover the 32-byte shared secret from the client's ciphertext using
287
- // the server's static secret key, write it to `outPtr`, return 0 / neg.
288
- // Backed by the same noble lib the client encapsulates with (dev == prod).
289
- 'crypto.mlkem_decapsulate': (
290
- ctPtr: number,
291
- ctLen: number,
292
- skPtr: number,
293
- skLen: number,
294
- outPtr: number,
295
- ): number => {
296
- if (ctLen !== 1088 || skLen !== 2400) return -4;
297
- try {
298
- const ct = new Uint8Array(readBytes(ref, ctPtr, ctLen));
299
- const sk = new Uint8Array(readBytes(ref, skPtr, skLen));
300
- const ss = ml_kem768.decapsulate(ct, sk); // 32 bytes; implicit rejection on bad ct
301
- writeBytes(ref, outPtr, Buffer.from(ss));
302
- return 0;
303
- } catch {
304
- return -5;
305
- }
306
- },
307
-
308
- // RFC 9497 OPRF (mode 0x00, ristretto255-SHA512) server evaluation for
309
- // the keyed-salt OPRF. Mirrors the edge host
310
- // (`voprf_evaluate_import.rs` / the `voprf` crate): derive the per-user
311
- // key from (seed, info=username) and blind-evaluate the client's blinded
312
- // element, writing the 32-byte evaluated element to `outPtr`. Backed by
313
- // `@noble/curves` ristretto255_oprf, which matches the edge byte-for-byte
314
- // (both RFC 9497), so dev == prod.
315
- 'crypto.voprf_evaluate': (
316
- seedPtr: number,
317
- seedLen: number,
318
- infoPtr: number,
319
- infoLen: number,
320
- blindedPtr: number,
321
- blindedLen: number,
322
- outPtr: number,
323
- ): number => {
324
- // seedLen MUST be exactly 32 (RFC 9497 Ns; noble deriveKeyPair rejects
325
- // other lengths) -- matching the edge so dev and prod never diverge.
326
- if (blindedLen !== 32 || seedLen !== 32 || infoLen > 512) return -4;
327
- try {
328
- const seed = new Uint8Array(readBytes(ref, seedPtr, seedLen));
329
- const info = new Uint8Array(readBytes(ref, infoPtr, infoLen));
330
- const blinded = new Uint8Array(readBytes(ref, blindedPtr, blindedLen));
331
- const oprf = ristretto255_oprf.oprf;
332
- const kp = oprf.deriveKeyPair(seed, info);
333
- const evaluated = oprf.blindEvaluate(kp.secretKey, blinded); // 32-byte element
334
- writeBytes(ref, outPtr, Buffer.from(evaluated));
335
- return 0;
336
- } catch {
337
- return -5;
338
- }
339
- },
340
- };
341
- }
342
-
343
- function importKey(
344
- cs: CryptoState,
345
- format: number,
346
- alg: number,
347
- hash: number,
348
- pr: ParamReader,
349
- key: Buffer,
350
- extractable: boolean,
351
- ): number {
352
- const newEntry = (e: Omit<KeyEntry, 'extractable'>): number => {
353
- const handle = cs.nextHandle++;
354
- cs.keys.set(handle, { ...e, extractable });
355
- return handle;
356
- };
357
-
358
- try {
359
- // Symmetric / MAC / KDF: raw bytes.
360
- if (
361
- alg === ALG.AES_GCM ||
362
- alg === ALG.AES_CBC ||
363
- alg === ALG.AES_CTR ||
364
- alg === ALG.AES_KW ||
365
- alg === ALG.HMAC ||
366
- alg === ALG.PBKDF2 ||
367
- alg === ALG.HKDF
368
- ) {
369
- if (format !== FMT.RAW) return ERR_UNSUPPORTED;
370
- return newEntry({ raw: key, keyObject: null, alg, hash, isPrivate: false });
371
- }
372
-
373
- // Asymmetric: pkcs8 (private) / spki (public). raw not supported in dev.
374
- const isPrivate = format === FMT.PKCS8;
375
- if (format === FMT.PKCS8) {
376
- const ko = nodeCrypto.createPrivateKey({ key, format: 'der', type: 'pkcs8' });
377
- return newEntry({ raw: null, keyObject: ko, alg, hash, isPrivate });
378
- }
379
- if (format === FMT.SPKI) {
380
- const ko = nodeCrypto.createPublicKey({ key, format: 'der', type: 'spki' });
381
- return newEntry({ raw: null, keyObject: ko, alg, hash, isPrivate });
382
- }
383
- return ERR_UNSUPPORTED;
384
- } catch {
385
- return ERR_INVALID_PARAMS;
386
- }
387
- }
388
-
389
- function aesAlgName(keyLen: number, mode: 'gcm' | 'cbc' | 'ctr'): string {
390
- const bits = keyLen === 16 ? 128 : keyLen === 32 ? 256 : 0;
391
- if (!bits) throw new Error('crypto: bad AES key length');
392
- return `aes-${String(bits)}-${mode}`;
393
- }
394
-
395
- function aesOp(
396
- cs: CryptoState,
397
- ref: MemoryRef,
398
- encrypt: boolean,
399
- handle: number,
400
- pp: number,
401
- pl: number,
402
- dp: number,
403
- dl: number,
404
- ): number {
405
- const e = cs.keys.get(handle);
406
- if (!e || !e.raw) throw new Error('crypto: invalid AES key handle');
407
- const pr = new ParamReader(readBytes(ref, pp, pl));
408
- const alg = pr.readI32();
409
- pr.readI32(); // hash (unused)
410
- const data = readBytes(ref, dp, dl);
411
- try {
412
- if (alg === ALG.AES_GCM) {
413
- const iv = pr.readBlob();
414
- const tagBits = pr.readI32();
415
- const aad = pr.readBlob();
416
- if (tagBits !== 0 && tagBits !== 128) return ERR_INVALID_PARAMS;
417
- if (encrypt) {
418
- const c = nodeCrypto.createCipheriv(
419
- aesAlgName(e.raw.length, 'gcm'),
420
- e.raw,
421
- iv,
422
- ) as nodeCrypto.CipherGCM;
423
- if (aad.length) c.setAAD(aad);
424
- const ct = Buffer.concat([c.update(data), c.final()]);
425
- return stash(cs, Buffer.concat([ct, c.getAuthTag()]));
426
- }
427
- // Ciphertext must be at least the 16-byte tag; shorter input can
428
- // never authenticate.
429
- if (data.length < 16) return ERR_OPERATION_FAILED;
430
- const d = nodeCrypto.createDecipheriv(
431
- aesAlgName(e.raw.length, 'gcm'),
432
- e.raw,
433
- iv,
434
- ) as nodeCrypto.DecipherGCM;
435
- if (aad.length) d.setAAD(aad);
436
- const tag = data.subarray(data.length - 16);
437
- const ct = data.subarray(0, data.length - 16);
438
- d.setAuthTag(tag);
439
- return stash(cs, Buffer.concat([d.update(ct), d.final()]));
440
- }
441
- if (alg === ALG.AES_CBC) {
442
- const iv = pr.readBlob();
443
- const c = encrypt
444
- ? nodeCrypto.createCipheriv(aesAlgName(e.raw.length, 'cbc'), e.raw, iv)
445
- : nodeCrypto.createDecipheriv(aesAlgName(e.raw.length, 'cbc'), e.raw, iv);
446
- return stash(cs, Buffer.concat([c.update(data), c.final()]));
447
- }
448
- if (alg === ALG.AES_CTR) {
449
- const counter = pr.readBlob();
450
- const c = encrypt
451
- ? nodeCrypto.createCipheriv(aesAlgName(e.raw.length, 'ctr'), e.raw, counter)
452
- : nodeCrypto.createDecipheriv(aesAlgName(e.raw.length, 'ctr'), e.raw, counter);
453
- return stash(cs, Buffer.concat([c.update(data), c.final()]));
454
- }
455
- return ERR_UNSUPPORTED;
456
- } catch {
457
- return ERR_OPERATION_FAILED;
458
- }
459
- }
460
-
461
- function signOp(
462
- cs: CryptoState,
463
- ref: MemoryRef,
464
- handle: number,
465
- pp: number,
466
- pl: number,
467
- dp: number,
468
- dl: number,
469
- ): number {
470
- const e = cs.keys.get(handle);
471
- if (!e) throw new Error('crypto.sign: invalid handle');
472
- const pr = new ParamReader(readBytes(ref, pp, pl));
473
- const alg = pr.readI32();
474
- const hash = pr.readI32();
475
- const data = readBytes(ref, dp, dl);
476
- try {
477
- if (e.alg === ALG.HMAC && e.raw) {
478
- return stash(cs, nodeCrypto.createHmac(hashName(e.hash), e.raw).update(data).digest());
479
- }
480
- if (e.alg === ALG.ECDSA && e.keyObject) {
481
- const sig = nodeCrypto.sign(hashName(hash), data, {
482
- key: e.keyObject,
483
- dsaEncoding: 'ieee-p1363',
484
- });
485
- return stash(cs, sig);
486
- }
487
- if (e.alg === ALG.ED25519 && e.keyObject) {
488
- return stash(cs, nodeCrypto.sign(null, data, e.keyObject));
489
- }
490
- void alg;
491
- return ERR_UNSUPPORTED;
492
- } catch {
493
- return ERR_OPERATION_FAILED;
494
- }
495
- }
496
-
497
- function verifyOp(
498
- cs: CryptoState,
499
- ref: MemoryRef,
500
- handle: number,
501
- pp: number,
502
- pl: number,
503
- sp: number,
504
- sl: number,
505
- dp: number,
506
- dl: number,
507
- ): number {
508
- const e = cs.keys.get(handle);
509
- if (!e) throw new Error('crypto.verify: invalid handle');
510
- const pr = new ParamReader(readBytes(ref, pp, pl));
511
- pr.readI32(); // alg
512
- const hash = pr.readI32();
513
- const sig = readBytes(ref, sp, sl);
514
- const data = readBytes(ref, dp, dl);
515
- try {
516
- if (e.alg === ALG.HMAC && e.raw) {
517
- const mac = nodeCrypto.createHmac(hashName(e.hash), e.raw).update(data).digest();
518
- return mac.length === sig.length && nodeCrypto.timingSafeEqual(mac, sig) ? 1 : 0;
519
- }
520
- if (e.alg === ALG.ECDSA && e.keyObject) {
521
- const ok = nodeCrypto.verify(
522
- hashName(hash),
523
- data,
524
- {
525
- key: e.keyObject,
526
- dsaEncoding: 'ieee-p1363',
527
- },
528
- sig,
529
- );
530
- return ok ? 1 : 0;
531
- }
532
- if (e.alg === ALG.ED25519 && e.keyObject) {
533
- return nodeCrypto.verify(null, data, e.keyObject, sig) ? 1 : 0;
534
- }
535
- return ERR_UNSUPPORTED;
536
- } catch {
537
- return ERR_GENERIC;
538
- }
539
- }
540
-
541
- function deriveBitsOp(
542
- cs: CryptoState,
543
- ref: MemoryRef,
544
- handle: number,
545
- pp: number,
546
- pl: number,
547
- lengthBits: number,
548
- ): number {
549
- if (lengthBits < 0 || lengthBits % 8 !== 0) return ERR_INVALID_PARAMS;
550
- const outLen = lengthBits / 8;
551
- if (outLen > MAX_OUTPUT) return ERR_INVALID_PARAMS;
552
- const e = cs.keys.get(handle);
553
- if (!e) throw new Error('crypto.derive_bits: invalid handle');
554
- const pr = new ParamReader(readBytes(ref, pp, pl));
555
- const alg = pr.readI32();
556
- const hash = pr.readI32();
557
- try {
558
- if (alg === ALG.PBKDF2 && e.raw) {
559
- const iterations = pr.readU32();
560
- const salt = pr.readBlob();
561
- return stash(
562
- cs,
563
- nodeCrypto.pbkdf2Sync(e.raw, salt, iterations, outLen, hashName(hash)),
564
- );
565
- }
566
- if (alg === ALG.HKDF && e.raw) {
567
- const salt = pr.readBlob();
568
- const info = pr.readBlob();
569
- const okm = nodeCrypto.hkdfSync(hashName(hash), e.raw, salt, info, outLen);
570
- return stash(cs, Buffer.from(okm));
571
- }
572
- if ((alg === ALG.ECDH || alg === ALG.X25519) && e.keyObject) {
573
- const peerHandle = pr.readI32();
574
- const peer = cs.keys.get(peerHandle);
575
- if (!peer || !peer.keyObject)
576
- throw new Error('crypto.derive_bits: invalid peer handle');
577
- const shared = nodeCrypto.diffieHellman({
578
- privateKey: e.keyObject,
579
- publicKey: peer.keyObject,
580
- });
581
- return stash(cs, Buffer.from(shared.subarray(0, Math.min(outLen, shared.length))));
582
- }
583
- return ERR_UNSUPPORTED;
584
- } catch {
585
- return ERR_OPERATION_FAILED;
586
- }
587
- }