@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,90 @@
1
+ // rer update [--version X]: move this rer to the registry's latest version (or
2
+ // X), the way it was installed. A user install (npx or install.sh) downloads,
3
+ // verifies and switches atomically through the new package's own
4
+ // `rer cli install`, keeping its channel; a failed or mismatched download
5
+ // leaves the current version selected. An npm global install runs npm for its
6
+ // own prefix and never writes a second launcher.
7
+ import { spawn } from 'node:child_process';
8
+ import { mkdtemp, readFile, rm } from 'node:fs/promises';
9
+ import { tmpdir } from 'node:os';
10
+ import { basename, dirname, join } from 'node:path';
11
+ import { layout } from '../cli/layout.mjs';
12
+ import { channelOf } from '../cli/status.mjs';
13
+ import { ownManifest, ownRoot, packageDigest, packageName } from '../package-info.mjs';
14
+ import { readPackage, writePackage } from './archive.mjs';
15
+ import { compareVersions, packageMetadata, pickRelease, registryUrl, UpdateFailure } from './registry.mjs';
16
+
17
+ const usage = 'Usage: rer update [--version X]\n';
18
+
19
+ function parse(args) {
20
+ if (!args.length) return {};
21
+ if (args.length === 1 && args[0].startsWith('--version=') && args[0].length > 10) return { version: args[0].slice(10) };
22
+ if (args.length === 2 && args[0] === '--version' && args[1] && !args[1].startsWith('-')) return { version: args[1] };
23
+ return undefined;
24
+ }
25
+
26
+ const run = (program, args, env = process.env) => new Promise((resolve, reject) => {
27
+ const child = spawn(program, args, { env, stdio: ['ignore', 'inherit', 'inherit'] });
28
+ child.once('error', reject);
29
+ child.once('close', (code, signal) => resolve(code ?? (signal ? 1 : 0)));
30
+ });
31
+
32
+ // <prefix>/lib/node_modules/@runeditrun/rer, npm's global layout on macOS and Linux.
33
+ function npmPrefix() {
34
+ const scope = dirname(ownRoot), modules = dirname(scope), lib = dirname(modules);
35
+ if (basename(scope) !== '@runeditrun' || basename(modules) !== 'node_modules' || basename(lib) !== 'lib') throw new UpdateFailure(`This npm global rer is at ${ownRoot}, outside npm's usual layout; update it with npm install -g ${packageName}.`);
36
+ return dirname(lib);
37
+ }
38
+
39
+ async function download(release) {
40
+ const response = await fetch(release.dist.tarball).catch(error => { throw new UpdateFailure(`Could not download ${release.dist.tarball} (${error.cause?.code ?? error.message}).`); });
41
+ if (!response.ok) throw new UpdateFailure(`${release.dist.tarball} answered ${response.status}.`);
42
+ return readPackage(Buffer.from(await response.arrayBuffer()), release.dist);
43
+ }
44
+
45
+ async function npmGlobal(version) {
46
+ const prefix = npmPrefix(), args = ['install', '-g', '--prefix', prefix, `${packageName}@${version}`];
47
+ const command = `npm ${args.map(arg => /^[\w@./:=-]+$/.test(arg) ? arg : JSON.stringify(arg)).join(' ')}`;
48
+ process.stdout.write(`Updating the npm global rer: ${command}\n`);
49
+ let code;
50
+ try { code = await run('npm', args); } catch (error) { code = 127; process.stderr.write(`Could not run npm (${error.code ?? error.message}).\n`); }
51
+ if (code !== 0) {
52
+ process.stderr.write(`npm could not update rer (exit ${code}); rer is unchanged. Fix the problem npm reports (for example, a prefix you cannot write), then run:\n ${command}\n`);
53
+ return code || 1;
54
+ }
55
+ const installed = JSON.parse(await readFile(join(prefix, 'lib/node_modules', packageName, 'package.json'), 'utf8')).version;
56
+ process.stdout.write(`rer is now ${installed} (npm global, prefix ${prefix}).\n`);
57
+ return 0;
58
+ }
59
+
60
+ export async function update(args) {
61
+ const options = parse(args);
62
+ if (!options) { process.stderr.write(`Unsupported: rer update ${args.join(' ')}\n${usage}`); return 2; }
63
+ const { channel } = await channelOf(layout()), current = ownManifest().version;
64
+ if (channel === 'source') { process.stderr.write(`This rer runs from a source checkout (${ownRoot}), which rer update does not change. Update the checkout with git, or install rer with: npx -y ${packageName} cli install\n`); return 1; }
65
+ const work = await mkdtemp(join(tmpdir(), 'rer-update-'));
66
+ try {
67
+ const release = pickRelease(await packageMetadata(), options.version);
68
+ if (!options.version && compareVersions(current, release.version) > 0) {
69
+ process.stdout.write(`rer ${current} is newer than the latest published version (${release.version}); nothing changed. rer update --version ${release.version} installs that one.\n`);
70
+ return 0;
71
+ }
72
+ // The same version counts as current only with the same contents: a
73
+ // different build of that version is an update. (A development build's
74
+ // version differs from its release's, so it always moves.)
75
+ if (release.version === current || channel !== 'npm-global') {
76
+ process.stdout.write(`Checking rer ${release.version} from ${registryUrl()}\n`);
77
+ await writePackage(await download(release), join(work, 'package'));
78
+ if (release.version === current && await packageDigest(join(work, 'package')) === await packageDigest(ownRoot)) {
79
+ process.stdout.write(`rer ${current} is already current. Nothing changed.\n`);
80
+ return 0;
81
+ }
82
+ }
83
+ if (channel === 'npm-global') return await npmGlobal(release.version);
84
+ return await run(process.execPath, [join(work, 'package/global/rer.mjs'), 'cli', 'install'], { ...process.env, RER_INSTALL_CHANNEL: channel });
85
+ } catch (error) {
86
+ if (!(error instanceof UpdateFailure)) throw error;
87
+ process.stderr.write(`rer update: ${error.message} rer ${current} is still selected.\n`);
88
+ return 1;
89
+ } finally { await rm(work, { recursive: true, force: true }); }
90
+ }
@@ -0,0 +1,6 @@
1
+ // Prints the registry's latest @runeditrun/rer version on one line. The update
2
+ // notice runs this as a child process so that it can kill it at its time budget.
3
+ import { packageMetadata } from './registry.mjs';
4
+
5
+ const latest = (await packageMetadata())['dist-tags']?.latest;
6
+ if (typeof latest === 'string') process.stdout.write(latest + '\n');
@@ -0,0 +1,58 @@
1
+ // The update notice: in human output on a terminal, at most once per 24 hours,
2
+ // one line naming a newer published version. Never in --json output or when
3
+ // stdout is not a terminal, never more than about 1.5 s of delay (even when the
4
+ // registry accepts the connection and never answers), and off with
5
+ // RER_NO_UPDATE_CHECK=1. The check time lives in ${XDG_CACHE_HOME:-~/.cache}/rer.
6
+ import { spawn } from 'node:child_process';
7
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
8
+ import { homedir } from 'node:os';
9
+ import { join } from 'node:path';
10
+ import { fileURLToPath } from 'node:url';
11
+ import { layout } from '../cli/layout.mjs';
12
+ import { channelOf } from '../cli/status.mjs';
13
+ import { ownManifest } from '../package-info.mjs';
14
+ import { compareVersions } from './registry.mjs';
15
+
16
+ const interval = 24 * 60 * 60 * 1000, budget = 1500;
17
+
18
+ export const wantsNotice = (argv, env = process.env) => env.RER_NO_UPDATE_CHECK !== '1' && Boolean(process.stdout.isTTY) && !argv.includes('--json');
19
+
20
+ export async function updateNotice(env = process.env) {
21
+ const file = join(env.XDG_CACHE_HOME || join(env.HOME || homedir(), '.cache'), 'rer', 'update-check.json');
22
+ try {
23
+ if ((await channelOf(layout(env))).channel === 'source') return;
24
+ let checkedAt = 0;
25
+ try { checkedAt = JSON.parse(await readFile(file, 'utf8')).checkedAt ?? 0; } catch {}
26
+ if (Date.now() - checkedAt < interval) return;
27
+ // Record the attempt first: a slow or failed registry costs one wait a day.
28
+ await mkdir(join(file, '..'), { recursive: true });
29
+ await writeFile(file, JSON.stringify({ checkedAt: Date.now() }) + '\n');
30
+ const latest = await latestVersion(env);
31
+ const current = ownManifest().version;
32
+ if (latest && compareVersions(latest, current) > 0) process.stderr.write(`rer ${latest} is available (this is ${current}). Update with: rer update\n`);
33
+ } catch {
34
+ // The notice never stands in the way of the command.
35
+ }
36
+ }
37
+
38
+ // The registry is asked by a child process that is killed at the budget. An
39
+ // in-process request can be aborted, but its pending TCP connect (or DNS
40
+ // lookup) still holds this process open until the system gives up: about 10 s
41
+ // when the registry drops packets.
42
+ function latestVersion(env) {
43
+ return new Promise(resolve => {
44
+ const child = spawn(process.execPath, [fileURLToPath(new URL('./latest.mjs', import.meta.url))], { env, stdio: ['ignore', 'pipe', 'ignore'] });
45
+ let output = '';
46
+ const finish = () => {
47
+ clearTimeout(timer);
48
+ child.kill('SIGKILL');
49
+ child.unref();
50
+ child.stdout.destroy();
51
+ resolve(/^\S+(?=\n)/.exec(output)?.[0]);
52
+ };
53
+ const timer = setTimeout(finish, budget);
54
+ child.stdout.setEncoding('utf8').on('data', data => { output += data; if (output.includes('\n')) finish(); });
55
+ child.once('error', finish);
56
+ child.once('close', finish);
57
+ });
58
+ }
@@ -0,0 +1,47 @@
1
+ // The npm registry's view of @runeditrun/rer: which versions exist, which is
2
+ // latest, and each one's tarball and integrity. The registry is
3
+ // npm_config_registry when set (npm sets it for npx), else the public one.
4
+ import { packageName } from '../package-info.mjs';
5
+
6
+ export const registryUrl = (env = process.env) => (env.npm_config_registry || 'https://registry.npmjs.org').replace(/\/+$/, '');
7
+
8
+ export class UpdateFailure extends Error {}
9
+
10
+ export async function packageMetadata({ env = process.env, signal } = {}) {
11
+ const url = `${registryUrl(env)}/${packageName.replace('/', '%2f')}`;
12
+ let response;
13
+ try { response = await fetch(url, { headers: { accept: 'application/json' }, signal }); }
14
+ catch (error) { if (error.name === 'AbortError' || error.name === 'TimeoutError') throw error; throw new UpdateFailure(`Could not reach ${registryUrl(env)} (${error.cause?.code ?? error.message}).`); }
15
+ if (!response.ok) throw new UpdateFailure(`${url} answered ${response.status}${response.status === 404 ? ': @runeditrun/rer is not published there' : ''}.`);
16
+ try { return await response.json(); } catch { throw new UpdateFailure(`${url} did not answer with package metadata.`); }
17
+ }
18
+
19
+ // The release to install: the exact version asked for, else latest.
20
+ export function pickRelease(metadata, wanted) {
21
+ const version = wanted ?? metadata['dist-tags']?.latest, release = metadata.versions?.[version];
22
+ if (!release) throw new UpdateFailure(wanted ? `Version ${wanted} of ${packageName} is not published.` : `The registry names no latest version of ${packageName}.`);
23
+ return release;
24
+ }
25
+
26
+ // Semantic version order, prereleases below their release:
27
+ // 0.1.0-dev.gaa9b4d4f < 0.1.0 < 0.1.1-dev.g12345678 < 0.1.1.
28
+ export function compareVersions(a, b) {
29
+ const parse = version => {
30
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.*)?$/.exec(version);
31
+ if (!match) throw new UpdateFailure(`Not a version: ${version}`);
32
+ return { core: match.slice(1, 4).map(Number), pre: match[4]?.split('.') ?? [] };
33
+ };
34
+ const x = parse(a), y = parse(b);
35
+ for (let i = 0; i < 3; i++) if (x.core[i] !== y.core[i]) return x.core[i] < y.core[i] ? -1 : 1;
36
+ if (!x.pre.length || !y.pre.length) return x.pre.length === y.pre.length ? 0 : x.pre.length ? -1 : 1;
37
+ for (let i = 0; i < Math.max(x.pre.length, y.pre.length); i++) {
38
+ const p = x.pre[i], q = y.pre[i];
39
+ if (p === undefined || q === undefined) return p === undefined ? -1 : 1;
40
+ if (p === q) continue;
41
+ const pn = /^\d+$/.test(p), qn = /^\d+$/.test(q);
42
+ if (pn && qn) return Number(p) < Number(q) ? -1 : 1;
43
+ if (pn !== qn) return pn ? -1 : 1;
44
+ return p < q ? -1 : 1;
45
+ }
46
+ return 0;
47
+ }
@@ -0,0 +1,29 @@
1
+ // rer --version: this rer's version on the first line. Inside a first-party
2
+ // checkout (or with --cwd DIR) a second line names the version that checkout
3
+ // pins: its package's, or the one its vendored copy recorded, which
4
+ // `rer describe` reports as cliVersion.
5
+ import { readFileSync } from 'node:fs';
6
+ import { dirname, join } from 'node:path';
7
+ import { dispatcher, locate } from './checkout.mjs';
8
+ import { describeCheckout } from './launch/facts.mjs';
9
+ import { ownManifest } from './package-info.mjs';
10
+
11
+ export async function versionCommand(argv) {
12
+ process.stdout.write(ownManifest().version + '\n');
13
+ const target = locate(argv);
14
+ if (target.profile !== 'first-party') return 0;
15
+ const { mode, entry } = dispatcher(target.root);
16
+ if (mode === 'bundled') return 0;
17
+ if (mode === 'package') {
18
+ const pinned = JSON.parse(readFileSync(join(dirname(dirname(entry)), 'package.json'), 'utf8')).version;
19
+ process.stdout.write(`This checkout (${target.root}) pins rer ${pinned} (package).\n`);
20
+ return 0;
21
+ }
22
+ let described;
23
+ try { described = await describeCheckout(target.root, entry, process.env); }
24
+ catch (failure) { process.stdout.write(`This checkout (${target.root}): its pinned rer version could not be read: ${failure.message.split('\n')[0]}\n`); return 0; }
25
+ process.stdout.write(described.cliVersion
26
+ ? `This checkout (${target.root}) pins rer ${described.cliVersion} (vendored scripts/rer.mjs).\n`
27
+ : `This checkout (${target.root}) pins an unversioned rer copy: its vendored scripts/rer.mjs is older than version recording. Refresh its vendored Base to record one.\n`);
28
+ return 0;
29
+ }
package/install.sh ADDED
@@ -0,0 +1,144 @@
1
+ #!/bin/sh
2
+ # Install the rer command (@runeditrun/rer) for this user:
3
+ #
4
+ # curl -fsSL https://runeditrun.com/install.sh | sh
5
+ #
6
+ # It reads the version, tarball and sha512 integrity from the npm registry
7
+ # (npm_config_registry, default https://registry.npmjs.org; RER_VERSION=X pins an
8
+ # exact version, otherwise latest), verifies the download, refuses archives with
9
+ # absolute paths, .. entries, links or devices (and anything tar could read
10
+ # differently from this script's own check), and installs through the
11
+ # package's own `rer cli install`: the same layout as
12
+ # `npx -y @runeditrun/rer cli install`. A failure leaves any previous install
13
+ # selected and working. It never edits shell profiles.
14
+ #
15
+ # Needs curl, tar and Node (the package's minimum). macOS or Linux on x64 or
16
+ # arm64; on Windows, run it inside WSL2.
17
+
18
+ # Everything runs from main, so a partly downloaded script does nothing.
19
+ main() {
20
+ set -eu
21
+ package='@runeditrun/rer'
22
+
23
+ case "$(uname -s 2>/dev/null || echo unknown)" in
24
+ Linux | Darwin) ;;
25
+ MINGW* | MSYS* | CYGWIN* | Windows_NT) fail 'native Windows is not supported; run this inside WSL2 (https://learn.microsoft.com/windows/wsl/install).' ;;
26
+ *) fail "this system ($(uname -s 2>/dev/null || echo unknown)) is not supported; rer runs on macOS and Linux (on Windows, inside WSL2)." ;;
27
+ esac
28
+ case "$(uname -m)" in
29
+ x86_64 | amd64 | arm64 | aarch64) ;;
30
+ *) fail "this processor ($(uname -m)) is not supported; rer runs on x64 and arm64." ;;
31
+ esac
32
+ for tool in curl tar node; do
33
+ command -v "$tool" >/dev/null 2>&1 || fail "$tool is required. Install it, then run this again."
34
+ done
35
+
36
+ registry=${npm_config_registry:-https://registry.npmjs.org}
37
+ registry=${registry%/}
38
+ work=$(mktemp -d "${TMPDIR:-/tmp}/rer-install.XXXXXX")
39
+ trap 'rm -rf "$work"' EXIT
40
+ trap 'exit 130' INT TERM
41
+
42
+ curl -fsSL --proto '=http,https' -H 'Accept: application/json' "$registry/@runeditrun%2frer" -o "$work/metadata.json" \
43
+ || fail "could not read $package from $registry."
44
+ # Writes version, tarball URL, integrity, file count and unpacked size, one per line.
45
+ node - "$work/metadata.json" "${RER_VERSION:-}" >"$work/release" <<'NODE' || exit 1
46
+ var fs = require('fs');
47
+ var wanted = process.argv[3];
48
+ function stop(message) { process.stderr.write('rer install: ' + message + '\n'); process.exit(1); }
49
+ var metadata;
50
+ try { metadata = JSON.parse(fs.readFileSync(process.argv[2], 'utf8')); } catch (error) { stop('the registry answered with something that is not package metadata.'); }
51
+ var version = wanted || (metadata['dist-tags'] || {}).latest;
52
+ var release = (metadata.versions || {})[version];
53
+ if (!release) stop(wanted ? 'version ' + wanted + ' of @runeditrun/rer is not published.' : 'the registry names no latest version of @runeditrun/rer.');
54
+ var dist = release.dist || {};
55
+ if (!/^sha512-[A-Za-z0-9+\/]+=*$/.test(dist.integrity || '')) stop('the registry gives no sha512 integrity for ' + version + '.');
56
+ if (!dist.tarball) stop('the registry gives no tarball for ' + version + '.');
57
+ var minimum = String((release.engines || {}).node || '0').replace(/^>=\s*/, '');
58
+ var have = process.versions.node.split('.').map(Number), need = minimum.split('.').map(Number);
59
+ for (var i = 0; i < 3; i++) {
60
+ if ((have[i] || 0) > (need[i] || 0)) break;
61
+ if ((have[i] || 0) < (need[i] || 0)) stop('rer ' + version + ' needs Node ' + minimum + ' or later; this is Node ' + process.versions.node + '. Install a newer Node, then run this again.');
62
+ }
63
+ process.stdout.write([version, dist.tarball, dist.integrity, dist.fileCount === undefined ? '' : dist.fileCount, dist.unpackedSize === undefined ? '' : dist.unpackedSize].join('\n') + '\n');
64
+ NODE
65
+ { read -r version; read -r tarball; read -r integrity; read -r files; read -r size; } <"$work/release"
66
+
67
+ printf 'Downloading rer %s from %s\n' "$version" "$registry"
68
+ curl -fsSL --proto '=http,https' "$tarball" -o "$work/rer.tgz" || fail "could not download $tarball."
69
+ # The exact bytes the registry names, and nothing tar could write outside its folder.
70
+ node - "$work/rer.tgz" "$integrity" "$files" "$size" <<'NODE' || fail "the download of rer $version was refused; nothing was installed."
71
+ var fs = require('fs'), hashes = require('crypto'), zlib = require('zlib');
72
+ function stop(message) { process.stderr.write('rer install: ' + message + '\n'); process.exit(1); }
73
+ var bytes = fs.readFileSync(process.argv[2]);
74
+ if ('sha512-' + hashes.createHash('sha512').update(bytes).digest('base64') !== process.argv[3]) stop('the download does not match the registry\'s sha512 integrity.');
75
+ var tar;
76
+ try { tar = zlib.gunzipSync(bytes); } catch (error) { stop('the download is not a gzip archive.'); }
77
+ function text(block, start, length) { var end = start; while (end < start + length && block[end] !== 0) end++; return block.toString('utf8', start, end); }
78
+ function zero(bytes) { for (var z = 0; z < bytes.length; z++) if (bytes[z] !== 0) return false; return true; }
79
+ // tar reads a pax extended header too; only path and size (both honoured here)
80
+ // and mtime (only a time) may appear, so both readers see the same entries.
81
+ function paxFields(data) {
82
+ var fields = {}, at = 0;
83
+ while (at < data.length) {
84
+ var space = data.indexOf(0x20, at), digits = space === -1 ? '' : data.toString('latin1', at, space), length = Number(digits);
85
+ if (!/^[1-9][0-9]*$/.test(digits) || at + length <= space + 1 || at + length > data.length || data[at + length - 1] !== 0x0a) stop('the archive has a damaged extended header.');
86
+ var record = data.toString('utf8', space + 1, at + length - 1), equals = record.indexOf('='), key = record.slice(0, equals), value = record.slice(equals + 1);
87
+ at += length;
88
+ if (equals < 1) stop('the archive has a damaged extended header.');
89
+ if (key === 'linkpath') stop('the archive contains a link.');
90
+ if (key === 'size' && !/^[0-9]+$/.test(value)) stop('the archive has a damaged extended header.');
91
+ if (key !== 'path' && key !== 'size' && key !== 'mtime') stop('the archive has an extended header field this installer does not read (' + key + ').');
92
+ fields[key] = key === 'size' ? Number(value) : value;
93
+ }
94
+ return fields;
95
+ }
96
+ var offset = 0, count = 0, total = 0, pax = null, ended = false;
97
+ while (offset + 512 <= tar.length) {
98
+ var block = tar.subarray(offset, offset + 512);
99
+ if (zero(block)) {
100
+ if (!zero(tar.subarray(offset))) stop('the archive has data after its end.');
101
+ ended = true;
102
+ break;
103
+ }
104
+ var sum = 0;
105
+ for (var i = 0; i < 512; i++) sum += i >= 148 && i < 156 ? 32 : block[i];
106
+ if (parseInt(text(block, 148, 8), 8) !== sum) stop('the archive has a damaged header.');
107
+ if (block.toString('latin1', 257, 265) !== 'ustar\u0000' + '00') stop('the archive is not a ustar archive.');
108
+ var sizeField = text(block, 124, 12).trim();
109
+ if (!/^[0-7]+$/.test(sizeField)) stop('the archive has a damaged header.');
110
+ var type = String.fromCharCode(block[156] || 48), length = type !== 'x' && pax && pax.size !== undefined ? pax.size : parseInt(sizeField, 8);
111
+ var data = tar.subarray(offset + 512, offset + 512 + length);
112
+ if (data.length < length) stop('the archive is truncated.');
113
+ offset += 512 + Math.ceil(length / 512) * 512;
114
+ if (type === 'x') {
115
+ if (pax) stop('the archive has two extended headers for one entry.');
116
+ pax = paxFields(data);
117
+ continue;
118
+ }
119
+ var name = pax && pax.path !== undefined ? pax.path : text(block, 345, 155) ? text(block, 345, 155) + '/' + text(block, 0, 100) : text(block, 0, 100);
120
+ pax = null;
121
+ if (type !== '0' && type !== '5') stop('the archive contains a link, device or other special entry (' + name + ').');
122
+ if (name.charAt(0) === '/' || name.split('/').indexOf('..') !== -1 || name.indexOf('\\') !== -1 || name.split('/')[0] !== 'package') stop('the archive contains an unsafe path (' + name + ').');
123
+ if (type === '5' && length !== 0) stop('the archive gives the folder ' + name + ' contents.');
124
+ if (type === '0' && name.charAt(name.length - 1) === '/') stop('the archive gives the file ' + name + ' a folder\'s name.');
125
+ // The registry's file count counts every entry, folders included.
126
+ count++;
127
+ total += length;
128
+ }
129
+ if (!ended || pax) stop('the archive is truncated.');
130
+ if (process.argv[4] !== '' && Number(process.argv[4]) !== count) stop('the archive holds ' + count + ' entries; the registry says ' + process.argv[4] + '.');
131
+ if (process.argv[5] !== '' && Number(process.argv[5]) !== total) stop('the archive unpacks to ' + total + ' bytes; the registry says ' + process.argv[5] + '.');
132
+ NODE
133
+ mkdir "$work/stage"
134
+ tar -xzf "$work/rer.tgz" -C "$work/stage" || fail "could not unpack rer $version; nothing was installed."
135
+ RER_INSTALL_CHANNEL=script node "$work/stage/package/global/rer.mjs" cli install </dev/null \
136
+ || fail "rer cli install failed; any previous install is still selected."
137
+ }
138
+
139
+ fail() {
140
+ printf 'rer install: %s\n' "$*" >&2
141
+ exit 1
142
+ }
143
+
144
+ main "$@"
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Run Edit Run
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,90 @@
1
+ # AI client
2
+
3
+ `ai` implements Base's `ai.provider.v1` slot. Copy this module with the matching
4
+ `operator-auth` module, as with mail. Import production code from `ai/index.mjs`.
5
+ There are no SDK dependencies, automatic retries, schema repairs or provider
6
+ fallbacks. The seed owns enablement, consent, deadlines, budgets and retry policy.
7
+
8
+ ```js
9
+ import { aiConfig, createAiClient, AiError } from './modules/ai/index.mjs';
10
+ const ai = createAiClient(aiConfig(env, { images: 'direct' }));
11
+ const response = await ai.responses({
12
+ model: 'openai/exact-model-id', input: approvedInput, store: false,
13
+ }, { feature: 'analysis', signal: request.signal });
14
+ ```
15
+
16
+ `chat`, `responses` and `embeddings` return the raw `Response`, including raw
17
+ usage, receipt headers and native SSE. Streaming passes through without buffering.
18
+ Consume JSON or SSE in the seed's own format. Embeddings have no native streaming
19
+ format; the direct transport passes the caller's fields without translating them.
20
+ `receipt(id)` calls the linked service's receipt endpoint. An omitted feature
21
+ leaves Models to use the app key's first/default feature. Do not forward
22
+ `x-models-*` headers to browsers. Pinned names (provider name, slash, then exact model ID) require an exact
23
+ `x-models-target` match when linked; aliases (including `@app/alias`) do not.
24
+
25
+ `AI_ENABLED=true` is required. Direct calls use `AI_API_KEY`, `AI_MODEL` and
26
+ `AI_BASE_URL` (defaults to OpenAI's `/v1`). Any OpenAI-compatible URL works,
27
+ including OpenRouter or Cloudflare AI Gateway. Direct calls preserve the supplied
28
+ API path prefix. Linked calls use `MODELS_SERVICE`
29
+ and `MODELS_KEY`. Neither a link nor credentials turn AI on. URLs must be HTTPS
30
+ or local loopback HTTP, with no credentials, query or fragment. Redirects fail.
31
+
32
+ Both transports configured for a feature give `AiError.code ===
33
+ 'ai_misconfigured'` when called, and diagnostics in `rer check` and `rer doctor`.
34
+ The app still starts. Declare `ai: { features: { images: 'direct' } }` on the
35
+ command adapter and pass the same feature map to `aiConfig` for capabilities
36
+ that deliberately use their own provider key while the app is linked. An
37
+ explicit feature transport never falls through to the other transport.
38
+
39
+ For a custom provider-edge adapter, `createAiClient(config, { transport })`
40
+ accepts `request({operation,body,feature,signal,selected}) -> Response`; selection,
41
+ enablement and pinned-target checks still apply. Ordinary HTTP uses `{ fetch }`.
42
+ Errors expose fixed text and typed codes, never upstream exception messages.
43
+
44
+ ## Local development
45
+
46
+ The reference and composed foundation mount `withDevAi` from `./dev/index.mjs` in their
47
+ local-only Worker entry. `GET /__dev/ai` lists captures as JSON. POST to
48
+ `/__dev/ai/v1/chat/completions`, `/responses`, or `/embeddings` to call the double.
49
+ Every surface needs operator-auth's `RER_DEV_KEY` header or its exchanged,
50
+ host-only cookie. Requests without the key return 404 even through a proxy.
51
+
52
+ Product routes can import `createDevAiClient` in their local-only implementation;
53
+ it also checks the originating product request's key gate. AI enablement still
54
+ comes from the seed. A local call answers text as `[dev] <feature> <hash8>`
55
+ (two chunks when streamed), `json_object` as `{}`, and embeddings as deterministic
56
+ input-derived vectors. Schema output and forced tools throw
57
+ `dev_fake_cannot_answer` with instructions to use a capped Models dev app.
58
+ The double produces development output only; it cannot stand in for a real
59
+ product result. `./fake/index.mjs` supports a supplied `script` for provider-edge tests.
60
+
61
+ Outbox rows use local D1 and survive restarts. They are bounded by age and count,
62
+ excluded from installation exports, and deleted with D1 by `rer reset --yes`.
63
+ Capture failures return `dev_outbox_unavailable` and close any live response.
64
+ Production imports neither `./dev/index.mjs` nor `./fake/index.mjs`. `rer build` scans output for
65
+ their marker and refuses a bundle containing it, even without dev identity.
66
+
67
+ For live dev, first create a Models **dev app** with a low cap, short expiry and
68
+ cheap model allow-list. Models enforces those limits; the client does not invent
69
+ a local budget or claim that the key prefix proves a cap. Pipe its key on stdin:
70
+
71
+ ```sh
72
+ your-secret-reader | rer dev --models live --models-service https://models.example
73
+ ```
74
+
75
+ The key is saved in `.rer/local/models.json` (0600, directories 0700), never in
76
+ arguments or tracked settings. Subsequent `rer dev --models live` reads the file,
77
+ checks the app's authenticated model catalogue, and prints
78
+ `RER_MODELS_LIVE <origin> via <providers>`. No failed live call switches to the
79
+ double. Live outbox rows contain receipt metadata and fixed error codes only.
80
+ `rer check` and `rer doctor` flag unsafe storage. A default `rer dev` still uses
81
+ the double, even when a live file exists. Stop dev before changing modes.
82
+
83
+ Build hides the private file and restores it afterward. Deploy, dry-run deploy
84
+ and deployment artifact/plan preparation refuse it; local binding names are
85
+ refused in deploy declarations too. Remove it explicitly before deployment.
86
+ `rer reset --yes` deletes it along with the checkout's other local-only state.
87
+
88
+ Models routing, billing and app administration, Worker probes and Pencil's first
89
+ analytics journey belong to their separate tasks. No provider account is needed
90
+ to run this module's tests.
@@ -0,0 +1,71 @@
1
+ import { AiError, serviceErrorCodes } from './errors.mjs';
2
+ import { selectTransport } from './config.mjs';
3
+
4
+ const endpoints = { chat: 'chat/completions', responses: 'responses', embeddings: 'embeddings' };
5
+ const featureName = value => typeof value === 'string' && /^[a-zA-Z0-9][a-zA-Z0-9_.:/-]{0,127}$/.test(value);
6
+ async function discard(response) {
7
+ try { await response.body?.cancel(); } catch {}
8
+ }
9
+ function endpoint(base, path, models) {
10
+ const url = new URL(base);
11
+ url.pathname = url.pathname.replace(/\/$/, '') + (models && !url.pathname.replace(/\/$/, '').endsWith('/v1') ? '/v1/' : '/') + path;
12
+ return url.href;
13
+ }
14
+
15
+ /** ai.provider.v1: one attempt, raw JSON/SSE and usage, caller-owned deadlines. */
16
+ export function createAiClient(config = {}, { fetch: send = globalThis.fetch, transport: adapter } = {}) {
17
+ async function request(operation, body, options = {}) {
18
+ const feature = options.feature ?? 'default';
19
+ if (!featureName(feature)) throw new AiError('ai_invalid_request', 400);
20
+ const selected = selectTransport(config, feature);
21
+ let model;
22
+ if (operation !== 'receipt') {
23
+ if (!body || typeof body !== 'object' || Array.isArray(body)) throw new AiError('ai_invalid_request', 400);
24
+ model = body.model ?? config.model;
25
+ if (typeof model !== 'string' || !model.trim()) throw new AiError('ai_invalid_request', 400);
26
+ } else if (selected.name !== 'models' || typeof body !== 'string' || !/^[A-Za-z0-9_-]{1,128}$/.test(body)) {
27
+ throw new AiError('ai_invalid_request', 400);
28
+ }
29
+ const payload = operation === 'receipt' ? undefined : { ...body, model };
30
+ const headers = { authorization: `Bearer ${selected.apiKey}`, accept: payload?.stream ? 'text/event-stream' : 'application/json' };
31
+ if (payload) headers['content-type'] = 'application/json';
32
+ if (selected.name === 'models') {
33
+ if (options.feature !== undefined) headers['x-models-feature'] = feature;
34
+ if (options.subject !== undefined) headers['x-models-subject'] = options.subject;
35
+ }
36
+ let response;
37
+ try {
38
+ if (options.signal?.aborted) throw new AiError('upstream_uncertain', 504);
39
+ response = adapter ? await adapter.request({ operation, body: payload, feature, signal: options.signal, selected }) :
40
+ await send(endpoint(selected.baseUrl, operation === 'receipt' ? `receipts/${body}` : endpoints[operation], selected.name === 'models'), {
41
+ method: payload ? 'POST' : 'GET', headers, body: payload ? JSON.stringify(payload) : undefined,
42
+ signal: options.signal, redirect: 'manual',
43
+ });
44
+ } catch (error) {
45
+ if (error instanceof AiError) throw error;
46
+ // A rejection may have been billed. Never retry it or switch transport.
47
+ throw new AiError('upstream_uncertain', 504);
48
+ }
49
+ if (!(response instanceof Response)) throw new AiError('ai_invalid_response');
50
+ if (!response.ok) {
51
+ let code;
52
+ // Only a fixed code is accepted; upstream messages are never returned.
53
+ if (selected.name === 'models') {
54
+ try { code = (await response.json()).error?.code; } catch {}
55
+ } else await discard(response);
56
+ const fallback = response.status === 429 ? 'upstream_limited' : response.status === 401 || response.status === 403 ? 'upstream_auth' : response.status >= 500 ? 'upstream_unavailable' : 'upstream_error';
57
+ throw new AiError(serviceErrorCodes.has(code) ? code : fallback, response.status);
58
+ }
59
+ if (selected.name === 'models' && operation !== 'receipt' && model.includes('/') && !model.startsWith('@') && response.headers.get('x-models-target') !== model) {
60
+ await discard(response);
61
+ throw new AiError('ai_target_mismatch');
62
+ }
63
+ return response;
64
+ }
65
+ return Object.freeze({
66
+ chat: (body, options) => request('chat', body, options),
67
+ responses: (body, options) => request('responses', body, options),
68
+ embeddings: (body, options) => request('embeddings', body, options),
69
+ receipt: (id, options) => request('receipt', id, options),
70
+ });
71
+ }
@@ -0,0 +1,39 @@
1
+ import { AiError } from './errors.mjs';
2
+
3
+ export function aiConfig(env = {}, features = {}) {
4
+ return {
5
+ enabled: env.AI_ENABLED === true || env.AI_ENABLED === 'true',
6
+ model: env.AI_MODEL,
7
+ direct: env.AI_BASE_URL || env.AI_API_KEY ? { baseUrl: env.AI_BASE_URL || 'https://api.openai.com/v1', apiKey: env.AI_API_KEY } : undefined,
8
+ models: env.MODELS_SERVICE || env.MODELS_KEY ? { baseUrl: env.MODELS_SERVICE, apiKey: env.MODELS_KEY } : undefined,
9
+ features,
10
+ };
11
+ }
12
+
13
+ export function validBaseUrl(value) {
14
+ try {
15
+ const url = new URL(value);
16
+ const local = url.hostname === 'localhost' || url.hostname === '[::1]' || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(url.hostname);
17
+ return (url.protocol === 'https:' || (url.protocol === 'http:' && local)) && !url.username && !url.password && !url.search && !url.hash;
18
+ } catch { return false; }
19
+ }
20
+
21
+ export function selectTransport(config = {}, feature = 'default') {
22
+ if (config.enabled !== true) throw new AiError('ai_disabled', 503);
23
+ const requested = config.features && Object.hasOwn(config.features, feature) ? config.features[feature] : undefined;
24
+ if (requested !== undefined && !['direct', 'models'].includes(requested)) throw new AiError('ai_misconfigured', 503);
25
+ const configured = ['direct', 'models'].filter(name => config[name] && (config[name].baseUrl || config[name].apiKey));
26
+ const name = requested ?? (configured.length === 1 ? configured[0] : undefined);
27
+ const transport = name && config[name];
28
+ if (!transport || !validBaseUrl(transport.baseUrl) || typeof transport.apiKey !== 'string' || !transport.apiKey || /\s/.test(transport.apiKey)) throw new AiError('ai_misconfigured', 503);
29
+ return { name, ...transport };
30
+ }
31
+
32
+ /** Diagnostics use the same selection as calls; no network or credential output. */
33
+ export function aiDiagnostics(config = {}) {
34
+ if (config.enabled !== true) return [];
35
+ return [...new Set(['default', ...Object.keys(config.features ?? {})])].flatMap(feature => {
36
+ try { selectTransport(config, feature); return []; }
37
+ catch (error) { return [{ feature, code: error.code, message: error.message }]; }
38
+ });
39
+ }
@@ -0,0 +1,6 @@
1
+ import type { AiClient, AiConfig, AiTransport } from '../index.mjs';
2
+ export const DEV_AI_MARKER: string;
3
+ export interface AiOutbox { put(record: object): Promise<void>; list(): Promise<object[]>; }
4
+ export function createAiOutbox(options: { db: D1Database; clock?: () => number; maxRequests?: number; maxAgeMs?: number }): AiOutbox;
5
+ export function createDevAiClient(config: AiConfig, dependencies: { request: Request; key?: string; origin: string; local: boolean; outbox: AiOutbox; live?: { baseUrl: string; apiKey: string }; fetch?: typeof fetch; script?: AiTransport['request'] }): AiClient;
6
+ export function withDevAi<Env, Worker extends { fetch?: (request: never, env: Env, execution: never) => unknown }>(worker: Worker, options?: { bindings?: (env: Env) => Env }): Worker;