@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,33 @@
1
+ import {localDependencyLinks} from './dependency-doctor.mjs';
2
+ import { contained } from './project.mjs';
3
+ import { missing, refuse } from './errors.mjs';
4
+ import { locateExport, locateImport } from './archive-path.mjs';
5
+ export async function transfer(project, options, signal, custody) {
6
+ const direction = options.verb, file = direction === 'export' ? options.output : options.input;
7
+ if (!file) throw missing(`Provide --${direction === 'export' ? 'output' : 'input'} FILE.`);
8
+ if (direction === 'import' && !options.yes) throw refuse('Import requires explicit --yes confirmation.');
9
+ const target = options.target ?? 'local', api = project.adapter.portability;
10
+ if(direction==='import' && options.legacyV1) {
11
+ if(!options.acknowledgeUnverifiedMetadata)throw refuse('Legacy v1 recovery requires --acknowledge-unverified-metadata: source identity, erasure metadata and other manifest metadata cannot be authenticated. See modules/portability/README.md#backup-only-v1-recovery.');
12
+ if(!options.output)throw missing('Legacy v1 recovery requires --output FILE for the new v2 backup.');
13
+ if(target!=='local'||options.platform==='container'||api?.legacyRecovery!==true)throw refuse('Legacy v1 recovery is supported only by the local Workers portability adapter in an empty isolated installation.');
14
+ }else if(direction==='import' && (options.acknowledgeUnverifiedMetadata||options.output))throw refuse('--acknowledge-unverified-metadata and import --output require --legacy-v1.');
15
+ if (!api || typeof api[direction] !== 'function' || (target === 'remote' && api.remote !== true)) throw refuse(`Complete ${target} ${direction} is unsupported: the reviewed portability API and binding policy must be adopted first.`);
16
+ const located = direction === 'export' ? await locateExport(project.root, file) : await locateImport(project.root, file), path = located.path;
17
+ const legacyOutput = options.legacyV1 ? await locateExport(project.root, options.output) : undefined;
18
+ const legacyRecovery=legacyOutput?{output:legacyOutput.path,acknowledged:options.acknowledgeUnverifiedMetadata}:undefined;
19
+ const sessionFile = options.sessionFile ? await contained(project.root, options.sessionFile, { privateFile: true }) : undefined;
20
+ if(options.journal && legacyRecovery)throw refuse('--journal requires normal v2 import; legacy v1 metadata cannot authenticate a later-journal recovery.');
21
+ if (options.journal && (direction !== 'import' || target !== 'local')) throw refuse('--journal applies to a local import only.');
22
+ // A later archive of the same installation carries its latest erasure journal.
23
+ const journal = options.journal ? await contained(project.root, options.journal, { privateFile: true }) : undefined;
24
+ await project.adapter.prepareData?.(project.root, custody.store, signal);
25
+ // Only now can the seed's Vite configuration load in a checkout that never built.
26
+ await located.unserved(); await legacyOutput?.unserved();
27
+ const result=await api[direction]({ root: project.root, target, path, journal, origin: options.origin, sessionFile, signal, platform:options.platform, legacyRecovery, ...custody });
28
+ if(direction==='import' && target==='local' && (await localDependencyLinks(project.root)).some(link=>link.needs_relink)) {
29
+ custody.store.report('Imported provider links need fresh approval. Run rer setup with RER_LINK_TOKEN_FILE to re-link this installation.');
30
+ return {...result,needsRelink:true,nextCommand:'rer setup'};
31
+ }
32
+ return result;
33
+ }
@@ -0,0 +1,36 @@
1
+ // The rer CLI version: one source (global/package.json in Base) for the npm
2
+ // package, `rer --version` and the version a vendored copy records. A commit
3
+ // tagged rer-v<version> is that version; any other commit stamps
4
+ // <version>-dev.g<sha8>, which sorts below the release.
5
+ import { execFileSync } from 'node:child_process';
6
+ import { readFileSync } from 'node:fs';
7
+ import { join } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ const packageName = '@runeditrun/rer';
11
+ const readJson = path => { try { return JSON.parse(readFileSync(path, 'utf8')); } catch (error) { if (error.code === 'ENOENT') return undefined; throw error; } };
12
+
13
+ export function stampedVersion(base, version, revision = 'HEAD') {
14
+ const git = args => execFileSync('git', ['-C', base, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim();
15
+ if (git(['tag', '--points-at', revision]).split('\n').includes(`rer-v${version}`)) return version;
16
+ return `${version}-dev.g${git(['rev-parse', '--short=8', revision])}`;
17
+ }
18
+
19
+ // The version of the rer source at `root`: a packed @runeditrun/rer carries it
20
+ // in its package.json; a Base checkout derives it from its version source and
21
+ // Git. undefined for a source tree without the version source.
22
+ export function cliVersion(root) {
23
+ const packed = readJson(join(root, 'package.json'));
24
+ if (packed?.name === packageName) return packed.version;
25
+ const source = readJson(join(root, 'global/package.json'));
26
+ return source ? stampedVersion(root, source.version) : undefined;
27
+ }
28
+
29
+ // The version a vendored copy recorded (scripts/base-cli/inventory.json), else
30
+ // the version of the rer source this file belongs to. undefined for a vendored
31
+ // copy too old to record one.
32
+ export function runningVersion() {
33
+ const vendored = readJson(new URL('../inventory.json', import.meta.url));
34
+ if (vendored) return vendored.cliVersion;
35
+ return cliVersion(fileURLToPath(new URL('..', import.meta.url)));
36
+ }
@@ -0,0 +1,111 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ export const sha256 = (bytes) =>
4
+ createHash("sha256").update(bytes).digest("hex");
5
+ export function git(repo, args) {
6
+ return execFileSync("git", ["--no-replace-objects", "-C", repo, ...args], {
7
+ maxBuffer: 128 * 1024 * 1024,
8
+ stdio: ["ignore", "pipe", "pipe"],
9
+ });
10
+ }
11
+ export function commit(repo, ref = "HEAD") {
12
+ if (typeof ref !== "string" || ref.startsWith("-"))
13
+ throw new Error("Invalid Git ref");
14
+ const sha = git(repo, ["rev-parse", "--verify", `${ref}^{commit}`])
15
+ .toString()
16
+ .trim();
17
+ if (!/^[a-f0-9]{40}$/.test(sha)) throw new Error("Expected SHA-1 Git commit");
18
+ return sha;
19
+ }
20
+ export function safePath(path) {
21
+ if (
22
+ typeof path !== "string" ||
23
+ !path ||
24
+ path.includes("\\") ||
25
+ /[\x00-\x1f\x7f]/.test(path) ||
26
+ path.split("/").some((p) => !p || p === "." || p === "..")
27
+ )
28
+ throw new Error(`Unsafe source or target: ${path}`);
29
+ if (
30
+ path
31
+ .split("/")
32
+ .some(
33
+ (p) =>
34
+ [
35
+ ".git",
36
+ ".seed",
37
+ ".worktrees",
38
+ "node_modules",
39
+ "dist",
40
+ ".output",
41
+ ".wrangler",
42
+ ".tanstack",
43
+ "test-results",
44
+ "playwright-report",
45
+ "coverage",
46
+ ".DS_Store",
47
+ ].includes(p) ||
48
+ /^\.env|^\.dev\.vars|\.(pem|key|p12|pfx|tsbuildinfo)$/.test(p),
49
+ ) ||
50
+ /(^|\/)(wrangler\.toml|wrangler\.local\.jsonc?|composition\.lock\.json)$/.test(
51
+ path,
52
+ )
53
+ )
54
+ throw new Error(`State or secret is not source: ${path}`);
55
+ return path;
56
+ }
57
+ export function tree(repo, sha) {
58
+ return git(repo, ["ls-tree", "-rz", "--full-tree", sha])
59
+ .toString()
60
+ .split("\0")
61
+ .filter(Boolean)
62
+ .map((line) => {
63
+ const tab = line.indexOf("\t");
64
+ const header = line.slice(0, tab),
65
+ path = line.slice(tab + 1);
66
+ const [mode, type, oid] = header.split(" ");
67
+ return { path, mode, type, oid };
68
+ });
69
+ }
70
+ export function blob(repo, sha, path) {
71
+ safePath(path);
72
+ return git(repo, ["show", `${sha}:${path}`]);
73
+ }
74
+ export function json(repo, sha, path) {
75
+ return JSON.parse(blob(repo, sha, path));
76
+ }
77
+ // Base's verification belongs in Base, rather than in each adopting seed.
78
+ export function testSource(path) {
79
+ return path.split('/').some(part => ['test', 'tests', 'fixtures'].includes(part)) ||
80
+ /(?:\.test\.[^/]+|(?:^|\/)test-manifest-support\.mjs$|(?:^|\/)(?:test-fixture|[^/]+-fixture)\.(?:mjs|cjs)$|(?:^|\/)(?:tests|test_[^/]+|[^/]*_tests)\.py|(?:^|\/)browser-(?:check|output)\.mjs)$/.test(path);
81
+ }
82
+ export function select(repo, sha, source, { includeTests = true } = {}) {
83
+ safePath(source);
84
+ const entries = tree(repo, sha).filter(
85
+ (e) => (e.path === source || e.path.startsWith(`${source}/`)) &&
86
+ (includeTests || !testSource(e.path)),
87
+ );
88
+ if (!entries.length) throw new Error(`Missing source: ${source}`);
89
+ return entries.map((e) => {
90
+ safePath(e.path);
91
+ if (e.type !== "blob" || !["100644", "100755"].includes(e.mode))
92
+ throw new Error(`Unsafe source mode: ${e.path}`);
93
+ return {
94
+ path: e.path,
95
+ relative: e.path === source ? "" : e.path.slice(source.length + 1),
96
+ bytes: git(repo, ["cat-file", "blob", e.oid]),
97
+ mode: e.mode === "100755" ? 0o755 : 0o644,
98
+ };
99
+ });
100
+ }
101
+ export function familyManifest(repo, sha) {
102
+ const data = json(repo, sha, "family.json");
103
+ // Bootstrap validates only what is needed to locate immutable tooling.
104
+ // The pinned exporter owns the complete schema and compatibility rules.
105
+ if (
106
+ typeof data?.base?.commit !== "string" ||
107
+ !/^[a-f0-9]{40}$/.test(data.base.commit)
108
+ )
109
+ throw new Error("family.json needs an immutable base commit");
110
+ return data;
111
+ }
@@ -0,0 +1,81 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import crypto from 'node:crypto';
4
+ import {execFileSync} from 'node:child_process';
5
+ export const hash = value => crypto.createHash('sha256').update(value).digest('hex');
6
+ export const json = value => JSON.stringify(value, null, 2) + '\n';
7
+ const environment = {...process.env, GIT_NO_REPLACE_OBJECTS: '1'};
8
+ export function git(root, ...args) {
9
+ return execFileSync('git', ['-C', root, ...args], {env: environment, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe']}).trim();
10
+ }
11
+ // Raw Git output, for committed source bytes. The limit fails explicitly rather than truncating.
12
+ function output(root, args, input) {
13
+ try {
14
+ return execFileSync('git', ['-C', root, ...args], {env: environment, input, maxBuffer: 64 * 1024 * 1024, stdio: [input === undefined ? 'ignore' : 'pipe', 'pipe', 'pipe']});
15
+ } catch (error) {
16
+ if (error.code === 'ENOBUFS') throw Error('Git source output exceeds the 64 MiB acquisition limit');
17
+ throw error;
18
+ }
19
+ }
20
+ export const raw = (root, ...args) => output(root, args);
21
+ export const batch = (root, input, ...args) => output(root, args, input);
22
+ export function safe(name) {
23
+ if (typeof name !== 'string' || !name || name.includes('\\') || /[\x00-\x1f\x7f]/.test(name) || path.posix.isAbsolute(name) || name.split('/').some(p => !p || p === '.' || p === '..' || p === '.git')) {
24
+ throw Error(`Unsafe path: ${name}`);
25
+ }
26
+ return name;
27
+ }
28
+ export function noLinks(root, relative) {
29
+ let current = root;
30
+ for (const part of relative.split('/')) {
31
+ current = path.join(current, part);
32
+ let stat;
33
+ try { stat = fs.lstatSync(current); }
34
+ catch (error) { if (error.code !== 'ENOENT') throw error; }
35
+ if (stat?.isSymbolicLink()) throw Error('Symlink in destination path');
36
+ }
37
+ }
38
+ export function tracked(root, allowMissing = false) {
39
+ const result = Object.create(null);
40
+ for (const name of git(root, 'ls-files', '-z').split('\0').filter(Boolean)) {
41
+ safe(name);
42
+ if (name === 'sources.lock.json' || name.startsWith('.edition/')) continue;
43
+ noLinks(root, name);
44
+ if (allowMissing && !fs.existsSync(path.join(root, name))) continue;
45
+ const stat = fs.statSync(path.join(root, name));
46
+ if (!stat.isFile()) throw Error(`Unsupported tracked source: ${name}`);
47
+ result[name] = {data: fs.readFileSync(path.join(root, name)).toString('base64'), executable: !!(stat.mode & 0o111)};
48
+ }
49
+ return result;
50
+ }
51
+ export const digest = files => hash(json(files));
52
+ // Base's test, fixture and browser-check sources, which portable copies leave out.
53
+ // Composition pins its tooling alone, so composition/git-source.mjs keeps its own copy.
54
+ export function testSource(path) {
55
+ return path.split('/').some(part => ['test', 'tests', 'fixtures'].includes(part)) ||
56
+ /(?:\.test\.[^/]+|(?:^|\/)test-manifest-support\.mjs$|(?:^|\/)(?:test-fixture|[^/]+-fixture)\.(?:mjs|cjs)$|(?:^|\/)(?:tests|test_[^/]+|[^/]*_tests)\.py|(?:^|\/)browser-(?:check|output)\.mjs)$/.test(path);
57
+ }
58
+ export function writeTree(root, files) {
59
+ // Validate the complete destination set before writing any selected source.
60
+ for (const name of Object.keys(files)) {
61
+ safe(name); noLinks(root, name);
62
+ if (fs.existsSync(path.join(root, name))) throw Error(`Source destination already exists: ${name}`);
63
+ }
64
+ for (const [name, value] of Object.entries(files)) {
65
+ const target = path.join(root, name);
66
+ fs.mkdirSync(path.dirname(target), {recursive: true});
67
+ fs.writeFileSync(target, Buffer.from(value.data, 'base64'), {mode: value.executable ? 0o755 : 0o644, flag: 'wx'});
68
+ }
69
+ }
70
+ export function fresh(destination, root) {
71
+ let absolute = path.resolve(destination);
72
+ let parent = path.dirname(absolute);
73
+ let tail = path.basename(absolute);
74
+ while (!fs.existsSync(parent)) {
75
+ tail = path.join(path.basename(parent), tail);
76
+ parent = path.dirname(parent);
77
+ }
78
+ absolute = path.join(fs.realpathSync(parent), tail);
79
+ if (absolute === root || absolute.startsWith(root + path.sep) || fs.existsSync(absolute)) throw Error('Output must be absent and outside edition');
80
+ return absolute;
81
+ }
@@ -0,0 +1,65 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import {safe} from './files.mjs';
4
+ export const VERSION = '1.1.0';
5
+ const identity = /^[a-zA-Z0-9][a-zA-Z0-9._-]*\/[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
6
+ export function origin(value) {
7
+ if (!value || typeof value.repository !== 'string' || !value.repository || value.repository.startsWith('-') || (!value.projection && !/^[a-f0-9]{40}$/.test(value.revision))) {
8
+ throw Error('Source requires repository and immutable full commit');
9
+ }
10
+ if (value.projection) {
11
+ const p = value.projection;
12
+ if (value.revision !== undefined || p.schemaVersion !== 1 || !/^[a-f0-9]{64}$/.test(p.originalSha256) || !/^[a-f0-9]{64}$/.test(p.recipeSha256) || Object.keys(p).sort().join(',') !== 'originalSha256,recipeSha256,schemaVersion') throw Error('Invalid public projection identity');
13
+ }
14
+ if (value.paths) {
15
+ if (!Array.isArray(value.paths) || !value.paths.length) throw Error('Origin paths must be nonempty');
16
+ value.paths.forEach(safe);
17
+ }
18
+ if (value.path !== undefined && value.path !== '.') safe(value.path);
19
+ }
20
+ export function manifest(root) {
21
+ const recipe = JSON.parse(fs.readFileSync(path.join(root, 'edition.json'), 'utf8'));
22
+ if (recipe.schemaVersion !== 1 || !identity.test(recipe.id)) throw Error('Invalid edition identity/schema');
23
+ if (recipe.toolchain?.id !== 'runeditrun/edition-authoring' || recipe.toolchain.version !== VERSION) throw Error('Unsupported independently pinned toolchain');
24
+ if (recipe.parent) origin(recipe.parent);
25
+ if (!Array.isArray(recipe.components)) throw Error('Components required');
26
+ const ids = new Set();
27
+ const paths = [];
28
+ let foundations = 0;
29
+ for (const component of recipe.components) {
30
+ if (!identity.test(component.id) || ids.has(component.id)) throw Error('Duplicate/invalid publisher-qualified component');
31
+ ids.add(component.id);
32
+ if (!['edition', 'module', 'family', 'foundation'].includes(component.role)) throw Error('Invalid component role');
33
+ if (component.role === 'foundation') foundations++;
34
+ const selected = component.source;
35
+ if (selected?.kind === 'local') {
36
+ if (!Array.isArray(selected.paths) || !selected.paths.length) throw Error('Local source paths required');
37
+ selected.paths.forEach(p => paths.push(safe(p)));
38
+ if (selected.origin) origin(selected.origin);
39
+ for (const mapping of selected.mappings || []) {
40
+ safe(mapping.path); safe(mapping.originPath);
41
+ if (!selected.origin || !selected.paths.some(p => mapping.path === p || mapping.path.startsWith(p + '/'))) {
42
+ throw Error('Mapping outside local source or missing origin');
43
+ }
44
+ }
45
+ } else if (selected?.kind === 'git') {
46
+ origin(selected);
47
+ paths.push(safe(selected.destination));
48
+ if (selected.workspace && !path.isAbsolute(selected.workspace)) throw Error('Workspace must be an explicit absolute checkout');
49
+ } else throw Error('Unknown source kind');
50
+ }
51
+ for (const component of recipe.components) {
52
+ for (const required of component.requires || []) if (!ids.has(required)) throw Error(`Missing selected dependency: ${required}`);
53
+ for (const conflict of component.conflicts || []) if (ids.has(conflict)) throw Error(`Conflicting selected component: ${conflict}`);
54
+ }
55
+ if (foundations > 1) throw Error('Select one runtime foundation');
56
+ for (let i = 0; i < paths.length; i++) {
57
+ if (paths[i] === 'edition.json' || paths[i] === 'sources.lock.json' || paths[i].startsWith('.edition')) throw Error('Reserved source destination');
58
+ for (let j = 0; j < i; j++) {
59
+ if (paths[i] === paths[j] || paths[i].startsWith(paths[j] + '/') || paths[j].startsWith(paths[i] + '/')) {
60
+ throw Error(`Colliding source paths: ${paths[i]} and ${paths[j]}`);
61
+ }
62
+ }
63
+ }
64
+ return recipe;
65
+ }
@@ -0,0 +1,158 @@
1
+ # rer
2
+
3
+ `rer` is the Run Edit Run command. Install it once, then run `rer <verb>` in any
4
+ Run Edit Run checkout: every verb runs that checkout's own pinned copy, so a
5
+ checkout always gets the behaviour it was built and tested with.
6
+
7
+ ## Install
8
+
9
+ Any one of these leaves `rer` on your PATH:
10
+
11
+ ```sh
12
+ npx -y @runeditrun/rer cli install # user install in ~/.local/share/rer, launcher ~/.local/bin/rer
13
+ curl -fsSL https://runeditrun.com/install.sh | sh # the same user install, without npm
14
+ npm install -g @runeditrun/rer # npm's own global layout
15
+ ```
16
+
17
+ `install.sh` is the file at the root of this package. It reads the version, the
18
+ tarball and its sha512 integrity from the npm registry (`npm_config_registry`,
19
+ default `https://registry.npmjs.org`; `RER_VERSION=X` pins an exact version,
20
+ otherwise the latest), checks the download's integrity, file count and size,
21
+ refuses archives with absolute paths, `..` entries, links or devices, then runs
22
+ the package's own `rer cli install`. A failed or refused download leaves the
23
+ version you had selected.
24
+
25
+ No installer edits shell profiles. When `~/.local/bin` is not on your PATH, the
26
+ install prints the exact line to add for your shell. The launcher runs `node` from
27
+ PATH, so a Node upgrade does not break it. A re-run with the same build changes
28
+ nothing; a different build is installed beside the current one, the previous one
29
+ is kept and older ones are removed. It refuses to replace a `~/.local/bin/rer`
30
+ that it did not write.
31
+
32
+ `rer --version` prints this rer's version; inside a checkout a second line
33
+ names the version the checkout pins, or says that its vendored copy is
34
+ unversioned (exported before copies recorded one).
35
+
36
+ `rer cli status` shows the version, the digest of the installed contents, the
37
+ install channel (`npx`, `script` or `npm-global`), the launcher, the install root
38
+ and every other `rer` on PATH. `rer cli uninstall` removes the launcher and the
39
+ install root it runs only; `~/.rer` (servers, jobs, Node runtimes) is untouched.
40
+ An npm global `rer` prints its `npm uninstall -g` command and leaves a user
41
+ install in place.
42
+
43
+ ### Requirements
44
+
45
+ - macOS or Linux, on x64 or arm64. WSL2 counts as Linux.
46
+ - Node 22 or later on PATH; `rer` stops with one line naming the minimum on an
47
+ older Node.
48
+ - For `install.sh`: `curl` and `tar`.
49
+ - For `rer dev` in a checkout: the checkout's own package manager (pnpm for
50
+ Run Edit Run seeds).
51
+
52
+ Not supported: native Windows (`install.sh` and `rer` say to use WSL2), and
53
+ `OPERATIONS.json` version 1 projects.
54
+
55
+ ## Update
56
+
57
+ ```sh
58
+ rer update # the latest published version
59
+ rer update --version X # exactly X
60
+ ```
61
+
62
+ `rer update` follows the way `rer` was installed. A user install (`npx` or
63
+ `install.sh`) downloads the version from the registry, checks it as `install.sh`
64
+ does and switches to it atomically, keeping the previous version and the same
65
+ channel; a damaged or mismatched download leaves the current version selected.
66
+ It says "already current" when the registry's version has the same contents. A
67
+ development build (`<version>-dev.g<sha8>`) moves to the release once that
68
+ version is published, and a different build of the same version counts as an
69
+ update. An npm global install runs `npm install -g @runeditrun/rer@X` for its own
70
+ prefix; when npm fails (for example, a prefix only root can write), `rer update`
71
+ exits non-zero with npm's message and the exact command to run.
72
+
73
+ In a terminal, `rer` checks the registry at most once a day and prints one line
74
+ when a newer version is published. It never prints in `--json` output or when
75
+ output is not a terminal, never delays a command by more than about 1.5 seconds,
76
+ and `RER_NO_UPDATE_CHECK=1` turns it off.
77
+
78
+ ## Launch a checkout
79
+
80
+ ```sh
81
+ rer dev
82
+ ```
83
+
84
+ In a first-party checkout this is the whole launch. It installs dependencies when
85
+ `node_modules` is missing, incomplete (no `node_modules/.modules.yaml`, or an
86
+ install a launch started did not finish) or older than the lockfile, sets up a local owner
87
+ (`owner@<checkout-name>.test`) on the first free port from 8787 when the checkout
88
+ has never been set up (`--port N` picks the port), fills any setup answer the
89
+ seed declares a `localDefault` for in `rer-setup.json` (a literal, a generated
90
+ secret kept only in the checkout's private settings, or the chosen local
91
+ origin), starts the app and prints:
92
+
93
+ ```
94
+ RER_READY http://127.0.0.1:8787
95
+ RER_SIGNED_IN owner@cradle.test
96
+ RER_OPEN http://127.0.0.1:8787/__dev/key#...
97
+ ```
98
+
99
+ or `RER_SIGN_IN <outbox>` for a seed that signs in through its development outbox.
100
+ It never prompts and never re-runs setup on a checkout that is already set up. A
101
+ setup a launch started that was stopped or failed is run again by the next
102
+ `rer dev`, keeping the owner and origin it saved, unless a setup has finished
103
+ there since (for example your own `rer setup`). A checkout whose pin reports it is
104
+ not set up (`rer describe`'s `local.prepared`) but that already holds an owner
105
+ (`local.ownerSaved`, for example when a newer manifest requires another setting)
106
+ finishes setup keeping that owner and origin. A required setup answer with no value and no
107
+ `localDefault` stops the launch with exit 3 and setup's message naming it.
108
+
109
+ Inside a checkout `rer` acts on the nearest `OPERATIONS.json` at or above the
110
+ working directory; `--cwd DIR` names the project root itself, exactly as
111
+ `node scripts/rer.mjs` reads it.
112
+
113
+ Without a terminal (an agent's shell tool) it returns as soon as the app is ready
114
+ and leaves it running, printing the server's private log path; in a terminal it
115
+ stays in the foreground and Ctrl-C stops it. `--detach` and `--foreground`
116
+ override the choice, and `--json` prints `progress` events and the ready event. A
117
+ first launch can take minutes: it prints a progress line at least every 30
118
+ seconds, and if the calling command is killed the launch carries on; run
119
+ `rer dev` again to reattach. A second `rer dev` reprints the ready lines.
120
+ `rer dev --stop` stops the server, or a launch still preparing (which then
121
+ reports that it was stopped), waits until every process they started has
122
+ exited and says what it stopped; if any is still running it exits non-zero
123
+ naming their PIDs.
124
+
125
+ Servers started through `rer` (`rer dev`, `rer preview`) get a 10-server limit and a 12-hour idle timeout
126
+ unless you set `RER_SERVER_LIMIT`, `RER_SERVER_IDLE_SECONDS` or `--idle-timeout`.
127
+ `rer` supplies them only to checkouts whose pinned copy applies lower defaults
128
+ or does not report its own (`rer describe` reports `defaults`), so a current
129
+ checkout never records a limit you did not set.
130
+ A start is never refused for machine load alone unless `RER_SERVERS_LOAD_THRESHOLD`
131
+ or `RER_JOBS_LOAD_THRESHOLD` is set; memory and disk guards stay.
132
+
133
+ ## Find what to launch
134
+
135
+ ```sh
136
+ rer list [DIR] [--json]
137
+ ```
138
+
139
+ lists the checkouts in a folder, newest change first, with their profile
140
+ (`first-party`, `independent` or `unsupported`), whether `rer dev` can launch
141
+ them, whether they are set up, and their running URL.
142
+
143
+ Independent projects (an `OPERATIONS.json` version 2 without a seed contract) run
144
+ their declared commands with `rer <verb> [-- args]`; zero-setup launching does not
145
+ apply to them. `OPERATIONS.json` version 1 is not supported.
146
+
147
+ ## Verbs
148
+
149
+ In a checkout, every verb runs that checkout's own pinned `rer`; `rer VERB --help`
150
+ there lists its flags:
151
+
152
+ `install`, `setup`, `dev`, `preview`, `build`, `verify`, `reset --yes`, `deploy`,
153
+ `export`, `import`, `outbox`, `doctor`, `describe`, `check`, `release`.
154
+
155
+ Anywhere: `rer list [DIR]`, `rer cli status|install|uninstall`, `rer update`,
156
+ `rer --version` and `rer --help`.
157
+
158
+ Licence: MIT.
@@ -0,0 +1,72 @@
1
+ // Find the project an invocation acts on: the nearest OPERATIONS.json at or
2
+ // above the working directory, or exactly --cwd DIR. Then pick whose code runs it.
3
+ import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { ownRoot, packageName } from './package-info.mjs';
6
+
7
+ // The value of --cwd among the wrapper flags (never after a -- separator).
8
+ function cwdFlag(args) {
9
+ for (let i = 0; i < args.length; i++) {
10
+ if (args[i] === '--') return undefined;
11
+ if (args[i] === '--cwd') return { index: i + 1, value: args[i + 1] };
12
+ }
13
+ return undefined;
14
+ }
15
+
16
+ export function descriptorProfile(file) {
17
+ let descriptor;
18
+ try { descriptor = JSON.parse(readFileSync(file, 'utf8')); } catch { return { profile: 'unreadable' }; }
19
+ if (descriptor?.version === 2) return { profile: descriptor.seedContract ? 'first-party' : 'independent' };
20
+ return { profile: 'unsupported', version: descriptor?.version };
21
+ }
22
+
23
+ const projectRoot = directory => { try { return statSync(join(directory, 'OPERATIONS.json')).isFile() ? realpathSync(directory) : undefined; } catch { return undefined; } };
24
+
25
+ // --cwd names the project root itself, as the pinned dispatcher reads it: no
26
+ // upward search. When it names no project, the dispatcher of the checkout
27
+ // around the working directory (else this package's own) receives it
28
+ // unchanged, as an absolute path, and refuses it with its own message.
29
+ export function locate(argv) {
30
+ const flag = cwdFlag(argv.slice(1)), args = [...argv];
31
+ if (flag?.value !== undefined) {
32
+ // A value the dispatcher's parser rejects (empty, or another flag) reaches it as given.
33
+ const usable = flag.value.trim() && !flag.value.startsWith('--'), named = resolve(process.cwd(), flag.value), root = usable ? projectRoot(named) : undefined;
34
+ if (root) { args[flag.index + 1] = root; return { root, args, ...descriptorProfile(join(root, 'OPERATIONS.json')) }; }
35
+ if (usable) args[flag.index + 1] = named;
36
+ const near = around(process.cwd());
37
+ return { root: near && ['first-party', 'independent'].includes(descriptorProfile(join(near, 'OPERATIONS.json')).profile) ? near : undefined, args, profile: 'refused' };
38
+ }
39
+ const root = around(process.cwd());
40
+ return { root, args, ...(root ? descriptorProfile(join(root, 'OPERATIONS.json')) : { profile: 'none' }) };
41
+ }
42
+
43
+ // The nearest project root at or above a directory.
44
+ function around(start) {
45
+ for (let directory = start; ; directory = dirname(directory)) {
46
+ const root = projectRoot(directory);
47
+ if (root) return root;
48
+ if (dirname(directory) === directory) return undefined;
49
+ }
50
+ }
51
+
52
+ export function unsupportedMessage(root, version) {
53
+ return `${join(root, 'OPERATIONS.json')} is an OPERATIONS version ${version ?? '(none)'} descriptor, which rer does not run. Use the commands that project documents, or move it to OPERATIONS version 2.`;
54
+ }
55
+
56
+ function declaresPackage(root) {
57
+ try {
58
+ const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
59
+ return Boolean(manifest.dependencies?.[packageName] ?? manifest.devDependencies?.[packageName]);
60
+ } catch { return false; }
61
+ }
62
+
63
+ // 1. the checkout's own pinned package, 2. its vendored scripts/rer.mjs,
64
+ // 3. this package's bundled dispatcher.
65
+ export function dispatcher(root) {
66
+ if (root && declaresPackage(root)) {
67
+ const pinned = join(root, 'node_modules', packageName);
68
+ if (existsSync(join(pinned, 'global/rer.mjs')) && realpathSync(pinned) !== ownRoot) return { mode: 'package', entry: join(realpathSync(pinned), 'global/rer.mjs') };
69
+ }
70
+ if (root && existsSync(join(root, 'scripts/rer.mjs'))) return { mode: 'vendored', entry: join(root, 'scripts/rer.mjs') };
71
+ return { mode: 'bundled', entry: join(ownRoot, 'bin/rer.mjs') };
72
+ }
@@ -0,0 +1,13 @@
1
+ // rer cli status|install|uninstall
2
+ const usage = 'Usage: rer cli status [--json] | rer cli install | rer cli uninstall\n';
3
+
4
+ export async function cliCommand(args) {
5
+ const [action, ...flags] = args;
6
+ if (!action || ['--help', '-h'].includes(action)) { process.stdout.write(usage); return 0; }
7
+ const allowed = action === 'status' ? ['--json'] : [];
8
+ const unknown = flags.find(flag => !allowed.includes(flag));
9
+ if (!['status', 'install', 'uninstall'].includes(action) || unknown !== undefined) { process.stderr.write(`Unsupported: rer cli ${args.join(' ')}\n${usage}`); return 2; }
10
+ if (action === 'status') return (await import('./status.mjs')).status({ json: flags.includes('--json') });
11
+ if (action === 'install') return (await import('./install.mjs')).install();
12
+ return (await import('./uninstall.mjs')).uninstall();
13
+ }
@@ -0,0 +1,75 @@
1
+ // rer cli install: copy the running package's own bytes into an immutable
2
+ // version directory, switch `current` atomically, keep the previous version,
3
+ // prune older ones and write the launcher. Never edits shell profiles.
4
+ import { randomUUID } from 'node:crypto';
5
+ import { chmod, cp, mkdir, readdir, readlink, rename, rm, symlink, writeFile } from 'node:fs/promises';
6
+ import { basename, join, resolve } from 'node:path';
7
+ import { ownManifest, ownRoot, packageDigest, packageFileList } from '../package-info.mjs';
8
+ import { installRecord, launcherOwner, launcherScript, layout } from './layout.mjs';
9
+
10
+ async function readLink(path) { try { return await readlink(path); } catch (error) { if (['ENOENT', 'EINVAL'].includes(error.code)) return undefined; throw error; } }
11
+
12
+ // Files read-only (immutable by intent); directories stay removable for pruning.
13
+ async function freeze(root) {
14
+ for (const path of await packageFileList(root)) await chmod(join(root, path), path.endsWith('global/rer.mjs') || path === 'bin/rer.mjs' ? 0o555 : 0o444);
15
+ }
16
+
17
+ async function copyVersion(paths, name) {
18
+ const staging = join(paths.versions, `.staging-${randomUUID()}`);
19
+ await mkdir(paths.versions, { recursive: true });
20
+ try {
21
+ await cp(ownRoot, staging, { recursive: true });
22
+ await freeze(staging);
23
+ await rename(staging, join(paths.versions, name));
24
+ } finally { await rm(staging, { recursive: true, force: true }); }
25
+ }
26
+
27
+ async function switchCurrent(paths, name) {
28
+ const temporary = `${paths.current}.${randomUUID()}`;
29
+ await symlink(join('versions', name), temporary);
30
+ await rename(temporary, paths.current);
31
+ }
32
+
33
+ async function writeLauncher(paths) {
34
+ await mkdir(paths.bin, { recursive: true });
35
+ const temporary = `${paths.launcher}.${randomUUID()}`;
36
+ await writeFile(temporary, launcherScript(paths.data), { mode: 0o755 });
37
+ await rename(temporary, paths.launcher);
38
+ }
39
+
40
+ export function pathAdvice(paths, env = process.env) {
41
+ const entries = (env.PATH ?? '').split(':').filter(Boolean).map(entry => resolve(entry));
42
+ if (entries.includes(resolve(paths.bin))) return undefined;
43
+ const shell = basename(env.SHELL ?? '');
44
+ if (shell === 'fish') return `${paths.bin} is not on your PATH. Run this once in fish, then open a new terminal:\n fish_add_path $HOME/.local/bin`;
45
+ const profile = shell === 'zsh' ? '~/.zshrc' : shell === 'bash' ? (process.platform === 'darwin' ? '~/.bash_profile' : '~/.bashrc') : '~/.profile';
46
+ return `${paths.bin} is not on your PATH. Add this line to ${profile}, then open a new terminal:\n export PATH="$HOME/.local/bin:$PATH"`;
47
+ }
48
+
49
+ export async function install() {
50
+ const paths = layout(), manifest = ownManifest(), digest = await packageDigest(ownRoot);
51
+ const name = `${manifest.version}-${digest.slice(0, 8)}`, channel = process.env.RER_INSTALL_CHANNEL === 'script' ? 'script' : 'npx';
52
+ const launcher = await launcherOwner(paths.launcher);
53
+ if (launcher.state === 'foreign') {
54
+ process.stderr.write(`rer cli install: ${paths.launcher} already exists and was not written by rer cli install (it may be the unrelated npm package "rer"). Nothing was changed. Remove or rename it, then run the install again.\n`);
55
+ return 4;
56
+ }
57
+ const record = await installRecord(paths), current = await readLink(paths.current);
58
+ const script = launcherScript(paths.data);
59
+ let present = false;
60
+ try { present = await packageDigest(join(paths.versions, name)) === digest; } catch (error) { if (error.code !== 'ENOENT') throw error; }
61
+ const advice = pathAdvice(paths);
62
+ if (present && current === join('versions', name) && launcher.text === script && record?.channel === channel) {
63
+ process.stdout.write(`rer ${manifest.version} is already current (${join(paths.versions, name)}). Nothing changed.\n${advice ? advice + '\n' : ''}`);
64
+ return 0;
65
+ }
66
+ if (!present) { await rm(join(paths.versions, name), { recursive: true, force: true }); await copyVersion(paths, name); }
67
+ const previousName = current?.startsWith('versions/') && current !== join('versions', name) ? current.slice('versions/'.length) : record?.previous;
68
+ if (current !== join('versions', name)) await switchCurrent(paths, name);
69
+ const keep = new Set([name, previousName].filter(Boolean));
70
+ for (const entry of await readdir(paths.versions)) if (!keep.has(entry) && !entry.startsWith('.staging-')) await rm(join(paths.versions, entry), { recursive: true, force: true });
71
+ await writeFile(paths.record, JSON.stringify({ channel, previous: previousName && keep.has(previousName) ? previousName : null }, null, 2) + '\n', { mode: 0o644 });
72
+ if (launcher.text !== script) await writeLauncher(paths);
73
+ process.stdout.write(`Installed rer ${manifest.version} in ${join(paths.versions, name)}.\n${paths.launcher} runs it.${previousName ? ` The previous version (${previousName}) is kept.` : ''}\n${advice ? advice + '\n' : ''}`);
74
+ return 0;
75
+ }