@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,16 @@
1
+ /** Explicitly retain verifier-only admission. This does not bypass mailbox verification. */
2
+ export function createVerifierResultOnlyEmailTrustPolicy() {
3
+ return { async assess() { return { trusted: true }; } };
4
+ }
5
+ /** Invalid, absent or throwing JavaScript bindings fail closed, including invalid results. */
6
+ export async function assessEmailTrust(policy) {
7
+ try {
8
+ const result = await policy.assess();
9
+ if (result?.trusted === true)
10
+ return { trusted: true };
11
+ if (result?.trusted === false && result.code === "EMAIL_TRUST_ENVELOPE_REFUSED")
12
+ return result;
13
+ }
14
+ catch { /* Do not expose policy or transport details. */ }
15
+ return { trusted: false, code: "EMAIL_TRUST_SETTINGS_UNAVAILABLE" };
16
+ }
@@ -0,0 +1,7 @@
1
+ import type { PersonalDataObligation } from "./contracts/privacy.js";
2
+ import { type PersonalDataContributor, type PrivacyStore } from "./privacyPorts.js";
3
+ export interface IdentityPrivacyPolicy {
4
+ /** Explicit dispositions for populated opaque contact fields; absence refuses erasure. */
5
+ retainedContactFields: Readonly<Record<string, PersonalDataObligation>>;
6
+ }
7
+ export declare function createIdentityPersonalDataContributor<C>(store: PrivacyStore<C>, policy: IdentityPrivacyPolicy, randomId: () => string): PersonalDataContributor<C>;
@@ -0,0 +1,46 @@
1
+ import { PrivacyRefusal } from "./privacyPorts.js";
2
+ const owned = new Set(["id", "email", "first_name", "last_name", "phone", "country", "principal_id", "created_at", "updated_at"]);
3
+ const populated = (value) => value !== null && value !== "" && !(typeof value === "object" && Object.keys(value).length === 0);
4
+ export function createIdentityPersonalDataContributor(store, policy, randomId) {
5
+ function obligations(identity) {
6
+ const contact = identity.contact;
7
+ const result = [{ owner: "identity", resource: "identity.audit-and-receipt", disposition: "retain", reasonCode: "PSEUDONYMOUS_AUDIT", remote: false }];
8
+ if (contact && typeof contact === "object" && !Array.isArray(contact)) {
9
+ for (const [key, value] of Object.entries(contact)) {
10
+ if (owned.has(key) || !populated(value))
11
+ continue;
12
+ const declaration = policy.retainedContactFields[key];
13
+ result.push(declaration?.disposition === "retain" && declaration.resource === `clients.${key}` ? declaration : { owner: "unassigned", resource: `clients.${key}`, disposition: "unresolved", reasonCode: "PRIVACY_OWNERSHIP_UNDECLARED", remote: false });
14
+ }
15
+ }
16
+ return result;
17
+ }
18
+ return {
19
+ id: "identity", version: "identity.personal-data.v1",
20
+ ownedResources: ["identity.contact-profile", "identity.principal", "identity.membership", "identity.invitations", "identity.audit-and-receipt"],
21
+ async prepareErasure() { },
22
+ async export(_context, subject) {
23
+ const unavailable = Array.isArray(subject.identity.unavailable) ? subject.identity.unavailable.map(String) : [];
24
+ const data = { ...subject.identity };
25
+ const contact = data.contact;
26
+ if (contact && typeof contact === "object" && !Array.isArray(contact)) {
27
+ data.contact = Object.fromEntries(Object.entries(contact).filter(([key]) => owned.has(key) || key === "auth_user_id"));
28
+ for (const key of Object.keys(contact))
29
+ if (!owned.has(key) && key !== "auth_user_id")
30
+ unavailable.push(`contact.${key}`);
31
+ }
32
+ return { contributorId: "identity", version: "identity.personal-data.v1", data,
33
+ coverage: { complete: unavailable.length === 0, included: Object.keys(subject.identity).filter(k => k !== "unavailable"), unavailable }, obligations: obligations(subject.identity) };
34
+ },
35
+ async assessErasure(_context, subject) {
36
+ const declared = obligations(subject.identity);
37
+ if (declared.some(o => o.disposition === "unresolved"))
38
+ throw new PrivacyRefusal("PRIVACY_OWNERSHIP_UNDECLARED");
39
+ return { obligations: declared };
40
+ },
41
+ async eraseOrRetain(context, subject, assessment, actor) {
42
+ await store.eraseIdentity(context, subject, actor, `erased+${randomId()}@identity.invalid`);
43
+ return { contributorId: "identity", version: "identity.personal-data.v1", obligations: assessment.obligations };
44
+ },
45
+ };
46
+ }
@@ -0,0 +1,10 @@
1
+ import type { ReadinessIssue } from "@openlup/core/readiness";
2
+ import { type EmailTrustPolicy } from "./emailTrustPolicy.js";
3
+ /** The module field stays structural so older core readiness types still compile; no new core code is needed. */
4
+ export declare function identityEmailTrustReadiness(policy: EmailTrustPolicy): Promise<readonly (ReadinessIssue & {
5
+ module: "identity";
6
+ })[]>;
7
+ /** Discovery and fresh key availability are independent readiness observations. */
8
+ export declare function identityOidcReadiness(verifier: import("./oidcIdentityVerifier.js").OidcIdentityVerifier): Promise<readonly (ReadinessIssue & {
9
+ module: "identity";
10
+ })[]>;
@@ -0,0 +1,25 @@
1
+ import { assessEmailTrust } from "./emailTrustPolicy.js";
2
+ /** The module field stays structural so older core readiness types still compile; no new core code is needed. */
3
+ export async function identityEmailTrustReadiness(policy) {
4
+ const result = await assessEmailTrust(policy);
5
+ if (result.trusted)
6
+ return [];
7
+ return [{
8
+ code: "OPENLUP_E_PORT_MISSING", package: "@openlup/platform", module: "identity",
9
+ subject: "emailTrustPolicy", observation: result.code,
10
+ fix: result.code === "EMAIL_TRUST_ENVELOPE_REFUSED"
11
+ ? "Disable automatic confirmation and declare only providers that verify email."
12
+ : "Restore access to valid public identity settings or bind an explicit email-trust policy.",
13
+ }];
14
+ }
15
+ /** Discovery and fresh key availability are independent readiness observations. */
16
+ export async function identityOidcReadiness(verifier) {
17
+ const report = await verifier.readiness();
18
+ if (report.state === "ready")
19
+ return [];
20
+ return [
21
+ ...(!report.discovery.valid ? ["oidcDiscovery"] : []),
22
+ ...(!report.jwks.loaded ? ["oidcJwks"] : []),
23
+ ].map(subject => ({ code: "OPENLUP_E_PORT_MISSING", package: "@openlup/platform", module: "identity", subject,
24
+ observation: report.code ?? "OIDC_JWKS_INVALID", fix: "Restore valid issuer discovery and fresh same-origin signing keys." }));
25
+ }
@@ -0,0 +1,67 @@
1
+ export * from "./adminMagicLinkHandler.js";
2
+ export * from "./reconcileAccountForPrincipal.js";
3
+ export * from "./customerVerifyOtpHandler.js";
4
+ export * from "./authVerifyUrl.js";
5
+ export * from "./customerIdentityVerifier.js";
6
+ export * from "./operatorTokenAdminAuth.js";
7
+ export * from "./managedIdentityVerifier.js";
8
+ export * from "./managedAdminAuthVerifier.js";
9
+ export * from "./managedCustomerMe.js";
10
+ export * from "./sql.js";
11
+ export * from "./customerMeHandler.js";
12
+ export * from "./messages.js";
13
+ export * from "./managedAccountLinkStore.js";
14
+ export * from "./customerIdentityBinding.js";
15
+ export * from "./adminUserActionPorts.js";
16
+ export * from "./contribution.js";
17
+ export * from "./customerContracts.js";
18
+ export * from "./machineActorWriteFence.js";
19
+ export * from "./managedClient.js";
20
+ export * from "./customerAuthorization.js";
21
+ export * from "./customerSessionIssuer.js";
22
+ export * from "./managedClientAuthLink.js";
23
+ export * from "./customerAuth.js";
24
+ export * from "./reconcileAccountHandler.js";
25
+ export * from "./postgresCustomerMe.js";
26
+ export * from "./ports.js";
27
+ export * from "./postgresCustomerRecovery.js";
28
+ export * from "./customerMagicLinkHandler.js";
29
+ export * from "./customerSessionBinding.js";
30
+ export * from "./adminUserHandlers.js";
31
+ export * from "./adminPreflight.js";
32
+ export * from "./adminAuthBinding.js";
33
+ export * from "./customerPorts.js";
34
+ export * from "./magicLinkPorts.js";
35
+ export * from "./inviteAdminUserUseCase.js";
36
+ export * from "./adminAuthorization.js";
37
+ export * from "./removeAdminUserUseCase.js";
38
+ export * from "./adminMeHandler.js";
39
+ export * from "./managedAdminUserGateways.js";
40
+ export * from "./jwtLibrary.js";
41
+ export * from "./platformAdminAuth.js";
42
+ export * from "./adminContracts.js";
43
+ export * from "./contracts/emailTrust.js";
44
+ export { createVerifierResultOnlyEmailTrustPolicy } from "./emailTrustPolicy.js";
45
+ export type { EmailTrustAssessment, EmailTrustPolicy } from "./emailTrustPolicy.js";
46
+ export * from "./managedEmailTrustPolicy.js";
47
+ export * from "./identityReadiness.js";
48
+ export * from "./operatorInvitationPorts.js";
49
+ export * from "./operatorInvitationLifecycle.js";
50
+ export * from "./directOperatorInvitationStore.js";
51
+ export * from "./operatorPorts.js";
52
+ export * from "./operatorSession.js";
53
+ export * from "./operatorIdentityVerifier.js";
54
+ export * from "./operatorAdminAuth.js";
55
+ export * from "./operatorAuthHandlers.js";
56
+ export * from "./postgresOperatorIdentity.js";
57
+ export * from "./privacyPorts.js";
58
+ export * from "./personalDataRegistry.js";
59
+ export * from "./privacyUseCases.js";
60
+ export * from "./identityPersonalDataContributor.js";
61
+ export * from "./postgresPrivacy.js";
62
+ export * from "./managedPrivacy.js";
63
+ export * from "./privacyHandlers.js";
64
+ export * from "./oidcIdentityVerifier.js";
65
+ export * from "./oidcPrincipal.js";
66
+ export * from "./postgresAccountLinkStore.js";
67
+ export * from "./contracts/oidc.js";
@@ -0,0 +1,66 @@
1
+ export * from "./adminMagicLinkHandler.js";
2
+ export * from "./reconcileAccountForPrincipal.js";
3
+ export * from "./customerVerifyOtpHandler.js";
4
+ export * from "./authVerifyUrl.js";
5
+ export * from "./customerIdentityVerifier.js";
6
+ export * from "./operatorTokenAdminAuth.js";
7
+ export * from "./managedIdentityVerifier.js";
8
+ export * from "./managedAdminAuthVerifier.js";
9
+ export * from "./managedCustomerMe.js";
10
+ export * from "./sql.js";
11
+ export * from "./customerMeHandler.js";
12
+ export * from "./messages.js";
13
+ export * from "./managedAccountLinkStore.js";
14
+ export * from "./customerIdentityBinding.js";
15
+ export * from "./adminUserActionPorts.js";
16
+ export * from "./contribution.js";
17
+ export * from "./customerContracts.js";
18
+ export * from "./machineActorWriteFence.js";
19
+ export * from "./managedClient.js";
20
+ export * from "./customerAuthorization.js";
21
+ export * from "./customerSessionIssuer.js";
22
+ export * from "./managedClientAuthLink.js";
23
+ export * from "./customerAuth.js";
24
+ export * from "./reconcileAccountHandler.js";
25
+ export * from "./postgresCustomerMe.js";
26
+ export * from "./ports.js";
27
+ export * from "./postgresCustomerRecovery.js";
28
+ export * from "./customerMagicLinkHandler.js";
29
+ export * from "./customerSessionBinding.js";
30
+ export * from "./adminUserHandlers.js";
31
+ export * from "./adminPreflight.js";
32
+ export * from "./adminAuthBinding.js";
33
+ export * from "./customerPorts.js";
34
+ export * from "./magicLinkPorts.js";
35
+ export * from "./inviteAdminUserUseCase.js";
36
+ export * from "./adminAuthorization.js";
37
+ export * from "./removeAdminUserUseCase.js";
38
+ export * from "./adminMeHandler.js";
39
+ export * from "./managedAdminUserGateways.js";
40
+ export * from "./jwtLibrary.js";
41
+ export * from "./platformAdminAuth.js";
42
+ export * from "./adminContracts.js";
43
+ export * from "./contracts/emailTrust.js";
44
+ export { createVerifierResultOnlyEmailTrustPolicy } from "./emailTrustPolicy.js";
45
+ export * from "./managedEmailTrustPolicy.js";
46
+ export * from "./identityReadiness.js";
47
+ export * from "./operatorInvitationPorts.js";
48
+ export * from "./operatorInvitationLifecycle.js";
49
+ export * from "./directOperatorInvitationStore.js";
50
+ export * from "./operatorPorts.js";
51
+ export * from "./operatorSession.js";
52
+ export * from "./operatorIdentityVerifier.js";
53
+ export * from "./operatorAdminAuth.js";
54
+ export * from "./operatorAuthHandlers.js";
55
+ export * from "./postgresOperatorIdentity.js";
56
+ export * from "./privacyPorts.js";
57
+ export * from "./personalDataRegistry.js";
58
+ export * from "./privacyUseCases.js";
59
+ export * from "./identityPersonalDataContributor.js";
60
+ export * from "./postgresPrivacy.js";
61
+ export * from "./managedPrivacy.js";
62
+ export * from "./privacyHandlers.js";
63
+ export * from "./oidcIdentityVerifier.js";
64
+ export * from "./oidcPrincipal.js";
65
+ export * from "./postgresAccountLinkStore.js";
66
+ export * from "./contracts/oidc.js";
@@ -0,0 +1,89 @@
1
+ import type { ManagedOperatorMembershipResult, OperatorInvitationConflict } from "./contracts/operatorInvitations.js";
2
+ import type { OperatorInvitationStore } from "./operatorInvitationPorts.js";
3
+ import { type IdentityMessages } from "./messages.js";
4
+ export type AdminUserInviteRole = "admin" | "distributor";
5
+ export declare const ADMIN_ROLE_NOTIFICATION_LOCALE: "en";
6
+ export type AdminRoleNotificationSkipReason = "admin_disabled" | "egress_suppressed";
7
+ export type InviteAdminUserResponse = {
8
+ [key: string]: unknown;
9
+ success?: boolean;
10
+ message?: string;
11
+ error?: string;
12
+ code?: string;
13
+ deliveryReference?: string | null;
14
+ deliveryReferencePresent?: boolean;
15
+ };
16
+ export interface InviteAdminUserGateway {
17
+ getUser: (accessToken: string) => Promise<{
18
+ user: {
19
+ id: string;
20
+ } | null;
21
+ error: unknown;
22
+ }>;
23
+ findAdminUser: (userId: string) => Promise<{
24
+ id: string;
25
+ role: string;
26
+ membership_state: string;
27
+ is_machine_actor: boolean;
28
+ } | null>;
29
+ findAdminUserByEmail: (email: string) => Promise<{
30
+ id: string;
31
+ } | null>;
32
+ findAuthUserByEmail: (email: string) => Promise<{
33
+ id: string;
34
+ email?: string | null;
35
+ } | null>;
36
+ inviteAuthUser: (input: {
37
+ email: string;
38
+ redirectTo: string;
39
+ role: AdminUserInviteRole;
40
+ }) => Promise<{
41
+ user: {
42
+ id: string;
43
+ } | null;
44
+ error: {
45
+ message: string;
46
+ } | null;
47
+ }>;
48
+ }
49
+ export interface AdminRoleNotificationPort {
50
+ sendRoleGranted: (input: {
51
+ email: string;
52
+ authUserId: string;
53
+ role: AdminUserInviteRole;
54
+ locale: "pl" | "en";
55
+ invitationId?: string;
56
+ expiresAt?: string;
57
+ }) => Promise<{
58
+ ok: boolean;
59
+ providerMessageId: string | null;
60
+ providerError: string | null;
61
+ skipped: boolean;
62
+ skipReason: AdminRoleNotificationSkipReason | null;
63
+ }>;
64
+ }
65
+ export declare function runInviteAdminUserUseCase(request: {
66
+ accessToken: string | null;
67
+ email: string;
68
+ role: string;
69
+ }, deps: {
70
+ gateway: InviteAdminUserGateway;
71
+ roleNotificationPort: AdminRoleNotificationPort;
72
+ siteUrl: string;
73
+ messages?: IdentityMessages;
74
+ notificationLocale?: "pl" | "en";
75
+ } & ({
76
+ invitationStore: OperatorInvitationStore;
77
+ ttlSeconds: number;
78
+ } | {
79
+ activateMembership: (input: {
80
+ principalId: string;
81
+ email: string;
82
+ role: AdminUserInviteRole;
83
+ }) => Promise<ManagedOperatorMembershipResult | {
84
+ code: OperatorInvitationConflict;
85
+ }>;
86
+ })): Promise<{
87
+ status: number;
88
+ body: InviteAdminUserResponse;
89
+ }>;
@@ -0,0 +1,75 @@
1
+ import { assertOperatorInvitationTtl } from "./operatorInvitationLifecycle.js";
2
+ import { identityMessages } from "./messages.js";
3
+ export const ADMIN_ROLE_NOTIFICATION_LOCALE = "en";
4
+ export async function runInviteAdminUserUseCase(request, deps) {
5
+ const messages = deps.messages ?? identityMessages.en;
6
+ try {
7
+ if ("invitationStore" in deps)
8
+ assertOperatorInvitationTtl(deps.ttlSeconds);
9
+ if (!request.accessToken) {
10
+ return { status: 401, body: { code: "UNAUTHORIZED", error: messages.unauthorized } };
11
+ }
12
+ const { user, error: authError } = await deps.gateway.getUser(request.accessToken);
13
+ if (authError || !user) {
14
+ return { status: 401, body: { code: "INVALID_TOKEN", error: messages.invalidToken } };
15
+ }
16
+ const callerAdmin = await deps.gateway.findAdminUser(user.id);
17
+ if (!callerAdmin || callerAdmin.role !== "admin" || callerAdmin.membership_state !== "active" || callerAdmin.is_machine_actor !== false) {
18
+ return { status: 403, body: { code: "INVITE_FORBIDDEN", error: messages.inviteForbidden } };
19
+ }
20
+ if (!request.email) {
21
+ return { status: 400, body: { code: "EMAIL_REQUIRED", error: messages.emailRequired } };
22
+ }
23
+ if (!isInviteRole(request.role)) {
24
+ return { status: 400, body: { code: "INVALID_ROLE", error: messages.invalidRole } };
25
+ }
26
+ const role = request.role;
27
+ const email = request.email.trim().toLowerCase();
28
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))
29
+ return { status: 400, body: { code: "INVALID_EMAIL", error: "Invalid email" } };
30
+ const existingMembership = await deps.gateway.findAdminUserByEmail(email);
31
+ let principal = await deps.gateway.findAuthUserByEmail(email);
32
+ if (existingMembership && existingMembership.id !== principal?.id)
33
+ return { status: 409, body: { code: "IDENTITY_CONFLICT", error: "IDENTITY_CONFLICT" } };
34
+ if (!principal) {
35
+ const invite = await deps.gateway.inviteAuthUser({ email, role, redirectTo: new URL("/admin/auth/callback", deps.siteUrl).toString() });
36
+ if (invite.error || !invite.user) {
37
+ // A provider duplicate race reuses the durable identity. Never delete it.
38
+ principal = await deps.gateway.findAuthUserByEmail(email);
39
+ if (!principal)
40
+ throw new Error("operator_identity_creation_failed");
41
+ }
42
+ else
43
+ principal = invite.user;
44
+ }
45
+ const issued = "invitationStore" in deps
46
+ ? await deps.invitationStore.issue({ actorPrincipalId: user.id, targetPrincipalId: principal.id, email, role, ttlSeconds: deps.ttlSeconds })
47
+ : await deps.activateMembership({ principalId: principal.id, email, role });
48
+ if (!("membershipState" in issued))
49
+ return { status: 409, body: { code: issued.code, error: issued.code } };
50
+ let delivery = {};
51
+ if (issued.code !== "ALREADY_INVITED" && issued.code !== "ALREADY_ACTIVE") {
52
+ try {
53
+ const notification = await deps.roleNotificationPort.sendRoleGranted({ email, authUserId: principal.id, role, locale: deps.notificationLocale ?? ADMIN_ROLE_NOTIFICATION_LOCALE, ...(issued.membershipState === "invited" ? { invitationId: issued.invitationId, expiresAt: issued.expiresAt } : {}) });
54
+ if (!notification.ok)
55
+ throw new Error("operator_invitation_notification_failed");
56
+ delivery = { deliveryReference: notification.skipped ? null : notification.providerMessageId, deliveryReferencePresent: !notification.skipped && Boolean(notification.providerMessageId) };
57
+ }
58
+ catch {
59
+ return { status: 503, body: issued.membershipState === "invited"
60
+ ? { code: "INVITATION_NOTIFICATION_FAILED", error: "Invitation persisted; notification unavailable", invitationId: issued.invitationId }
61
+ : { ...issued, code: "INVITATION_NOTIFICATION_FAILED", error: "Membership active; notification unavailable" } };
62
+ }
63
+ }
64
+ return { status: 200, body: { success: true, ...issued, ...delivery, message: issued.membershipState === "invited" ? `Invitation pending until ${issued.expiresAt}` : "Operator membership active" } };
65
+ }
66
+ catch (err) {
67
+ const failure = err;
68
+ if (failure.identityCode)
69
+ return { status: failure.bffCode === "FORBIDDEN" ? 403 : 409, body: { code: failure.identityCode, error: failure.identityCode } };
70
+ return { status: 503, body: { code: "IDENTITY_ACTION_FAILED", error: String(err) } };
71
+ }
72
+ }
73
+ function isInviteRole(value) {
74
+ return value === "admin" || value === "distributor";
75
+ }
@@ -0,0 +1,54 @@
1
+ export interface IdentityJwk {
2
+ [key: string]: unknown;
3
+ kty?: string;
4
+ alg?: string;
5
+ crv?: string;
6
+ kid?: string;
7
+ use?: string;
8
+ x?: string;
9
+ y?: string;
10
+ d?: string;
11
+ }
12
+ type Key = CryptoKey | Uint8Array;
13
+ interface Signer {
14
+ setProtectedHeader(header: {
15
+ alg: string;
16
+ kid: string;
17
+ typ: string;
18
+ }): Signer;
19
+ setSubject(value: string): Signer;
20
+ setIssuer(value: string): Signer;
21
+ setAudience(value: string): Signer;
22
+ setIssuedAt(value: number): Signer;
23
+ setExpirationTime(value: number): Signer;
24
+ sign(key: Key): Promise<string>;
25
+ }
26
+ /** The host loads its selected JWT implementation only for the selected adapter. */
27
+ export interface IdentityJwtLibrary {
28
+ importJWK(jwk: IdentityJwk, alg: string): Promise<Key>;
29
+ jwtVerify(token: string, key: (header: {
30
+ alg?: string;
31
+ kid?: string;
32
+ }) => Promise<Key>, options: {
33
+ algorithms: string[];
34
+ audience: string;
35
+ issuer: string;
36
+ currentDate?: Date;
37
+ clockTolerance?: number;
38
+ }): Promise<{
39
+ payload: IdentityJwtClaims;
40
+ }>;
41
+ SignJWT: new (payload: Record<string, unknown>) => Signer;
42
+ }
43
+ export type IdentityJwtLibraryLoader = () => Promise<IdentityJwtLibrary>;
44
+ /** Claims returned only after signature verification by the host library. */
45
+ export interface IdentityJwtClaims {
46
+ [claim: string]: unknown;
47
+ sub?: string;
48
+ iss?: string;
49
+ aud?: string | string[];
50
+ exp?: number;
51
+ iat?: number;
52
+ nbf?: number;
53
+ }
54
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { HttpResponse } from "../http/index.js";
2
+ import { type IdentityResponseOptions } from "./response.js";
3
+ export declare function refusesMachineActorRequest(route: string, method: string | undefined, isMachineActor: boolean | undefined, writeRoutes?: readonly string[]): boolean;
4
+ export declare function sendMachineActorWriteRefused(res: HttpResponse, options?: IdentityResponseOptions): void;
@@ -0,0 +1,13 @@
1
+ import { createIdentityResponder } from "./response.js";
2
+ export function refusesMachineActorRequest(route, method, isMachineActor, writeRoutes = []) {
3
+ if (isMachineActor === false)
4
+ return false;
5
+ const verb = (method ?? "").toUpperCase();
6
+ return verb !== "GET" && verb !== "HEAD" && !writeRoutes.includes(route);
7
+ }
8
+ export function sendMachineActorWriteRefused(res, options = {}) {
9
+ const { sendBffError } = createIdentityResponder(options);
10
+ sendBffError(res, "FORBIDDEN", "Human operator required", {
11
+ details: { reason: "machine_actor_write_refused" },
12
+ });
13
+ }
@@ -0,0 +1,28 @@
1
+ export interface MagicLinkAuthClient {
2
+ auth: {
3
+ signInWithOtp(input: {
4
+ email: string;
5
+ options: {
6
+ shouldCreateUser: false;
7
+ emailRedirectTo: string;
8
+ };
9
+ }): Promise<{
10
+ error: {
11
+ name?: string;
12
+ message?: string;
13
+ } | null;
14
+ }>;
15
+ };
16
+ }
17
+ export interface MagicLinkRateLimitClient {
18
+ rpc(fn: string, args: Record<string, unknown>): Promise<{
19
+ data: unknown;
20
+ error: {
21
+ message?: string;
22
+ } | null;
23
+ }>;
24
+ }
25
+ export interface MagicLinkDecision {
26
+ allowed: boolean;
27
+ reason?: string;
28
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { AccountLinkStore } from "./ports.js";
2
+ export declare function createSupabaseAccountLinkStore(rawClient: unknown): AccountLinkStore;
@@ -0,0 +1,93 @@
1
+ export function createSupabaseAccountLinkStore(rawClient) {
2
+ const client = rawClient;
3
+ return {
4
+ async findAccountByPrincipalId(principalId) {
5
+ const { data, error } = await client
6
+ .from("clients")
7
+ .select("id, email, auth_user_id")
8
+ .eq("auth_user_id", principalId)
9
+ .maybeSingle();
10
+ if (error)
11
+ throw error;
12
+ if (!data)
13
+ return null;
14
+ return { id: data.id, email: data.email ?? null, principalId: data.auth_user_id ?? null };
15
+ },
16
+ async findAccountByEmail(email) {
17
+ const rows = await findManagedContactsByEmail(client, email, false);
18
+ if (rows.length > 1) {
19
+ throw Object.assign(new Error("multiple rows returned"), { code: "PGRST116" });
20
+ }
21
+ const data = rows[0];
22
+ if (!data)
23
+ return null;
24
+ return { id: data.id, email: data.email ?? null, principalId: data.auth_user_id ?? null };
25
+ },
26
+ async isReservedPrincipal(principalId) {
27
+ const { data, error } = await client
28
+ .from("admin_users")
29
+ .select("id, is_machine_actor")
30
+ .eq("id", principalId)
31
+ .maybeSingle();
32
+ if (error)
33
+ throw error;
34
+ if (!data)
35
+ return false;
36
+ return data.is_machine_actor !== false;
37
+ },
38
+ async linkPrincipalToAccount(accountId, principalId) {
39
+ const { data, error } = await client
40
+ .from("clients")
41
+ .update({ auth_user_id: principalId })
42
+ .eq("id", accountId)
43
+ .is("auth_user_id", null)
44
+ .select("auth_user_id")
45
+ .maybeSingle();
46
+ if (error)
47
+ throw error;
48
+ if (data?.auth_user_id === principalId) {
49
+ return { ok: true, alreadyLinked: false };
50
+ }
51
+ const { data: current, error: currentError } = await client
52
+ .from("clients")
53
+ .select("auth_user_id")
54
+ .eq("id", accountId)
55
+ .maybeSingle();
56
+ if (currentError)
57
+ throw currentError;
58
+ if (current?.auth_user_id === principalId) {
59
+ return { ok: true, alreadyLinked: true };
60
+ }
61
+ return { ok: false, existingPrincipalId: current?.auth_user_id ?? null };
62
+ },
63
+ async createAccount(input) {
64
+ const { data, error } = await client
65
+ .from("clients")
66
+ .insert({
67
+ email: input.email,
68
+ auth_user_id: input.principalId,
69
+ acquisition_source: input.acquisitionSource,
70
+ lifecycle_stage: input.lifecycleStage,
71
+ })
72
+ .select("id")
73
+ .single();
74
+ if (error)
75
+ throw error;
76
+ return { id: data.id };
77
+ },
78
+ };
79
+ }
80
+ async function findManagedContactsByEmail(client, email, oldestFirst) {
81
+ const normalized = email.trim().toLowerCase();
82
+ // Escaping bounds the database prefilter; Unicode regex folding can still
83
+ // widen it, so only exact normalized addresses may cross this boundary.
84
+ let query = client.from("clients")
85
+ .select("id, email, auth_user_id")
86
+ .filter("email", "imatch", `^${normalized.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&")}$`);
87
+ if (oldestFirst)
88
+ query = query.order("created_at", { ascending: true });
89
+ const { data, error } = await query.limit(10);
90
+ if (error)
91
+ throw error;
92
+ return (data ?? []).filter((row) => row.email?.trim().toLowerCase() === normalized);
93
+ }
@@ -0,0 +1,7 @@
1
+ import type { SupabaseCreateClient } from "../data/index.js";
2
+ import type { AdminAuthPort } from "./ports.js";
3
+ export declare function createSupabaseAdminAuth(rawClient: unknown): AdminAuthPort;
4
+ export declare function createSupabaseAdminAuthFromEnv(env: {
5
+ url: string;
6
+ anonKey: string;
7
+ }, accessToken: string | null, createClient: SupabaseCreateClient): AdminAuthPort;
@@ -0,0 +1,27 @@
1
+ import { authorizeAdminWithUser } from "./adminAuthorization.js";
2
+ export function createSupabaseAdminAuth(rawClient) {
3
+ const client = rawClient;
4
+ return {
5
+ async authorize(accessToken, options) {
6
+ const authz = await authorizeAdminWithUser(client, accessToken, options);
7
+ if (authz.ok === false) {
8
+ return { ok: false, code: authz.code, message: authz.message };
9
+ }
10
+ return {
11
+ ok: true,
12
+ principalId: authz.userId,
13
+ role: authz.role,
14
+ isMachineActor: authz.isMachineActor,
15
+ };
16
+ },
17
+ };
18
+ }
19
+ export function createSupabaseAdminAuthFromEnv(env, accessToken, createClient) {
20
+ const client = createClient(env.url, env.anonKey, {
21
+ auth: { persistSession: false, autoRefreshToken: false },
22
+ global: {
23
+ headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : {},
24
+ },
25
+ });
26
+ return createSupabaseAdminAuth(client);
27
+ }