@openlup/platform 0.0.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/LICENSE +204 -0
  3. package/README.md +471 -1
  4. package/dist/bff/dispatch.d.ts +27 -0
  5. package/dist/bff/dispatch.js +47 -0
  6. package/dist/bff/envelope.d.ts +46 -0
  7. package/dist/bff/envelope.js +80 -0
  8. package/dist/bff/health.d.ts +24 -0
  9. package/dist/bff/health.js +19 -0
  10. package/dist/bff/index.d.ts +6 -0
  11. package/dist/bff/index.js +6 -0
  12. package/dist/bff/lazyRoute.d.ts +4 -0
  13. package/dist/bff/lazyRoute.js +13 -0
  14. package/dist/bff/requestContext.d.ts +17 -0
  15. package/dist/bff/requestContext.js +26 -0
  16. package/dist/bff/routerRewrite.d.ts +2 -0
  17. package/dist/bff/routerRewrite.js +31 -0
  18. package/dist/blob/binding.d.ts +16 -0
  19. package/dist/blob/binding.js +37 -0
  20. package/dist/blob/filesystem.d.ts +8 -0
  21. package/dist/blob/filesystem.js +71 -0
  22. package/dist/blob/index.d.ts +6 -0
  23. package/dist/blob/index.js +6 -0
  24. package/dist/blob/s3.d.ts +32 -0
  25. package/dist/blob/s3.js +56 -0
  26. package/dist/blob/s3Client.d.ts +25 -0
  27. package/dist/blob/s3Client.js +76 -0
  28. package/dist/blob/supabase.d.ts +40 -0
  29. package/dist/blob/supabase.js +59 -0
  30. package/dist/blob/vercel.d.ts +63 -0
  31. package/dist/blob/vercel.js +69 -0
  32. package/dist/composition/composeBundle.d.ts +47 -0
  33. package/dist/composition/composeBundle.js +45 -0
  34. package/dist/composition/httpBinding.d.ts +8 -0
  35. package/dist/composition/httpBinding.js +18 -0
  36. package/dist/composition/index.d.ts +3 -0
  37. package/dist/composition/index.js +3 -0
  38. package/dist/composition/nodeHost.d.ts +103 -0
  39. package/dist/composition/nodeHost.js +145 -0
  40. package/dist/data/binding.d.ts +34 -0
  41. package/dist/data/binding.js +92 -0
  42. package/dist/data/index.d.ts +5 -0
  43. package/dist/data/index.js +5 -0
  44. package/dist/data/postgresGateway.d.ts +42 -0
  45. package/dist/data/postgresGateway.js +135 -0
  46. package/dist/data/queryBuilder.d.ts +54 -0
  47. package/dist/data/queryBuilder.js +240 -0
  48. package/dist/data/queryBuilderSql.d.ts +76 -0
  49. package/dist/data/queryBuilderSql.js +145 -0
  50. package/dist/data/supabaseClientFactory.d.ts +34 -0
  51. package/dist/data/supabaseClientFactory.js +56 -0
  52. package/dist/data/supabaseGateway.d.ts +22 -0
  53. package/dist/data/supabaseGateway.js +49 -0
  54. package/dist/http/deadline.d.ts +20 -0
  55. package/dist/http/deadline.js +93 -0
  56. package/dist/http/index.d.ts +6 -0
  57. package/dist/http/index.js +5 -0
  58. package/dist/http/requestAdapter.d.ts +38 -0
  59. package/dist/http/requestAdapter.js +203 -0
  60. package/dist/http/runtime.d.ts +83 -0
  61. package/dist/http/runtime.js +199 -0
  62. package/dist/http/security.d.ts +44 -0
  63. package/dist/http/security.js +114 -0
  64. package/dist/http/staticAssets.d.ts +3 -0
  65. package/dist/http/staticAssets.js +42 -0
  66. package/dist/http/types.d.ts +23 -0
  67. package/dist/http/types.js +6 -0
  68. package/dist/identity/adminAuthBinding.d.ts +28 -0
  69. package/dist/identity/adminAuthBinding.js +66 -0
  70. package/dist/identity/adminAuthorization.d.ts +34 -0
  71. package/dist/identity/adminAuthorization.js +72 -0
  72. package/dist/identity/adminContracts.d.ts +70 -0
  73. package/dist/identity/adminContracts.js +43 -0
  74. package/dist/identity/adminMagicLinkHandler.d.ts +39 -0
  75. package/dist/identity/adminMagicLinkHandler.js +94 -0
  76. package/dist/identity/adminMeHandler.d.ts +15 -0
  77. package/dist/identity/adminMeHandler.js +49 -0
  78. package/dist/identity/adminPreflight.d.ts +16 -0
  79. package/dist/identity/adminPreflight.js +38 -0
  80. package/dist/identity/adminUserActionPorts.d.ts +31 -0
  81. package/dist/identity/adminUserActionPorts.js +51 -0
  82. package/dist/identity/adminUserHandlers.d.ts +38 -0
  83. package/dist/identity/adminUserHandlers.js +140 -0
  84. package/dist/identity/authVerifyUrl.d.ts +6 -0
  85. package/dist/identity/authVerifyUrl.js +54 -0
  86. package/dist/identity/contracts/contracts.d.ts +8 -0
  87. package/dist/identity/contracts/contracts.js +2 -0
  88. package/dist/identity/contracts/emailTrust.d.ts +3 -0
  89. package/dist/identity/contracts/emailTrust.js +4 -0
  90. package/dist/identity/contracts/index.d.ts +8 -0
  91. package/dist/identity/contracts/index.js +8 -0
  92. package/dist/identity/contracts/oidc.d.ts +3 -0
  93. package/dist/identity/contracts/oidc.js +9 -0
  94. package/dist/identity/contracts/operatorAuth.d.ts +35 -0
  95. package/dist/identity/contracts/operatorAuth.js +53 -0
  96. package/dist/identity/contracts/operatorInvitations.d.ts +37 -0
  97. package/dist/identity/contracts/operatorInvitations.js +1 -0
  98. package/dist/identity/contracts/ports.d.ts +22 -0
  99. package/dist/identity/contracts/ports.js +1 -0
  100. package/dist/identity/contracts/privacy.d.ts +62 -0
  101. package/dist/identity/contracts/privacy.js +99 -0
  102. package/dist/identity/contracts/providerList.d.ts +3 -0
  103. package/dist/identity/contracts/providerList.js +11 -0
  104. package/dist/identity/contracts/types.d.ts +16 -0
  105. package/dist/identity/contracts/types.js +4 -0
  106. package/dist/identity/contribution.d.ts +8 -0
  107. package/dist/identity/contribution.js +22 -0
  108. package/dist/identity/customerAuth.d.ts +8 -0
  109. package/dist/identity/customerAuth.js +1 -0
  110. package/dist/identity/customerAuthorization.d.ts +5 -0
  111. package/dist/identity/customerAuthorization.js +22 -0
  112. package/dist/identity/customerContracts.d.ts +42 -0
  113. package/dist/identity/customerContracts.js +43 -0
  114. package/dist/identity/customerIdentityBinding.d.ts +44 -0
  115. package/dist/identity/customerIdentityBinding.js +60 -0
  116. package/dist/identity/customerIdentityVerifier.d.ts +8 -0
  117. package/dist/identity/customerIdentityVerifier.js +101 -0
  118. package/dist/identity/customerMagicLinkHandler.d.ts +38 -0
  119. package/dist/identity/customerMagicLinkHandler.js +115 -0
  120. package/dist/identity/customerMeHandler.d.ts +11 -0
  121. package/dist/identity/customerMeHandler.js +46 -0
  122. package/dist/identity/customerPorts.d.ts +4 -0
  123. package/dist/identity/customerPorts.js +1 -0
  124. package/dist/identity/customerSessionBinding.d.ts +38 -0
  125. package/dist/identity/customerSessionBinding.js +80 -0
  126. package/dist/identity/customerSessionIssuer.d.ts +10 -0
  127. package/dist/identity/customerSessionIssuer.js +57 -0
  128. package/dist/identity/customerVerifyOtpHandler.d.ts +8 -0
  129. package/dist/identity/customerVerifyOtpHandler.js +41 -0
  130. package/dist/identity/directOperatorInvitationStore.d.ts +19 -0
  131. package/dist/identity/directOperatorInvitationStore.js +193 -0
  132. package/dist/identity/emailTrustPolicy.d.ts +14 -0
  133. package/dist/identity/emailTrustPolicy.js +16 -0
  134. package/dist/identity/identityPersonalDataContributor.d.ts +7 -0
  135. package/dist/identity/identityPersonalDataContributor.js +46 -0
  136. package/dist/identity/identityReadiness.d.ts +10 -0
  137. package/dist/identity/identityReadiness.js +25 -0
  138. package/dist/identity/index.d.ts +67 -0
  139. package/dist/identity/index.js +66 -0
  140. package/dist/identity/inviteAdminUserUseCase.d.ts +89 -0
  141. package/dist/identity/inviteAdminUserUseCase.js +75 -0
  142. package/dist/identity/jwtLibrary.d.ts +54 -0
  143. package/dist/identity/jwtLibrary.js +1 -0
  144. package/dist/identity/machineActorWriteFence.d.ts +4 -0
  145. package/dist/identity/machineActorWriteFence.js +13 -0
  146. package/dist/identity/magicLinkPorts.d.ts +28 -0
  147. package/dist/identity/magicLinkPorts.js +1 -0
  148. package/dist/identity/managedAccountLinkStore.d.ts +2 -0
  149. package/dist/identity/managedAccountLinkStore.js +93 -0
  150. package/dist/identity/managedAdminAuthVerifier.d.ts +7 -0
  151. package/dist/identity/managedAdminAuthVerifier.js +27 -0
  152. package/dist/identity/managedAdminUserGateways.d.ts +123 -0
  153. package/dist/identity/managedAdminUserGateways.js +127 -0
  154. package/dist/identity/managedClient.d.ts +90 -0
  155. package/dist/identity/managedClient.js +10 -0
  156. package/dist/identity/managedClientAuthLink.d.ts +3 -0
  157. package/dist/identity/managedClientAuthLink.js +115 -0
  158. package/dist/identity/managedCustomerMe.d.ts +13 -0
  159. package/dist/identity/managedCustomerMe.js +30 -0
  160. package/dist/identity/managedEmailTrustPolicy.d.ts +11 -0
  161. package/dist/identity/managedEmailTrustPolicy.js +105 -0
  162. package/dist/identity/managedIdentityVerifier.d.ts +2 -0
  163. package/dist/identity/managedIdentityVerifier.js +16 -0
  164. package/dist/identity/managedPrivacy.d.ts +4 -0
  165. package/dist/identity/managedPrivacy.js +39 -0
  166. package/dist/identity/messages.d.ts +29 -0
  167. package/dist/identity/messages.js +39 -0
  168. package/dist/identity/oidcIdentityVerifier.d.ts +45 -0
  169. package/dist/identity/oidcIdentityVerifier.js +309 -0
  170. package/dist/identity/oidcPrincipal.d.ts +2 -0
  171. package/dist/identity/oidcPrincipal.js +10 -0
  172. package/dist/identity/operatorAdminAuth.d.ts +6 -0
  173. package/dist/identity/operatorAdminAuth.js +13 -0
  174. package/dist/identity/operatorAuthHandlers.d.ts +18 -0
  175. package/dist/identity/operatorAuthHandlers.js +71 -0
  176. package/dist/identity/operatorIdentityVerifier.d.ts +8 -0
  177. package/dist/identity/operatorIdentityVerifier.js +19 -0
  178. package/dist/identity/operatorInvitationLifecycle.d.ts +7 -0
  179. package/dist/identity/operatorInvitationLifecycle.js +15 -0
  180. package/dist/identity/operatorInvitationPorts.d.ts +31 -0
  181. package/dist/identity/operatorInvitationPorts.js +1 -0
  182. package/dist/identity/operatorPorts.d.ts +37 -0
  183. package/dist/identity/operatorPorts.js +1 -0
  184. package/dist/identity/operatorSession.d.ts +13 -0
  185. package/dist/identity/operatorSession.js +31 -0
  186. package/dist/identity/operatorTokenAdminAuth.d.ts +15 -0
  187. package/dist/identity/operatorTokenAdminAuth.js +50 -0
  188. package/dist/identity/personalDataRegistry.d.ts +4 -0
  189. package/dist/identity/personalDataRegistry.js +11 -0
  190. package/dist/identity/platformAdminAuth.d.ts +15 -0
  191. package/dist/identity/platformAdminAuth.js +1 -0
  192. package/dist/identity/ports.d.ts +127 -0
  193. package/dist/identity/ports.js +38 -0
  194. package/dist/identity/postgresAccountLinkStore.d.ts +7 -0
  195. package/dist/identity/postgresAccountLinkStore.js +52 -0
  196. package/dist/identity/postgresCustomerMe.d.ts +3 -0
  197. package/dist/identity/postgresCustomerMe.js +21 -0
  198. package/dist/identity/postgresCustomerRecovery.d.ts +11 -0
  199. package/dist/identity/postgresCustomerRecovery.js +57 -0
  200. package/dist/identity/postgresOperatorIdentity.d.ts +5 -0
  201. package/dist/identity/postgresOperatorIdentity.js +137 -0
  202. package/dist/identity/postgresPrivacy.d.ts +7 -0
  203. package/dist/identity/postgresPrivacy.js +126 -0
  204. package/dist/identity/privacyHandlers.d.ts +10 -0
  205. package/dist/identity/privacyHandlers.js +35 -0
  206. package/dist/identity/privacyPorts.d.ts +72 -0
  207. package/dist/identity/privacyPorts.js +8 -0
  208. package/dist/identity/privacyUseCases.d.ts +5 -0
  209. package/dist/identity/privacyUseCases.js +55 -0
  210. package/dist/identity/reconcileAccountForPrincipal.d.ts +20 -0
  211. package/dist/identity/reconcileAccountForPrincipal.js +66 -0
  212. package/dist/identity/reconcileAccountHandler.d.ts +11 -0
  213. package/dist/identity/reconcileAccountHandler.js +30 -0
  214. package/dist/identity/removeAdminUserUseCase.d.ts +31 -0
  215. package/dist/identity/removeAdminUserUseCase.js +60 -0
  216. package/dist/identity/response.d.ts +3 -0
  217. package/dist/identity/response.js +2 -0
  218. package/dist/identity/sql.d.ts +44 -0
  219. package/dist/identity/sql.js +10 -0
  220. package/dist/job-ledger/index.d.ts +5 -0
  221. package/dist/job-ledger/index.js +3 -0
  222. package/dist/job-ledger/ports.d.ts +10 -0
  223. package/dist/job-ledger/ports.js +7 -0
  224. package/dist/job-ledger/postgres.d.ts +10 -0
  225. package/dist/job-ledger/postgres.js +101 -0
  226. package/dist/job-ledger/sql.d.ts +7 -0
  227. package/dist/job-ledger/sql.js +10 -0
  228. package/dist/job-ledger/supabase.d.ts +77 -0
  229. package/dist/job-ledger/supabase.js +202 -0
  230. package/dist/kernel/index.d.ts +1 -0
  231. package/dist/kernel/index.js +1 -0
  232. package/dist/kernel/platformKernel.d.ts +34 -0
  233. package/dist/kernel/platformKernel.js +115 -0
  234. package/dist/migrations/index.d.ts +1 -0
  235. package/dist/migrations/index.js +1 -0
  236. package/dist/migrations/postgresRunner.d.ts +50 -0
  237. package/dist/migrations/postgresRunner.js +176 -0
  238. package/dist/scheduler/advisoryLock.d.ts +44 -0
  239. package/dist/scheduler/advisoryLock.js +114 -0
  240. package/dist/scheduler/cronGuard.d.ts +10 -0
  241. package/dist/scheduler/cronGuard.js +19 -0
  242. package/dist/scheduler/cronSecret.d.ts +5 -0
  243. package/dist/scheduler/cronSecret.js +23 -0
  244. package/dist/scheduler/handlers.d.ts +9 -0
  245. package/dist/scheduler/handlers.js +10 -0
  246. package/dist/scheduler/httpEntry.d.ts +16 -0
  247. package/dist/scheduler/httpEntry.js +31 -0
  248. package/dist/scheduler/index.d.ts +9 -0
  249. package/dist/scheduler/index.js +9 -0
  250. package/dist/scheduler/jobRegistry.d.ts +21 -0
  251. package/dist/scheduler/jobRegistry.js +39 -0
  252. package/dist/scheduler/jobs.d.ts +48 -0
  253. package/dist/scheduler/jobs.js +92 -0
  254. package/dist/scheduler/nodeScheduler.d.ts +42 -0
  255. package/dist/scheduler/nodeScheduler.js +73 -0
  256. package/dist/scheduler/vercelScheduler.d.ts +29 -0
  257. package/dist/scheduler/vercelScheduler.js +51 -0
  258. package/package.json +116 -3
  259. package/release-gates.json +143 -0
  260. package/sql/20260809150000_job_run_ledger.sql +301 -0
  261. package/sql/20260809150001_job_run_ledger_v3.sql +70 -0
  262. package/sql/20260810180001_self_host_actor_auth.sql +40 -0
  263. package/sql/20260810204057_customer_identity_read.sql +31 -0
  264. package/sql/20260814090000_customer_selfservice_recovery.sql +477 -0
  265. package/sql/20260901143000_admin_membership_authority_foundation.sql +234 -0
  266. package/sql/20261018120000_identity_operator_invitations.sql +42 -0
  267. package/sql/20261018180000_identity_operator_challenges.sql +56 -0
  268. package/sql/20261018190000_identity_privacy_erasures.sql +15 -0
  269. package/src/bff/dispatch.ts +81 -0
  270. package/src/bff/envelope.ts +142 -0
  271. package/src/bff/health.ts +37 -0
  272. package/src/bff/index.ts +30 -0
  273. package/src/bff/lazyRoute.ts +28 -0
  274. package/src/bff/requestContext.ts +48 -0
  275. package/src/bff/routerRewrite.ts +38 -0
  276. package/src/blob/binding.ts +55 -0
  277. package/src/blob/filesystem.ts +86 -0
  278. package/src/blob/index.ts +17 -0
  279. package/src/blob/s3.ts +87 -0
  280. package/src/blob/s3Client.ts +91 -0
  281. package/src/blob/supabase.ts +88 -0
  282. package/src/blob/vercel.ts +127 -0
  283. package/src/composition/composeBundle.ts +109 -0
  284. package/src/composition/httpBinding.ts +30 -0
  285. package/src/composition/index.ts +17 -0
  286. package/src/composition/nodeHost.ts +289 -0
  287. package/src/data/binding.ts +157 -0
  288. package/src/data/index.ts +33 -0
  289. package/src/data/postgresGateway.ts +186 -0
  290. package/src/data/queryBuilder.ts +300 -0
  291. package/src/data/queryBuilderSql.ts +183 -0
  292. package/src/data/supabaseClientFactory.ts +92 -0
  293. package/src/data/supabaseGateway.ts +76 -0
  294. package/src/http/deadline.ts +117 -0
  295. package/src/http/index.ts +36 -0
  296. package/src/http/requestAdapter.ts +215 -0
  297. package/src/http/runtime.ts +319 -0
  298. package/src/http/security.ts +155 -0
  299. package/src/http/staticAssets.ts +42 -0
  300. package/src/http/types.ts +31 -0
  301. package/src/identity/adminAuthBinding.ts +76 -0
  302. package/src/identity/adminAuthorization.ts +106 -0
  303. package/src/identity/adminContracts.ts +52 -0
  304. package/src/identity/adminMagicLinkHandler.ts +132 -0
  305. package/src/identity/adminMeHandler.ts +64 -0
  306. package/src/identity/adminPreflight.ts +46 -0
  307. package/src/identity/adminUserActionPorts.ts +78 -0
  308. package/src/identity/adminUserHandlers.ts +174 -0
  309. package/src/identity/authVerifyUrl.ts +56 -0
  310. package/src/identity/contracts/contracts.ts +15 -0
  311. package/src/identity/contracts/emailTrust.ts +5 -0
  312. package/src/identity/contracts/index.ts +8 -0
  313. package/src/identity/contracts/oidc.ts +10 -0
  314. package/src/identity/contracts/operatorAuth.ts +61 -0
  315. package/src/identity/contracts/operatorInvitations.ts +32 -0
  316. package/src/identity/contracts/ports.ts +25 -0
  317. package/src/identity/contracts/privacy.ts +86 -0
  318. package/src/identity/contracts/providerList.ts +13 -0
  319. package/src/identity/contracts/types.ts +25 -0
  320. package/src/identity/contribution.ts +29 -0
  321. package/src/identity/customerAuth.ts +3 -0
  322. package/src/identity/customerAuthorization.ts +38 -0
  323. package/src/identity/customerContracts.ts +52 -0
  324. package/src/identity/customerIdentityBinding.ts +125 -0
  325. package/src/identity/customerIdentityVerifier.ts +141 -0
  326. package/src/identity/customerMagicLinkHandler.ts +171 -0
  327. package/src/identity/customerMeHandler.ts +64 -0
  328. package/src/identity/customerPorts.ts +2 -0
  329. package/src/identity/customerSessionBinding.ts +114 -0
  330. package/src/identity/customerSessionIssuer.ts +71 -0
  331. package/src/identity/customerVerifyOtpHandler.ts +44 -0
  332. package/src/identity/directOperatorInvitationStore.ts +178 -0
  333. package/src/identity/emailTrustPolicy.ts +16 -0
  334. package/src/identity/identityPersonalDataContributor.ts +48 -0
  335. package/src/identity/identityReadiness.ts +26 -0
  336. package/src/identity/index.ts +69 -0
  337. package/src/identity/inviteAdminUserUseCase.ts +134 -0
  338. package/src/identity/jwtLibrary.ts +24 -0
  339. package/src/identity/machineActorWriteFence.ts +19 -0
  340. package/src/identity/magicLinkPorts.ts +7 -0
  341. package/src/identity/managedAccountLinkStore.ts +105 -0
  342. package/src/identity/managedAdminAuthVerifier.ts +40 -0
  343. package/src/identity/managedAdminUserGateways.ts +164 -0
  344. package/src/identity/managedClient.ts +58 -0
  345. package/src/identity/managedClientAuthLink.ts +120 -0
  346. package/src/identity/managedCustomerMe.ts +52 -0
  347. package/src/identity/managedEmailTrustPolicy.ts +90 -0
  348. package/src/identity/managedIdentityVerifier.ts +20 -0
  349. package/src/identity/managedPrivacy.ts +37 -0
  350. package/src/identity/messages.ts +41 -0
  351. package/src/identity/oidcIdentityVerifier.ts +229 -0
  352. package/src/identity/oidcPrincipal.ts +10 -0
  353. package/src/identity/operatorAdminAuth.ts +14 -0
  354. package/src/identity/operatorAuthHandlers.ts +52 -0
  355. package/src/identity/operatorIdentityVerifier.ts +19 -0
  356. package/src/identity/operatorInvitationLifecycle.ts +14 -0
  357. package/src/identity/operatorInvitationPorts.ts +11 -0
  358. package/src/identity/operatorPorts.ts +11 -0
  359. package/src/identity/operatorSession.ts +30 -0
  360. package/src/identity/operatorTokenAdminAuth.ts +79 -0
  361. package/src/identity/personalDataRegistry.ts +8 -0
  362. package/src/identity/platformAdminAuth.ts +7 -0
  363. package/src/identity/ports.ts +158 -0
  364. package/src/identity/postgresAccountLinkStore.ts +49 -0
  365. package/src/identity/postgresCustomerMe.ts +33 -0
  366. package/src/identity/postgresCustomerRecovery.ts +72 -0
  367. package/src/identity/postgresOperatorIdentity.ts +123 -0
  368. package/src/identity/postgresPrivacy.ts +117 -0
  369. package/src/identity/privacyHandlers.ts +33 -0
  370. package/src/identity/privacyPorts.ts +52 -0
  371. package/src/identity/privacyUseCases.ts +48 -0
  372. package/src/identity/reconcileAccountForPrincipal.ts +99 -0
  373. package/src/identity/reconcileAccountHandler.ts +36 -0
  374. package/src/identity/removeAdminUserUseCase.ts +85 -0
  375. package/src/identity/response.ts +3 -0
  376. package/src/identity/sql.ts +10 -0
  377. package/src/job-ledger/index.ts +25 -0
  378. package/src/job-ledger/ports.ts +27 -0
  379. package/src/job-ledger/postgres.ts +121 -0
  380. package/src/job-ledger/sql.ts +12 -0
  381. package/src/job-ledger/supabase.ts +294 -0
  382. package/src/kernel/index.ts +17 -0
  383. package/src/kernel/platformKernel.ts +153 -0
  384. package/src/migrations/index.ts +10 -0
  385. package/src/migrations/postgresRunner.ts +255 -0
  386. package/src/scheduler/advisoryLock.ts +145 -0
  387. package/src/scheduler/cronGuard.ts +30 -0
  388. package/src/scheduler/cronSecret.ts +26 -0
  389. package/src/scheduler/handlers.ts +24 -0
  390. package/src/scheduler/httpEntry.ts +49 -0
  391. package/src/scheduler/index.ts +47 -0
  392. package/src/scheduler/jobRegistry.ts +57 -0
  393. package/src/scheduler/jobs.ts +119 -0
  394. package/src/scheduler/nodeScheduler.ts +123 -0
  395. package/src/scheduler/vercelScheduler.ts +71 -0
