@runeditrun/rer 0.0.0-stage → 0.1.1

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 (527) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +157 -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 +182 -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 +158 -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 +117 -0
  71. package/global/launch/facts.mjs +94 -0
  72. package/global/launch/failure.mjs +5 -0
  73. package/global/launch/local-defaults.mjs +4 -0
  74. package/global/launch/prepare.mjs +63 -0
  75. package/global/launch/render.mjs +44 -0
  76. package/global/launch/state.mjs +106 -0
  77. package/global/launch/steps.mjs +90 -0
  78. package/global/launch/stop.mjs +89 -0
  79. package/global/launch/worker.mjs +62 -0
  80. package/global/list.mjs +59 -0
  81. package/global/main.mjs +53 -0
  82. package/global/package-info.mjs +38 -0
  83. package/global/registry.mjs +24 -0
  84. package/global/rer.mjs +29 -0
  85. package/global/update/archive.mjs +89 -0
  86. package/global/update/command.mjs +90 -0
  87. package/global/update/latest.mjs +6 -0
  88. package/global/update/notice.mjs +58 -0
  89. package/global/update/registry.mjs +47 -0
  90. package/global/version.mjs +29 -0
  91. package/install.sh +144 -0
  92. package/modules/ai/LICENSE +21 -0
  93. package/modules/ai/README.md +90 -0
  94. package/modules/ai/client.mjs +71 -0
  95. package/modules/ai/config.mjs +39 -0
  96. package/modules/ai/dev/index.d.mts +6 -0
  97. package/modules/ai/dev/index.mjs +64 -0
  98. package/modules/ai/dev/outbox.mjs +33 -0
  99. package/modules/ai/errors.mjs +28 -0
  100. package/modules/ai/fake/index.d.mts +3 -0
  101. package/modules/ai/fake/index.mjs +82 -0
  102. package/modules/ai/index.d.mts +10 -0
  103. package/modules/ai/index.mjs +3 -0
  104. package/modules/ai/package.json +6 -0
  105. package/modules/container/README.md +156 -0
  106. package/modules/container/adapters/d1.mjs +34 -0
  107. package/modules/container/adapters/egress.mjs +40 -0
  108. package/modules/container/adapters/jobs.mjs +47 -0
  109. package/modules/container/adapters/objects.mjs +84 -0
  110. package/modules/container/adapters/retained.mjs +14 -0
  111. package/modules/container/adapters/sqlite-error.mjs +7 -0
  112. package/modules/container/adapters/sqlite-worker.mjs +26 -0
  113. package/modules/container/assets.mjs +14 -0
  114. package/modules/container/bindings.mjs +1 -0
  115. package/modules/container/boundary.mjs +38 -0
  116. package/modules/container/build.mjs +65 -0
  117. package/modules/container/deploy-input.mjs +17 -0
  118. package/modules/container/entrypoint.sh +5 -0
  119. package/modules/container/host.mjs +43 -0
  120. package/modules/container/ingress.mjs +23 -0
  121. package/modules/container/lock.mjs +11 -0
  122. package/modules/container/migrations.mjs +16 -0
  123. package/modules/container/node-engine.mjs +39 -0
  124. package/modules/container/portability-schema.mjs +14 -0
  125. package/modules/container/remote/deploy.py +76 -0
  126. package/modules/container/remote/files.py +275 -0
  127. package/modules/container/remote/resources.py +157 -0
  128. package/modules/container/runner.mjs +10 -0
  129. package/modules/container/ssh-plan.mjs +44 -0
  130. package/modules/container/ssh.mjs +63 -0
  131. package/modules/container/transfer.mjs +27 -0
  132. package/modules/container/worker-engine.mjs +32 -0
  133. package/modules/dependencies/README.md +211 -0
  134. package/modules/dependencies/approval.mjs +51 -0
  135. package/modules/dependencies/auth.mjs +40 -0
  136. package/modules/dependencies/authority.mjs +14 -0
  137. package/modules/dependencies/crypto.mjs +13 -0
  138. package/modules/dependencies/index.d.mts +23 -0
  139. package/modules/dependencies/index.mjs +113 -0
  140. package/modules/dependencies/logout.mjs +42 -0
  141. package/modules/dependencies/native.mjs +9 -0
  142. package/modules/dependencies/protocol.mjs +23 -0
  143. package/modules/dependencies/schema/approval-attempt.sql +3 -0
  144. package/modules/dependencies/schema/dependencies.sql +15 -0
  145. package/modules/dependencies/store.mjs +19 -0
  146. package/modules/deploy-kit/README.md +308 -0
  147. package/modules/deploy-kit/artifact.mjs +47 -0
  148. package/modules/deploy-kit/build-modules.mjs +21 -0
  149. package/modules/deploy-kit/check.mjs +13 -0
  150. package/modules/deploy-kit/cli.mjs +50 -0
  151. package/modules/deploy-kit/container-config.mjs +8 -0
  152. package/modules/deploy-kit/default-stage.mjs +14 -0
  153. package/modules/deploy-kit/deploy.mjs +80 -0
  154. package/modules/deploy-kit/health-request.mjs +86 -0
  155. package/modules/deploy-kit/health.mjs +99 -0
  156. package/modules/deploy-kit/index.mjs +12 -0
  157. package/modules/deploy-kit/local-only.mjs +10 -0
  158. package/modules/deploy-kit/migrations.mjs +48 -0
  159. package/modules/deploy-kit/owner-cli.mjs +63 -0
  160. package/modules/deploy-kit/owner.mjs +297 -0
  161. package/modules/deploy-kit/prepare.mjs +62 -0
  162. package/modules/deploy-kit/provider.mjs +99 -0
  163. package/modules/deploy-kit/queue-consumer.mjs +10 -0
  164. package/modules/deploy-kit/receipt.mjs +16 -0
  165. package/modules/deploy-kit/render.mjs +47 -0
  166. package/modules/deploy-kit/resources.mjs +106 -0
  167. package/modules/deploy-kit/service-grants.mjs +25 -0
  168. package/modules/deploy-kit/sql-safety.mjs +94 -0
  169. package/modules/deploy-kit/sql-tokens.mjs +49 -0
  170. package/modules/deploy-kit/teardown.mjs +100 -0
  171. package/modules/deploy-kit/templates.mjs +31 -0
  172. package/modules/deploy-kit/validation.mjs +58 -0
  173. package/modules/deploy-kit/worker.mjs +105 -0
  174. package/modules/erasure/CONTRACT.md +90 -0
  175. package/modules/erasure/README.md +221 -0
  176. package/modules/erasure/audit.mjs +23 -0
  177. package/modules/erasure/blobs.mjs +45 -0
  178. package/modules/erasure/cascade.mjs +91 -0
  179. package/modules/erasure/completion.mjs +62 -0
  180. package/modules/erasure/declaration.mjs +51 -0
  181. package/modules/erasure/fence.mjs +19 -0
  182. package/modules/erasure/index.d.mts +62 -0
  183. package/modules/erasure/index.mjs +85 -0
  184. package/modules/erasure/order.mjs +56 -0
  185. package/modules/erasure/plan.mjs +121 -0
  186. package/modules/erasure/rate.mjs +57 -0
  187. package/modules/erasure/receipt.mjs +32 -0
  188. package/modules/erasure/root.mjs +21 -0
  189. package/modules/erasure/schema/erasure-rates.sql +5 -0
  190. package/modules/erasure/schema/erasure.sql +27 -0
  191. package/modules/erasure/scope.mjs +29 -0
  192. package/modules/erasure/sql.mjs +23 -0
  193. package/modules/erasure/verification.mjs +69 -0
  194. package/modules/integrations/core/CONTRACT.md +50 -0
  195. package/modules/integrations/core/README.md +27 -0
  196. package/modules/integrations/core/crypto.ts +19 -0
  197. package/modules/integrations/core/database.ts +21 -0
  198. package/modules/integrations/core/delivery.ts +97 -0
  199. package/modules/integrations/core/destination.ts +13 -0
  200. package/modules/integrations/core/index.ts +7 -0
  201. package/modules/integrations/core/node-transport.ts +72 -0
  202. package/modules/integrations/core/public-address.ts +57 -0
  203. package/modules/integrations/core/repository.ts +74 -0
  204. package/modules/integrations/core/schema.sql +36 -0
  205. package/modules/integrations/core/sqlite.ts +20 -0
  206. package/modules/integrations/core/timestamped-body-signature.ts +38 -0
  207. package/modules/integrations/core/tokens.ts +71 -0
  208. package/modules/integrations/core/types.ts +52 -0
  209. package/modules/integrations/core/upgrade-token-usage-context.sql +5 -0
  210. package/modules/integrations/core/webhook.ts +73 -0
  211. package/modules/job-queue/README.md +173 -0
  212. package/modules/job-queue/cli.mjs +64 -0
  213. package/modules/job-queue/command.mjs +64 -0
  214. package/modules/job-queue/config.mjs +48 -0
  215. package/modules/job-queue/identity.mjs +48 -0
  216. package/modules/job-queue/index.mjs +135 -0
  217. package/modules/job-queue/membership.mjs +30 -0
  218. package/modules/job-queue/module.json +10 -0
  219. package/modules/job-queue/policy.mjs +29 -0
  220. package/modules/job-queue/processes.mjs +80 -0
  221. package/modules/job-queue/resources.mjs +37 -0
  222. package/modules/job-queue/storage.mjs +64 -0
  223. package/modules/job-queue/supervisor.mjs +30 -0
  224. package/modules/job-queue/waiting.mjs +16 -0
  225. package/modules/mail/LICENSE +21 -0
  226. package/modules/mail/README.md +336 -0
  227. package/modules/mail/doctor.mjs +81 -0
  228. package/modules/mail/index.mjs +8 -0
  229. package/modules/mail/live-proof/README.md +113 -0
  230. package/modules/mail/live-proof/run.mjs +55 -0
  231. package/modules/mail/package.json +19 -0
  232. package/modules/mail/pnpm-lock.yaml +537 -0
  233. package/modules/mail/src/adapters/cloudflare/README.md +84 -0
  234. package/modules/mail/src/adapters/cloudflare/headers.mjs +63 -0
  235. package/modules/mail/src/adapters/cloudflare/index.mjs +47 -0
  236. package/modules/mail/src/adapters/cloudflare/response.mjs +99 -0
  237. package/modules/mail/src/adapters/messaging/README.md +92 -0
  238. package/modules/mail/src/adapters/messaging/contract.mjs +66 -0
  239. package/modules/mail/src/adapters/messaging/event-schema.mjs +28 -0
  240. package/modules/mail/src/adapters/messaging/index.mjs +61 -0
  241. package/modules/mail/src/adapters/messaging/jws.mjs +68 -0
  242. package/modules/mail/src/adapters/messaging/request.mjs +52 -0
  243. package/modules/mail/src/adapters/messaging/serialize.mjs +21 -0
  244. package/modules/mail/src/adapters/resend/README.md +120 -0
  245. package/modules/mail/src/adapters/resend/index.mjs +22 -0
  246. package/modules/mail/src/adapters/resend/response.mjs +54 -0
  247. package/modules/mail/src/adapters/resend/serialize.mjs +46 -0
  248. package/modules/mail/src/adapters/resend/size.mjs +99 -0
  249. package/modules/mail/src/adapters/sendgrid/README.md +75 -0
  250. package/modules/mail/src/adapters/sendgrid/index.mjs +35 -0
  251. package/modules/mail/src/adapters/sendgrid/serialize.mjs +104 -0
  252. package/modules/mail/src/core/errors.mjs +9 -0
  253. package/modules/mail/src/core/transport.mjs +33 -0
  254. package/modules/mail/src/core/validation.mjs +172 -0
  255. package/modules/mail/src/development/index.d.mts +37 -0
  256. package/modules/mail/src/development/index.mjs +35 -0
  257. package/modules/mail/src/development/outbox.mjs +78 -0
  258. package/modules/mail/src/development/schema.sql +9 -0
  259. package/modules/mail/src/development/viewer-html.mjs +42 -0
  260. package/modules/mail/src/development/viewer.mjs +65 -0
  261. package/modules/mail/src/doctor/README.md +107 -0
  262. package/modules/mail/src/doctor/common.mjs +64 -0
  263. package/modules/mail/src/doctor/dns.mjs +102 -0
  264. package/modules/mail/src/doctor/index.mjs +28 -0
  265. package/modules/mail/src/doctor/probe.mjs +66 -0
  266. package/modules/mail/src/doctor/receive.mjs +81 -0
  267. package/modules/mail/src/doctor/records.mjs +45 -0
  268. package/modules/mail/src/events/README.md +268 -0
  269. package/modules/mail/src/events/d1-schema.sql +25 -0
  270. package/modules/mail/src/events/d1-storage.mjs +76 -0
  271. package/modules/mail/src/events/index.mjs +3 -0
  272. package/modules/mail/src/events/intake.mjs +201 -0
  273. package/modules/mail/src/events/storage.mjs +52 -0
  274. package/modules/mail/src/events/verify.mjs +92 -0
  275. package/modules/mail/src/inbound/README.md +137 -0
  276. package/modules/mail/src/inbound/bytes.mjs +91 -0
  277. package/modules/mail/src/inbound/headers.mjs +143 -0
  278. package/modules/mail/src/inbound/index.mjs +29 -0
  279. package/modules/mail/src/inbound/mime.mjs +36 -0
  280. package/modules/mail/src/inbound/multipart.mjs +27 -0
  281. package/modules/mail/src/inbound/resend-attachment.mjs +43 -0
  282. package/modules/mail/src/inbound/resend.mjs +54 -0
  283. package/modules/mail/src/inbound/sendgrid.mjs +60 -0
  284. package/modules/mail/src/sender.mjs +33 -0
  285. package/modules/mail/src/sendgrid-email/index.d.mts +33 -0
  286. package/modules/mail/src/sendgrid-email/index.mjs +86 -0
  287. package/modules/mail/src/unsubscribe/index.mjs +142 -0
  288. package/modules/operator-auth/README.md +599 -0
  289. package/modules/operator-auth/accounts/adapter.mjs +41 -0
  290. package/modules/operator-auth/accounts/admin.mjs +159 -0
  291. package/modules/operator-auth/accounts/credentials.mjs +27 -0
  292. package/modules/operator-auth/accounts/editor-owner.mjs +13 -0
  293. package/modules/operator-auth/accounts/index.d.mts +9 -0
  294. package/modules/operator-auth/accounts/index.mjs +9 -0
  295. package/modules/operator-auth/accounts/native.d.mts +38 -0
  296. package/modules/operator-auth/accounts/native.mjs +171 -0
  297. package/modules/operator-auth/accounts/oa.mjs +90 -0
  298. package/modules/operator-auth/accounts/provider-control.mjs +50 -0
  299. package/modules/operator-auth/accounts/provider-pin.mjs +14 -0
  300. package/modules/operator-auth/accounts/roles.mjs +26 -0
  301. package/modules/operator-auth/accounts/schema/dependency-setup.sql +17 -0
  302. package/modules/operator-auth/accounts/schema/dev-sessions.sql +22 -0
  303. package/modules/operator-auth/accounts/schema/domain-rules-step-up.sql +20 -0
  304. package/modules/operator-auth/accounts/schema/invitation-cancellation.sql +17 -0
  305. package/modules/operator-auth/accounts/schema/operator-auth.sql +142 -0
  306. package/modules/operator-auth/accounts/schema/provider-control.sql +30 -0
  307. package/modules/operator-auth/accounts/schema/provider-pins.sql +6 -0
  308. package/modules/operator-auth/accounts/settings-page.mjs +4 -0
  309. package/modules/operator-auth/accounts/store.mjs +246 -0
  310. package/modules/operator-auth/branding.mjs +66 -0
  311. package/modules/operator-auth/config.mjs +35 -0
  312. package/modules/operator-auth/conformance/README.md +81 -0
  313. package/modules/operator-auth/conformance/index.d.mts +43 -0
  314. package/modules/operator-auth/conformance/index.mjs +300 -0
  315. package/modules/operator-auth/conformance/presentation.mjs +57 -0
  316. package/modules/operator-auth/crypto.mjs +17 -0
  317. package/modules/operator-auth/dev/badge.mjs +62 -0
  318. package/modules/operator-auth/dev/index.d.mts +14 -0
  319. package/modules/operator-auth/dev/index.mjs +137 -0
  320. package/modules/operator-auth/dev/personas.mjs +17 -0
  321. package/modules/operator-auth/dev/sign-in-as.d.mts +3 -0
  322. package/modules/operator-auth/dev/sign-in-as.mjs +25 -0
  323. package/modules/operator-auth/dev-admission.d.mts +4 -0
  324. package/modules/operator-auth/dev-admission.mjs +10 -0
  325. package/modules/operator-auth/dev-gate.mjs +86 -0
  326. package/modules/operator-auth/docs/README.md +78 -0
  327. package/modules/operator-auth/docs/native-accounts.md +313 -0
  328. package/modules/operator-auth/docs/tanstack-start.md +218 -0
  329. package/modules/operator-auth/docs/vite-spa.md +144 -0
  330. package/modules/operator-auth/errors.mjs +9 -0
  331. package/modules/operator-auth/http.mjs +42 -0
  332. package/modules/operator-auth/identity/admission.mjs +105 -0
  333. package/modules/operator-auth/identity/after-confirm.mjs +18 -0
  334. package/modules/operator-auth/identity/email-link/confirmation.mjs +14 -0
  335. package/modules/operator-auth/identity/email-link/index.d.mts +48 -0
  336. package/modules/operator-auth/identity/email-link/index.mjs +128 -0
  337. package/modules/operator-auth/identity/email-link/message.mjs +16 -0
  338. package/modules/operator-auth/identity/index.d.mts +7 -0
  339. package/modules/operator-auth/identity/index.mjs +5 -0
  340. package/modules/operator-auth/identity/oidc/README.md +171 -0
  341. package/modules/operator-auth/identity/oidc/client-auth.mjs +16 -0
  342. package/modules/operator-auth/identity/oidc/config.mjs +102 -0
  343. package/modules/operator-auth/identity/oidc/crypto.mjs +29 -0
  344. package/modules/operator-auth/identity/oidc/errors.mjs +5 -0
  345. package/modules/operator-auth/identity/oidc/index.d.mts +33 -0
  346. package/modules/operator-auth/identity/oidc/index.mjs +287 -0
  347. package/modules/operator-auth/identity/oidc/jwt.mjs +102 -0
  348. package/modules/operator-auth/identity/oidc/network.mjs +93 -0
  349. package/modules/operator-auth/identity/oidc/presets.mjs +26 -0
  350. package/modules/operator-auth/identity/oidc/schema/oidc.sql +50 -0
  351. package/modules/operator-auth/identity/oidc/store.mjs +68 -0
  352. package/modules/operator-auth/identity/principal.mjs +28 -0
  353. package/modules/operator-auth/index.d.mts +223 -0
  354. package/modules/operator-auth/index.mjs +11 -0
  355. package/modules/operator-auth/input.mjs +55 -0
  356. package/modules/operator-auth/local-cli.mjs +16 -0
  357. package/modules/operator-auth/page.mjs +34 -0
  358. package/modules/operator-auth/policy.mjs +20 -0
  359. package/modules/operator-auth/routes.mjs +91 -0
  360. package/modules/operator-auth/service.mjs +152 -0
  361. package/modules/operator-auth/signin/index.mjs +67 -0
  362. package/modules/owner-claim/README.md +137 -0
  363. package/modules/owner-claim/idp.mjs +40 -0
  364. package/modules/owner-claim/index.d.mts +27 -0
  365. package/modules/owner-claim/index.mjs +39 -0
  366. package/modules/owner-claim/page.mjs +11 -0
  367. package/modules/owner-claim/schema/idp.sql +4 -0
  368. package/modules/owner-claim/schema/owner-claim.sql +18 -0
  369. package/modules/owner-claim/transaction.mjs +87 -0
  370. package/modules/owner-claim/verify.mjs +80 -0
  371. package/modules/portability/README.md +444 -0
  372. package/modules/portability/bridge.mjs +102 -0
  373. package/modules/portability/catalogue.mjs +118 -0
  374. package/modules/portability/cli-options.mjs +38 -0
  375. package/modules/portability/cli.mjs +56 -0
  376. package/modules/portability/copies.mjs +68 -0
  377. package/modules/portability/dev-data.mjs +32 -0
  378. package/modules/portability/diff.mjs +33 -0
  379. package/modules/portability/export.mjs +129 -0
  380. package/modules/portability/files.mjs +65 -0
  381. package/modules/portability/format.mjs +122 -0
  382. package/modules/portability/generated.mjs +60 -0
  383. package/modules/portability/hash.mjs +79 -0
  384. package/modules/portability/http.mjs +42 -0
  385. package/modules/portability/import.mjs +185 -0
  386. package/modules/portability/index.d.mts +58 -0
  387. package/modules/portability/index.mjs +22 -0
  388. package/modules/portability/journal.mjs +49 -0
  389. package/modules/portability/legacy-files.mjs +43 -0
  390. package/modules/portability/legacy-safety.mjs +27 -0
  391. package/modules/portability/lines.mjs +36 -0
  392. package/modules/portability/migration-history.mjs +18 -0
  393. package/modules/portability/migration-statements.mjs +23 -0
  394. package/modules/portability/payloads.mjs +52 -0
  395. package/modules/portability/provider-data.mjs +25 -0
  396. package/modules/portability/restore-safety.mjs +30 -0
  397. package/modules/portability/schema/portability.sql +25 -0
  398. package/modules/portability/storage.mjs +49 -0
  399. package/modules/release/README.md +212 -0
  400. package/modules/release/catalogue.mjs +79 -0
  401. package/modules/release/export.mjs +51 -0
  402. package/modules/release/produce.mjs +136 -0
  403. package/modules/release/public-child-transport-state.cjs +29 -0
  404. package/modules/release/public-child.mjs +71 -0
  405. package/modules/release/public-git.mjs +21 -0
  406. package/modules/release/publication-scan.mjs +22 -0
  407. package/modules/release/publish-handoff.mjs +37 -0
  408. package/modules/release/source.mjs +71 -0
  409. package/modules/release/test-summary.mjs +50 -0
  410. package/onboarding/README.md +163 -0
  411. package/onboarding/activity.mjs +31 -0
  412. package/onboarding/adapter-auth.mjs +88 -0
  413. package/onboarding/adapter-hosting.mjs +35 -0
  414. package/onboarding/adapter-labels.mjs +13 -0
  415. package/onboarding/adapter-settings.mjs +129 -0
  416. package/onboarding/adapter.mjs +238 -0
  417. package/onboarding/agent-handoff.mjs +9 -0
  418. package/onboarding/app-processes.mjs +21 -0
  419. package/onboarding/archive-output.d.mts +3 -0
  420. package/onboarding/archive-output.mjs +54 -0
  421. package/onboarding/command-custody.mjs +24 -0
  422. package/onboarding/command-recovery.mjs +8 -0
  423. package/onboarding/commands.mjs +166 -0
  424. package/onboarding/dependency-approval.mjs +36 -0
  425. package/onboarding/dev-identity.mjs +23 -0
  426. package/onboarding/email.mjs +24 -0
  427. package/onboarding/failures.mjs +42 -0
  428. package/onboarding/input-limits.mjs +7 -0
  429. package/onboarding/installer-inputs.mjs +24 -0
  430. package/onboarding/launcher.mjs +34 -0
  431. package/onboarding/local/build-files.mjs +64 -0
  432. package/onboarding/local/build.mjs +49 -0
  433. package/onboarding/local/environment.mjs +30 -0
  434. package/onboarding/local/files.mjs +35 -0
  435. package/onboarding/local/operation.mjs +166 -0
  436. package/onboarding/local/owner.mjs +34 -0
  437. package/onboarding/local/process-table.mjs +114 -0
  438. package/onboarding/local/recovery.mjs +79 -0
  439. package/onboarding/local/state.mjs +31 -0
  440. package/onboarding/metadata.mjs +7 -0
  441. package/onboarding/operator-install.mjs +45 -0
  442. package/onboarding/operator-installer.mjs +39 -0
  443. package/onboarding/operator-prerequisites.mjs +27 -0
  444. package/onboarding/package.json +6 -0
  445. package/onboarding/prefill.mjs +16 -0
  446. package/onboarding/private-files.mjs +97 -0
  447. package/onboarding/private.mjs +35 -0
  448. package/onboarding/process-cleanup.mjs +134 -0
  449. package/onboarding/process-diagnostics.mjs +91 -0
  450. package/onboarding/process-scope.mjs +118 -0
  451. package/onboarding/process-table.mjs +118 -0
  452. package/onboarding/process-tree.mjs +36 -0
  453. package/onboarding/production-modules.mjs +22 -0
  454. package/onboarding/production-options.mjs +40 -0
  455. package/onboarding/production-plan.mjs +8 -0
  456. package/onboarding/production-runtime.mjs +30 -0
  457. package/onboarding/project-vite.mjs +14 -0
  458. package/onboarding/providers.mjs +289 -0
  459. package/onboarding/queue.mjs +53 -0
  460. package/onboarding/queued-entry.mjs +34 -0
  461. package/onboarding/readiness.mjs +59 -0
  462. package/onboarding/redaction-jwt.mjs +32 -0
  463. package/onboarding/redaction.mjs +298 -0
  464. package/onboarding/schema/SETUP.schema.json +514 -0
  465. package/onboarding/schema/dependencies.mjs +35 -0
  466. package/onboarding/schema/json-schema.mjs +202 -0
  467. package/onboarding/schema/setup-validation.mjs +325 -0
  468. package/onboarding/secrets.mjs +21 -0
  469. package/onboarding/server.mjs +188 -0
  470. package/onboarding/setup-manifest.mjs +116 -0
  471. package/onboarding/state.mjs +46 -0
  472. package/onboarding/theme-files.mjs +37 -0
  473. package/onboarding/theme.mjs +118 -0
  474. package/onboarding/ui/activity.js +98 -0
  475. package/onboarding/ui/address-client.mjs +33 -0
  476. package/onboarding/ui/app.js +377 -0
  477. package/onboarding/ui/index.html +1 -0
  478. package/onboarding/ui/model-core.mjs +127 -0
  479. package/onboarding/ui/model.mjs +5 -0
  480. package/onboarding/ui/style.css +63 -0
  481. package/onboarding/ui/theme.css +37 -0
  482. package/onboarding/ui/workspace-art.js +30 -0
  483. package/onboarding/wrangler-auth.mjs +43 -0
  484. package/operations/README.md +246 -0
  485. package/operations/operations.mjs +168 -0
  486. package/operations/project-operations.mjs +157 -0
  487. package/package.json +11 -4
  488. package/scripts/publish-check/README.md +72 -0
  489. package/scripts/publish-check/checksum_maps.py +52 -0
  490. package/scripts/publish-check/cli.py +34 -0
  491. package/scripts/publish-check/command_arguments.py +51 -0
  492. package/scripts/publish-check/command_shell_quotes.py +41 -0
  493. package/scripts/publish-check/command_source_quotes.py +120 -0
  494. package/scripts/publish-check/content_identities.py +250 -0
  495. package/scripts/publish-check/copy_identities.py +41 -0
  496. package/scripts/publish-check/der.py +61 -0
  497. package/scripts/publish-check/destination.py +117 -0
  498. package/scripts/publish-check/env_values.py +74 -0
  499. package/scripts/publish-check/font_licence.py +23 -0
  500. package/scripts/publish-check/git_history.py +115 -0
  501. package/scripts/publish-check/github_refs.py +217 -0
  502. package/scripts/publish-check/gitleaks.py +72 -0
  503. package/scripts/publish-check/gitleaks.toml +40 -0
  504. package/scripts/publish-check/history_scan.py +176 -0
  505. package/scripts/publish-check/hit_location.py +18 -0
  506. package/scripts/publish-check/hygiene_config.py +42 -0
  507. package/scripts/publish-check/hygiene_text.py +11 -0
  508. package/scripts/publish-check/identity-recipe.mjs +54 -0
  509. package/scripts/publish-check/json_identity.py +79 -0
  510. package/scripts/publish-check/license-exceptions.json +11 -0
  511. package/scripts/publish-check/licenses.py +49 -0
  512. package/scripts/publish-check/policy.py +18 -0
  513. package/scripts/publish-check/project_identity.py +89 -0
  514. package/scripts/publish-check/provenance.py +91 -0
  515. package/scripts/publish-check/provenance_pins.py +33 -0
  516. package/scripts/publish-check/public_base.py +63 -0
  517. package/scripts/publish-check/public_hygiene.py +80 -0
  518. package/scripts/publish-check/publication-config.json +12 -0
  519. package/scripts/publish-check/publication_config.py +34 -0
  520. package/scripts/publish-check/report.py +52 -0
  521. package/scripts/publish-check/repository_commands.py +75 -0
  522. package/scripts/publish-check/repository_intent.py +52 -0
  523. package/scripts/publish-check/reviewed.py +41 -0
  524. package/scripts/publish-check/source_hashes.mjs +6 -0
  525. package/scripts/publish-check/tree_scan.py +88 -0
  526. package/scripts/publish-check/trust_bundle.py +87 -0
  527. package/scripts/publish-check.mjs +58 -0
