@runeditrun/rer 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (526) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +154 -2
  3. package/bin/rer.mjs +3 -0
  4. package/cli/README.md +243 -0
  5. package/cli/adapter.mjs +10 -0
  6. package/cli/ai-local.mjs +65 -0
  7. package/cli/archive-path.mjs +52 -0
  8. package/cli/archive-vite.mjs +55 -0
  9. package/cli/archive.mjs +8 -0
  10. package/cli/auth-copy.mjs +80 -0
  11. package/cli/bounded.mjs +70 -0
  12. package/cli/cache-doctor.mjs +63 -0
  13. package/cli/container-transfer.mjs +35 -0
  14. package/cli/container.mjs +62 -0
  15. package/cli/contract.mjs +25 -0
  16. package/cli/dependencies.mjs +45 -0
  17. package/cli/dependency-approval.mjs +33 -0
  18. package/cli/dependency-doctor.mjs +34 -0
  19. package/cli/dependency-input.mjs +43 -0
  20. package/cli/deploy-config.mjs +118 -0
  21. package/cli/deploy.mjs +37 -0
  22. package/cli/dev-identity.mjs +80 -0
  23. package/cli/errors.mjs +14 -0
  24. package/cli/export.mjs +42 -0
  25. package/cli/font-cache.mjs +29 -0
  26. package/cli/hosted-output.mjs +110 -0
  27. package/cli/independent.mjs +29 -0
  28. package/cli/inspect.mjs +174 -0
  29. package/cli/jsonc.mjs +111 -0
  30. package/cli/lifecycle.mjs +148 -0
  31. package/cli/local.mjs +100 -0
  32. package/cli/main.mjs +57 -0
  33. package/cli/managed-server.mjs +143 -0
  34. package/cli/node-runtime-cache.mjs +68 -0
  35. package/cli/node-runtime-discovery.mjs +56 -0
  36. package/cli/node-runtime-download.mjs +59 -0
  37. package/cli/node-runtime.mjs +50 -0
  38. package/cli/output.mjs +22 -0
  39. package/cli/parse.mjs +77 -0
  40. package/cli/port.mjs +52 -0
  41. package/cli/portability-worker.mjs +56 -0
  42. package/cli/portability.mjs +66 -0
  43. package/cli/preview-cache.mjs +99 -0
  44. package/cli/project.mjs +48 -0
  45. package/cli/release.mjs +24 -0
  46. package/cli/runtime-front-door.mjs +46 -0
  47. package/cli/scheduled.mjs +81 -0
  48. package/cli/server-activity.mjs +12 -0
  49. package/cli/server-proxy.mjs +93 -0
  50. package/cli/server-registry.mjs +177 -0
  51. package/cli/server-resources.mjs +22 -0
  52. package/cli/settings.mjs +15 -0
  53. package/cli/setup-answers.mjs +29 -0
  54. package/cli/setup-input.mjs +113 -0
  55. package/cli/shared.mjs +7 -0
  56. package/cli/transfers.mjs +33 -0
  57. package/cli/version.mjs +36 -0
  58. package/composition/git-source.mjs +111 -0
  59. package/edition-authoring/files.mjs +81 -0
  60. package/edition-authoring/manifest.mjs +65 -0
  61. package/global/README.md +155 -0
  62. package/global/checkout.mjs +72 -0
  63. package/global/cli/command.mjs +13 -0
  64. package/global/cli/install.mjs +75 -0
  65. package/global/cli/layout.mjs +45 -0
  66. package/global/cli/status.mjs +54 -0
  67. package/global/cli/uninstall.mjs +36 -0
  68. package/global/delegate.mjs +13 -0
  69. package/global/launch/capacity.mjs +72 -0
  70. package/global/launch/dev.mjs +129 -0
  71. package/global/launch/facts.mjs +93 -0
  72. package/global/launch/failure.mjs +5 -0
  73. package/global/launch/local-defaults.mjs +4 -0
  74. package/global/launch/prepare.mjs +61 -0
  75. package/global/launch/render.mjs +44 -0
  76. package/global/launch/state.mjs +97 -0
  77. package/global/launch/steps.mjs +81 -0
  78. package/global/launch/worker.mjs +43 -0
  79. package/global/list.mjs +59 -0
  80. package/global/main.mjs +53 -0
  81. package/global/package-info.mjs +38 -0
  82. package/global/registry.mjs +24 -0
  83. package/global/rer.mjs +29 -0
  84. package/global/update/archive.mjs +89 -0
  85. package/global/update/command.mjs +90 -0
  86. package/global/update/latest.mjs +6 -0
  87. package/global/update/notice.mjs +58 -0
  88. package/global/update/registry.mjs +47 -0
  89. package/global/version.mjs +29 -0
  90. package/install.sh +144 -0
  91. package/modules/ai/LICENSE +21 -0
  92. package/modules/ai/README.md +90 -0
  93. package/modules/ai/client.mjs +71 -0
  94. package/modules/ai/config.mjs +39 -0
  95. package/modules/ai/dev/index.d.mts +6 -0
  96. package/modules/ai/dev/index.mjs +64 -0
  97. package/modules/ai/dev/outbox.mjs +33 -0
  98. package/modules/ai/errors.mjs +28 -0
  99. package/modules/ai/fake/index.d.mts +3 -0
  100. package/modules/ai/fake/index.mjs +82 -0
  101. package/modules/ai/index.d.mts +10 -0
  102. package/modules/ai/index.mjs +3 -0
  103. package/modules/ai/package.json +6 -0
  104. package/modules/container/README.md +156 -0
  105. package/modules/container/adapters/d1.mjs +34 -0
  106. package/modules/container/adapters/egress.mjs +40 -0
  107. package/modules/container/adapters/jobs.mjs +47 -0
  108. package/modules/container/adapters/objects.mjs +84 -0
  109. package/modules/container/adapters/retained.mjs +14 -0
  110. package/modules/container/adapters/sqlite-error.mjs +7 -0
  111. package/modules/container/adapters/sqlite-worker.mjs +26 -0
  112. package/modules/container/assets.mjs +14 -0
  113. package/modules/container/bindings.mjs +1 -0
  114. package/modules/container/boundary.mjs +38 -0
  115. package/modules/container/build.mjs +65 -0
  116. package/modules/container/deploy-input.mjs +17 -0
  117. package/modules/container/entrypoint.sh +5 -0
  118. package/modules/container/host.mjs +43 -0
  119. package/modules/container/ingress.mjs +23 -0
  120. package/modules/container/lock.mjs +11 -0
  121. package/modules/container/migrations.mjs +16 -0
  122. package/modules/container/node-engine.mjs +39 -0
  123. package/modules/container/portability-schema.mjs +14 -0
  124. package/modules/container/remote/deploy.py +76 -0
  125. package/modules/container/remote/files.py +275 -0
  126. package/modules/container/remote/resources.py +157 -0
  127. package/modules/container/runner.mjs +10 -0
  128. package/modules/container/ssh-plan.mjs +44 -0
  129. package/modules/container/ssh.mjs +63 -0
  130. package/modules/container/transfer.mjs +27 -0
  131. package/modules/container/worker-engine.mjs +32 -0
  132. package/modules/dependencies/README.md +211 -0
  133. package/modules/dependencies/approval.mjs +51 -0
  134. package/modules/dependencies/auth.mjs +40 -0
  135. package/modules/dependencies/authority.mjs +14 -0
  136. package/modules/dependencies/crypto.mjs +13 -0
  137. package/modules/dependencies/index.d.mts +23 -0
  138. package/modules/dependencies/index.mjs +113 -0
  139. package/modules/dependencies/logout.mjs +42 -0
  140. package/modules/dependencies/native.mjs +9 -0
  141. package/modules/dependencies/protocol.mjs +23 -0
  142. package/modules/dependencies/schema/approval-attempt.sql +3 -0
  143. package/modules/dependencies/schema/dependencies.sql +15 -0
  144. package/modules/dependencies/store.mjs +19 -0
  145. package/modules/deploy-kit/README.md +308 -0
  146. package/modules/deploy-kit/artifact.mjs +47 -0
  147. package/modules/deploy-kit/build-modules.mjs +21 -0
  148. package/modules/deploy-kit/check.mjs +13 -0
  149. package/modules/deploy-kit/cli.mjs +50 -0
  150. package/modules/deploy-kit/container-config.mjs +8 -0
  151. package/modules/deploy-kit/default-stage.mjs +14 -0
  152. package/modules/deploy-kit/deploy.mjs +80 -0
  153. package/modules/deploy-kit/health-request.mjs +86 -0
  154. package/modules/deploy-kit/health.mjs +99 -0
  155. package/modules/deploy-kit/index.mjs +12 -0
  156. package/modules/deploy-kit/local-only.mjs +10 -0
  157. package/modules/deploy-kit/migrations.mjs +48 -0
  158. package/modules/deploy-kit/owner-cli.mjs +63 -0
  159. package/modules/deploy-kit/owner.mjs +297 -0
  160. package/modules/deploy-kit/prepare.mjs +62 -0
  161. package/modules/deploy-kit/provider.mjs +99 -0
  162. package/modules/deploy-kit/queue-consumer.mjs +10 -0
  163. package/modules/deploy-kit/receipt.mjs +16 -0
  164. package/modules/deploy-kit/render.mjs +47 -0
  165. package/modules/deploy-kit/resources.mjs +106 -0
  166. package/modules/deploy-kit/service-grants.mjs +25 -0
  167. package/modules/deploy-kit/sql-safety.mjs +94 -0
  168. package/modules/deploy-kit/sql-tokens.mjs +49 -0
  169. package/modules/deploy-kit/teardown.mjs +100 -0
  170. package/modules/deploy-kit/templates.mjs +31 -0
  171. package/modules/deploy-kit/validation.mjs +58 -0
  172. package/modules/deploy-kit/worker.mjs +105 -0
  173. package/modules/erasure/CONTRACT.md +90 -0
  174. package/modules/erasure/README.md +221 -0
  175. package/modules/erasure/audit.mjs +23 -0
  176. package/modules/erasure/blobs.mjs +45 -0
  177. package/modules/erasure/cascade.mjs +91 -0
  178. package/modules/erasure/completion.mjs +62 -0
  179. package/modules/erasure/declaration.mjs +51 -0
  180. package/modules/erasure/fence.mjs +19 -0
  181. package/modules/erasure/index.d.mts +62 -0
  182. package/modules/erasure/index.mjs +85 -0
  183. package/modules/erasure/order.mjs +56 -0
  184. package/modules/erasure/plan.mjs +121 -0
  185. package/modules/erasure/rate.mjs +57 -0
  186. package/modules/erasure/receipt.mjs +32 -0
  187. package/modules/erasure/root.mjs +21 -0
  188. package/modules/erasure/schema/erasure-rates.sql +5 -0
  189. package/modules/erasure/schema/erasure.sql +27 -0
  190. package/modules/erasure/scope.mjs +29 -0
  191. package/modules/erasure/sql.mjs +23 -0
  192. package/modules/erasure/verification.mjs +69 -0
  193. package/modules/integrations/core/CONTRACT.md +50 -0
  194. package/modules/integrations/core/README.md +27 -0
  195. package/modules/integrations/core/crypto.ts +19 -0
  196. package/modules/integrations/core/database.ts +21 -0
  197. package/modules/integrations/core/delivery.ts +97 -0
  198. package/modules/integrations/core/destination.ts +13 -0
  199. package/modules/integrations/core/index.ts +7 -0
  200. package/modules/integrations/core/node-transport.ts +72 -0
  201. package/modules/integrations/core/public-address.ts +57 -0
  202. package/modules/integrations/core/repository.ts +74 -0
  203. package/modules/integrations/core/schema.sql +36 -0
  204. package/modules/integrations/core/sqlite.ts +20 -0
  205. package/modules/integrations/core/timestamped-body-signature.ts +38 -0
  206. package/modules/integrations/core/tokens.ts +71 -0
  207. package/modules/integrations/core/types.ts +52 -0
  208. package/modules/integrations/core/upgrade-token-usage-context.sql +5 -0
  209. package/modules/integrations/core/webhook.ts +73 -0
  210. package/modules/job-queue/README.md +173 -0
  211. package/modules/job-queue/cli.mjs +64 -0
  212. package/modules/job-queue/command.mjs +64 -0
  213. package/modules/job-queue/config.mjs +48 -0
  214. package/modules/job-queue/identity.mjs +48 -0
  215. package/modules/job-queue/index.mjs +135 -0
  216. package/modules/job-queue/membership.mjs +30 -0
  217. package/modules/job-queue/module.json +10 -0
  218. package/modules/job-queue/policy.mjs +29 -0
  219. package/modules/job-queue/processes.mjs +80 -0
  220. package/modules/job-queue/resources.mjs +37 -0
  221. package/modules/job-queue/storage.mjs +64 -0
  222. package/modules/job-queue/supervisor.mjs +30 -0
  223. package/modules/job-queue/waiting.mjs +16 -0
  224. package/modules/mail/LICENSE +21 -0
  225. package/modules/mail/README.md +336 -0
  226. package/modules/mail/doctor.mjs +81 -0
  227. package/modules/mail/index.mjs +8 -0
  228. package/modules/mail/live-proof/README.md +113 -0
  229. package/modules/mail/live-proof/run.mjs +55 -0
  230. package/modules/mail/package.json +19 -0
  231. package/modules/mail/pnpm-lock.yaml +537 -0
  232. package/modules/mail/src/adapters/cloudflare/README.md +84 -0
  233. package/modules/mail/src/adapters/cloudflare/headers.mjs +63 -0
  234. package/modules/mail/src/adapters/cloudflare/index.mjs +47 -0
  235. package/modules/mail/src/adapters/cloudflare/response.mjs +99 -0
  236. package/modules/mail/src/adapters/messaging/README.md +92 -0
  237. package/modules/mail/src/adapters/messaging/contract.mjs +66 -0
  238. package/modules/mail/src/adapters/messaging/event-schema.mjs +28 -0
  239. package/modules/mail/src/adapters/messaging/index.mjs +61 -0
  240. package/modules/mail/src/adapters/messaging/jws.mjs +68 -0
  241. package/modules/mail/src/adapters/messaging/request.mjs +52 -0
  242. package/modules/mail/src/adapters/messaging/serialize.mjs +21 -0
  243. package/modules/mail/src/adapters/resend/README.md +120 -0
  244. package/modules/mail/src/adapters/resend/index.mjs +22 -0
  245. package/modules/mail/src/adapters/resend/response.mjs +54 -0
  246. package/modules/mail/src/adapters/resend/serialize.mjs +46 -0
  247. package/modules/mail/src/adapters/resend/size.mjs +99 -0
  248. package/modules/mail/src/adapters/sendgrid/README.md +75 -0
  249. package/modules/mail/src/adapters/sendgrid/index.mjs +35 -0
  250. package/modules/mail/src/adapters/sendgrid/serialize.mjs +104 -0
  251. package/modules/mail/src/core/errors.mjs +9 -0
  252. package/modules/mail/src/core/transport.mjs +33 -0
  253. package/modules/mail/src/core/validation.mjs +172 -0
  254. package/modules/mail/src/development/index.d.mts +37 -0
  255. package/modules/mail/src/development/index.mjs +35 -0
  256. package/modules/mail/src/development/outbox.mjs +78 -0
  257. package/modules/mail/src/development/schema.sql +9 -0
  258. package/modules/mail/src/development/viewer-html.mjs +42 -0
  259. package/modules/mail/src/development/viewer.mjs +65 -0
  260. package/modules/mail/src/doctor/README.md +107 -0
  261. package/modules/mail/src/doctor/common.mjs +64 -0
  262. package/modules/mail/src/doctor/dns.mjs +102 -0
  263. package/modules/mail/src/doctor/index.mjs +28 -0
  264. package/modules/mail/src/doctor/probe.mjs +66 -0
  265. package/modules/mail/src/doctor/receive.mjs +81 -0
  266. package/modules/mail/src/doctor/records.mjs +45 -0
  267. package/modules/mail/src/events/README.md +268 -0
  268. package/modules/mail/src/events/d1-schema.sql +25 -0
  269. package/modules/mail/src/events/d1-storage.mjs +76 -0
  270. package/modules/mail/src/events/index.mjs +3 -0
  271. package/modules/mail/src/events/intake.mjs +201 -0
  272. package/modules/mail/src/events/storage.mjs +52 -0
  273. package/modules/mail/src/events/verify.mjs +92 -0
  274. package/modules/mail/src/inbound/README.md +137 -0
  275. package/modules/mail/src/inbound/bytes.mjs +91 -0
  276. package/modules/mail/src/inbound/headers.mjs +143 -0
  277. package/modules/mail/src/inbound/index.mjs +29 -0
  278. package/modules/mail/src/inbound/mime.mjs +36 -0
  279. package/modules/mail/src/inbound/multipart.mjs +27 -0
  280. package/modules/mail/src/inbound/resend-attachment.mjs +43 -0
  281. package/modules/mail/src/inbound/resend.mjs +54 -0
  282. package/modules/mail/src/inbound/sendgrid.mjs +60 -0
  283. package/modules/mail/src/sender.mjs +33 -0
  284. package/modules/mail/src/sendgrid-email/index.d.mts +33 -0
  285. package/modules/mail/src/sendgrid-email/index.mjs +86 -0
  286. package/modules/mail/src/unsubscribe/index.mjs +142 -0
  287. package/modules/operator-auth/README.md +599 -0
  288. package/modules/operator-auth/accounts/adapter.mjs +41 -0
  289. package/modules/operator-auth/accounts/admin.mjs +159 -0
  290. package/modules/operator-auth/accounts/credentials.mjs +27 -0
  291. package/modules/operator-auth/accounts/editor-owner.mjs +13 -0
  292. package/modules/operator-auth/accounts/index.d.mts +9 -0
  293. package/modules/operator-auth/accounts/index.mjs +9 -0
  294. package/modules/operator-auth/accounts/native.d.mts +38 -0
  295. package/modules/operator-auth/accounts/native.mjs +171 -0
  296. package/modules/operator-auth/accounts/oa.mjs +90 -0
  297. package/modules/operator-auth/accounts/provider-control.mjs +50 -0
  298. package/modules/operator-auth/accounts/provider-pin.mjs +14 -0
  299. package/modules/operator-auth/accounts/roles.mjs +26 -0
  300. package/modules/operator-auth/accounts/schema/dependency-setup.sql +17 -0
  301. package/modules/operator-auth/accounts/schema/dev-sessions.sql +22 -0
  302. package/modules/operator-auth/accounts/schema/domain-rules-step-up.sql +20 -0
  303. package/modules/operator-auth/accounts/schema/invitation-cancellation.sql +17 -0
  304. package/modules/operator-auth/accounts/schema/operator-auth.sql +142 -0
  305. package/modules/operator-auth/accounts/schema/provider-control.sql +30 -0
  306. package/modules/operator-auth/accounts/schema/provider-pins.sql +6 -0
  307. package/modules/operator-auth/accounts/settings-page.mjs +4 -0
  308. package/modules/operator-auth/accounts/store.mjs +246 -0
  309. package/modules/operator-auth/branding.mjs +66 -0
  310. package/modules/operator-auth/config.mjs +35 -0
  311. package/modules/operator-auth/conformance/README.md +81 -0
  312. package/modules/operator-auth/conformance/index.d.mts +43 -0
  313. package/modules/operator-auth/conformance/index.mjs +300 -0
  314. package/modules/operator-auth/conformance/presentation.mjs +57 -0
  315. package/modules/operator-auth/crypto.mjs +17 -0
  316. package/modules/operator-auth/dev/badge.mjs +62 -0
  317. package/modules/operator-auth/dev/index.d.mts +14 -0
  318. package/modules/operator-auth/dev/index.mjs +137 -0
  319. package/modules/operator-auth/dev/personas.mjs +17 -0
  320. package/modules/operator-auth/dev/sign-in-as.d.mts +3 -0
  321. package/modules/operator-auth/dev/sign-in-as.mjs +25 -0
  322. package/modules/operator-auth/dev-admission.d.mts +4 -0
  323. package/modules/operator-auth/dev-admission.mjs +10 -0
  324. package/modules/operator-auth/dev-gate.mjs +86 -0
  325. package/modules/operator-auth/docs/README.md +78 -0
  326. package/modules/operator-auth/docs/native-accounts.md +313 -0
  327. package/modules/operator-auth/docs/tanstack-start.md +218 -0
  328. package/modules/operator-auth/docs/vite-spa.md +144 -0
  329. package/modules/operator-auth/errors.mjs +9 -0
  330. package/modules/operator-auth/http.mjs +42 -0
  331. package/modules/operator-auth/identity/admission.mjs +105 -0
  332. package/modules/operator-auth/identity/after-confirm.mjs +18 -0
  333. package/modules/operator-auth/identity/email-link/confirmation.mjs +14 -0
  334. package/modules/operator-auth/identity/email-link/index.d.mts +48 -0
  335. package/modules/operator-auth/identity/email-link/index.mjs +128 -0
  336. package/modules/operator-auth/identity/email-link/message.mjs +16 -0
  337. package/modules/operator-auth/identity/index.d.mts +7 -0
  338. package/modules/operator-auth/identity/index.mjs +5 -0
  339. package/modules/operator-auth/identity/oidc/README.md +171 -0
  340. package/modules/operator-auth/identity/oidc/client-auth.mjs +16 -0
  341. package/modules/operator-auth/identity/oidc/config.mjs +102 -0
  342. package/modules/operator-auth/identity/oidc/crypto.mjs +29 -0
  343. package/modules/operator-auth/identity/oidc/errors.mjs +5 -0
  344. package/modules/operator-auth/identity/oidc/index.d.mts +33 -0
  345. package/modules/operator-auth/identity/oidc/index.mjs +287 -0
  346. package/modules/operator-auth/identity/oidc/jwt.mjs +102 -0
  347. package/modules/operator-auth/identity/oidc/network.mjs +93 -0
  348. package/modules/operator-auth/identity/oidc/presets.mjs +26 -0
  349. package/modules/operator-auth/identity/oidc/schema/oidc.sql +50 -0
  350. package/modules/operator-auth/identity/oidc/store.mjs +68 -0
  351. package/modules/operator-auth/identity/principal.mjs +28 -0
  352. package/modules/operator-auth/index.d.mts +223 -0
  353. package/modules/operator-auth/index.mjs +11 -0
  354. package/modules/operator-auth/input.mjs +55 -0
  355. package/modules/operator-auth/local-cli.mjs +16 -0
  356. package/modules/operator-auth/page.mjs +34 -0
  357. package/modules/operator-auth/policy.mjs +20 -0
  358. package/modules/operator-auth/routes.mjs +91 -0
  359. package/modules/operator-auth/service.mjs +152 -0
  360. package/modules/operator-auth/signin/index.mjs +67 -0
  361. package/modules/owner-claim/README.md +137 -0
  362. package/modules/owner-claim/idp.mjs +40 -0
  363. package/modules/owner-claim/index.d.mts +27 -0
  364. package/modules/owner-claim/index.mjs +39 -0
  365. package/modules/owner-claim/page.mjs +11 -0
  366. package/modules/owner-claim/schema/idp.sql +4 -0
  367. package/modules/owner-claim/schema/owner-claim.sql +18 -0
  368. package/modules/owner-claim/transaction.mjs +87 -0
  369. package/modules/owner-claim/verify.mjs +80 -0
  370. package/modules/portability/README.md +444 -0
  371. package/modules/portability/bridge.mjs +102 -0
  372. package/modules/portability/catalogue.mjs +118 -0
  373. package/modules/portability/cli-options.mjs +38 -0
  374. package/modules/portability/cli.mjs +56 -0
  375. package/modules/portability/copies.mjs +68 -0
  376. package/modules/portability/dev-data.mjs +32 -0
  377. package/modules/portability/diff.mjs +33 -0
  378. package/modules/portability/export.mjs +129 -0
  379. package/modules/portability/files.mjs +65 -0
  380. package/modules/portability/format.mjs +122 -0
  381. package/modules/portability/generated.mjs +60 -0
  382. package/modules/portability/hash.mjs +79 -0
  383. package/modules/portability/http.mjs +42 -0
  384. package/modules/portability/import.mjs +185 -0
  385. package/modules/portability/index.d.mts +58 -0
  386. package/modules/portability/index.mjs +22 -0
  387. package/modules/portability/journal.mjs +49 -0
  388. package/modules/portability/legacy-files.mjs +43 -0
  389. package/modules/portability/legacy-safety.mjs +27 -0
  390. package/modules/portability/lines.mjs +36 -0
  391. package/modules/portability/migration-history.mjs +18 -0
  392. package/modules/portability/migration-statements.mjs +23 -0
  393. package/modules/portability/payloads.mjs +52 -0
  394. package/modules/portability/provider-data.mjs +25 -0
  395. package/modules/portability/restore-safety.mjs +30 -0
  396. package/modules/portability/schema/portability.sql +25 -0
  397. package/modules/portability/storage.mjs +49 -0
  398. package/modules/release/README.md +212 -0
  399. package/modules/release/catalogue.mjs +79 -0
  400. package/modules/release/export.mjs +51 -0
  401. package/modules/release/produce.mjs +136 -0
  402. package/modules/release/public-child-transport-state.cjs +29 -0
  403. package/modules/release/public-child.mjs +71 -0
  404. package/modules/release/public-git.mjs +21 -0
  405. package/modules/release/publication-scan.mjs +22 -0
  406. package/modules/release/publish-handoff.mjs +37 -0
  407. package/modules/release/source.mjs +71 -0
  408. package/modules/release/test-summary.mjs +50 -0
  409. package/onboarding/README.md +163 -0
  410. package/onboarding/activity.mjs +31 -0
  411. package/onboarding/adapter-auth.mjs +88 -0
  412. package/onboarding/adapter-hosting.mjs +35 -0
  413. package/onboarding/adapter-labels.mjs +13 -0
  414. package/onboarding/adapter-settings.mjs +129 -0
  415. package/onboarding/adapter.mjs +238 -0
  416. package/onboarding/agent-handoff.mjs +9 -0
  417. package/onboarding/app-processes.mjs +21 -0
  418. package/onboarding/archive-output.d.mts +3 -0
  419. package/onboarding/archive-output.mjs +54 -0
  420. package/onboarding/command-custody.mjs +24 -0
  421. package/onboarding/command-recovery.mjs +8 -0
  422. package/onboarding/commands.mjs +166 -0
  423. package/onboarding/dependency-approval.mjs +36 -0
  424. package/onboarding/dev-identity.mjs +23 -0
  425. package/onboarding/email.mjs +24 -0
  426. package/onboarding/failures.mjs +42 -0
  427. package/onboarding/input-limits.mjs +7 -0
  428. package/onboarding/installer-inputs.mjs +24 -0
  429. package/onboarding/launcher.mjs +34 -0
  430. package/onboarding/local/build-files.mjs +64 -0
  431. package/onboarding/local/build.mjs +49 -0
  432. package/onboarding/local/environment.mjs +30 -0
  433. package/onboarding/local/files.mjs +35 -0
  434. package/onboarding/local/operation.mjs +166 -0
  435. package/onboarding/local/owner.mjs +34 -0
  436. package/onboarding/local/process-table.mjs +114 -0
  437. package/onboarding/local/recovery.mjs +79 -0
  438. package/onboarding/local/state.mjs +31 -0
  439. package/onboarding/metadata.mjs +7 -0
  440. package/onboarding/operator-install.mjs +45 -0
  441. package/onboarding/operator-installer.mjs +39 -0
  442. package/onboarding/operator-prerequisites.mjs +27 -0
  443. package/onboarding/package.json +6 -0
  444. package/onboarding/prefill.mjs +16 -0
  445. package/onboarding/private-files.mjs +97 -0
  446. package/onboarding/private.mjs +35 -0
  447. package/onboarding/process-cleanup.mjs +134 -0
  448. package/onboarding/process-diagnostics.mjs +91 -0
  449. package/onboarding/process-scope.mjs +118 -0
  450. package/onboarding/process-table.mjs +118 -0
  451. package/onboarding/process-tree.mjs +36 -0
  452. package/onboarding/production-modules.mjs +22 -0
  453. package/onboarding/production-options.mjs +40 -0
  454. package/onboarding/production-plan.mjs +8 -0
  455. package/onboarding/production-runtime.mjs +30 -0
  456. package/onboarding/project-vite.mjs +14 -0
  457. package/onboarding/providers.mjs +289 -0
  458. package/onboarding/queue.mjs +53 -0
  459. package/onboarding/queued-entry.mjs +34 -0
  460. package/onboarding/readiness.mjs +59 -0
  461. package/onboarding/redaction-jwt.mjs +32 -0
  462. package/onboarding/redaction.mjs +298 -0
  463. package/onboarding/schema/SETUP.schema.json +514 -0
  464. package/onboarding/schema/dependencies.mjs +35 -0
  465. package/onboarding/schema/json-schema.mjs +202 -0
  466. package/onboarding/schema/setup-validation.mjs +325 -0
  467. package/onboarding/secrets.mjs +21 -0
  468. package/onboarding/server.mjs +188 -0
  469. package/onboarding/setup-manifest.mjs +116 -0
  470. package/onboarding/state.mjs +46 -0
  471. package/onboarding/theme-files.mjs +37 -0
  472. package/onboarding/theme.mjs +118 -0
  473. package/onboarding/ui/activity.js +98 -0
  474. package/onboarding/ui/address-client.mjs +33 -0
  475. package/onboarding/ui/app.js +377 -0
  476. package/onboarding/ui/index.html +1 -0
  477. package/onboarding/ui/model-core.mjs +127 -0
  478. package/onboarding/ui/model.mjs +5 -0
  479. package/onboarding/ui/style.css +63 -0
  480. package/onboarding/ui/theme.css +37 -0
  481. package/onboarding/ui/workspace-art.js +30 -0
  482. package/onboarding/wrangler-auth.mjs +43 -0
  483. package/operations/README.md +246 -0
  484. package/operations/operations.mjs +168 -0
  485. package/operations/project-operations.mjs +157 -0
  486. package/package.json +11 -4
  487. package/scripts/publish-check/README.md +72 -0
  488. package/scripts/publish-check/checksum_maps.py +52 -0
  489. package/scripts/publish-check/cli.py +34 -0
  490. package/scripts/publish-check/command_arguments.py +51 -0
  491. package/scripts/publish-check/command_shell_quotes.py +41 -0
  492. package/scripts/publish-check/command_source_quotes.py +120 -0
  493. package/scripts/publish-check/content_identities.py +250 -0
  494. package/scripts/publish-check/copy_identities.py +41 -0
  495. package/scripts/publish-check/der.py +61 -0
  496. package/scripts/publish-check/destination.py +117 -0
  497. package/scripts/publish-check/env_values.py +74 -0
  498. package/scripts/publish-check/font_licence.py +23 -0
  499. package/scripts/publish-check/git_history.py +115 -0
  500. package/scripts/publish-check/github_refs.py +217 -0
  501. package/scripts/publish-check/gitleaks.py +72 -0
  502. package/scripts/publish-check/gitleaks.toml +40 -0
  503. package/scripts/publish-check/history_scan.py +176 -0
  504. package/scripts/publish-check/hit_location.py +18 -0
  505. package/scripts/publish-check/hygiene_config.py +42 -0
  506. package/scripts/publish-check/hygiene_text.py +11 -0
  507. package/scripts/publish-check/identity-recipe.mjs +54 -0
  508. package/scripts/publish-check/json_identity.py +79 -0
  509. package/scripts/publish-check/license-exceptions.json +11 -0
  510. package/scripts/publish-check/licenses.py +49 -0
  511. package/scripts/publish-check/policy.py +18 -0
  512. package/scripts/publish-check/project_identity.py +89 -0
  513. package/scripts/publish-check/provenance.py +91 -0
  514. package/scripts/publish-check/provenance_pins.py +33 -0
  515. package/scripts/publish-check/public_base.py +63 -0
  516. package/scripts/publish-check/public_hygiene.py +80 -0
  517. package/scripts/publish-check/publication-config.json +12 -0
  518. package/scripts/publish-check/publication_config.py +34 -0
  519. package/scripts/publish-check/report.py +52 -0
  520. package/scripts/publish-check/repository_commands.py +75 -0
  521. package/scripts/publish-check/repository_intent.py +52 -0
  522. package/scripts/publish-check/reviewed.py +41 -0
  523. package/scripts/publish-check/source_hashes.mjs +6 -0
  524. package/scripts/publish-check/tree_scan.py +88 -0
  525. package/scripts/publish-check/trust_bundle.py +87 -0
  526. package/scripts/publish-check.mjs +58 -0
