@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.
- package/CHANGELOG.md +59 -0
- package/LICENSE +204 -0
- package/README.md +471 -1
- package/dist/bff/dispatch.d.ts +27 -0
- package/dist/bff/dispatch.js +47 -0
- package/dist/bff/envelope.d.ts +46 -0
- package/dist/bff/envelope.js +80 -0
- package/dist/bff/health.d.ts +24 -0
- package/dist/bff/health.js +19 -0
- package/dist/bff/index.d.ts +6 -0
- package/dist/bff/index.js +6 -0
- package/dist/bff/lazyRoute.d.ts +4 -0
- package/dist/bff/lazyRoute.js +13 -0
- package/dist/bff/requestContext.d.ts +17 -0
- package/dist/bff/requestContext.js +26 -0
- package/dist/bff/routerRewrite.d.ts +2 -0
- package/dist/bff/routerRewrite.js +31 -0
- package/dist/blob/binding.d.ts +16 -0
- package/dist/blob/binding.js +37 -0
- package/dist/blob/filesystem.d.ts +8 -0
- package/dist/blob/filesystem.js +71 -0
- package/dist/blob/index.d.ts +6 -0
- package/dist/blob/index.js +6 -0
- package/dist/blob/s3.d.ts +32 -0
- package/dist/blob/s3.js +56 -0
- package/dist/blob/s3Client.d.ts +25 -0
- package/dist/blob/s3Client.js +76 -0
- package/dist/blob/supabase.d.ts +40 -0
- package/dist/blob/supabase.js +59 -0
- package/dist/blob/vercel.d.ts +63 -0
- package/dist/blob/vercel.js +69 -0
- package/dist/composition/composeBundle.d.ts +47 -0
- package/dist/composition/composeBundle.js +45 -0
- package/dist/composition/httpBinding.d.ts +8 -0
- package/dist/composition/httpBinding.js +18 -0
- package/dist/composition/index.d.ts +3 -0
- package/dist/composition/index.js +3 -0
- package/dist/composition/nodeHost.d.ts +103 -0
- package/dist/composition/nodeHost.js +145 -0
- package/dist/data/binding.d.ts +34 -0
- package/dist/data/binding.js +92 -0
- package/dist/data/index.d.ts +5 -0
- package/dist/data/index.js +5 -0
- package/dist/data/postgresGateway.d.ts +42 -0
- package/dist/data/postgresGateway.js +135 -0
- package/dist/data/queryBuilder.d.ts +54 -0
- package/dist/data/queryBuilder.js +240 -0
- package/dist/data/queryBuilderSql.d.ts +76 -0
- package/dist/data/queryBuilderSql.js +145 -0
- package/dist/data/supabaseClientFactory.d.ts +34 -0
- package/dist/data/supabaseClientFactory.js +56 -0
- package/dist/data/supabaseGateway.d.ts +22 -0
- package/dist/data/supabaseGateway.js +49 -0
- package/dist/http/deadline.d.ts +20 -0
- package/dist/http/deadline.js +93 -0
- package/dist/http/index.d.ts +6 -0
- package/dist/http/index.js +5 -0
- package/dist/http/requestAdapter.d.ts +38 -0
- package/dist/http/requestAdapter.js +203 -0
- package/dist/http/runtime.d.ts +83 -0
- package/dist/http/runtime.js +199 -0
- package/dist/http/security.d.ts +44 -0
- package/dist/http/security.js +114 -0
- package/dist/http/staticAssets.d.ts +3 -0
- package/dist/http/staticAssets.js +42 -0
- package/dist/http/types.d.ts +23 -0
- package/dist/http/types.js +6 -0
- package/dist/identity/adminAuthBinding.d.ts +28 -0
- package/dist/identity/adminAuthBinding.js +66 -0
- package/dist/identity/adminAuthorization.d.ts +34 -0
- package/dist/identity/adminAuthorization.js +72 -0
- package/dist/identity/adminContracts.d.ts +70 -0
- package/dist/identity/adminContracts.js +43 -0
- package/dist/identity/adminMagicLinkHandler.d.ts +39 -0
- package/dist/identity/adminMagicLinkHandler.js +94 -0
- package/dist/identity/adminMeHandler.d.ts +15 -0
- package/dist/identity/adminMeHandler.js +49 -0
- package/dist/identity/adminPreflight.d.ts +16 -0
- package/dist/identity/adminPreflight.js +38 -0
- package/dist/identity/adminUserActionPorts.d.ts +31 -0
- package/dist/identity/adminUserActionPorts.js +51 -0
- package/dist/identity/adminUserHandlers.d.ts +38 -0
- package/dist/identity/adminUserHandlers.js +140 -0
- package/dist/identity/authVerifyUrl.d.ts +6 -0
- package/dist/identity/authVerifyUrl.js +54 -0
- package/dist/identity/contracts/contracts.d.ts +8 -0
- package/dist/identity/contracts/contracts.js +2 -0
- package/dist/identity/contracts/emailTrust.d.ts +3 -0
- package/dist/identity/contracts/emailTrust.js +4 -0
- package/dist/identity/contracts/index.d.ts +8 -0
- package/dist/identity/contracts/index.js +8 -0
- package/dist/identity/contracts/oidc.d.ts +3 -0
- package/dist/identity/contracts/oidc.js +9 -0
- package/dist/identity/contracts/operatorAuth.d.ts +35 -0
- package/dist/identity/contracts/operatorAuth.js +53 -0
- package/dist/identity/contracts/operatorInvitations.d.ts +37 -0
- package/dist/identity/contracts/operatorInvitations.js +1 -0
- package/dist/identity/contracts/ports.d.ts +22 -0
- package/dist/identity/contracts/ports.js +1 -0
- package/dist/identity/contracts/privacy.d.ts +62 -0
- package/dist/identity/contracts/privacy.js +99 -0
- package/dist/identity/contracts/providerList.d.ts +3 -0
- package/dist/identity/contracts/providerList.js +11 -0
- package/dist/identity/contracts/types.d.ts +16 -0
- package/dist/identity/contracts/types.js +4 -0
- package/dist/identity/contribution.d.ts +8 -0
- package/dist/identity/contribution.js +22 -0
- package/dist/identity/customerAuth.d.ts +8 -0
- package/dist/identity/customerAuth.js +1 -0
- package/dist/identity/customerAuthorization.d.ts +5 -0
- package/dist/identity/customerAuthorization.js +22 -0
- package/dist/identity/customerContracts.d.ts +42 -0
- package/dist/identity/customerContracts.js +43 -0
- package/dist/identity/customerIdentityBinding.d.ts +44 -0
- package/dist/identity/customerIdentityBinding.js +60 -0
- package/dist/identity/customerIdentityVerifier.d.ts +8 -0
- package/dist/identity/customerIdentityVerifier.js +101 -0
- package/dist/identity/customerMagicLinkHandler.d.ts +38 -0
- package/dist/identity/customerMagicLinkHandler.js +115 -0
- package/dist/identity/customerMeHandler.d.ts +11 -0
- package/dist/identity/customerMeHandler.js +46 -0
- package/dist/identity/customerPorts.d.ts +4 -0
- package/dist/identity/customerPorts.js +1 -0
- package/dist/identity/customerSessionBinding.d.ts +38 -0
- package/dist/identity/customerSessionBinding.js +80 -0
- package/dist/identity/customerSessionIssuer.d.ts +10 -0
- package/dist/identity/customerSessionIssuer.js +57 -0
- package/dist/identity/customerVerifyOtpHandler.d.ts +8 -0
- package/dist/identity/customerVerifyOtpHandler.js +41 -0
- package/dist/identity/directOperatorInvitationStore.d.ts +19 -0
- package/dist/identity/directOperatorInvitationStore.js +193 -0
- package/dist/identity/emailTrustPolicy.d.ts +14 -0
- package/dist/identity/emailTrustPolicy.js +16 -0
- package/dist/identity/identityPersonalDataContributor.d.ts +7 -0
- package/dist/identity/identityPersonalDataContributor.js +46 -0
- package/dist/identity/identityReadiness.d.ts +10 -0
- package/dist/identity/identityReadiness.js +25 -0
- package/dist/identity/index.d.ts +67 -0
- package/dist/identity/index.js +66 -0
- package/dist/identity/inviteAdminUserUseCase.d.ts +89 -0
- package/dist/identity/inviteAdminUserUseCase.js +75 -0
- package/dist/identity/jwtLibrary.d.ts +54 -0
- package/dist/identity/jwtLibrary.js +1 -0
- package/dist/identity/machineActorWriteFence.d.ts +4 -0
- package/dist/identity/machineActorWriteFence.js +13 -0
- package/dist/identity/magicLinkPorts.d.ts +28 -0
- package/dist/identity/magicLinkPorts.js +1 -0
- package/dist/identity/managedAccountLinkStore.d.ts +2 -0
- package/dist/identity/managedAccountLinkStore.js +93 -0
- package/dist/identity/managedAdminAuthVerifier.d.ts +7 -0
- package/dist/identity/managedAdminAuthVerifier.js +27 -0
- package/dist/identity/managedAdminUserGateways.d.ts +123 -0
- package/dist/identity/managedAdminUserGateways.js +127 -0
- package/dist/identity/managedClient.d.ts +90 -0
- package/dist/identity/managedClient.js +10 -0
- package/dist/identity/managedClientAuthLink.d.ts +3 -0
- package/dist/identity/managedClientAuthLink.js +115 -0
- package/dist/identity/managedCustomerMe.d.ts +13 -0
- package/dist/identity/managedCustomerMe.js +30 -0
- package/dist/identity/managedEmailTrustPolicy.d.ts +11 -0
- package/dist/identity/managedEmailTrustPolicy.js +105 -0
- package/dist/identity/managedIdentityVerifier.d.ts +2 -0
- package/dist/identity/managedIdentityVerifier.js +16 -0
- package/dist/identity/managedPrivacy.d.ts +4 -0
- package/dist/identity/managedPrivacy.js +39 -0
- package/dist/identity/messages.d.ts +29 -0
- package/dist/identity/messages.js +39 -0
- package/dist/identity/oidcIdentityVerifier.d.ts +45 -0
- package/dist/identity/oidcIdentityVerifier.js +309 -0
- package/dist/identity/oidcPrincipal.d.ts +2 -0
- package/dist/identity/oidcPrincipal.js +10 -0
- package/dist/identity/operatorAdminAuth.d.ts +6 -0
- package/dist/identity/operatorAdminAuth.js +13 -0
- package/dist/identity/operatorAuthHandlers.d.ts +18 -0
- package/dist/identity/operatorAuthHandlers.js +71 -0
- package/dist/identity/operatorIdentityVerifier.d.ts +8 -0
- package/dist/identity/operatorIdentityVerifier.js +19 -0
- package/dist/identity/operatorInvitationLifecycle.d.ts +7 -0
- package/dist/identity/operatorInvitationLifecycle.js +15 -0
- package/dist/identity/operatorInvitationPorts.d.ts +31 -0
- package/dist/identity/operatorInvitationPorts.js +1 -0
- package/dist/identity/operatorPorts.d.ts +37 -0
- package/dist/identity/operatorPorts.js +1 -0
- package/dist/identity/operatorSession.d.ts +13 -0
- package/dist/identity/operatorSession.js +31 -0
- package/dist/identity/operatorTokenAdminAuth.d.ts +15 -0
- package/dist/identity/operatorTokenAdminAuth.js +50 -0
- package/dist/identity/personalDataRegistry.d.ts +4 -0
- package/dist/identity/personalDataRegistry.js +11 -0
- package/dist/identity/platformAdminAuth.d.ts +15 -0
- package/dist/identity/platformAdminAuth.js +1 -0
- package/dist/identity/ports.d.ts +127 -0
- package/dist/identity/ports.js +38 -0
- package/dist/identity/postgresAccountLinkStore.d.ts +7 -0
- package/dist/identity/postgresAccountLinkStore.js +52 -0
- package/dist/identity/postgresCustomerMe.d.ts +3 -0
- package/dist/identity/postgresCustomerMe.js +21 -0
- package/dist/identity/postgresCustomerRecovery.d.ts +11 -0
- package/dist/identity/postgresCustomerRecovery.js +57 -0
- package/dist/identity/postgresOperatorIdentity.d.ts +5 -0
- package/dist/identity/postgresOperatorIdentity.js +137 -0
- package/dist/identity/postgresPrivacy.d.ts +7 -0
- package/dist/identity/postgresPrivacy.js +126 -0
- package/dist/identity/privacyHandlers.d.ts +10 -0
- package/dist/identity/privacyHandlers.js +35 -0
- package/dist/identity/privacyPorts.d.ts +72 -0
- package/dist/identity/privacyPorts.js +8 -0
- package/dist/identity/privacyUseCases.d.ts +5 -0
- package/dist/identity/privacyUseCases.js +55 -0
- package/dist/identity/reconcileAccountForPrincipal.d.ts +20 -0
- package/dist/identity/reconcileAccountForPrincipal.js +66 -0
- package/dist/identity/reconcileAccountHandler.d.ts +11 -0
- package/dist/identity/reconcileAccountHandler.js +30 -0
- package/dist/identity/removeAdminUserUseCase.d.ts +31 -0
- package/dist/identity/removeAdminUserUseCase.js +60 -0
- package/dist/identity/response.d.ts +3 -0
- package/dist/identity/response.js +2 -0
- package/dist/identity/sql.d.ts +44 -0
- package/dist/identity/sql.js +10 -0
- package/dist/job-ledger/index.d.ts +5 -0
- package/dist/job-ledger/index.js +3 -0
- package/dist/job-ledger/ports.d.ts +10 -0
- package/dist/job-ledger/ports.js +7 -0
- package/dist/job-ledger/postgres.d.ts +10 -0
- package/dist/job-ledger/postgres.js +101 -0
- package/dist/job-ledger/sql.d.ts +7 -0
- package/dist/job-ledger/sql.js +10 -0
- package/dist/job-ledger/supabase.d.ts +77 -0
- package/dist/job-ledger/supabase.js +202 -0
- package/dist/kernel/index.d.ts +1 -0
- package/dist/kernel/index.js +1 -0
- package/dist/kernel/platformKernel.d.ts +34 -0
- package/dist/kernel/platformKernel.js +115 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.js +1 -0
- package/dist/migrations/postgresRunner.d.ts +50 -0
- package/dist/migrations/postgresRunner.js +176 -0
- package/dist/scheduler/advisoryLock.d.ts +44 -0
- package/dist/scheduler/advisoryLock.js +114 -0
- package/dist/scheduler/cronGuard.d.ts +10 -0
- package/dist/scheduler/cronGuard.js +19 -0
- package/dist/scheduler/cronSecret.d.ts +5 -0
- package/dist/scheduler/cronSecret.js +23 -0
- package/dist/scheduler/handlers.d.ts +9 -0
- package/dist/scheduler/handlers.js +10 -0
- package/dist/scheduler/httpEntry.d.ts +16 -0
- package/dist/scheduler/httpEntry.js +31 -0
- package/dist/scheduler/index.d.ts +9 -0
- package/dist/scheduler/index.js +9 -0
- package/dist/scheduler/jobRegistry.d.ts +21 -0
- package/dist/scheduler/jobRegistry.js +39 -0
- package/dist/scheduler/jobs.d.ts +48 -0
- package/dist/scheduler/jobs.js +92 -0
- package/dist/scheduler/nodeScheduler.d.ts +42 -0
- package/dist/scheduler/nodeScheduler.js +73 -0
- package/dist/scheduler/vercelScheduler.d.ts +29 -0
- package/dist/scheduler/vercelScheduler.js +51 -0
- package/package.json +116 -3
- package/release-gates.json +143 -0
- package/sql/20260809150000_job_run_ledger.sql +301 -0
- package/sql/20260809150001_job_run_ledger_v3.sql +70 -0
- package/sql/20260810180001_self_host_actor_auth.sql +40 -0
- package/sql/20260810204057_customer_identity_read.sql +31 -0
- package/sql/20260814090000_customer_selfservice_recovery.sql +477 -0
- package/sql/20260901143000_admin_membership_authority_foundation.sql +234 -0
- package/sql/20261018120000_identity_operator_invitations.sql +42 -0
- package/sql/20261018180000_identity_operator_challenges.sql +56 -0
- package/sql/20261018190000_identity_privacy_erasures.sql +15 -0
- package/src/bff/dispatch.ts +81 -0
- package/src/bff/envelope.ts +142 -0
- package/src/bff/health.ts +37 -0
- package/src/bff/index.ts +30 -0
- package/src/bff/lazyRoute.ts +28 -0
- package/src/bff/requestContext.ts +48 -0
- package/src/bff/routerRewrite.ts +38 -0
- package/src/blob/binding.ts +55 -0
- package/src/blob/filesystem.ts +86 -0
- package/src/blob/index.ts +17 -0
- package/src/blob/s3.ts +87 -0
- package/src/blob/s3Client.ts +91 -0
- package/src/blob/supabase.ts +88 -0
- package/src/blob/vercel.ts +127 -0
- package/src/composition/composeBundle.ts +109 -0
- package/src/composition/httpBinding.ts +30 -0
- package/src/composition/index.ts +17 -0
- package/src/composition/nodeHost.ts +289 -0
- package/src/data/binding.ts +157 -0
- package/src/data/index.ts +33 -0
- package/src/data/postgresGateway.ts +186 -0
- package/src/data/queryBuilder.ts +300 -0
- package/src/data/queryBuilderSql.ts +183 -0
- package/src/data/supabaseClientFactory.ts +92 -0
- package/src/data/supabaseGateway.ts +76 -0
- package/src/http/deadline.ts +117 -0
- package/src/http/index.ts +36 -0
- package/src/http/requestAdapter.ts +215 -0
- package/src/http/runtime.ts +319 -0
- package/src/http/security.ts +155 -0
- package/src/http/staticAssets.ts +42 -0
- package/src/http/types.ts +31 -0
- package/src/identity/adminAuthBinding.ts +76 -0
- package/src/identity/adminAuthorization.ts +106 -0
- package/src/identity/adminContracts.ts +52 -0
- package/src/identity/adminMagicLinkHandler.ts +132 -0
- package/src/identity/adminMeHandler.ts +64 -0
- package/src/identity/adminPreflight.ts +46 -0
- package/src/identity/adminUserActionPorts.ts +78 -0
- package/src/identity/adminUserHandlers.ts +174 -0
- package/src/identity/authVerifyUrl.ts +56 -0
- package/src/identity/contracts/contracts.ts +15 -0
- package/src/identity/contracts/emailTrust.ts +5 -0
- package/src/identity/contracts/index.ts +8 -0
- package/src/identity/contracts/oidc.ts +10 -0
- package/src/identity/contracts/operatorAuth.ts +61 -0
- package/src/identity/contracts/operatorInvitations.ts +32 -0
- package/src/identity/contracts/ports.ts +25 -0
- package/src/identity/contracts/privacy.ts +86 -0
- package/src/identity/contracts/providerList.ts +13 -0
- package/src/identity/contracts/types.ts +25 -0
- package/src/identity/contribution.ts +29 -0
- package/src/identity/customerAuth.ts +3 -0
- package/src/identity/customerAuthorization.ts +38 -0
- package/src/identity/customerContracts.ts +52 -0
- package/src/identity/customerIdentityBinding.ts +125 -0
- package/src/identity/customerIdentityVerifier.ts +141 -0
- package/src/identity/customerMagicLinkHandler.ts +171 -0
- package/src/identity/customerMeHandler.ts +64 -0
- package/src/identity/customerPorts.ts +2 -0
- package/src/identity/customerSessionBinding.ts +114 -0
- package/src/identity/customerSessionIssuer.ts +71 -0
- package/src/identity/customerVerifyOtpHandler.ts +44 -0
- package/src/identity/directOperatorInvitationStore.ts +178 -0
- package/src/identity/emailTrustPolicy.ts +16 -0
- package/src/identity/identityPersonalDataContributor.ts +48 -0
- package/src/identity/identityReadiness.ts +26 -0
- package/src/identity/index.ts +69 -0
- package/src/identity/inviteAdminUserUseCase.ts +134 -0
- package/src/identity/jwtLibrary.ts +24 -0
- package/src/identity/machineActorWriteFence.ts +19 -0
- package/src/identity/magicLinkPorts.ts +7 -0
- package/src/identity/managedAccountLinkStore.ts +105 -0
- package/src/identity/managedAdminAuthVerifier.ts +40 -0
- package/src/identity/managedAdminUserGateways.ts +164 -0
- package/src/identity/managedClient.ts +58 -0
- package/src/identity/managedClientAuthLink.ts +120 -0
- package/src/identity/managedCustomerMe.ts +52 -0
- package/src/identity/managedEmailTrustPolicy.ts +90 -0
- package/src/identity/managedIdentityVerifier.ts +20 -0
- package/src/identity/managedPrivacy.ts +37 -0
- package/src/identity/messages.ts +41 -0
- package/src/identity/oidcIdentityVerifier.ts +229 -0
- package/src/identity/oidcPrincipal.ts +10 -0
- package/src/identity/operatorAdminAuth.ts +14 -0
- package/src/identity/operatorAuthHandlers.ts +52 -0
- package/src/identity/operatorIdentityVerifier.ts +19 -0
- package/src/identity/operatorInvitationLifecycle.ts +14 -0
- package/src/identity/operatorInvitationPorts.ts +11 -0
- package/src/identity/operatorPorts.ts +11 -0
- package/src/identity/operatorSession.ts +30 -0
- package/src/identity/operatorTokenAdminAuth.ts +79 -0
- package/src/identity/personalDataRegistry.ts +8 -0
- package/src/identity/platformAdminAuth.ts +7 -0
- package/src/identity/ports.ts +158 -0
- package/src/identity/postgresAccountLinkStore.ts +49 -0
- package/src/identity/postgresCustomerMe.ts +33 -0
- package/src/identity/postgresCustomerRecovery.ts +72 -0
- package/src/identity/postgresOperatorIdentity.ts +123 -0
- package/src/identity/postgresPrivacy.ts +117 -0
- package/src/identity/privacyHandlers.ts +33 -0
- package/src/identity/privacyPorts.ts +52 -0
- package/src/identity/privacyUseCases.ts +48 -0
- package/src/identity/reconcileAccountForPrincipal.ts +99 -0
- package/src/identity/reconcileAccountHandler.ts +36 -0
- package/src/identity/removeAdminUserUseCase.ts +85 -0
- package/src/identity/response.ts +3 -0
- package/src/identity/sql.ts +10 -0
- package/src/job-ledger/index.ts +25 -0
- package/src/job-ledger/ports.ts +27 -0
- package/src/job-ledger/postgres.ts +121 -0
- package/src/job-ledger/sql.ts +12 -0
- package/src/job-ledger/supabase.ts +294 -0
- package/src/kernel/index.ts +17 -0
- package/src/kernel/platformKernel.ts +153 -0
- package/src/migrations/index.ts +10 -0
- package/src/migrations/postgresRunner.ts +255 -0
- package/src/scheduler/advisoryLock.ts +145 -0
- package/src/scheduler/cronGuard.ts +30 -0
- package/src/scheduler/cronSecret.ts +26 -0
- package/src/scheduler/handlers.ts +24 -0
- package/src/scheduler/httpEntry.ts +49 -0
- package/src/scheduler/index.ts +47 -0
- package/src/scheduler/jobRegistry.ts +57 -0
- package/src/scheduler/jobs.ts +119 -0
- package/src/scheduler/nodeScheduler.ts +123 -0
- package/src/scheduler/vercelScheduler.ts +71 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 5,
|
|
3
|
+
"kind": "rail",
|
|
4
|
+
"compatibilityPolicies": {
|
|
5
|
+
"internal-candidate": "Development-preview API; no stable compatibility claim."
|
|
6
|
+
},
|
|
7
|
+
"packageSurface": {
|
|
8
|
+
"./http": {
|
|
9
|
+
"role": "rail",
|
|
10
|
+
"maturity": "experimental",
|
|
11
|
+
"compatibilityPolicy": "internal-candidate",
|
|
12
|
+
"packageSmokeEvidence": [
|
|
13
|
+
"test/packageBoundary.test.ts",
|
|
14
|
+
"test/http/runtime.test.ts"
|
|
15
|
+
],
|
|
16
|
+
"entrypoint": "dist/http/index.d.ts",
|
|
17
|
+
"snapshot": "api/http.api.md"
|
|
18
|
+
},
|
|
19
|
+
"./bff": {
|
|
20
|
+
"role": "rail",
|
|
21
|
+
"maturity": "experimental",
|
|
22
|
+
"compatibilityPolicy": "internal-candidate",
|
|
23
|
+
"packageSmokeEvidence": [
|
|
24
|
+
"test/packageBoundary.test.ts",
|
|
25
|
+
"test/bff/dispatch.test.ts"
|
|
26
|
+
],
|
|
27
|
+
"entrypoint": "dist/bff/index.d.ts",
|
|
28
|
+
"snapshot": "api/bff.api.md"
|
|
29
|
+
},
|
|
30
|
+
"./scheduler": {
|
|
31
|
+
"role": "rail",
|
|
32
|
+
"maturity": "experimental",
|
|
33
|
+
"compatibilityPolicy": "internal-candidate",
|
|
34
|
+
"packageSmokeEvidence": [
|
|
35
|
+
"test/packageBoundary.test.ts",
|
|
36
|
+
"test/scheduler/jobs.test.ts"
|
|
37
|
+
],
|
|
38
|
+
"entrypoint": "dist/scheduler/index.d.ts",
|
|
39
|
+
"snapshot": "api/scheduler.api.md"
|
|
40
|
+
},
|
|
41
|
+
"./blob": {
|
|
42
|
+
"role": "rail",
|
|
43
|
+
"maturity": "experimental",
|
|
44
|
+
"compatibilityPolicy": "internal-candidate",
|
|
45
|
+
"packageSmokeEvidence": [
|
|
46
|
+
"test/packageBoundary.test.ts",
|
|
47
|
+
"test/blob/binding.test.ts"
|
|
48
|
+
],
|
|
49
|
+
"entrypoint": "dist/blob/index.d.ts",
|
|
50
|
+
"snapshot": "api/blob.api.md"
|
|
51
|
+
},
|
|
52
|
+
"./data": {
|
|
53
|
+
"role": "rail",
|
|
54
|
+
"maturity": "experimental",
|
|
55
|
+
"compatibilityPolicy": "internal-candidate",
|
|
56
|
+
"packageSmokeEvidence": [
|
|
57
|
+
"test/packageBoundary.test.ts",
|
|
58
|
+
"test/data/binding.test.ts"
|
|
59
|
+
],
|
|
60
|
+
"entrypoint": "dist/data/index.d.ts",
|
|
61
|
+
"snapshot": "api/data.api.md"
|
|
62
|
+
},
|
|
63
|
+
"./migrations": {
|
|
64
|
+
"role": "rail",
|
|
65
|
+
"maturity": "experimental",
|
|
66
|
+
"compatibilityPolicy": "internal-candidate",
|
|
67
|
+
"packageSmokeEvidence": [
|
|
68
|
+
"test/packageBoundary.test.ts",
|
|
69
|
+
"test/migrations/postgresRunner.test.ts"
|
|
70
|
+
],
|
|
71
|
+
"entrypoint": "dist/migrations/index.d.ts",
|
|
72
|
+
"snapshot": "api/migrations.api.md"
|
|
73
|
+
},
|
|
74
|
+
"./job-ledger": {
|
|
75
|
+
"role": "rail",
|
|
76
|
+
"maturity": "experimental",
|
|
77
|
+
"compatibilityPolicy": "internal-candidate",
|
|
78
|
+
"packageSmokeEvidence": [
|
|
79
|
+
"test/packageBoundary.test.ts",
|
|
80
|
+
"test/job-ledger/postgres.test.ts"
|
|
81
|
+
],
|
|
82
|
+
"entrypoint": "dist/job-ledger/index.d.ts",
|
|
83
|
+
"snapshot": "api/job-ledger.api.md"
|
|
84
|
+
},
|
|
85
|
+
"./kernel": {
|
|
86
|
+
"role": "rail",
|
|
87
|
+
"maturity": "experimental",
|
|
88
|
+
"compatibilityPolicy": "internal-candidate",
|
|
89
|
+
"packageSmokeEvidence": [
|
|
90
|
+
"test/packageBoundary.test.ts",
|
|
91
|
+
"test/kernel/platformKernel.test.ts"
|
|
92
|
+
],
|
|
93
|
+
"entrypoint": "dist/kernel/index.d.ts",
|
|
94
|
+
"snapshot": "api/kernel.api.md"
|
|
95
|
+
},
|
|
96
|
+
"./composition": {
|
|
97
|
+
"role": "rail",
|
|
98
|
+
"maturity": "experimental",
|
|
99
|
+
"compatibilityPolicy": "internal-candidate",
|
|
100
|
+
"packageSmokeEvidence": [
|
|
101
|
+
"test/packageBoundary.test.ts",
|
|
102
|
+
"test/composition/composeBundle.test.ts"
|
|
103
|
+
],
|
|
104
|
+
"entrypoint": "dist/composition/index.d.ts",
|
|
105
|
+
"snapshot": "api/composition.api.md"
|
|
106
|
+
},
|
|
107
|
+
"./identity": {
|
|
108
|
+
"role": "capability",
|
|
109
|
+
"maturity": "experimental",
|
|
110
|
+
"compatibilityPolicy": "internal-candidate",
|
|
111
|
+
"packageSmokeEvidence": [
|
|
112
|
+
"test/packageBoundary.test.ts",
|
|
113
|
+
"test/identity/adminConformance.test.ts"
|
|
114
|
+
],
|
|
115
|
+
"entrypoint": "dist/identity/index.d.ts",
|
|
116
|
+
"snapshot": "api/identity.api.md"
|
|
117
|
+
},
|
|
118
|
+
"./identity/contracts": {
|
|
119
|
+
"role": "capability",
|
|
120
|
+
"maturity": "experimental",
|
|
121
|
+
"compatibilityPolicy": "internal-candidate",
|
|
122
|
+
"packageSmokeEvidence": [
|
|
123
|
+
"test/packageBoundary.test.ts",
|
|
124
|
+
"test/identity/contracts.test.ts"
|
|
125
|
+
],
|
|
126
|
+
"entrypoint": "dist/identity/contracts/index.d.ts",
|
|
127
|
+
"snapshot": "api/identity-contracts.api.md"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"pack": {
|
|
131
|
+
"code": {
|
|
132
|
+
"maxPackedBytes": 131072,
|
|
133
|
+
"maxFiles": 240
|
|
134
|
+
},
|
|
135
|
+
"docs": {
|
|
136
|
+
"maxPackedBytes": 16384,
|
|
137
|
+
"maxFiles": 12
|
|
138
|
+
},
|
|
139
|
+
"maxPackedBytes": 196608,
|
|
140
|
+
"maxUnpackedBytes": 1048576,
|
|
141
|
+
"maxFiles": 256
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
-- Public platform job-run ledger: the two relations a scheduled job needs to be
|
|
2
|
+
-- mutually exclusive across runners, and the two verbs its runtime actually calls.
|
|
3
|
+
--
|
|
4
|
+
-- WHAT THIS FORWARD SHIPS, AND WHY IT IS TWO VERBS AND NOT THREE. The second bundle
|
|
5
|
+
-- already has reads, a queue, a customer mutation, an operator mutation and a shipment
|
|
6
|
+
-- machine. What it has never had is the thing that lets a *scheduled* job run at all:
|
|
7
|
+
-- somewhere to say "this attempt is mine, nobody else start", and somewhere to say
|
|
8
|
+
-- "it is finished, and this is what it did". The consumer of this ledger asks for
|
|
9
|
+
-- exactly those two things -- a claim and a finish -- and for nothing else. There is
|
|
10
|
+
-- no heartbeat, no renew and no extend anywhere in the runtime that drives it, so
|
|
11
|
+
-- there is none here: a lease is issued once, and it is released by finishing or by
|
|
12
|
+
-- expiring. A failure is a finish with status 'failed', not a separate verb.
|
|
13
|
+
--
|
|
14
|
+
-- EXCLUSIVITY IS THE CONTROL ROW, NOT AN ADVISORY LOCK. The claim upserts the job's
|
|
15
|
+
-- control row and then takes `FOR UPDATE` on it. A second claimer arriving in the same
|
|
16
|
+
-- instant blocks on that row rather than racing past it, and once the first claimer
|
|
17
|
+
-- commits it reads a live lease and is refused. This is deliberate and it is the
|
|
18
|
+
-- property the harness proves with two concurrent connections. An advisory lock would
|
|
19
|
+
-- be a different machine: it is not carried by the row, so it would vanish with the
|
|
20
|
+
-- session and leave the ledger claiming a run that nobody holds. The lease, in
|
|
21
|
+
-- contrast, outlives the connection and is what makes a crashed runner recoverable --
|
|
22
|
+
-- after the lease elapses, and not before.
|
|
23
|
+
--
|
|
24
|
+
-- WHAT A FINISH IS ALLOWED TO DO. A finish always stamps its own run row, because a
|
|
25
|
+
-- runner that lost its lease still owes the ledger the truth about what it did. It
|
|
26
|
+
-- releases the *job* only when the control row still carries its own token. So a
|
|
27
|
+
-- zombie -- a runner whose lease expired and whose job was re-claimed by somebody else
|
|
28
|
+
-- -- writes its own epitaph and returns false, and cannot clear a lease it no longer
|
|
29
|
+
-- holds. That returned boolean is the fencing signal, and the harness asserts it.
|
|
30
|
+
--
|
|
31
|
+
-- WHERE THE SEMANTICS COME FROM, AND EVERY PLACE THIS KERNEL DEPARTS FROM THEM. The
|
|
32
|
+
-- behaviour above is derived from the managed chain's own claim/finish pair, read in
|
|
33
|
+
-- full rather than summarised: its two relations and its first begin/finish, the later
|
|
34
|
+
-- migration that added the second finish and the driver/lease/counter columns, the
|
|
35
|
+
-- migration that rewrote the claim into its current 199-line body, and the migration
|
|
36
|
+
-- that introduced a neutral trigger vocabulary. Five departures, each named because a
|
|
37
|
+
-- silent one is how a kernel and its origin quietly stop being the same machine:
|
|
38
|
+
--
|
|
39
|
+
-- 1. THE RUNNER VOCABULARY IS NEUTRAL: 'worker', 'scheduler', 'operator'. The chain's
|
|
40
|
+
-- set enumerates two named cron mechanisms, one of which is the scheduler of a
|
|
41
|
+
-- specific hosting vendor. Which scheduler a deployment happens to run is a fact
|
|
42
|
+
-- about that deployment, never a fact about a platform, and this kernel may not
|
|
43
|
+
-- carry a vendor's name in a CHECK constraint. The vocabulary chosen is not
|
|
44
|
+
-- invented here either: it is the one the chain's own newest control-plane
|
|
45
|
+
-- migration introduced, in its words, so that a deployment adapter is EVIDENCE
|
|
46
|
+
-- rather than an authorization decision. The concrete adapter label survives
|
|
47
|
+
-- losslessly in `p_metadata`, which is caller-supplied jsonb this kernel stores
|
|
48
|
+
-- and never interprets.
|
|
49
|
+
-- 2. THE FIRST CLAIMER DEFINES THE JOB'S ACTIVE RUNNER. Upstream the control row is
|
|
50
|
+
-- created with a fixed default runner, so on a fresh install the first tick of a
|
|
51
|
+
-- long-running worker is refused as the wrong runner until an operator edits a
|
|
52
|
+
-- row by hand. That is a migration artefact of a live cutover, not a platform
|
|
53
|
+
-- rule. Here the auto-created row adopts the runner that created it; changing
|
|
54
|
+
-- runners afterwards stays an explicit operator UPDATE, and the refusal below
|
|
55
|
+
-- still protects a job whose runner has been pinned.
|
|
56
|
+
-- 3. ONE LEASE COLUMN AND ONE COUNTER PAIR. Upstream carries `lease_until` and
|
|
57
|
+
-- `lease_expires_at` for one lease, and `checked`/`checked_count`,
|
|
58
|
+
-- `updated`/`updated_count` for one pair of counts, writing both of each on every
|
|
59
|
+
-- call. Those are compatibility shadows of an earlier signature. This kernel has
|
|
60
|
+
-- no earlier signature, so it ships one of each. For the same reason the run row
|
|
61
|
+
-- records its runner once, where upstream writes the same value into three
|
|
62
|
+
-- columns.
|
|
63
|
+
-- 4. NO `SECURITY DEFINER`, NO `GRANT`/`REVOKE`, NO ROW-LEVEL SECURITY, matching
|
|
64
|
+
-- every forward this catalogue already carries. This kernel creates zero roles.
|
|
65
|
+
-- Said out loud rather than assumed: ON THIS KERNEL THE FUNCTIONS BELOW ARE NOT A
|
|
66
|
+
-- SECURITY BOUNDARY -- the host application is what authenticates, and a caller
|
|
67
|
+
-- that can reach these functions can already reach the tables. `SET search_path`
|
|
68
|
+
-- is kept, because that one is a correctness property and not a role property.
|
|
69
|
+
-- 5. THE FINISH KEEPS ITS `_v2` SUFFIX. There is no v1 in this kernel and the suffix
|
|
70
|
+
-- describes the version history of a different codebase. It is kept anyway: it is
|
|
71
|
+
-- the name the shipped consumer calls, and giving a public kernel a second,
|
|
72
|
+
-- prettier name for one verb would be worse than carrying one inherited one.
|
|
73
|
+
--
|
|
74
|
+
-- WHAT THIS FORWARD DELIBERATELY DOES NOT SHIP, enumerated so nobody has to infer it:
|
|
75
|
+
-- * no runtime binding. Not one line of the application runtime is rewired onto this
|
|
76
|
+
-- ledger by this forward; the files that would do it belong to another line of work
|
|
77
|
+
-- in flight, and the falsifier for this kernel is its own parity harness driving
|
|
78
|
+
-- the shipped port's two calls;
|
|
79
|
+
-- * no job seed. A job NAME is a deployment fact, so this kernel names none. The
|
|
80
|
+
-- claim creates the control row it needs on first contact;
|
|
81
|
+
-- * no lease extension and no reaper. Neither exists upstream either. A lease that
|
|
82
|
+
-- elapses is simply claimable again, and a job that must not be re-entered before
|
|
83
|
+
-- its own work finishes must ask for a lease long enough to cover it;
|
|
84
|
+
-- * no attempt counter and no poison-pill policy. Upstream has none on this ledger,
|
|
85
|
+
-- and inventing one here would be a policy this kernel has no way to falsify;
|
|
86
|
+
-- * no scheduling. WHEN a job runs is the host's problem. This ledger only answers
|
|
87
|
+
-- whether an attempt that has already begun is allowed to proceed.
|
|
88
|
+
|
|
89
|
+
CREATE TABLE IF NOT EXISTS public.platform_job_controls (
|
|
90
|
+
job_name text PRIMARY KEY,
|
|
91
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
92
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
93
|
+
enabled boolean NOT NULL DEFAULT true,
|
|
94
|
+
active_driver text NOT NULL
|
|
95
|
+
CHECK (active_driver IN ('worker', 'scheduler', 'operator')),
|
|
96
|
+
lease_owner text,
|
|
97
|
+
lease_token uuid,
|
|
98
|
+
lease_until timestamptz,
|
|
99
|
+
last_started_at timestamptz,
|
|
100
|
+
last_finished_at timestamptz,
|
|
101
|
+
last_success_at timestamptz,
|
|
102
|
+
last_status text
|
|
103
|
+
CHECK (last_status IS NULL OR last_status IN ('running', 'success', 'failed', 'skipped')),
|
|
104
|
+
last_run_id uuid,
|
|
105
|
+
metadata jsonb NOT NULL DEFAULT '{}'::jsonb
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
CREATE TABLE IF NOT EXISTS public.platform_job_runs (
|
|
109
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
110
|
+
job_name text NOT NULL REFERENCES public.platform_job_controls(job_name),
|
|
111
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
112
|
+
started_at timestamptz NOT NULL DEFAULT now(),
|
|
113
|
+
finished_at timestamptz,
|
|
114
|
+
status text NOT NULL DEFAULT 'running'
|
|
115
|
+
CHECK (status IN ('running', 'success', 'failed', 'skipped')),
|
|
116
|
+
driver text NOT NULL
|
|
117
|
+
CHECK (driver IN ('worker', 'scheduler', 'operator')),
|
|
118
|
+
lease_until timestamptz,
|
|
119
|
+
checked integer CHECK (checked IS NULL OR checked >= 0),
|
|
120
|
+
updated integer CHECK (updated IS NULL OR updated >= 0),
|
|
121
|
+
error text,
|
|
122
|
+
support_code text,
|
|
123
|
+
metadata jsonb NOT NULL DEFAULT '{}'::jsonb
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
CREATE INDEX IF NOT EXISTS idx_platform_job_runs_job_started
|
|
127
|
+
ON public.platform_job_runs (job_name, started_at DESC);
|
|
128
|
+
|
|
129
|
+
CREATE INDEX IF NOT EXISTS idx_platform_job_runs_status_started
|
|
130
|
+
ON public.platform_job_runs (status, started_at DESC);
|
|
131
|
+
|
|
132
|
+
COMMENT ON TABLE public.platform_job_controls IS
|
|
133
|
+
'One row per scheduled job: whether it may run, which runner class owns it, and the live lease.';
|
|
134
|
+
COMMENT ON TABLE public.platform_job_runs IS
|
|
135
|
+
'Append-only attempt ledger. A refused attempt is recorded as a skipped run, so a job that never runs is visible.';
|
|
136
|
+
COMMENT ON COLUMN public.platform_job_runs.driver IS
|
|
137
|
+
'Neutral runner class of the attempt. The concrete adapter, if any, lives in metadata as evidence.';
|
|
138
|
+
|
|
139
|
+
CREATE OR REPLACE FUNCTION public.platform_claim_job_run(
|
|
140
|
+
p_job_name text,
|
|
141
|
+
p_driver text,
|
|
142
|
+
p_lease_seconds integer DEFAULT 900,
|
|
143
|
+
p_metadata jsonb DEFAULT '{}'::jsonb
|
|
144
|
+
)
|
|
145
|
+
RETURNS TABLE (
|
|
146
|
+
acquired boolean,
|
|
147
|
+
run_id uuid,
|
|
148
|
+
reason text,
|
|
149
|
+
lease_until timestamptz
|
|
150
|
+
)
|
|
151
|
+
LANGUAGE plpgsql
|
|
152
|
+
SET search_path = public, pg_catalog
|
|
153
|
+
AS $$
|
|
154
|
+
DECLARE
|
|
155
|
+
v_control public.platform_job_controls%ROWTYPE;
|
|
156
|
+
v_job_name text := btrim(COALESCE(p_job_name, ''));
|
|
157
|
+
v_driver text := COALESCE(NULLIF(btrim(p_driver), ''), 'worker');
|
|
158
|
+
v_lease_seconds integer;
|
|
159
|
+
v_run_id uuid;
|
|
160
|
+
v_now timestamptz := now();
|
|
161
|
+
v_metadata jsonb := COALESCE(p_metadata, '{}'::jsonb);
|
|
162
|
+
v_lease_until timestamptz;
|
|
163
|
+
v_refusal text;
|
|
164
|
+
BEGIN
|
|
165
|
+
IF v_job_name = '' THEN
|
|
166
|
+
RAISE EXCEPTION 'platform_job_name_required' USING ERRCODE = '22023';
|
|
167
|
+
END IF;
|
|
168
|
+
|
|
169
|
+
IF v_driver NOT IN ('worker', 'scheduler', 'operator') THEN
|
|
170
|
+
RAISE EXCEPTION 'platform_job_invalid_driver' USING ERRCODE = '22023';
|
|
171
|
+
END IF;
|
|
172
|
+
|
|
173
|
+
v_lease_seconds := LEAST(GREATEST(COALESCE(p_lease_seconds, 900), 60), 3600);
|
|
174
|
+
|
|
175
|
+
INSERT INTO public.platform_job_controls (job_name, active_driver)
|
|
176
|
+
VALUES (v_job_name, v_driver)
|
|
177
|
+
ON CONFLICT (job_name) DO NOTHING;
|
|
178
|
+
|
|
179
|
+
-- The row lock IS the exclusivity. Everything below runs with the control row held.
|
|
180
|
+
SELECT * INTO v_control
|
|
181
|
+
FROM public.platform_job_controls
|
|
182
|
+
WHERE public.platform_job_controls.job_name = v_job_name
|
|
183
|
+
FOR UPDATE;
|
|
184
|
+
|
|
185
|
+
v_lease_until := v_control.lease_until;
|
|
186
|
+
v_refusal := CASE
|
|
187
|
+
WHEN NOT v_control.enabled THEN 'job_disabled'
|
|
188
|
+
WHEN v_control.active_driver <> v_driver THEN 'inactive_driver'
|
|
189
|
+
WHEN v_lease_until IS NOT NULL AND v_lease_until > v_now THEN 'lease_active'
|
|
190
|
+
ELSE NULL
|
|
191
|
+
END;
|
|
192
|
+
|
|
193
|
+
IF v_refusal IS NOT NULL THEN
|
|
194
|
+
-- A refusal is still an attempt, and an attempt nobody records is an outage
|
|
195
|
+
-- nobody can see. The refused run carries WHY, and the control row records that
|
|
196
|
+
-- somebody tried; the live lease is left exactly as it was found.
|
|
197
|
+
INSERT INTO public.platform_job_runs (
|
|
198
|
+
job_name, status, driver, started_at, finished_at, lease_until, error, metadata
|
|
199
|
+
)
|
|
200
|
+
VALUES (
|
|
201
|
+
v_job_name, 'skipped', v_driver, v_now, v_now,
|
|
202
|
+
CASE WHEN v_refusal = 'lease_active' THEN v_lease_until ELSE NULL END,
|
|
203
|
+
v_refusal,
|
|
204
|
+
v_metadata || jsonb_build_object('activeDriver', v_control.active_driver, 'leaseOwner', v_control.lease_owner)
|
|
205
|
+
)
|
|
206
|
+
RETURNING id INTO v_run_id;
|
|
207
|
+
|
|
208
|
+
UPDATE public.platform_job_controls
|
|
209
|
+
SET updated_at = v_now,
|
|
210
|
+
last_started_at = v_now,
|
|
211
|
+
last_finished_at = v_now,
|
|
212
|
+
last_status = 'skipped',
|
|
213
|
+
last_run_id = v_run_id
|
|
214
|
+
WHERE public.platform_job_controls.job_name = v_job_name;
|
|
215
|
+
|
|
216
|
+
RETURN QUERY SELECT false, v_run_id, v_refusal,
|
|
217
|
+
CASE WHEN v_refusal = 'lease_active' THEN v_lease_until ELSE NULL::timestamptz END;
|
|
218
|
+
RETURN;
|
|
219
|
+
END IF;
|
|
220
|
+
|
|
221
|
+
v_run_id := gen_random_uuid();
|
|
222
|
+
v_lease_until := v_now + make_interval(secs => v_lease_seconds);
|
|
223
|
+
|
|
224
|
+
UPDATE public.platform_job_controls
|
|
225
|
+
SET updated_at = v_now,
|
|
226
|
+
lease_owner = v_driver,
|
|
227
|
+
lease_token = v_run_id,
|
|
228
|
+
lease_until = v_lease_until,
|
|
229
|
+
last_started_at = v_now,
|
|
230
|
+
last_status = 'running',
|
|
231
|
+
last_run_id = v_run_id
|
|
232
|
+
WHERE public.platform_job_controls.job_name = v_job_name;
|
|
233
|
+
|
|
234
|
+
INSERT INTO public.platform_job_runs (
|
|
235
|
+
id, job_name, status, driver, started_at, lease_until, metadata
|
|
236
|
+
)
|
|
237
|
+
VALUES (
|
|
238
|
+
v_run_id, v_job_name, 'running', v_driver, v_now, v_lease_until, v_metadata
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
RETURN QUERY SELECT true, v_run_id, 'acquired', v_lease_until;
|
|
242
|
+
END;
|
|
243
|
+
$$;
|
|
244
|
+
|
|
245
|
+
CREATE OR REPLACE FUNCTION public.platform_finish_job_run_v2(
|
|
246
|
+
p_job_name text,
|
|
247
|
+
p_run_id uuid,
|
|
248
|
+
p_status text,
|
|
249
|
+
p_checked integer DEFAULT NULL,
|
|
250
|
+
p_updated integer DEFAULT NULL,
|
|
251
|
+
p_error text DEFAULT NULL,
|
|
252
|
+
p_support_code text DEFAULT NULL,
|
|
253
|
+
p_metadata jsonb DEFAULT '{}'::jsonb
|
|
254
|
+
)
|
|
255
|
+
RETURNS boolean
|
|
256
|
+
LANGUAGE plpgsql
|
|
257
|
+
SET search_path = public, pg_catalog
|
|
258
|
+
AS $$
|
|
259
|
+
DECLARE
|
|
260
|
+
v_now timestamptz := now();
|
|
261
|
+
v_job_name text := btrim(COALESCE(p_job_name, ''));
|
|
262
|
+
v_metadata jsonb := COALESCE(p_metadata, '{}'::jsonb);
|
|
263
|
+
v_released boolean;
|
|
264
|
+
BEGIN
|
|
265
|
+
IF p_status IS NULL OR p_status NOT IN ('success', 'failed') THEN
|
|
266
|
+
RAISE EXCEPTION 'platform_job_invalid_finish_status' USING ERRCODE = '22023';
|
|
267
|
+
END IF;
|
|
268
|
+
|
|
269
|
+
-- The run row is always stamped, even by a runner whose lease is gone: a runner that
|
|
270
|
+
-- lost its lease still owes the ledger the truth about what it did. Deliberately NOT
|
|
271
|
+
-- guarded on `finished_at IS NULL` -- upstream re-stamps too, and a kernel that
|
|
272
|
+
-- silently ignored a second finish would answer a different last-writer than the
|
|
273
|
+
-- bundle it is compared against.
|
|
274
|
+
UPDATE public.platform_job_runs
|
|
275
|
+
SET status = p_status,
|
|
276
|
+
finished_at = v_now,
|
|
277
|
+
checked = p_checked,
|
|
278
|
+
updated = p_updated,
|
|
279
|
+
error = p_error,
|
|
280
|
+
support_code = p_support_code,
|
|
281
|
+
metadata = public.platform_job_runs.metadata || v_metadata
|
|
282
|
+
WHERE id = p_run_id
|
|
283
|
+
AND public.platform_job_runs.job_name = v_job_name;
|
|
284
|
+
|
|
285
|
+
-- The lease is released ONLY by the token that holds it. This predicate is the fence.
|
|
286
|
+
UPDATE public.platform_job_controls
|
|
287
|
+
SET updated_at = v_now,
|
|
288
|
+
lease_owner = NULL,
|
|
289
|
+
lease_token = NULL,
|
|
290
|
+
lease_until = NULL,
|
|
291
|
+
last_finished_at = v_now,
|
|
292
|
+
last_success_at = CASE WHEN p_status = 'success' THEN v_now ELSE last_success_at END,
|
|
293
|
+
last_status = p_status,
|
|
294
|
+
last_run_id = p_run_id
|
|
295
|
+
WHERE public.platform_job_controls.job_name = v_job_name
|
|
296
|
+
AND lease_token = p_run_id
|
|
297
|
+
RETURNING true INTO v_released;
|
|
298
|
+
|
|
299
|
+
RETURN COALESCE(v_released, false);
|
|
300
|
+
END;
|
|
301
|
+
$$;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
-- Job-run ledger v3 entry points: invocation-aware claim and finish.
|
|
2
|
+
--
|
|
3
|
+
-- Applies after 20260809150000_job_run_ledger.sql, whose v2 claim and finish these delegate to.
|
|
4
|
+
-- The trigger kind and invocation source are evidence folded into the run metadata, never an
|
|
5
|
+
-- authorization control. CREATE OR REPLACE lets a database whose own migration chain already
|
|
6
|
+
-- defines these functions with the same bodies apply this file without change.
|
|
7
|
+
|
|
8
|
+
CREATE OR REPLACE FUNCTION public.platform_claim_job_run_v3(
|
|
9
|
+
p_job_name text,
|
|
10
|
+
p_trigger_kind text,
|
|
11
|
+
p_invocation_source text,
|
|
12
|
+
p_lease_seconds integer DEFAULT 900,
|
|
13
|
+
p_metadata jsonb DEFAULT '{}'::jsonb
|
|
14
|
+
)
|
|
15
|
+
RETURNS TABLE (
|
|
16
|
+
acquired boolean,
|
|
17
|
+
run_id uuid,
|
|
18
|
+
reason text,
|
|
19
|
+
lease_until timestamptz
|
|
20
|
+
)
|
|
21
|
+
LANGUAGE plpgsql
|
|
22
|
+
SET search_path = public, pg_catalog
|
|
23
|
+
AS $$
|
|
24
|
+
DECLARE
|
|
25
|
+
v_trigger_kind text := COALESCE(NULLIF(btrim(p_trigger_kind), ''), '');
|
|
26
|
+
v_invocation_source text := COALESCE(NULLIF(btrim(p_invocation_source), ''), '');
|
|
27
|
+
BEGIN
|
|
28
|
+
IF p_job_name IS NULL OR btrim(p_job_name) = '' THEN
|
|
29
|
+
RAISE EXCEPTION 'platform_job_name_required' USING ERRCODE = '22023';
|
|
30
|
+
END IF;
|
|
31
|
+
|
|
32
|
+
IF v_trigger_kind NOT IN ('worker', 'scheduler', 'operator') THEN
|
|
33
|
+
RAISE EXCEPTION 'platform_job_invalid_trigger_kind' USING ERRCODE = '22023';
|
|
34
|
+
END IF;
|
|
35
|
+
|
|
36
|
+
IF v_invocation_source = '' OR length(v_invocation_source) > 128 THEN
|
|
37
|
+
RAISE EXCEPTION 'platform_job_invocation_source_required' USING ERRCODE = '22023';
|
|
38
|
+
END IF;
|
|
39
|
+
|
|
40
|
+
-- The invocation source is evidence, never an authorization control, so it is folded into
|
|
41
|
+
-- the metadata this ledger stores and never interprets.
|
|
42
|
+
RETURN QUERY
|
|
43
|
+
SELECT claimed.acquired, claimed.run_id, claimed.reason, claimed.lease_until
|
|
44
|
+
FROM public.platform_claim_job_run(
|
|
45
|
+
p_job_name,
|
|
46
|
+
v_trigger_kind,
|
|
47
|
+
p_lease_seconds,
|
|
48
|
+
COALESCE(p_metadata, '{}'::jsonb) || jsonb_build_object(
|
|
49
|
+
'triggerKind', v_trigger_kind, 'invocationSource', v_invocation_source)
|
|
50
|
+
) AS claimed;
|
|
51
|
+
END;
|
|
52
|
+
$$;
|
|
53
|
+
|
|
54
|
+
CREATE OR REPLACE FUNCTION public.platform_finish_job_run_v3(
|
|
55
|
+
p_job_name text,
|
|
56
|
+
p_run_id uuid,
|
|
57
|
+
p_status text,
|
|
58
|
+
p_checked integer DEFAULT NULL,
|
|
59
|
+
p_updated integer DEFAULT NULL,
|
|
60
|
+
p_error text DEFAULT NULL,
|
|
61
|
+
p_support_code text DEFAULT NULL,
|
|
62
|
+
p_metadata jsonb DEFAULT '{}'::jsonb
|
|
63
|
+
)
|
|
64
|
+
RETURNS boolean
|
|
65
|
+
LANGUAGE sql
|
|
66
|
+
SET search_path = public, pg_catalog
|
|
67
|
+
AS $$
|
|
68
|
+
SELECT public.platform_finish_job_run_v2(
|
|
69
|
+
p_job_name, p_run_id, p_status, p_checked, p_updated, p_error, p_support_code, p_metadata);
|
|
70
|
+
$$;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- Public self-host actor-auth bootstrap.
|
|
2
|
+
--
|
|
3
|
+
-- This append-only platform forward establishes only the default-deny actor
|
|
4
|
+
-- roles and `auth.uid()` primitive required by a future actor-scoped
|
|
5
|
+
-- capability. The node-postgres runtime applies this exact manifest unit
|
|
6
|
+
-- before listening; it does not select the historical private compatibility
|
|
7
|
+
-- bootstrap. No customer mapping, table privilege, policy, verifier, managed
|
|
8
|
+
-- migration, service role, or additional auth helper is introduced here.
|
|
9
|
+
--
|
|
10
|
+
-- openlup:allow-grant: grants only auth schema usage and auth.uid() execution to the two
|
|
11
|
+
-- default-deny actor roles; fresh final-image Compose proof verifies their exact ACLs and RLS lane.
|
|
12
|
+
|
|
13
|
+
CREATE ROLE anon NOLOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS;
|
|
14
|
+
CREATE ROLE authenticated NOLOGIN NOINHERIT NOSUPERUSER NOCREATEDB NOCREATEROLE NOREPLICATION NOBYPASSRLS;
|
|
15
|
+
|
|
16
|
+
CREATE SCHEMA auth;
|
|
17
|
+
|
|
18
|
+
CREATE FUNCTION auth.uid()
|
|
19
|
+
RETURNS uuid
|
|
20
|
+
LANGUAGE sql
|
|
21
|
+
STABLE
|
|
22
|
+
SET search_path = pg_catalog
|
|
23
|
+
AS $$
|
|
24
|
+
SELECT CASE
|
|
25
|
+
WHEN current_setting('request.jwt.claims', true) IS NULL THEN NULL
|
|
26
|
+
WHEN current_setting('request.jwt.claims', true) = '' THEN NULL
|
|
27
|
+
WHEN jsonb_typeof(current_setting('request.jwt.claims', true)::jsonb -> 'sub') <> 'string' THEN NULL
|
|
28
|
+
WHEN current_setting('request.jwt.claims', true)::jsonb ->> 'sub'
|
|
29
|
+
!~* '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' THEN NULL
|
|
30
|
+
ELSE (current_setting('request.jwt.claims', true)::jsonb ->> 'sub')::uuid
|
|
31
|
+
END
|
|
32
|
+
$$;
|
|
33
|
+
|
|
34
|
+
REVOKE ALL ON SCHEMA auth FROM PUBLIC;
|
|
35
|
+
REVOKE ALL ON FUNCTION auth.uid() FROM PUBLIC;
|
|
36
|
+
GRANT USAGE ON SCHEMA auth TO anon, authenticated;
|
|
37
|
+
GRANT EXECUTE ON FUNCTION auth.uid() TO anon, authenticated;
|
|
38
|
+
|
|
39
|
+
GRANT anon TO CURRENT_USER WITH INHERIT FALSE, SET TRUE, ADMIN FALSE;
|
|
40
|
+
GRANT authenticated TO CURRENT_USER WITH INHERIT FALSE, SET TRUE, ADMIN FALSE;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
-- Customer identity read catalog forward.
|
|
2
|
+
--
|
|
3
|
+
-- This append-only delta adds only an optional neutral principal link to the
|
|
4
|
+
-- existing client profile. Authenticated callers can select their own bounded
|
|
5
|
+
-- response columns through the existing invoker-rights actor lane. It does not
|
|
6
|
+
-- add a customer mutation, privileged role, auth table, routine, or trigger.
|
|
7
|
+
--
|
|
8
|
+
-- openlup:allow-unique-index: a non-null principal maps to at most one client; the fresh-database proof verifies the exact partial index.
|
|
9
|
+
-- openlup:allow-rls: the one authenticated SELECT policy is proven through the shipped actor transaction with two principals.
|
|
10
|
+
-- openlup:allow-grant: PUBLIC and anon remain denied; authenticated receives only the five profile response columns, proven by catalog ACL checks.
|
|
11
|
+
|
|
12
|
+
ALTER TABLE public.clients ADD COLUMN principal_id uuid;
|
|
13
|
+
|
|
14
|
+
-- squawk-ignore require-concurrent-index-creation
|
|
15
|
+
CREATE UNIQUE INDEX clients_principal_id_unique
|
|
16
|
+
ON public.clients (principal_id)
|
|
17
|
+
WHERE principal_id IS NOT NULL;
|
|
18
|
+
|
|
19
|
+
ALTER TABLE public.clients ENABLE ROW LEVEL SECURITY;
|
|
20
|
+
|
|
21
|
+
CREATE POLICY clients_select_own_principal
|
|
22
|
+
ON public.clients
|
|
23
|
+
FOR SELECT
|
|
24
|
+
TO authenticated
|
|
25
|
+
USING (principal_id = auth.uid());
|
|
26
|
+
|
|
27
|
+
REVOKE ALL ON TABLE public.clients FROM PUBLIC;
|
|
28
|
+
REVOKE ALL ON TABLE public.clients FROM anon;
|
|
29
|
+
REVOKE ALL ON TABLE public.clients FROM authenticated;
|
|
30
|
+
GRANT SELECT (id, email, first_name, last_name, lifecycle_stage)
|
|
31
|
+
ON TABLE public.clients TO authenticated;
|