@@ -0,0 +1,163 @@
1
+ # Shared local setup lifecycle
2
+
3
+ First-party seeds expose public operations through the RER dispatcher. From a
4
+ runnable seed checkout, the supported local sequence begins with
5
+ `rer install`, `rer setup` and
6
+ `rer dev`; owner sign-in uses the printed local outbox. The
7
+ command contract and flags are documented in the runnable checkout's root
8
+ `RUN-LOCALLY.md`.
9
+
10
+ This directory contains the shared lifecycle and adapter helpers used by a
11
+ seed's RER setup and runtime commands. It centralizes manifest validation,
12
+ private settings, captured child commands, owner bootstrap, sign-in, local
13
+ state safety, readiness and cleanup. A seed declares its actual product inputs
14
+ and effects; the shared lifecycle does not create a product fallback or
15
+ provider behavior.
16
+
17
+ ## Adapter contract
18
+
19
+ A first-party adapter in `scripts/installer/local.mjs` exports `commandAdapter`
20
+ and its setup hooks. The command adapter selects one root `rer-setup.json`
21
+ manifest and declares real targets and policy for dependencies, build,
22
+ migrations, development, preview, verification, deployment and portability.
23
+ Package scripts for public verbs run the vendored `scripts/rer.mjs` with the verb;
24
+ internal targets use different names so the CLI cannot call its own alias
25
+ recursively.
26
+
27
+ The shared setup lifecycle supports these hooks: `node`, `tools`, `prepare`,
28
+ `prepareData`, `dependencies`, `origin`, `secrets`, `build`, `migrate`, `start`, `health`,
29
+ `owner`, `signIn`, `hosting`, `guard`, `failure`, `features` and
30
+ `sessionSecretKey` (the setting that holds the application's session secret,
31
+ default `SESSION_SECRET`; a seed whose settings call it `AUTH_SECRET` declares
32
+ that). `prepareData` runs before `rer export` and `rer import`: declare it when those commands read
33
+ files the seed generates (a generated Worker config, for one) so a copy that never ran
34
+ setup or build still completes. It takes no input and must be safe to repeat. Setup also stops, before any request, when the process listening on the
35
+ expected port is not the one it started. A hook can
36
+ declare an argv command or use its provided context and command store. The
37
+ adapter owns real migrations, resource names, auth hooks, settings names, data
38
+ policy and deployment effects. The CLI owns parsing, public flags, pins,
39
+ containment, locking, capture, cancellation, output, exit mapping and
40
+ sequencing.
41
+
42
+ For `rer setup`, `dev` and `preview`, a custom `start` hook must bind its app
43
+ to `127.0.0.1:context.runtimePort`. rer's traffic proxy owns the port in
44
+ `context.origin`; use `context.origin` for public URLs and cookies, rather
45
+ than as the app's listening address.
46
+
47
+ A seed that declares `devIdentity` on its command adapter gets the key-gated way
48
+ in from the installer without declaring anything more: before setup the installer
49
+ creates the checkout's dev key (as `rer setup` does) and passes it to the hooks as
50
+ `context.devKey`. The `start` hook must give it to the temporary app (an
51
+ `RER_DEV_KEY` binding), because the `signIn` request reaches the key-gated outbox
52
+ with it. When setup completes, the installer page offers the outbox through the
53
+ key exchange (`RER_OPEN`); the key never enters saved state or logs. A seed
54
+ without `devIdentity` gets no key and its installer is unchanged.
55
+
56
+ `rer-setup.json` is the only setup schema. Its fields, groups, defaults,
57
+ conditional requirements and ordered steps define which answers are accepted.
58
+ Secrets are read privately from declared inputs, generated only where the
59
+ manifest specifies a generation method, and never accepted as CLI values.
60
+ `--owner-email` maps to the manifest's owner-claim field. A non-interactive
61
+ setup must supply every required answer; it never silently adopts the git
62
+ identity. Conflicting flag and answer-file values fail before effects.
63
+
64
+ ## Seed theme
65
+
66
+ A seed dresses Base's installer and its shared sign-in and first-run frames in
67
+ its own look by declaring one theme: a plain CSS file at the root of the
68
+ directory its app serves as `/`, conventionally `public/rer-theme.css`. The file
69
+ holds only a `:root { }` block of `--rer-*` tokens and `@font-face` rules for
70
+ font files the app already serves; anything else is refused.
71
+
72
+ | Token | Value | Used for |
73
+ | --- | --- | --- |
74
+ | `--rer-page`, `--rer-surface` | `#rgb`/`#rrggbb` | page backdrop; cards and panels |
75
+ | `--rer-text`, `--rer-muted` | colour | body text; secondary text |
76
+ | `--rer-border` | colour | input and control boundaries |
77
+ | `--rer-focus` | colour | focus outlines |
78
+ | `--rer-accent`, `--rer-accent-text` | colour, declared together (optional) | primary buttons |
79
+ | `--rer-link` | colour (optional, defaults to text) | links and edit actions |
80
+ | `--rer-font-body`, `--rer-font-heading` | font stack (optional) | text; headings and product name |
81
+ | `--rer-radius` | `px` or `rem` length (optional) | cards, inputs, buttons |
82
+ | `--rer-logo` | `url("/path")` to an svg, png or webp the app serves (optional) | mark beside the product name |
83
+
84
+ Contrast is checked against the declared colours before the installer starts:
85
+ text on page and surface, muted text on page and surface, links on surface and
86
+ accent text on accent need 4.5:1; focus on page and surface and borders on
87
+ surface need 3:1. A failing pair is named with its ratio. Every `url()` must
88
+ name a same-origin file under the served directory.
89
+
90
+ The app must serve the file at `/rer-theme.css` with its fonts and logo; a
91
+ Worker that runs first and admits only listed static paths lists it too. If the
92
+ file cannot load, the frames fall back to readable neutrals.
93
+
94
+ Declare the theme in two places that name the same file:
95
+
96
+ - the installer seed descriptor (`scripts/installer/seed.mjs`) returns
97
+ `theme: 'public/rer-theme.css'`, a root-relative path. The installer then
98
+ links it, serves exactly the files it names, and loads its own token skin
99
+ (`ui/theme.css`); the product name stays the descriptor's
100
+ `branding.name`/`product`, and with no `--rer-accent` the buttons keep
101
+ `branding.accent`.
102
+ - the Worker passes the served path to Base's frames: operator-auth
103
+ `branding: { productName, theme: '/rer-theme.css' }` for sign-in confirmation,
104
+ and `firstRunResponse(request, bindings, auth, { theme: { href:
105
+ '/rer-theme.css', productName, accentColor? } })` from `src/base/setup` for
106
+ `/setup`; the foundation sign-in uses `themeFrame` from
107
+ `src/base/theme-frame` the same way, and the development outbox takes
108
+ `createDevelopmentOutboxHandler({ ..., theme: '/rer-theme.css' })`.
109
+ `accentColor` colours buttons when the theme declares no accent. A seed's own
110
+ pages may read the same tokens by linking the file.
111
+
112
+ Without a theme every page is unchanged. `default-seed/public/rer-theme.css`
113
+ and the foundation template's `public/rer-theme.css` are worked examples.
114
+
115
+ ## Setup behavior and custody
116
+
117
+ Setup validates answers before effects, then uses the declared lifecycle to
118
+ prepare local state, private settings, build and migrations, start the real
119
+ application briefly, prepare the first owner and verify ordinary sign-in via
120
+ the loopback development outbox. It stops the temporary app before returning.
121
+ Reruns preserve an existing owner, data and exact settings bytes; setup does
122
+ not create a second owner or rotate secrets. Dev and preview use the saved
123
+ owner and canonical durable state. A normal sign-in uses the same local
124
+ outbox; no external email is sent by local commands.
125
+
126
+ Adapters use the shared captured command store for child work. It redacts
127
+ registered credential values from terminal output and private logs, records
128
+ child outcomes, and stops owned descendants on failure or cancellation.
129
+ Readiness checks the application's real health endpoint and obeys cancellation
130
+ and deadlines. Builds temporarily remove declared private files from the build
131
+ environment and restore their exact bytes and permissions afterward. Do not
132
+ pass secrets in argv, print credentials, or substitute mocks for app behavior.
133
+
134
+ Canonical local durable data is `.wrangler/state`; CLI bookkeeping is
135
+ `.rer/local`; setup drafts and logs are under `.seed/installer`. Private
136
+ settings use mode 0600 and secret-bearing directories use mode 0700. State
137
+ selection rejects unsafe symlinks, traversal and overlap with source, exports,
138
+ dependencies or build outputs. Ambiguous existing state is preserved for
139
+ explicit recovery rather than adopted, moved or deleted silently. Reset uses
140
+ the adapter's declared removal inventory and preserves source, dependencies,
141
+ exports and deployment receipts.
142
+
143
+ ## Data, deployment and verification
144
+
145
+ Each first-party adapter declares which resources local export/import supports.
146
+ Every first-party seed verifies a complete local export/import/export round
147
+ trip across those resources. Archives are private and integrity-checked;
148
+ owner/auth, outbox, private settings and transient runtime state remain
149
+ excluded. Import validates and restores atomically into an empty destination.
150
+ Remote transfer is supported only when every required resource has a complete
151
+ adapter implementation; unsupported targets fail visibly.
152
+
153
+ Deployment uses each seed's actual owner-account declaration, resource policy,
154
+ migrations and health check. Dry run validates and builds locally without
155
+ provider requests. Local tests and structural checks do not establish hosted
156
+ acceptance or external mail delivery.
157
+
158
+ Keep server authorization in every private handler, including direct server
159
+ function transports, and keep server-only code and secrets out of browser
160
+ bundles. Preserve applied migration history and use verified forward
161
+ migrations for schema changes. Keep files focused and choose shared source
162
+ placement for maintainability; a seed may adapt its stack and integration to
163
+ its real product requirements.
@@ -0,0 +1,31 @@
1
+ // Activity is session-only: a restarted process must not imply work is still running.
2
+ const topics = Object.freeze({workspace:'workspace details',owner:'owner details',hosting:'hosting details',email:'email setup',setup:'setup details'});
3
+ const phases = Object.freeze({checking:'Checking',needs_input:'Needs your input for',complete:'Finished checking'});
4
+ export function validateAgentActivity(input) {
5
+ if(!input||typeof input!=='object'||Array.isArray(input)||Object.keys(input).some(key=>!['phase','topic'].includes(key))||!Object.hasOwn(phases,input.phase)||!Object.hasOwn(topics,input.topic))throw Error('Choose a supported activity phase and topic.');
6
+ return {phase:input.phase,topic:input.topic};
7
+ }
8
+ export function createActivity(state,allowedFields=Object.keys(state.draft??{})) {
9
+ const accepted=new Set(allowedFields);
10
+ state.activity=[];state.agent={mode:'manual',attached:false,attachedAt:null,lastSeenAt:null};let sequence=0;
11
+ const attach=()=>{const at=new Date().toISOString();state.agent={mode:'connected',attached:true,attachedAt:state.agent.attachedAt||at,lastSeenAt:at};};
12
+ const append=(source,phase,topic,message,keys)=>{
13
+ const previous=state.activity.at(-1);
14
+ if(previous?.source===source&&previous.phase===phase&&previous.topic===topic&&previous.message===message&&JSON.stringify(previous.keys)===JSON.stringify(keys))return previous;
15
+ const entry={id:++sequence,at:new Date().toISOString(),source,phase,topic,message,...(keys?{keys}: {})};
16
+ state.activity.push(entry);state.activity=state.activity.slice(-24);return entry;
17
+ };
18
+ return {
19
+ agent(input){const {phase,topic}=validateAgentActivity(input);attach();return append('agent',phase,topic,`${phases[phase]} ${topics[topic]}.`);},
20
+ filled(keys){const safe=keys.filter(key=>accepted.has(key));if(safe.length){attach();return append('agent','filled','setup',`Updated ${safe.length} setup ${safe.length===1?'field':'fields'}.`,safe);}},
21
+ secrets(){attach();return append('agent','filled','credentials','Supplied credentials securely for the current setup details.');},
22
+ provider(provider,status){
23
+ if(!['cloudflare','github'].includes(provider))return;
24
+ const name=provider==='cloudflare'?'Cloudflare':'GitHub';
25
+ const states={starting:['checking',`Starting ${name} sign-in.`],awaiting_browser:['needs_input',`Complete ${name} sign-in in your browser.`],refreshing:['checking',`Checking ${name} connection.`],connected:['complete',`${name} connection confirmed.`],auth_required:['needs_input',`${name} sign-in is required.`],not_installed:['needs_input',`${name} command-line tool is required.`],failed:['failed',`${name} connection was not confirmed.`],cancelled:['failed',`${name} sign-in was cancelled.`]};
26
+ const entry=states[status];if(entry)return append('provider',entry[0],provider,entry[1]);
27
+ },
28
+ step(message){return append('installer','checking','installation',message);},
29
+ phase(phase){if(phase==='complete')return append('installer','complete','installation','Installation completed.');if(phase==='failed')return append('installer','failed','installation','Installation stopped. Review the installation details.');},
30
+ };
31
+ }
@@ -0,0 +1,88 @@
1
+ import { approveSetupDependencies } from './dependency-approval.mjs';
2
+ import { createHmac } from 'node:crypto';
3
+ import {commandFailure,installationFailure} from './failures.mjs';
4
+ import { labels } from './adapter-labels.mjs';
5
+ const outboxPath = '/__dev/outbox'; // modules/mail/src/development default path
6
+
7
+ // The CLI's own requests to its loopback server prove they come from the
8
+ // installation's owner-side tooling (modules/operator-auth/local-cli.mjs), so
9
+ // setup and dev restarts do not spend the owner's sign-in rate limit. A server
10
+ // that is not in local mode ignores the header. The proof comes from the
11
+ // setting the seed's adapter declares as its session secret (sessionSecretKey,
12
+ // default SESSION_SECRET).
13
+ const localCliProof = secret => createHmac('sha256', secret).update('local-cli\0sign-in').digest('hex');
14
+ const post = (context, path, body) => {
15
+ const secret = context.vars[context.sessionSecretKey ?? 'SESSION_SECRET'];
16
+ return fetch(new URL(path, context.origin), {
17
+ method: 'POST', redirect: 'manual', signal: context.signal,
18
+ headers: { Origin: context.origin, 'Content-Type': 'application/json', ...(typeof secret === 'string' && secret ? { 'x-rer-local-cli': localCliProof(secret) } : {}) }, body: JSON.stringify(body),
19
+ });
20
+ };
21
+ const errorCode = async response => { try { const code = (await response.json())?.error; return typeof code === 'string' && /^[a-z_]{1,64}$/.test(code) ? code : 'no code'; } catch { return 'no code'; } };
22
+
23
+ // Claim the first owner through Base operator-auth POST /auth/bootstrap with
24
+ // the private setup token, or run the seed's own documented bootstrap. An
25
+ // already claimed installation keeps its owner.
26
+ export async function owner(context, hook) {
27
+ const { store } = context;
28
+ await store.step(labels.owner);
29
+ await approveSetupDependencies(context, post, outboxMessages);
30
+ if(context.ownerClaim?.mode==='idp'){context.ownerClaimed='pending-idp';await store.step('The linked provider must grant the designated installation owner');return;}
31
+ const { path = '/auth/bootstrap', tokenKey = context.ownerClaim?.tokenField ?? 'SETUP_TOKEN', displayName = input => input.displayName || input.name || 'Owner', returnTo = '/' } = hook;
32
+ const token = context.vars[tokenKey];
33
+ if (!token && hook.existingOwnerViaSignIn) { await store.step('Checking the existing owner through ordinary sign-in'); return; }
34
+ if (!token) {
35
+ throw authFailure(context,labels.owner,`${tokenKey} is missing from the private settings.`);
36
+ }
37
+ let response;
38
+ try { response = await post(context, path, { token, displayName: displayName(context.input), returnTo }); } catch (error) {
39
+ if (context.signal?.aborted) throw error;
40
+ throw authFailure(context,labels.owner,'the application did not answer.');
41
+ }
42
+ if (response.status === 303) { await response.body?.cancel(); context.ownerClaimed = 'claimed'; await store.step('First owner claimed'); return; }
43
+ const code = await errorCode(response);
44
+ if (response.status === 409 && code === 'already_initialized') { context.ownerClaimed = 'kept'; await store.step('An owner is already claimed; the existing owner was kept'); return; }
45
+ throw authFailure(context,labels.owner,`HTTP ${response.status} (${code}).`);
46
+ }
47
+
48
+ // Request a sign-in link for the owner, then find it in the Base development
49
+ // outbox. The installer finishes on that captured message, so a local trial
50
+ // needs no mail provider and no email is sent.
51
+ export async function signIn(context, hook) {
52
+ const { store } = context;
53
+ if(context.ownerClaim?.mode==='idp' && context.ownerClaimed==='pending-idp')return;
54
+ await store.step(labels.signIn);
55
+ if (typeof hook === 'function') { context.appUrl = await hook(context); return; }
56
+ const { magicLink = '/auth/magic-link', outbox = outboxPath, email = input => context.ownerClaim ? (context.vars[context.ownerClaim.emailField] ?? input[context.ownerClaim.emailField]) : input.email ?? input.ownerEmail, emailKey, returnTo = '/', attempts = 50 } = hook;
57
+ const address = context.signInEmail ?? (emailKey ? context.vars[emailKey] : email(context.input));
58
+ if (typeof address !== 'string' || !address.includes('@')) { throw authFailure(context,labels.signIn,'no owner email.'); }
59
+ const before = new Set(await outboxMessages(context, outbox, address, true));
60
+ let response;
61
+ try { response = await post(context, magicLink, { email: address, returnTo }); } catch (error) {
62
+ if (context.signal?.aborted) throw error;
63
+ throw authFailure(context,labels.signIn,'the application did not answer.');
64
+ }
65
+ if (response.status !== 202) { throw authFailure(context,labels.signIn,`HTTP ${response.status} (${await errorCode(response)}).`); }
66
+ await response.body?.cancel();
67
+ for (let attempt = 0; attempt < attempts; attempt++) {
68
+ const id = (await outboxMessages(context, outbox, address)).find(message => !before.has(message));
69
+ if (id) { context.appUrl = new URL(`${outbox}?message=${encodeURIComponent(id)}`, context.origin).href; await store.step('Your sign-in link is waiting in the development outbox'); return; }
70
+ await new Promise(resolve => setTimeout(resolve, 200));
71
+ }
72
+ throw authFailure(context,labels.signIn,'no message reached the development outbox. Check that the retained database owner matches the private owner settings; preserve data or run rer reset --yes.');
73
+ }
74
+
75
+ async function outboxMessages(context, path, address, required = false) {
76
+ let response;
77
+ // A dev-identity seed gates its outbox with the checkout's key; present it.
78
+ try { response = await fetch(new URL(path, context.origin), { signal: context.signal, headers: context.devKey ? { 'x-rer-dev-key': context.devKey } : {} }); } catch (error) {
79
+ if (context.signal?.aborted) throw error;
80
+ if(required){context.store.report?.('Local development outbox is unavailable. Run rer setup before requesting sign-in.');throw context.fail('setup');}
81
+ return [];
82
+ }
83
+ if (!response.ok) { await response.body?.cancel();if(required){context.store.report?.('Local development outbox is unavailable. Run rer setup before requesting sign-in.');throw context.fail('setup');}return []; }
84
+ const html = await response.text(), wanted = `To: ${address.replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]))}</p>`;
85
+ return html.split('<article>').slice(1).filter(article => article.toLowerCase().includes(wanted.toLowerCase())).map(article => /\?message=([^"&]+)"/.exec(article)?.[1]).filter(Boolean).map(decodeURIComponent);
86
+ }
87
+
88
+ function authFailure(context,label,reason){const message=context.store.redact?.(`${label}: ${reason}`)??`${label}: ${reason}`;context.store.report?.(message);return installationFailure('command_failed',{step:'setup',diagnostic:commandFailure(message)});}
@@ -0,0 +1,35 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { join, resolve } from 'node:path';
3
+ import { labels } from './adapter-labels.mjs';
4
+
5
+ // The optional hosting hook: deploy to the owner's own Cloudflare account with
6
+ // Base deploy-kit owner-account mode (modules/deploy-kit/owner-cli.mjs, copied
7
+ // by the seed), then check the deployed /health. It runs only when the owner
8
+ // chose the remote target in the shared hosting group, with the account id and
9
+ // API token from that group; `secrets(context)` adds the first-deploy secrets
10
+ // the declaration names. The token and those secrets reach only the deploy
11
+ // command's environment and are registered for redaction first.
12
+ export function ownerAccountHosting({ cli, declaration = 'deploy.json', environment = 'production', product, state, secrets, when = input => input.target === 'remote' } = {}) {
13
+ if (typeof cli !== 'string' || !cli) throw new TypeError('Name the seed\'s copy of deploy-kit owner-cli.mjs.');
14
+ return async context => {
15
+ const { input, store, root } = context;
16
+ if (!when(input)) { await store.step('Hosting was not requested; the application runs on this computer'); return; }
17
+ const { accountId, apiToken } = input;
18
+ if (!/^[a-f0-9]{32}$/i.test(accountId ?? '') || typeof apiToken !== 'string' || !apiToken || /[\r\n]/.test(apiToken)) {
19
+ store.report?.(`${labels.hosting}: choose a Cloudflare account and supply its API token.`);
20
+ throw context.fail('deploy');
21
+ }
22
+ const extra = typeof secrets === 'function' ? await secrets(context) : secrets ?? {};
23
+ store.addSecrets?.([apiToken, ...Object.values(extra).filter(value => typeof value === 'string')]);
24
+ const env = { ...process.env, ...extra, CLOUDFLARE_ACCOUNT_ID: accountId, CLOUDFLARE_API_TOKEN: apiToken };
25
+ const args = ['--declaration', declaration, '--environment', environment, ...(product ? ['--product', product] : []), ...(state ? ['--state', state] : [])];
26
+ await context.run(labels.hosting, process.execPath, [cli, 'deploy', ...args], { step: 'deploy', env });
27
+ await context.run('Checking the deployed application', process.execPath, [cli, 'health', ...args], { step: 'deploy', env });
28
+ let receipt;
29
+ try { receipt = JSON.parse(await readFile(resolve(root, state ?? join('.rer', 'deploy', `${environment}.json`)), 'utf8')).receipt; } catch {}
30
+ const origin = typeof receipt?.origin === 'string' && /^https:\/\/[^\s/]+$/.test(receipt.origin) ? receipt.origin : undefined;
31
+ if (origin) context.hostedUrl = origin;
32
+ await store.step(origin ? `Deployed to ${origin}` : 'Deployed to your Cloudflare account');
33
+ };
34
+ }
35
+
@@ -0,0 +1,13 @@
1
+ export const labels = Object.freeze({
2
+ prepareData: 'Preparing generated files (prepareData)',
3
+ dependencies: 'Installing locked dependencies',
4
+ secrets: 'Saving private local settings',
5
+ build: 'Building your application',
6
+ migrate: 'Applying database migrations',
7
+ start: 'Starting your application on this computer',
8
+ owner: 'Claiming the first owner',
9
+ signIn: 'Opening sign-in through the development outbox',
10
+ hosting: 'Deploying to your Cloudflare account',
11
+ complete: 'Your application is running locally',
12
+ });
13
+
@@ -0,0 +1,129 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { createServer } from 'node:net';
3
+ import { isAbsolute, relative, resolve, sep } from 'node:path';
4
+ import { labels } from './adapter-labels.mjs';
5
+ import { credentialValues } from './redaction.mjs';
6
+ import { privateDirectory, readPrivateFile, writePrivateFile } from './private-files.mjs';
7
+ import { localVariables } from './local/environment.mjs';
8
+ import { assertRegular, inspect } from './local/files.mjs';
9
+ import { localOperation } from './local/operation.mjs';
10
+ import { recoverInterrupted } from './local/recovery.mjs';
11
+
12
+ async function freePort() {
13
+ const socket = createServer();
14
+ await new Promise((resolve, reject) => { socket.once('error', reject); socket.listen(0, '127.0.0.1', resolve); });
15
+ const { port } = socket.address();
16
+ await new Promise(resolve => socket.close(resolve));
17
+ return port;
18
+ }
19
+
20
+ // A rerun keeps the loopback origin already saved in the seed's settings, so
21
+ // sessions, links and the owner's bookmarks stay valid.
22
+ async function chooseOrigin(context, hooks) {
23
+ if (context.selectedOrigin) return context.selectedOrigin;
24
+ if (typeof hooks.origin === 'function') return hooks.origin(context);
25
+ const key = hooks.secrets?.originKey;
26
+ if (key) {
27
+ const saved = (await readSettings(context.root, hooks.secrets)).values[key];
28
+ try { const url = new URL(saved); if (url.protocol === 'http:' && url.hostname === '127.0.0.1' && url.port && url.origin === saved) return saved; } catch {}
29
+ }
30
+ return `http://127.0.0.1:${await freePort()}`;
31
+ }
32
+
33
+ async function readSettings(root, { file = '.dev.vars', format = 'dotenv' }) {
34
+ const path = resolve(root, file);
35
+ const within = relative(root, path);
36
+ if (!within || within === '..' || within.startsWith('..' + sep) || isAbsolute(within)) throw new Error('Installer settings must stay inside the checkout.');
37
+ await privateDirectory(root, within.split(sep).slice(0, -1));
38
+ const status = await inspect(path);
39
+ assertRegular(status);
40
+ if (!status) return { path, values: {}, text: undefined };
41
+ const text = await readPrivateFile(path);
42
+ if (format === 'json') {
43
+ let values;
44
+ try { values = JSON.parse(text); } catch { throw new Error(`${file} is not valid JSON; restore it before installing.`); }
45
+ if (!values || typeof values !== 'object' || Array.isArray(values)) throw new Error(`${file} must hold a JSON object.`);
46
+ return { path, values, text };
47
+ }
48
+ return { path, values: localVariables(text), text };
49
+ }
50
+
51
+ const dotenvValue = value => /^[A-Za-z0-9._@:/+=,-]*$/.test(value) ? value : JSON.stringify(value);
52
+
53
+ // A kept settings file gains only the managed generated secrets a newer
54
+ // manifest declares and the file lacks (an install from before them). Saved
55
+ // values and bytes are untouched, and an owner-visible token the owner removed
56
+ // stays removed. A file is kept only when it holds an earlier setup's owner
57
+ // (`context.ownerKey`, where the caller names it); one that holds only other
58
+ // keys gains this setup's settings beside them.
59
+ async function keepSettings(current, { manifest, store }, { format = 'dotenv' }) {
60
+ const added = Object.fromEntries((manifest?.fields ?? []).filter(field => field.kind === 'secret' && field.input === 'managed' && field.generate && !Object.hasOwn(current.values, field.name))
61
+ .map(field => [field.name, randomBytes(32).toString(field.generate)]));
62
+ if (!Object.keys(added).length) return current.values;
63
+ store.addSecrets?.(Object.values(added));
64
+ const merged = { ...current.values, ...added };
65
+ await writePrivateFile(current.path, format === 'json' ? JSON.stringify(merged, null, 1) + '\n'
66
+ : current.text.replace(/\n*$/, '\n').replace(/^\n$/, '') + Object.entries(added).map(([key, value]) => `${key}=${dotenvValue(value)}`).join('\n') + '\n');
67
+ return merged;
68
+ }
69
+
70
+ // Generate and store private settings. Approved public/entered answers win;
71
+ // existing generated values and untouched rerun bytes are preserved. Credential
72
+ // values are registered for redaction before any later command can print them.
73
+ // The file is owner-only (0600); both formats are written under the local
74
+ // operation lock after interrupted builds are recovered.
75
+ async function writeSecrets(context, options) {
76
+ const { root, store } = context;
77
+ const { generate = [], encoding = 'hex', values, format = 'dotenv' } = options;
78
+ await store.step(labels.secrets);
79
+ {
80
+ const current = await readSettings(root, options);
81
+ if (options.keepExisting && current.text !== undefined && (!context.ownerKey || current.values[context.ownerKey])) { store.addSecrets?.(credentialValues(current.values, context.manifest?.fields.filter(field => field.kind === 'secret').map(field => field.name))); return keepSettings(current, context, options); }
82
+ const wanted = { ...(typeof values === 'function' ? await values(context) : values ?? {}) };
83
+ const manifest=context.manifest;
84
+ const generated=manifest?manifest.fields.filter(field=>field.kind==='secret'&&field.generate):generate.map(name=>({name,generate:encoding}));
85
+ if(manifest){
86
+ for(const field of manifest.fields)if(typeof context.input[field.name]==='string')wanted[field.name]=context.input[field.name];
87
+ }
88
+ for (const field of generated)if(!Object.hasOwn(current.values,field.name))wanted[field.name] = randomBytes(32).toString(field.generate);
89
+ for(const field of manifest?.fields??[])if(field.kind==='secret'&&field.input!=='entered'&&!field.generate&&(field.required||field.presentations?.some(item=>item.required))&&!(current.values[field.name]||wanted[field.name]))throw Error(`Required supplied secret ${field.name} is missing.`);
90
+ const approved = new Set((manifest?.fields ?? []).filter(field => field.kind !== 'secret' || field.input === 'entered').map(field => field.name));
91
+ const updates = Object.fromEntries(Object.entries(wanted).filter(([key, value]) => typeof value === 'string' &&
92
+ (!Object.hasOwn(current.values, key) || (approved.has(key) && current.values[key] !== value))));
93
+ for (const [key, value] of Object.entries(updates)) if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) || /[\r\n\0]/.test(value)) throw new TypeError(`Unsupported local setting ${key}.`);
94
+ store.addSecrets?.((manifest?.fields??[]).filter(field=>field.kind==='secret').flatMap(field=>[current.values[field.name],wanted[field.name]]).filter(Boolean));
95
+ const merged = { ...current.values, ...updates };
96
+ store.addSecrets?.([...generated.map(field => merged[field.name]).filter(Boolean), ...(manifest?.fields??[]).filter(field=>field.kind==='secret').map(field=>merged[field.name]).filter(Boolean), ...credentialValues(merged)]);
97
+ if (Object.keys(updates).length) {
98
+ const replacing = Object.keys(updates).some(key => Object.hasOwn(current.values, key));
99
+ const text = format === 'json'
100
+ ? JSON.stringify(merged, null, 1) + '\n'
101
+ : (replacing ? '' : (current.text === undefined ? '' : current.text.replace(/\n*$/, '\n').replace(/^\n$/, ''))) + Object.entries(replacing ? merged : updates).map(([key, value]) => `${key}=${dotenvValue(value)}`).join('\n') + '\n';
102
+ await writePrivateFile(current.path, text);
103
+ }
104
+ return merged;
105
+ }
106
+ }
107
+
108
+ // Setup on another port moves the checkout: only the saved origin changes.
109
+ // The key is the one the CLI reads (the declared originKey, else AUTH_ORIGIN).
110
+ async function moveSavedOrigin(context, options, values) {
111
+ const key = options.originKey ?? 'AUTH_ORIGIN', origin = context.selectedOrigin;
112
+ if (!origin || values[key] === undefined || values[key] === origin) return values;
113
+ const current = await readSettings(context.root, options), format = options.format ?? 'dotenv', merged = { ...values, [key]: origin };
114
+ const text = format === 'json' ? JSON.stringify(merged, null, 1) + '\n' : current.text.replace(new RegExp(`^${key}=.*$`, 'm'), `${key}=${dotenvValue(origin)}`);
115
+ if (format !== 'json' && localVariables(text)[key] !== origin) throw new Error(`Could not move ${key} in ${options.file ?? '.dev.vars'}; put ${key}=${origin} on its own line.`);
116
+ await writePrivateFile(current.path, text);
117
+ return merged;
118
+ }
119
+
120
+ // Select the origin only after recovery, under the same lock as publication.
121
+ export async function prepareSettings(context, hooks) {
122
+ const operation = context.operationToken ? await localOperation(context.root, context.operationToken) : await recoverInterrupted(context.root) ?? await localOperation(context.root);
123
+ try {
124
+ context.origin = await chooseOrigin(context, hooks);
125
+ context.vars = await moveSavedOrigin(context, hooks.secrets, await writeSecrets(context, hooks.secrets));
126
+ } finally { await operation.release(); }
127
+ }
128
+
129
+ export { freePort, chooseOrigin, readSettings };