@@ -0,0 +1,171 @@
1
+ # Identity providers (OpenID Connect)
2
+
3
+ Server-only portable ESM using Fetch and WebCrypto. An app offers several
4
+ providers at once; each is pinned when linked and has its own routes. A
5
+ provider's output is a verified principal, which the admission (an accounts
6
+ adapter, `../admission.mjs`) turns into a session. Apply `schema/oidc.sql` as a
7
+ new numbered migration on the primary D1 database; every statement is
8
+ `IF NOT EXISTS`, so a store that had the earlier single-issuer adapter applies it
9
+ again as its next migration.
10
+
11
+ ```js
12
+ import { createOperatorAuth, createAuthHandler, createSignInHandler } from './modules/operator-auth/index.mjs';
13
+ const auth = createOperatorAuth({
14
+ db: env.DB, clientIp, mailSender,
15
+ // The runtime's fetch; on workerd use redirect 'manual' and refuse every 3xx.
16
+ fetch: providerFetch,
17
+ waitUntil: promise => execution.waitUntil(promise),
18
+ config: {
19
+ origin: 'https://app.example.com', OWNER_EMAIL: env.OWNER_EMAIL, SESSION_SECRET: env.SESSION_SECRET,
20
+ // Independent of SESSION_SECRET; at least 32 characters. Both are Worker secrets.
21
+ OIDC_TRANSACTION_SECRET: env.OIDC_TRANSACTION_SECRET,
22
+ providers: [
23
+ // The app's private key (a Worker secret) authenticates it: no shared secret exists.
24
+ { id: 'auth', preset: 'auth', issuer: env.IDENTITY_PROVIDER, clientId: env.IDENTITY_CLIENT_ID, privateKey: JSON.parse(env.IDENTITY_PRIVATE_KEY) },
25
+ { id: 'google', preset: 'google', clientId: env.GOOGLE_CLIENT_ID, tokenAuthMethod: 'client_secret_basic', clientSecret: env.GOOGLE_CLIENT_SECRET },
26
+ { id: 'corp', preset: 'okta', issuer: 'https://corp.okta.com', clientId: env.OKTA_CLIENT_ID, privateKey: JSON.parse(env.OKTA_PRIVATE_KEY),
27
+ subjectEmails: { '00u1abcd': 'operator@corp.example' } },
28
+ ],
29
+ },
30
+ });
31
+ // GET /signin: "Continue with…" for each linked, reachable provider, then the email link.
32
+ const page = await createSignInHandler(auth)(request);
33
+ // /auth/oidc/<id>/start and /auth/oidc/<id>/callback, with the rest of /auth/*.
34
+ const response = page ?? await createAuthHandler(auth)(request);
35
+ ```
36
+
37
+ Register each provider's own redirect URI: `${origin}/auth/oidc/<id>/callback`,
38
+ or an explicit same-origin `redirectUri` for an incumbent route. Both exported
39
+ HTTP handlers own that configured callback outside `/auth/oidc/` too. The old
40
+ default route is unowned after an override. Conflicting callbacks, foreign
41
+ origins, credentials, query and fragment components are refused.
42
+ `createOidcProviders({ admission, db, config, clientIp, fetch, clock, waitUntil })`
43
+ is the same client for a seed whose accounts adapter is its own.
44
+
45
+ ## Presets
46
+
47
+ | Preset | Issuer | ID-token algorithms | Client authentication | Email trust |
48
+ | --- | --- | --- | --- | --- |
49
+ | `auth` (RER's Auth) | the install's exact HTTPS issuer | ES256 | `private_key_jwt` only | `email_verified` with `email_verified_at` in the last 30 days |
50
+ | `google` | `https://accounts.google.com` (fixed) | RS256 | `private_key_jwt` (default), `client_secret_basic`, `client_secret_post` | `email_verified`, and only for `@gmail.com` or tokens carrying a matching `hd` |
51
+ | `microsoft` | `https://login.microsoftonline.com/<tenant>/v2.0` from `tenant` (never `common`, `organizations` or `consumers`) | RS256 | as Google | never by email: only `subjectEmails` |
52
+ | `okta` | the organisation's exact HTTPS issuer | RS256 | as Google | never by email: only `subjectEmails` |
53
+ | `legacy-rs256` (explicit incumbent opt-in) | exact HTTPS issuer plus required exact `endpointPins` | RS256 | as Google | signed verified email; missing timestamp counts at sign-in, supplied timestamp must be current and valid |
54
+
55
+ `none` and every `HS*` algorithm are never accepted; a token whose `alg` is not
56
+ in its link's pin is refused before any key is looked up. GitHub is not an
57
+ OpenID provider and is not offered. Outside the explicit incumbent preset, other upstreams identify people only
58
+ through explicit `subjectEmails`, a trusted server map from the provider's `sub`
59
+ to an existing operator's email (never populated from a callback, a token email
60
+ or a request).
61
+
62
+ An `auth` provider must state, in discovery, the interface it serves:
63
+ `"rer_interfaces": ["oidc-provider@1.0.0"]`. One below the minimum
64
+ (`MINIMUM_PROVIDER_VERSION`, or a provider's higher `minimumVersion`) is refused
65
+ and nothing is pinned.
66
+
67
+ The incumbent preset requires `endpointPins: { authorization, token, jwks }`.
68
+ Discovery must match these exact HTTPS URLs; this does not loosen Okta,
69
+ Microsoft, Google or Auth trust. See [native adoption](../../docs/native-accounts.md)
70
+ for the full persistence and callback contract.
71
+
72
+ Callback overrides cannot occupy shared owner-claim, sign-in, auth, dependency
73
+ or dev routes, including `/auth/owner-claim`, `/auth/dev/enter`, `/__dev/key` and
74
+ `/__dev/personas`. These routes keep their original handlers; an incumbent path
75
+ such as `/api/auth/identity/callback` is supported with the same transaction
76
+ binding as the default callback.
77
+
78
+ ## Linking and pinning
79
+
80
+ A provider is linked at its first use: discovery is fetched and the link pins
81
+ the issuer, client id, JWKS URI, authorization and token endpoints, the allowed
82
+ algorithms (the preset's, as advertised), the client authentication method, and
83
+ whether the provider sends RFC 9207 `iss`. Every later start fetches discovery
84
+ again and refuses (and hides the provider) if it no longer matches the pin; only
85
+ the owner's re-link changes a pin.
86
+
87
+ A changed configuration (for example a new `IDENTITY_PROVIDER` answer: another
88
+ issuer or client id) only records a **pending re-link**. Sign-in keeps using the
89
+ pinned provider; nothing is swapped in place. The owner completes the re-link at
90
+ `POST /auth/providers/relink {provider}`, or ends a link at
91
+ `POST /auth/providers/unlink {provider}`, each with a fresh step-up proof.
92
+ `GET /auth/providers` lists the pins and pending re-links. Completing a re-link
93
+ invalidates logins in flight. An unlinked provider stays unlinked even while its
94
+ configuration remains, until the owner re-links it.
95
+
96
+ ## The protocol
97
+
98
+ `POST /auth/oidc/<id>/start` (exact Origin, matching Host, no cross-site Fetch
99
+ Metadata; JSON or a native form with `returnTo`, at most 4096 bytes) sends
100
+ `response_type=code`, `response_mode=query`, the preset's scope, independent
101
+ 256-bit state and nonce, and mandatory S256 PKCE to the pinned authorization
102
+ endpoint, with a per-state browser-binding cookie (`__Host-oa_oidc_<state>`, or
103
+ `oa_oidc_local_<port>_<state>` on a loopback origin). State is keyed to its provider:
104
+ an authorization response for one provider presented at another provider's
105
+ redirect URI finds no transaction and is refused (the mix-up defence), and no
106
+ code reaches the wrong token endpoint.
107
+
108
+ `GET /auth/oidc/<id>/callback`, in order: exact route and method, no duplicate
109
+ parameters, state and its browser binding consume the durable transaction once
110
+ (`DELETE … RETURNING`, before any exchange), the transaction belongs to this
111
+ provider, RFC 9207: `iss` must equal the pinned issuer where the provider sends
112
+ it (and is required where its discovery says so), a provider error is reported
113
+ without its text, then the code is exchanged at the pinned token endpoint. With
114
+ `private_key_jwt` the app sends a one-minute RFC 7523 assertion signed by its own
115
+ key (`iss`=`sub`=client id, `aud` the token endpoint, unique `jti`); no secret is
116
+ shared. The ID token's header must name a pinned algorithm and a kid; the key
117
+ comes from the link's cached JWKS, refetched **once** when the kid is unknown and
118
+ refused if still unknown; a substituted key under a known kid fails without a
119
+ refetch. Then the signature, `iss` (the pinned issuer), `aud`/`azp` (this client,
120
+ plus explicitly trusted `additionalAudiences`), `exp`/`iat`/`nbf`, `nonce`, and
121
+ `at_hash`/`c_hash` when present. Access and refresh tokens are never stored or
122
+ returned.
123
+
124
+ The principal then carries the provider's email only as far as its preset
125
+ trusts it, and the admission refuses, in production (not `local`), `amr`
126
+ containing `dev` and addresses under `.localhost`, `.test` or `.invalid`. A
127
+ proof older than 30 days does not count. Successful callback returns 303 to the
128
+ **stored** local `returnTo` with the session cookie.
129
+
130
+ Errors are JSON `{error:code}` for API callers; a browser navigation or native
131
+ form post (`Accept: text/html`) is sent back to the sign-in page with
132
+ `?notice=<code>` and the email link. Codes include `oidc_invalid_correlation`,
133
+ `oidc_issuer_mismatch`, `oidc_audience_mismatch`, `oidc_algorithm_refused`,
134
+ `oidc_unknown_key`, `oidc_provider_denied`, `oidc_admission_denied`,
135
+ `oidc_provider_required`, `oidc_provider_unavailable`, `oidc_relink_required`,
136
+ `oidc_provider_version_unsupported`, `oidc_rate_limited`, `oidc_storage_unavailable`.
137
+
138
+ ## Reachability
139
+
140
+ Every discovery and JWKS call records the provider's health in
141
+ `oa_identity_provider_health`. A provider that has failed discovery or JWKS for
142
+ 5 minutes (`HIDE_AFTER_MS`), or answered 404 or a DNS failure (a resolver error,
143
+ or the 530 a Worker receives for an origin DNS failure), is hidden from the
144
+ sign-in page, which offers the email link instead of redirecting. A hidden
145
+ provider is checked again at most once a minute, after the page answers
146
+ (`waitUntil`), and shown again once a check succeeds.
147
+
148
+ ## Storage and limits
149
+
150
+ `oa_oidc_transactions` stores domain-separated HMAC hashes of state, binding and
151
+ the provider's pin, plus the AES-GCM sealed nonce, verifier, returnTo, expiry and
152
+ provider id. `oa_oidc_limits` counts starts per provider, client address and
153
+ 15-minute window (default 30, `identityStartLimit`). `oa_identity_providers`
154
+ holds the pins and cached JWKS. Delete expired rows from the two transaction
155
+ tables periodically (`expires_at <= now`, milliseconds). Discovery and token
156
+ JSON are limited to 64 KiB, JWKS to 256 KiB and 100 keys; each call has a
157
+ deadline including the body (default 5000 ms, `identityTimeoutMs`); redirects are
158
+ never followed.
159
+
160
+ ## Checks and proof boundary
161
+
162
+ `node --test modules/operator-auth/identity/oidc/tests/*.test.mjs` runs the
163
+ protocol suite on Node SQLite (`client.test.mjs`, `boundaries.test.mjs`) and the
164
+ fake-provider suite through the public HTTP door in real workerd with D1
165
+ (`providers.test.mjs`): a happy path per preset, the mix-up, wrong `iss` and
166
+ `aud`, `none`/HS256/unlisted algorithms, an unknown kid refetched once then
167
+ refused, a replayed state, `amr: ["dev"]`, unverified, stale and unproven
168
+ emails, bindings, the domain rule, step-up for each action, reachability, the
169
+ minimum version and the re-link. Fakes stand only at the provider edge
170
+ (`idp.mjs`, `fake-worker.mjs`). This proves the module, not a real provider
171
+ account, client registration or deployment.
@@ -0,0 +1,16 @@
1
+ import { encode, utf8, random } from './crypto.mjs';
2
+
3
+ const ALGORITHMS = { ES256: { name: 'ECDSA', namedCurve: 'P-256', hash: 'SHA-256' }, RS256: { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' } };
4
+
5
+ // RFC 7523 client authentication (`private_key_jwt`): a one-minute assertion,
6
+ // unique by jti, addressed to the pinned token endpoint.
7
+ export async function clientAssertion(provider, link, now) {
8
+ const algorithm = ALGORITHMS[provider.keyAlgorithm];
9
+ const { kid, alg: _, use: __, key_ops: ___, ...jwk } = provider.privateKey;
10
+ const key = await crypto.subtle.importKey('jwk', jwk, algorithm, false, ['sign']);
11
+ const iat = Math.floor(now / 1000);
12
+ const header = { alg: provider.keyAlgorithm, kid, typ: 'JWT' };
13
+ const claims = { iss: link.clientId, sub: link.clientId, aud: link.token, jti: random(), iat, exp: iat + 60 };
14
+ const input = `${encode(utf8.encode(JSON.stringify(header)))}.${encode(utf8.encode(JSON.stringify(claims)))}`;
15
+ return `${input}.${encode(await crypto.subtle.sign(algorithm, key, utf8.encode(input)))}`;
16
+ }
@@ -0,0 +1,102 @@
1
+ import { normalizeEmail } from '../../policy.mjs';
2
+ import { isLoopbackHost } from '../../http.mjs';
3
+ import { check } from './errors.mjs';
4
+ import { PRESETS, MINIMUM_PROVIDER_VERSION, compareVersions, validVersion } from './presets.mjs';
5
+
6
+ function integer(value, defaultValue, min, max) {
7
+ const v = value ?? defaultValue;
8
+ check(Number.isSafeInteger(v) && v >= min && v <= max, 'oidc_invalid_configuration', 503); return v;
9
+ }
10
+ function httpsUrl(value) {
11
+ const u = new URL(value);
12
+ check(typeof value === 'string' && u.protocol === 'https:' && !u.username && !u.password && !u.search && !u.hash && !/[\s\\]/.test(value));
13
+ return u;
14
+ }
15
+ // A private JWK for private_key_jwt. Its public half is what the provider holds.
16
+ function privateKey(jwk, algorithm) {
17
+ check(jwk && typeof jwk === 'object' && typeof jwk.kid === 'string' && jwk.kid.length > 0 && jwk.kid.length <= 256 && typeof jwk.d === 'string');
18
+ check(algorithm === 'ES256' ? jwk.kty === 'EC' && jwk.crv === 'P-256' : jwk.kty === 'RSA');
19
+ return Object.freeze({ ...jwk });
20
+ }
21
+
22
+ function provider(input, origin) {
23
+ check(input && typeof input === 'object' && typeof input.id === 'string' && /^[a-z][a-z0-9-]{0,31}$/.test(input.id));
24
+ const preset = PRESETS[input.preset];
25
+ check(preset && Object.hasOwn(PRESETS, input.preset));
26
+ let issuer = preset.issuer ?? input.issuer;
27
+ if (preset.tenantIssuer) {
28
+ // A tenant-specific issuer only: never common, organizations or consumers.
29
+ check(typeof input.tenant === 'string' && /^[A-Za-z0-9-]{1,64}(\.[A-Za-z0-9-]{1,63})*$/.test(input.tenant) && !['common', 'organizations', 'consumers'].includes(input.tenant.toLowerCase()));
30
+ issuer = preset.tenantIssuer(input.tenant);
31
+ }
32
+ check(input.issuer === undefined || input.issuer === issuer);
33
+ const issuerUrl = httpsUrl(issuer);
34
+ check(typeof input.clientId === 'string' && input.clientId.length > 0 && input.clientId.length <= 512 && !/[\x00-\x1f\x7f]/.test(input.clientId));
35
+ const tokenAuthMethod = input.tokenAuthMethod ?? preset.methods[0];
36
+ check(preset.methods.includes(tokenAuthMethod));
37
+ check(tokenAuthMethod === 'private_key_jwt' ? input.clientSecret === undefined : input.privateKey === undefined);
38
+ check(!tokenAuthMethod.startsWith('client_secret') || typeof input.clientSecret === 'string' && input.clientSecret.length > 0 && input.clientSecret.length <= 4096);
39
+ const keyAlgorithm = tokenAuthMethod === 'private_key_jwt' ? input.privateKey?.alg ?? (input.privateKey?.kty === 'EC' ? 'ES256' : 'RS256') : undefined;
40
+ check(keyAlgorithm === undefined || ['ES256', 'RS256'].includes(keyAlgorithm));
41
+ const additionalAudiences = input.additionalAudiences ?? [];
42
+ check(Array.isArray(additionalAudiences) && additionalAudiences.length <= 10 && additionalAudiences.every(a => typeof a === 'string' && a.length > 0 && a.length <= 512));
43
+ const endpointOrigins = input.endpointOrigins ?? preset.endpointOrigins ?? [issuerUrl.origin];
44
+ check(Array.isArray(endpointOrigins) && endpointOrigins.length > 0 && endpointOrigins.every(o => { const u = new URL(o); return u.origin === o && u.protocol === 'https:'; }));
45
+ const subjectEmails = Object.fromEntries(Object.entries(input.subjectEmails ?? {}).map(([subject, email]) => {
46
+ check(subject.length > 0 && subject.length <= 255); return [subject, normalizeEmail(email)];
47
+ }));
48
+ const minimumVersion = preset.interface ? input.minimumVersion ?? MINIMUM_PROVIDER_VERSION : undefined;
49
+ check(minimumVersion === undefined || validVersion(minimumVersion) && compareVersions(minimumVersion, MINIMUM_PROVIDER_VERSION) >= 0);
50
+ const label = input.label ?? preset.label;
51
+ check(typeof label === 'string' && label.length > 0 && label.length <= 60 && !/[\x00-\x1f\x7f]/.test(label));
52
+ const redirectUri = input.redirectUri ?? `${origin}/auth/oidc/${input.id}/callback`;
53
+ const redirect = new URL(redirectUri);
54
+ check(typeof redirectUri === 'string' && redirect.href === redirectUri && redirect.origin === origin && !redirect.username && !redirect.password && !redirect.search && !redirect.hash && !/[\s\\]/.test(redirectUri));
55
+ // Incumbent trust is a separate explicit preset, scoped to exact server-owned
56
+ // endpoints. No verified-email switch can broaden Okta/Microsoft defaults.
57
+ let endpointPins;
58
+ if (input.preset === 'legacy-rs256') {
59
+ check(input.endpointPins && typeof input.endpointPins === 'object');
60
+ endpointPins = Object.freeze(Object.fromEntries(['authorization', 'token', 'jwks'].map(key => {
61
+ const value = input.endpointPins[key], u = httpsUrl(value);
62
+ check(u.href === value && endpointOrigins.includes(u.origin));
63
+ return [key, value];
64
+ })));
65
+ } else check(input.endpointPins === undefined);
66
+ return Object.freeze({ id: input.id, preset: input.preset, label, issuer, clientId: input.clientId, tokenAuthMethod,
67
+ clientSecret: input.clientSecret, privateKey: keyAlgorithm ? privateKey(input.privateKey, keyAlgorithm) : undefined, keyAlgorithm,
68
+ algorithms: Object.freeze([...preset.algorithms]), email: preset.email, scope: preset.scope, interface: preset.interface, minimumVersion,
69
+ additionalAudiences: Object.freeze([...new Set(additionalAudiences)]), endpointOrigins: Object.freeze([...new Set(endpointOrigins)]), subjectEmails: Object.freeze(subjectEmails),
70
+ // Each provider has its own redirect URI; its state is bound to it.
71
+ endpointPins, startPath: `/auth/oidc/${input.id}/start`, redirectUri });
72
+ }
73
+
74
+ export function configure(input) {
75
+ try {
76
+ const origin = new URL(input.origin);
77
+ check(origin.origin === input.origin && !origin.username && !origin.password);
78
+ const local = input.local === true;
79
+ check(local ? isLoopbackHost(origin.hostname) && ['http:', 'https:'].includes(origin.protocol) : origin.protocol === 'https:');
80
+ check(typeof input.transactionSecret === 'string' && input.transactionSecret.length >= 32 && input.transactionSecret.length <= 1024);
81
+ check(Array.isArray(input.providers) && input.providers.length <= 8);
82
+ const providers = input.providers.map(entry => provider(entry, input.origin));
83
+ check(new Set(providers.map(p => p.id)).size === providers.length);
84
+ const callbacks = providers.map(p => new URL(p.redirectUri).pathname);
85
+ check(new Set(callbacks).size === providers.length);
86
+ // Auth routes, owner-claim handlers and the local dev gate retain their
87
+ // handlers even when an edition chooses its own OIDC callback pathname.
88
+ const reserved = new Set([input.signInPath ?? '/signin', '/auth/owner-claim', '/auth/dev/enter', '/__dev/personas', '/__dev/key', '/auth/bootstrap', '/auth/magic-link', '/auth/confirm', '/auth/signout', '/auth/session', '/auth/invite', '/auth/invite/cancel', '/auth/review-session', '/auth/operators', '/auth/sessions', '/auth/operator/status', '/auth/operator/role', '/auth/session/revoke', '/auth/step-up', '/auth/domain-rules', '/auth/providers', '/auth/providers/unlink', '/auth/providers/relink', '/auth/settings/identity', '/auth/setup-complete']);
89
+ check(callbacks.every((path, index) => !reserved.has(path) && !path.startsWith('/.well-known/') && !path.startsWith('/auth/dependencies/') && !providers.some(p => path === p.startPath) && (!path.startsWith('/auth/oidc/') || path === `/auth/oidc/${providers[index].id}/callback`)));
90
+
91
+ return Object.freeze({ origin: input.origin, local, secure: origin.protocol === 'https:', transactionSecret: input.transactionSecret, providers: Object.freeze(providers),
92
+ signInPath: input.signInPath ?? '/signin',
93
+ transactionSeconds: integer(input.transactionSeconds, 600, 60, 900), timeoutMs: integer(input.timeoutMs, 5000, 100, 15000),
94
+ clockSkewSeconds: integer(input.clockSkewSeconds, 30, 0, 120), maxTokenAgeSeconds: integer(input.maxTokenAgeSeconds, 600, 60, 3600),
95
+ startLimit: integer(input.startLimit, 30, 1, 1000) });
96
+ } catch { check(false, 'oidc_invalid_configuration', 503); }
97
+ }
98
+
99
+ export function endpoint(value, provider) {
100
+ try { const u = new URL(value); check(typeof value === 'string' && u.href === value && u.protocol === 'https:' && !u.username && !u.password && !u.hash && !u.search && provider.endpointOrigins.includes(u.origin)); return u.href; }
101
+ catch { check(false, 'oidc_untrusted_endpoint', 503); }
102
+ }
@@ -0,0 +1,29 @@
1
+ import { check } from './errors.mjs';
2
+ export const utf8 = new TextEncoder();
3
+ export function encode(bytes) { return btoa(String.fromCharCode(...new Uint8Array(bytes))).replaceAll('+', '-').replaceAll('/', '_').replaceAll('=', ''); }
4
+ export function decode(value) {
5
+ check(typeof value === 'string' && /^[A-Za-z0-9_-]+$/.test(value));
6
+ const bytes = Uint8Array.from(atob(value.replaceAll('-', '+').replaceAll('_', '/')), c => c.charCodeAt(0));
7
+ check(encode(bytes) === value);
8
+ return bytes;
9
+ }
10
+ export function random() { return encode(crypto.getRandomValues(new Uint8Array(32))); }
11
+ export function isRandom(value) { return typeof value === 'string' && /^[A-Za-z0-9_-]{43}$/.test(value); }
12
+ export async function digest(value) { return encode(await crypto.subtle.digest('SHA-256', utf8.encode(value))); }
13
+ export async function keyedHash(secret, purpose, value) {
14
+ const key = await crypto.subtle.importKey('raw', utf8.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
15
+ return encode(await crypto.subtle.sign('HMAC', key, utf8.encode(`oidc-v1:${purpose}\0${value}`)));
16
+ }
17
+ async function encryptionKey(secret) {
18
+ return crypto.subtle.importKey('raw', await crypto.subtle.digest('SHA-256', utf8.encode(`oidc-v1:encryption\0${secret}`)), 'AES-GCM', false, ['encrypt', 'decrypt']);
19
+ }
20
+ export async function seal(secret, stateHash, value) {
21
+ const iv = crypto.getRandomValues(new Uint8Array(12));
22
+ const ciphertext = await crypto.subtle.encrypt({ name: 'AES-GCM', iv, additionalData: utf8.encode(stateHash) }, await encryptionKey(secret), utf8.encode(JSON.stringify(value)));
23
+ return `${encode(iv)}.${encode(ciphertext)}`;
24
+ }
25
+ export async function unseal(secret, stateHash, value) {
26
+ const [iv, ciphertext, extra] = value.split('.');
27
+ check(!extra);
28
+ return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(await crypto.subtle.decrypt({ name: 'AES-GCM', iv: decode(iv), additionalData: utf8.encode(stateHash) }, await encryptionKey(secret), decode(ciphertext))));
29
+ }
@@ -0,0 +1,5 @@
1
+ export class OidcError extends Error {
2
+ constructor(code, status = 400) { super(code); this.name = 'OidcError'; this.code = code; this.status = status; }
3
+ }
4
+ export function fail(code = 'oidc_invalid_response', status = 400) { throw new OidcError(code, status); }
5
+ export function check(value, code, status) { if (!value) fail(code, status); }
@@ -0,0 +1,33 @@
1
+ import type { Admission, Role, Database, IdentityProviderConfig, IdentityProviders } from '../../index.mjs';
2
+ export interface OidcProvidersConfig {
3
+ origin: string;
4
+ local?: boolean;
5
+ /** Independent high-entropy secret of at least 32 characters; never browser data. */
6
+ transactionSecret: string;
7
+ providers: IdentityProviderConfig[];
8
+ signInPath?: string;
9
+ transactionSeconds?: number;
10
+ timeoutMs?: number;
11
+ clockSkewSeconds?: number;
12
+ maxTokenAgeSeconds?: number;
13
+ startLimit?: number;
14
+ }
15
+ export interface OidcProvidersOptions<R extends string = Role> {
16
+ admission: Pick<Admission<R>, 'admit'> & Partial<Pick<Admission<R>,'accounts'>>;
17
+ enabled?:()=>Promise<boolean>;
18
+ policyVersion?:()=>Promise<number>;
19
+ claimScope?:()=>Promise<boolean>;
20
+ claim?:(request:Request,token:string,pin:{id:string;issuer:string;clientId:string;linkedAt:number})=>Promise<Response|null>;
21
+ db: Database;
22
+ config: OidcProvidersConfig;
23
+ clientIp: (request: Request) => string | Promise<string>;
24
+ fetch?: typeof globalThis.fetch;
25
+ clock?: () => number;
26
+ waitUntil?: (promise: Promise<unknown>) => void;
27
+ }
28
+ export const HIDE_AFTER_MS: number;
29
+ export const MINIMUM_PROVIDER_VERSION: string;
30
+ export const PRESETS: Readonly<Record<'auth' | 'google' | 'microsoft' | 'okta' | 'legacy-rs256', { label: string; algorithms: string[]; methods: string[]; email: 'verified-at' | 'google' | 'subject' | 'legacy-verified' }>>;
31
+ export function createOidcProviders<R extends string>(options: OidcProvidersOptions<R>): IdentityProviders;
32
+ export function createOidcHandler(providers: IdentityProviders): (request: Request) => Promise<Response | null>;
33
+ export class OidcError extends Error { constructor(code: string, status?: number); code: string; status: number }