@@ -0,0 +1,60 @@
1
+ import { identityMessages } from "./messages.js";
2
+ export async function runRemoveAdminUserUseCase(request, gateway, messages = identityMessages.en, invitationStore) {
3
+ try {
4
+ if (!request.accessToken) {
5
+ return { status: 401, body: { code: "UNAUTHORIZED", error: messages.unauthorized } };
6
+ }
7
+ const { user, error: authError } = await gateway.getUser(request.accessToken);
8
+ if (authError || !user) {
9
+ return { status: 401, body: { code: "INVALID_TOKEN", error: messages.invalidToken } };
10
+ }
11
+ const callerAdmin = await gateway.findAdminUser(user.id);
12
+ if (!callerAdmin || callerAdmin.role !== "admin") {
13
+ return { status: 403, body: { code: "REMOVE_FORBIDDEN", error: messages.removeForbidden } };
14
+ }
15
+ if (!request.userId) {
16
+ return { status: 400, body: { code: "USER_ID_REQUIRED", error: messages.userIdRequired } };
17
+ }
18
+ if (request.userId === user.id) {
19
+ return { status: 403, body: { code: "SELF_REVOKE_FORBIDDEN", error: messages.selfRemoveForbidden } };
20
+ }
21
+ if (invitationStore) {
22
+ try {
23
+ await invitationStore.remove({ actorPrincipalId: user.id, targetPrincipalId: request.userId });
24
+ return { status: 200, body: { revoked: true } };
25
+ }
26
+ catch (error) {
27
+ const failure = error;
28
+ if (failure.identityCode)
29
+ return { status: failure.bffCode === "FORBIDDEN" ? 403 : failure.bffCode === "BAD_REQUEST" ? 400 : 409, body: { code: failure.identityCode, error: failure.identityCode } };
30
+ return mapRevokeError(failure.message ?? "revoke_failed", messages);
31
+ }
32
+ }
33
+ const { error: revokeError } = await gateway.revokeAdminUser(request.userId);
34
+ if (revokeError) {
35
+ return mapRevokeError(revokeError.message, messages);
36
+ }
37
+ return { status: 200, body: { revoked: true } };
38
+ }
39
+ catch (err) {
40
+ return { status: 500, body: { code: "IDENTITY_ACTION_FAILED", error: String(err) } };
41
+ }
42
+ }
43
+ function mapRevokeError(message, messages) {
44
+ if (message.includes("last_active_human_admin") || message.includes("last_admin_lockout")) {
45
+ return { status: 409, body: { code: "LAST_ACTIVE_HUMAN_ADMIN", error: messages.lastAdmin } };
46
+ }
47
+ if (message.includes("self_revoke_forbidden")) {
48
+ return { status: 403, body: { code: "SELF_REVOKE_FORBIDDEN", error: messages.selfRevoke } };
49
+ }
50
+ if (message.includes("machine_actor_revoke_forbidden")) {
51
+ return { status: 403, body: { code: "MACHINE_ACTOR_REVOKE_FORBIDDEN", error: messages.machineRevoke } };
52
+ }
53
+ if (message.includes("target_not_found") || message.includes("target_not_active")) {
54
+ return { status: 400, body: { code: "ADMIN_NOT_FOUND", error: messages.adminNotFound } };
55
+ }
56
+ if (message.includes("forbidden")) {
57
+ return { status: 403, body: { code: "ADMIN_REQUIRED", error: messages.adminRequired } };
58
+ }
59
+ return { status: 500, body: { code: "REVOKE_FAILED", error: messages.revokeFailed(message) } };
60
+ }
@@ -0,0 +1,3 @@
1
+ import { createBffResponder, type BffResponderOptions } from "../bff/index.js";
2
+ export type IdentityResponseOptions = BffResponderOptions;
3
+ export declare const createIdentityResponder: typeof createBffResponder;
@@ -0,0 +1,2 @@
1
+ import { createBffResponder } from "../bff/index.js";
2
+ export const createIdentityResponder = createBffResponder;
@@ -0,0 +1,44 @@
1
+ /** A projection of canonical migration units, never a second migration chain. */
2
+ export declare const IDENTITY_MIGRATIONS: readonly [{
3
+ readonly id: "20260810180001_self_host_actor_auth";
4
+ readonly catalogPath: "db/platform/migrations/20260810180001_self_host_actor_auth.sql";
5
+ readonly position: 11;
6
+ readonly sha256: "84c80d328785151f1fdb5fc4b69220469ffb9c8579054c473ead910a273dfe7b";
7
+ readonly url: URL;
8
+ }, {
9
+ readonly id: "20260810204057_customer_identity_read";
10
+ readonly catalogPath: "db/platform/migrations/20260810204057_customer_identity_read.sql";
11
+ readonly position: 12;
12
+ readonly sha256: "1aa626c0187a4ed9d08f152540e0d17c68cd678d2caf3e896ac444b5a38aafe3";
13
+ readonly url: URL;
14
+ }, {
15
+ readonly id: "20260814090000_customer_selfservice_recovery";
16
+ readonly catalogPath: "db/platform/migrations/20260814090000_customer_selfservice_recovery.sql";
17
+ readonly position: 29;
18
+ readonly sha256: "ca7f58994533727eb58da148d549ff986fe8f55bb2ffc9eaf61e7d239675ba2e";
19
+ readonly url: URL;
20
+ }, {
21
+ readonly id: "20260901143000_admin_membership_authority_foundation";
22
+ readonly catalogPath: "db/platform/migrations/20260901143000_admin_membership_authority_foundation.sql";
23
+ readonly position: 60;
24
+ readonly sha256: "bb4703b669d17e5a0eb4d9a4e8889d12e5286d4b5a813226a77ef2b71df8281f";
25
+ readonly url: URL;
26
+ }, {
27
+ readonly id: "20261018120000_identity_operator_invitations";
28
+ readonly catalogPath: "db/platform/migrations/20261018120000_identity_operator_invitations.sql";
29
+ readonly position: 67;
30
+ readonly sha256: "b73034908bd5e27819bcd421d17037a0f00a24aa3df1be1f8f9ca411bf984349";
31
+ readonly url: URL;
32
+ }, {
33
+ readonly id: "20261018180000_identity_operator_challenges";
34
+ readonly catalogPath: "db/platform/migrations/20261018180000_identity_operator_challenges.sql";
35
+ readonly position: 68;
36
+ readonly sha256: "191cf0c151a5882ad20d6043624da50afad799df739fff326d67560d3e00a031";
37
+ readonly url: URL;
38
+ }, {
39
+ readonly id: "20261018190000_identity_privacy_erasures";
40
+ readonly catalogPath: "db/platform/migrations/20261018190000_identity_privacy_erasures.sql";
41
+ readonly position: 69;
42
+ readonly sha256: "f39b691cb14c0e9ec1a7460d77dc46e16bca4d2448838e4882f78885a6d92351";
43
+ readonly url: URL;
44
+ }];
@@ -0,0 +1,10 @@
1
+ /** A projection of canonical migration units, never a second migration chain. */
2
+ export const IDENTITY_MIGRATIONS = [
3
+ { id: "20260810180001_self_host_actor_auth", catalogPath: "db/platform/migrations/20260810180001_self_host_actor_auth.sql", position: 11, sha256: "84c80d328785151f1fdb5fc4b69220469ffb9c8579054c473ead910a273dfe7b", url: new URL("../../sql/20260810180001_self_host_actor_auth.sql", import.meta.url) },
4
+ { id: "20260810204057_customer_identity_read", catalogPath: "db/platform/migrations/20260810204057_customer_identity_read.sql", position: 12, sha256: "1aa626c0187a4ed9d08f152540e0d17c68cd678d2caf3e896ac444b5a38aafe3", url: new URL("../../sql/20260810204057_customer_identity_read.sql", import.meta.url) },
5
+ { id: "20260814090000_customer_selfservice_recovery", catalogPath: "db/platform/migrations/20260814090000_customer_selfservice_recovery.sql", position: 29, sha256: "ca7f58994533727eb58da148d549ff986fe8f55bb2ffc9eaf61e7d239675ba2e", url: new URL("../../sql/20260814090000_customer_selfservice_recovery.sql", import.meta.url) },
6
+ { id: "20260901143000_admin_membership_authority_foundation", catalogPath: "db/platform/migrations/20260901143000_admin_membership_authority_foundation.sql", position: 60, sha256: "bb4703b669d17e5a0eb4d9a4e8889d12e5286d4b5a813226a77ef2b71df8281f", url: new URL("../../sql/20260901143000_admin_membership_authority_foundation.sql", import.meta.url) },
7
+ { id: "20261018120000_identity_operator_invitations", catalogPath: "db/platform/migrations/20261018120000_identity_operator_invitations.sql", position: 67, sha256: "b73034908bd5e27819bcd421d17037a0f00a24aa3df1be1f8f9ca411bf984349", url: new URL("../../sql/20261018120000_identity_operator_invitations.sql", import.meta.url) },
8
+ { id: "20261018180000_identity_operator_challenges", catalogPath: "db/platform/migrations/20261018180000_identity_operator_challenges.sql", position: 68, sha256: "191cf0c151a5882ad20d6043624da50afad799df739fff326d67560d3e00a031", url: new URL("../../sql/20261018180000_identity_operator_challenges.sql", import.meta.url) },
9
+ { id: "20261018190000_identity_privacy_erasures", catalogPath: "db/platform/migrations/20261018190000_identity_privacy_erasures.sql", position: 69, sha256: "f39b691cb14c0e9ec1a7460d77dc46e16bca4d2448838e4882f78885a6d92351", url: new URL("../../sql/20261018190000_identity_privacy_erasures.sql", import.meta.url) },
10
+ ];
@@ -0,0 +1,5 @@
1
+ export type { PlatformJobBackstopState, PlatformJobClaim, PlatformJobFinishStatus, PlatformJobFinishSummary, PlatformJobInvocation, PlatformJobRunLedgerPort, PlatformJobTriggerKind, } from "./ports.js";
2
+ export type { PgQueryExecutor } from "../data/index.js";
3
+ export { createPostgresPlatformJobRunLedger, type PostgresPlatformJobRunLedgerOptions, } from "./postgres.js";
4
+ export { JOB_RUN_LEDGER_MIGRATIONS, JOB_RUN_LEDGER_SQL_URL, JOB_RUN_LEDGER_V3_SQL_URL } from "./sql.js";
5
+ export { createManagedJobRunCalls, createSupabasePlatformJobRunLedger, platformJobInvocationForDriver, type ManagedJobRunOptions, type PlatformJobClient, type PlatformJobDriver, type PlatformJobSupabaseClient, type SupabasePlatformJobRunLedgerOptions, } from "./supabase.js";
@@ -0,0 +1,3 @@
1
+ export { createPostgresPlatformJobRunLedger, } from "./postgres.js";
2
+ export { JOB_RUN_LEDGER_MIGRATIONS, JOB_RUN_LEDGER_SQL_URL, JOB_RUN_LEDGER_V3_SQL_URL } from "./sql.js";
3
+ export { createManagedJobRunCalls, createSupabasePlatformJobRunLedger, platformJobInvocationForDriver, } from "./supabase.js";
@@ -0,0 +1,10 @@
1
+ import type { JobLeasePort } from "@openlup/core/platform-runtime";
2
+ export type { PlatformJobClaim, PlatformJobFinishStatus, PlatformJobFinishSummary, PlatformJobInvocation, PlatformJobTriggerKind, } from "@openlup/core/platform-runtime";
3
+ export type PlatformJobBackstopState = {
4
+ lastStatus: string | null;
5
+ lastSuccessAt: string | null;
6
+ };
7
+ export interface PlatformJobRunLedgerPort extends JobLeasePort {
8
+ readJobBackstopState(jobName: string): Promise<PlatformJobBackstopState | null>;
9
+ readLatestTerminalRunMetadata(jobName: string): Promise<Record<string, unknown> | null>;
10
+ }
@@ -0,0 +1,7 @@
1
+ // Persistence-neutral scheduled-job lease and attempt ledger port.
2
+ //
3
+ // The claim and finish contract is core's `JobLeasePort`. A job-run ledger adds the two reads a
4
+ // scheduled job uses for its backstop and checkpoint. Invocation is deployment evidence supplied by
5
+ // the composition root; a job never sees a database client, SDK query, RPC name, vendor driver or
6
+ // environment configuration.
7
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { PgQueryExecutor } from "../data/index.js";
2
+ import type { PlatformJobRunLedgerPort } from "./ports.js";
3
+ export interface PostgresPlatformJobRunLedgerOptions {
4
+ /** Release and deployment identity merged into every claim and finish row's metadata. */
5
+ releaseCorrelation: () => Record<string, string | null>;
6
+ /** Failure reason recorded when a failed run's summary carries none. */
7
+ defaultFailureReason: string;
8
+ }
9
+ /** Direct PostgreSQL adapter for the public neutral-vocabulary job-control rail. */
10
+ export declare function createPostgresPlatformJobRunLedger(executor: PgQueryExecutor, options: PostgresPlatformJobRunLedgerOptions): PlatformJobRunLedgerPort;
@@ -0,0 +1,101 @@
1
+ // Direct PostgreSQL adapter for the public job-run ledger (claim, finish, backstop, checkpoint).
2
+ //
3
+ // The RPCs and tables come from the package's job-run ledger SQL. Every claim and finish row
4
+ // carries the invocation and the deployment's release correlation in its metadata.
5
+ const CLAIM_SQL = `
6
+ SELECT acquired, run_id, reason
7
+ FROM public.platform_claim_job_run_v3($1, $2, $3, $4, $5::jsonb)`;
8
+ const FINISH_SQL = `
9
+ SELECT public.platform_finish_job_run_v3(
10
+ $1, $2::uuid, $3, $4, $5, $6, $7, $8::jsonb
11
+ ) AS released`;
12
+ const BACKSTOP_SQL = `
13
+ SELECT last_status, last_success_at
14
+ FROM public.platform_job_controls
15
+ WHERE job_name = $1`;
16
+ const LATEST_TERMINAL_METADATA_SQL = `
17
+ SELECT metadata
18
+ FROM public.platform_job_runs
19
+ WHERE job_name = $1
20
+ AND status IN ('success', 'failed')
21
+ AND finished_at IS NOT NULL
22
+ ORDER BY started_at DESC
23
+ LIMIT 1`;
24
+ /** Direct PostgreSQL adapter for the public neutral-vocabulary job-control rail. */
25
+ export function createPostgresPlatformJobRunLedger(executor, options) {
26
+ return {
27
+ async claimJobRun(jobName, invocation, leaseSeconds = 900) {
28
+ const invocationSource = requiredInvocationSource(invocation.invocationSource);
29
+ const result = await executor.query(CLAIM_SQL, [
30
+ jobName,
31
+ invocation.triggerKind,
32
+ invocationSource,
33
+ leaseSeconds,
34
+ {
35
+ triggerKind: invocation.triggerKind,
36
+ invocationSource,
37
+ ...options.releaseCorrelation(),
38
+ },
39
+ ]);
40
+ const row = plainRecord(result.rows[0]);
41
+ return {
42
+ acquired: row?.acquired === true,
43
+ runId: typeof row?.run_id === "string" ? row.run_id : null,
44
+ reason: typeof row?.reason === "string" ? row.reason : "unknown",
45
+ };
46
+ },
47
+ async finishJobRun(jobName, runId, invocation, status, summary, extraMetadata) {
48
+ const invocationSource = requiredInvocationSource(invocation.invocationSource);
49
+ const result = await executor.query(FINISH_SQL, [
50
+ jobName,
51
+ runId,
52
+ status,
53
+ summary.checked,
54
+ summary.updated,
55
+ status === "failed" ? summary.reason ?? options.defaultFailureReason : null,
56
+ null,
57
+ {
58
+ failures: summary.failures,
59
+ skipped: summary.skipped,
60
+ reason: summary.reason ?? null,
61
+ ...options.releaseCorrelation(),
62
+ ...(extraMetadata ?? {}),
63
+ triggerKind: invocation.triggerKind,
64
+ invocationSource,
65
+ driver: invocationSource,
66
+ },
67
+ ]);
68
+ return plainRecord(result.rows[0])?.released === true;
69
+ },
70
+ async readJobBackstopState(jobName) {
71
+ const result = await executor.query(BACKSTOP_SQL, [jobName]);
72
+ const row = plainRecord(result.rows[0]);
73
+ return row ? {
74
+ lastStatus: typeof row.last_status === "string" ? row.last_status : null,
75
+ lastSuccessAt: timestampString(row.last_success_at),
76
+ } : null;
77
+ },
78
+ async readLatestTerminalRunMetadata(jobName) {
79
+ const result = await executor.query(LATEST_TERMINAL_METADATA_SQL, [jobName]);
80
+ return plainRecord(plainRecord(result.rows[0])?.metadata);
81
+ },
82
+ };
83
+ }
84
+ function plainRecord(value) {
85
+ if (typeof value !== "object" || value === null || Array.isArray(value))
86
+ return null;
87
+ return { ...value };
88
+ }
89
+ function timestampString(value) {
90
+ if (typeof value === "string")
91
+ return value;
92
+ if (value instanceof Date)
93
+ return value.toISOString();
94
+ return null;
95
+ }
96
+ function requiredInvocationSource(value) {
97
+ const source = value.trim();
98
+ if (!source)
99
+ throw new Error("platform_job_invocation_source_required");
100
+ return source;
101
+ }
@@ -0,0 +1,7 @@
1
+ export declare const JOB_RUN_LEDGER_SQL_URL: URL;
2
+ export declare const JOB_RUN_LEDGER_V3_SQL_URL: URL;
3
+ /** Every job-run ledger migration, ordered by migration identity. */
4
+ export declare const JOB_RUN_LEDGER_MIGRATIONS: ReadonlyArray<{
5
+ readonly id: string;
6
+ readonly url: URL;
7
+ }>;
@@ -0,0 +1,10 @@
1
+ // The job-run ledger SQL a fresh installation applies through its own migration chain, in order.
2
+ // The first file's bytes and migration identity equal the reference application's platform
3
+ // migration of the same name; the second adds the v3 claim and finish entry points.
4
+ export const JOB_RUN_LEDGER_SQL_URL = new URL("../../sql/20260809150000_job_run_ledger.sql", import.meta.url);
5
+ export const JOB_RUN_LEDGER_V3_SQL_URL = new URL("../../sql/20260809150001_job_run_ledger_v3.sql", import.meta.url);
6
+ /** Every job-run ledger migration, ordered by migration identity. */
7
+ export const JOB_RUN_LEDGER_MIGRATIONS = [
8
+ { id: "20260809150000_job_run_ledger", url: JOB_RUN_LEDGER_SQL_URL },
9
+ { id: "20260809150001_job_run_ledger_v3", url: JOB_RUN_LEDGER_V3_SQL_URL },
10
+ ];
@@ -0,0 +1,77 @@
1
+ import type { PlatformJobFinishStatus, PlatformJobFinishSummary, PlatformJobInvocation, PlatformJobRunLedgerPort } from "./ports.js";
2
+ export type PlatformJobDriver = "manual_admin" | "pg_cron" | "vercel_cron" | "worker";
3
+ type RpcResult<T> = {
4
+ data: T | null;
5
+ error: {
6
+ message?: string;
7
+ } | null;
8
+ };
9
+ type PlatformJobMetadataQuery = {
10
+ select(columns: "metadata"): PlatformJobMetadataQuery;
11
+ eq(column: "job_name", value: string): PlatformJobMetadataQuery;
12
+ in(column: "status", values: readonly ["success", "failed"]): PlatformJobMetadataQuery;
13
+ not(column: "finished_at", operator: "is", value: null): PlatformJobMetadataQuery;
14
+ order(column: "started_at", options: {
15
+ ascending: false;
16
+ }): PlatformJobMetadataQuery;
17
+ limit(count: 1): PlatformJobMetadataQuery;
18
+ maybeSingle(): PromiseLike<{
19
+ data: {
20
+ metadata?: unknown;
21
+ } | null;
22
+ error: {
23
+ message?: string;
24
+ } | null;
25
+ }>;
26
+ };
27
+ type PlatformJobControlQuery = {
28
+ select(columns: "last_status,last_success_at"): PlatformJobControlQuery;
29
+ eq(column: "job_name", value: string): PlatformJobControlQuery;
30
+ maybeSingle(): PromiseLike<{
31
+ data: {
32
+ last_status?: string | null;
33
+ last_success_at?: string | null;
34
+ } | null;
35
+ error: {
36
+ message?: string;
37
+ } | null;
38
+ }>;
39
+ };
40
+ export interface PlatformJobSupabaseClient {
41
+ rpc<T = unknown>(name: string, args: Record<string, unknown>): PromiseLike<RpcResult<T>>;
42
+ from(table: "platform_job_runs"): PlatformJobMetadataQuery;
43
+ from(table: "platform_job_controls"): PlatformJobControlQuery;
44
+ }
45
+ /** Minimal compatibility client for the legacy free-function surface. */
46
+ export type PlatformJobClient = Pick<PlatformJobSupabaseClient, "rpc">;
47
+ export declare function platformJobInvocationForDriver(driver: PlatformJobDriver): PlatformJobInvocation;
48
+ export interface ManagedJobRunOptions {
49
+ /** Release and deployment identity merged into every claim and finish row's metadata. */
50
+ releaseCorrelation: () => Record<string, string | null>;
51
+ /** Failure reason recorded when a failed run's summary carries none. */
52
+ defaultFailureReason: string;
53
+ }
54
+ export interface SupabasePlatformJobRunLedgerOptions extends ManagedJobRunOptions {
55
+ /** Message of the error thrown when the backstop state cannot be read. */
56
+ backstopReadError: string;
57
+ /** Message of the error thrown when the latest terminal run cannot be read. */
58
+ checkpointReadError: string;
59
+ }
60
+ /** The managed v2/v3 compatibility calls, bound to the deployment's release correlation. */
61
+ export declare function createManagedJobRunCalls(options: ManagedJobRunOptions): {
62
+ claimJobRun: (client: PlatformJobClient, jobName: string, driver: PlatformJobDriver, leaseSeconds?: number) => Promise<{
63
+ acquired: boolean;
64
+ runId: string | null;
65
+ reason: string;
66
+ }>;
67
+ claimJobRunV3: (client: PlatformJobClient, jobName: string, invocation: PlatformJobInvocation, leaseSeconds?: number) => Promise<{
68
+ acquired: boolean;
69
+ runId: string | null;
70
+ reason: string;
71
+ }>;
72
+ finishJobRun: (client: PlatformJobClient, jobName: string, runId: string, status: PlatformJobFinishStatus, result: PlatformJobFinishSummary, extraMetadata?: Record<string, unknown>) => Promise<boolean>;
73
+ finishJobRunV3: (client: PlatformJobClient, jobName: string, runId: string, status: PlatformJobFinishStatus, result: PlatformJobFinishSummary, extraMetadata?: Record<string, unknown>) => Promise<void>;
74
+ };
75
+ /** Managed adapter for the semantic job-run port. */
76
+ export declare function createSupabasePlatformJobRunLedger(client: PlatformJobSupabaseClient, options: SupabasePlatformJobRunLedgerOptions): PlatformJobRunLedgerPort;
77
+ export {};
@@ -0,0 +1,202 @@
1
+ // Managed (Supabase) adapter for the job-run ledger, and the managed v2/v3 compatibility calls.
2
+ //
3
+ // It speaks the managed job-control RPCs (`platform_claim_job_run`, `platform_finish_job_run_v2`
4
+ // and their v3 forms) through an injected client. Every claim and finish row carries the
5
+ // deployment's release correlation; the default failure reason and the two read-failure messages
6
+ // are the deployment's own values.
7
+ function triggerSourceForDriver(driver) {
8
+ switch (driver) {
9
+ case "vercel_cron": return "vercel_cron";
10
+ case "pg_cron": return "pg_cron_scheduler";
11
+ case "worker": return "worker";
12
+ case "manual_admin": return "manual_admin";
13
+ }
14
+ }
15
+ export function platformJobInvocationForDriver(driver) {
16
+ switch (driver) {
17
+ case "manual_admin": return { triggerKind: "operator", invocationSource: driver };
18
+ case "pg_cron":
19
+ case "vercel_cron": return { triggerKind: "scheduler", invocationSource: driver };
20
+ case "worker": return { triggerKind: "worker", invocationSource: driver };
21
+ }
22
+ }
23
+ function managedDriverForInvocation(invocation) {
24
+ if (!["worker", "scheduler", "operator"].includes(invocation.triggerKind)) {
25
+ throw new Error("platform_job_invalid_trigger_kind");
26
+ }
27
+ const source = invocation.invocationSource.trim();
28
+ const driver = source;
29
+ const expected = platformJobInvocationForDriver(driver);
30
+ if (!expected || expected.triggerKind !== invocation.triggerKind) {
31
+ throw new Error("platform_job_invalid_invocation");
32
+ }
33
+ return driver;
34
+ }
35
+ function claimResult(data) {
36
+ const row = Array.isArray(data) ? data[0] : data;
37
+ const record = plainRecord(row);
38
+ return {
39
+ acquired: record?.acquired === true,
40
+ runId: typeof record?.run_id === "string" ? record.run_id : null,
41
+ reason: typeof record?.reason === "string" ? record.reason : "unknown",
42
+ };
43
+ }
44
+ /** The managed v2/v3 compatibility calls, bound to the deployment's release correlation. */
45
+ export function createManagedJobRunCalls(options) {
46
+ /** Compatibility surface for existing managed v2 consumers. */
47
+ async function claimJobRun(client, jobName, driver, leaseSeconds = 900) {
48
+ const { data, error } = await client.rpc("platform_claim_job_run", {
49
+ p_job_name: jobName,
50
+ p_driver: driver,
51
+ p_lease_seconds: leaseSeconds,
52
+ p_metadata: {
53
+ driver,
54
+ triggerSource: driver === "vercel_cron" ? "vercel_cron_manual" : driver,
55
+ ...options.releaseCorrelation(),
56
+ },
57
+ });
58
+ if (error)
59
+ throw new Error(error.message ?? "platform_claim_job_run failed");
60
+ return claimResult(data);
61
+ }
62
+ /** Compatibility surface for existing managed v3 consumers. */
63
+ async function claimJobRunV3(client, jobName, invocation, leaseSeconds = 900) {
64
+ const invocationSource = invocation.invocationSource.trim();
65
+ if (!invocationSource)
66
+ throw new Error("platform_job_invocation_source_required");
67
+ const { data, error } = await client.rpc("platform_claim_job_run_v3", {
68
+ p_job_name: jobName,
69
+ p_trigger_kind: invocation.triggerKind,
70
+ p_invocation_source: invocationSource,
71
+ p_lease_seconds: leaseSeconds,
72
+ p_metadata: {
73
+ triggerKind: invocation.triggerKind,
74
+ invocationSource,
75
+ ...options.releaseCorrelation(),
76
+ },
77
+ });
78
+ if (error)
79
+ throw new Error(error.message ?? "platform_claim_job_run_v3 failed");
80
+ return claimResult(data);
81
+ }
82
+ /** Compatibility surface for existing managed v2 consumers. */
83
+ async function finishJobRun(client, jobName, runId, status, result, extraMetadata) {
84
+ const { data, error } = await client.rpc("platform_finish_job_run_v2", {
85
+ p_job_name: jobName,
86
+ p_run_id: runId,
87
+ p_status: status,
88
+ p_checked: result.checked,
89
+ p_updated: result.updated,
90
+ p_error: status === "failed" ? result.reason ?? options.defaultFailureReason : null,
91
+ p_support_code: null,
92
+ p_metadata: {
93
+ driver: "manual_admin",
94
+ failures: result.failures,
95
+ skipped: result.skipped,
96
+ reason: result.reason ?? null,
97
+ ...options.releaseCorrelation(),
98
+ ...(extraMetadata ?? {}),
99
+ },
100
+ });
101
+ if (error)
102
+ throw new Error(error.message ?? "platform_finish_job_run_v2 failed");
103
+ return data === true;
104
+ }
105
+ /** Compatibility surface for existing managed v3 consumers. */
106
+ async function finishJobRunV3(client, jobName, runId, status, result, extraMetadata) {
107
+ const { error } = await client.rpc("platform_finish_job_run_v3", {
108
+ p_job_name: jobName,
109
+ p_run_id: runId,
110
+ p_status: status,
111
+ p_checked: result.checked,
112
+ p_updated: result.updated,
113
+ p_error: status === "failed" ? result.reason ?? options.defaultFailureReason : null,
114
+ p_support_code: null,
115
+ p_metadata: {
116
+ failures: result.failures,
117
+ skipped: result.skipped,
118
+ reason: result.reason ?? null,
119
+ ...options.releaseCorrelation(),
120
+ ...(extraMetadata ?? {}),
121
+ },
122
+ });
123
+ if (error)
124
+ throw new Error(error.message ?? "platform_finish_job_run_v3 failed");
125
+ }
126
+ return { claimJobRun, claimJobRunV3, finishJobRun, finishJobRunV3 };
127
+ }
128
+ /** Managed adapter for the semantic job-run port. */
129
+ export function createSupabasePlatformJobRunLedger(client, options) {
130
+ return {
131
+ async claimJobRun(jobName, invocation, leaseSeconds = 900) {
132
+ const driver = managedDriverForInvocation(invocation);
133
+ const { data, error } = await client.rpc("platform_claim_job_run", {
134
+ p_job_name: jobName,
135
+ p_driver: driver,
136
+ p_lease_seconds: leaseSeconds,
137
+ p_metadata: {
138
+ driver,
139
+ triggerSource: triggerSourceForDriver(driver),
140
+ ...options.releaseCorrelation(),
141
+ },
142
+ });
143
+ if (error)
144
+ throw new Error(error.message ?? "platform_claim_job_run failed");
145
+ return claimResult(data);
146
+ },
147
+ async finishJobRun(jobName, runId, invocation, status, result, extraMetadata) {
148
+ const driver = managedDriverForInvocation(invocation);
149
+ const { data, error } = await client.rpc("platform_finish_job_run_v2", {
150
+ p_job_name: jobName,
151
+ p_run_id: runId,
152
+ p_status: status,
153
+ p_checked: result.checked,
154
+ p_updated: result.updated,
155
+ p_error: status === "failed" ? result.reason ?? options.defaultFailureReason : null,
156
+ p_support_code: null,
157
+ p_metadata: {
158
+ failures: result.failures,
159
+ skipped: result.skipped,
160
+ reason: result.reason ?? null,
161
+ ...options.releaseCorrelation(),
162
+ ...(extraMetadata ?? {}),
163
+ driver,
164
+ },
165
+ });
166
+ if (error)
167
+ throw new Error(error.message ?? "platform_finish_job_run_v2 failed");
168
+ return data === true;
169
+ },
170
+ async readJobBackstopState(jobName) {
171
+ const { data, error } = await client
172
+ .from("platform_job_controls")
173
+ .select("last_status,last_success_at")
174
+ .eq("job_name", jobName)
175
+ .maybeSingle();
176
+ if (error)
177
+ throw new Error(options.backstopReadError);
178
+ return data ? {
179
+ lastStatus: data.last_status ?? null,
180
+ lastSuccessAt: data.last_success_at ?? null,
181
+ } : null;
182
+ },
183
+ async readLatestTerminalRunMetadata(jobName) {
184
+ const { data, error } = await client
185
+ .from("platform_job_runs")
186
+ .select("metadata")
187
+ .eq("job_name", jobName)
188
+ .in("status", ["success", "failed"])
189
+ .order("started_at", { ascending: false })
190
+ .limit(1)
191
+ .maybeSingle();
192
+ if (error)
193
+ throw new Error(options.checkpointReadError);
194
+ return plainRecord(data?.metadata);
195
+ },
196
+ };
197
+ }
198
+ function plainRecord(value) {
199
+ if (typeof value !== "object" || value === null || Array.isArray(value))
200
+ return null;
201
+ return { ...value };
202
+ }
@@ -0,0 +1 @@
1
+ export { BLOB_CAPABILITIES, DEFAULT_PLATFORM_BUNDLE, ENV_MISSING_CODE, PLATFORM_BUNDLE_DESCRIPTORS, PLATFORM_BUNDLE_IDS, getBundleDescriptor, isPlatformBundleId, platformEnvSchema, resolveBlobCapability, resolveBundleId, type BlobCapability, type PlatformBundleDescriptor, type PlatformBundleId, type PlatformBundleReadiness, type PlatformEnv, } from "./platformKernel.js";
@@ -0,0 +1 @@
1
+ export { BLOB_CAPABILITIES, DEFAULT_PLATFORM_BUNDLE, ENV_MISSING_CODE, PLATFORM_BUNDLE_DESCRIPTORS, PLATFORM_BUNDLE_IDS, getBundleDescriptor, isPlatformBundleId, platformEnvSchema, resolveBlobCapability, resolveBundleId, } from "./platformKernel.js";
@@ -0,0 +1,34 @@
1
+ import { z } from "zod";
2
+ import { type PlatformBundleDescriptor as CorePlatformBundleDescriptor, type PlatformBundleReadiness, type PlatformEnvInput } from "@openlup/core/platform-runtime";
3
+ /** The bundles a deployment can select with `PLATFORM_BUNDLE`. */
4
+ export declare const PLATFORM_BUNDLE_IDS: readonly ["vercel-supabase", "node-supabase", "node-postgres"];
5
+ export type PlatformBundleId = (typeof PLATFORM_BUNDLE_IDS)[number];
6
+ /** The bundle selected when `PLATFORM_BUNDLE` is absent or unknown. */
7
+ export declare const DEFAULT_PLATFORM_BUNDLE: PlatformBundleId;
8
+ export declare const isPlatformBundleId: import("@openlup/core/platform-runtime").PlatformBundleIdGuard<"vercel-supabase" | "node-supabase" | "node-postgres">;
9
+ export type PlatformBundleDescriptor = CorePlatformBundleDescriptor & {
10
+ id: PlatformBundleId;
11
+ };
12
+ export type { PlatformBundleReadiness };
13
+ /** The readiness code a bundle reports when a selected capability lacks its configuration. */
14
+ export declare const ENV_MISSING_CODE = "OPENLUP_E_ENV_MISSING";
15
+ /** The blob capabilities a deployment can select with `PLATFORM_BLOB`. */
16
+ export declare const BLOB_CAPABILITIES: readonly ["filesystem", "s3", "supabase", "vercel-blob"];
17
+ export type BlobCapability = (typeof BLOB_CAPABILITIES)[number];
18
+ /**
19
+ * The blob capability in effect: a valid `PLATFORM_BLOB` selection, else the bundle's own. An
20
+ * invalid selection keeps the bundle's own here and is refused by readiness.
21
+ */
22
+ export declare function resolveBlobCapability(descriptor: Pick<PlatformBundleDescriptor, "capabilities">, env: PlatformEnvInput): string;
23
+ export declare const PLATFORM_BUNDLE_DESCRIPTORS: readonly PlatformBundleDescriptor[];
24
+ export declare function getBundleDescriptor(id: PlatformBundleId): PlatformBundleDescriptor;
25
+ export declare function resolveBundleId(env: PlatformEnvInput): PlatformBundleId;
26
+ export declare const platformEnvSchema: z.ZodObject<{
27
+ APP_BASE_URL: z.ZodOptional<z.ZodString>;
28
+ PLATFORM_BUNDLE: z.ZodOptional<z.ZodEnum<{
29
+ "vercel-supabase": "vercel-supabase";
30
+ "node-supabase": "node-supabase";
31
+ "node-postgres": "node-postgres";
32
+ }>>;
33
+ }, z.core.$strip>;
34
+ export type PlatformEnv = z.infer<typeof platformEnvSchema>;