@learncard/network-brain-service 3.19.0 → 4.0.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/.env.example +47 -82
- package/AGENTS.md +52 -0
- package/CHANGELOG.md +147 -0
- package/README.md +51 -2
- package/bootstrapLambda.test.ts +72 -0
- package/config/config.dev.json +29 -0
- package/config/config.example.json +29 -0
- package/config/config.json +1 -0
- package/config/config.production.json +29 -0
- package/config/config.scouts.dev.json +24 -0
- package/config/config.scouts.production.json +24 -0
- package/contractEventsLambda.ts +18 -0
- package/contractEventsLambdaApp.ts +19 -0
- package/didWebLambda.ts +13 -18
- package/didWebLambdaApp.ts +22 -0
- package/dist/accesslayer/app-manifest-version/create.d.ts +10 -0
- package/dist/accesslayer/app-manifest-version/create.d.ts.map +1 -0
- package/dist/accesslayer/app-manifest-version/read.d.ts +11 -0
- package/dist/accesslayer/app-manifest-version/read.d.ts.map +1 -0
- package/dist/accesslayer/app-manifest-version/update.d.ts +7 -0
- package/dist/accesslayer/app-manifest-version/update.d.ts.map +1 -0
- package/dist/accesslayer/app-store-listing/read.d.ts +2 -1
- package/dist/accesslayer/app-store-listing/read.d.ts.map +1 -1
- package/dist/accesslayer/app-store-listing/relationships/create.d.ts +1 -0
- package/dist/accesslayer/app-store-listing/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/app-store-listing/relationships/read.d.ts +2 -0
- package/dist/accesslayer/app-store-listing/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/app-store-listing/update.d.ts +1 -0
- package/dist/accesslayer/app-store-listing/update.d.ts.map +1 -1
- package/dist/accesslayer/boost/relationships/create.d.ts +2 -1
- package/dist/accesslayer/boost/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/create.d.ts +9 -1
- package/dist/accesslayer/consentflowcontract/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/read.d.ts +34 -3
- package/dist/accesslayer/consentflowcontract/read.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/create.d.ts +4 -1
- package/dist/accesslayer/consentflowcontract/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/delete.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/read.d.ts +3 -2
- package/dist/accesslayer/consentflowcontract/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/recipients.d.ts +12 -0
- package/dist/accesslayer/consentflowcontract/relationships/recipients.d.ts.map +1 -0
- package/dist/accesslayer/consentflowcontract/relationships/smartResume.d.ts +12 -0
- package/dist/accesslayer/consentflowcontract/relationships/smartResume.d.ts.map +1 -0
- package/dist/accesslayer/consentflowcontract/relationships/update.d.ts +8 -5
- package/dist/accesslayer/consentflowcontract/relationships/update.d.ts.map +1 -1
- package/dist/accesslayer/credential/create.d.ts +2 -1
- package/dist/accesslayer/credential/create.d.ts.map +1 -1
- package/dist/accesslayer/credential/relationships/create.d.ts +4 -3
- package/dist/accesslayer/credential/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/inbox-credential/relationships/create.d.ts +2 -1
- package/dist/accesslayer/inbox-credential/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/inbox-credential/update.d.ts +2 -1
- package/dist/accesslayer/inbox-credential/update.d.ts.map +1 -1
- package/dist/accesslayer/presentation/read.d.ts.map +1 -1
- package/dist/accesslayer/presentation/relationships/create.d.ts +2 -2
- package/dist/accesslayer/presentation/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/presentation/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/share-link/abandon.d.ts +3 -0
- package/dist/accesslayer/share-link/abandon.d.ts.map +1 -0
- package/dist/accesslayer/share-link/attachment.d.ts +37 -0
- package/dist/accesslayer/share-link/attachment.d.ts.map +1 -0
- package/dist/accesslayer/share-link/cleanup.d.ts +6 -0
- package/dist/accesslayer/share-link/cleanup.d.ts.map +1 -0
- package/dist/accesslayer/share-link/errors.d.ts +8 -0
- package/dist/accesslayer/share-link/errors.d.ts.map +1 -0
- package/dist/accesslayer/share-link/finalize.d.ts +3 -0
- package/dist/accesslayer/share-link/finalize.d.ts.map +1 -0
- package/dist/accesslayer/share-link/helpers.d.ts +59 -0
- package/dist/accesslayer/share-link/helpers.d.ts.map +1 -0
- package/dist/accesslayer/share-link/index.d.ts +12 -0
- package/dist/accesslayer/share-link/index.d.ts.map +1 -0
- package/dist/accesslayer/share-link/list.d.ts +5 -0
- package/dist/accesslayer/share-link/list.d.ts.map +1 -0
- package/dist/accesslayer/share-link/read.d.ts +5 -0
- package/dist/accesslayer/share-link/read.d.ts.map +1 -0
- package/dist/accesslayer/share-link/receipt.d.ts +11 -0
- package/dist/accesslayer/share-link/receipt.d.ts.map +1 -0
- package/dist/accesslayer/share-link/recovery.d.ts +6 -0
- package/dist/accesslayer/share-link/recovery.d.ts.map +1 -0
- package/dist/accesslayer/share-link/reserve.d.ts +4 -0
- package/dist/accesslayer/share-link/reserve.d.ts.map +1 -0
- package/dist/accesslayer/share-link/revoke.d.ts +3 -0
- package/dist/accesslayer/share-link/revoke.d.ts.map +1 -0
- package/dist/accesslayer/share-link/transaction-execution.d.ts +18 -0
- package/dist/accesslayer/share-link/transaction-execution.d.ts.map +1 -0
- package/dist/accesslayer/share-link/transaction.d.ts +15 -0
- package/dist/accesslayer/share-link/transaction.d.ts.map +1 -0
- package/dist/accesslayer/share-link/types.d.ts +375 -0
- package/dist/accesslayer/share-link/types.d.ts.map +1 -0
- package/dist/app.d.ts +4 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/cache/app-store.caches.d.ts +49 -0
- package/dist/cache/app-store.caches.d.ts.map +1 -1
- package/dist/config/applyDockerStageConfig.d.ts +2 -0
- package/dist/config/applyDockerStageConfig.d.ts.map +1 -0
- package/dist/config/environment.d.ts +14 -0
- package/dist/config/environment.d.ts.map +1 -1
- package/dist/config/serverlessFunctionEnv.test.d.ts +2 -0
- package/dist/config/serverlessFunctionEnv.test.d.ts.map +1 -0
- package/dist/config/stageConfig.d.ts +112 -0
- package/dist/config/stageConfig.d.ts.map +1 -0
- package/dist/config/stageConfig.test.d.ts +2 -0
- package/dist/config/stageConfig.test.d.ts.map +1 -0
- package/dist/constants/auth-grant.d.ts +2 -0
- package/dist/constants/auth-grant.d.ts.map +1 -1
- package/dist/didkit_wasm_bg.wasm +0 -0
- package/dist/docker-entry.d.ts +1 -1
- package/dist/docker-entry.d.ts.map +1 -1
- package/dist/helpers/app-manifest.helpers.d.ts +5 -0
- package/dist/helpers/app-manifest.helpers.d.ts.map +1 -0
- package/dist/helpers/boost.helpers.d.ts.map +1 -1
- package/dist/helpers/claim-hooks.helpers.d.ts +2 -1
- package/dist/helpers/claim-hooks.helpers.d.ts.map +1 -1
- package/dist/helpers/consent-referral.helpers.d.ts +2 -0
- package/dist/helpers/consent-referral.helpers.d.ts.map +1 -0
- package/dist/helpers/consent-scopes.helpers.d.ts +7 -0
- package/dist/helpers/consent-scopes.helpers.d.ts.map +1 -0
- package/dist/helpers/contract-event-maintenance.helpers.d.ts +3 -0
- package/dist/helpers/contract-event-maintenance.helpers.d.ts.map +1 -0
- package/dist/helpers/contract-events.helpers.d.ts +25 -0
- package/dist/helpers/contract-events.helpers.d.ts.map +1 -0
- package/dist/helpers/contract-requests.helpers.d.ts +19 -0
- package/dist/helpers/contract-requests.helpers.d.ts.map +1 -0
- package/dist/helpers/credentialSubject.helpers.d.ts +3 -0
- package/dist/helpers/credentialSubject.helpers.d.ts.map +1 -0
- package/dist/helpers/credentialSubject.helpers.test.d.ts +2 -0
- package/dist/helpers/credentialSubject.helpers.test.d.ts.map +1 -0
- package/dist/helpers/finalize-inbox.helpers.d.ts +3 -3
- package/dist/helpers/finalize-inbox.helpers.d.ts.map +1 -1
- package/dist/helpers/inbox.helpers.d.ts.map +1 -1
- package/dist/helpers/inline-template.helpers.d.ts +45 -0
- package/dist/helpers/inline-template.helpers.d.ts.map +1 -0
- package/dist/helpers/notificationMessages.d.ts +1 -1
- package/dist/helpers/notificationMessages.d.ts.map +1 -1
- package/dist/helpers/notificationQueue.helpers.d.ts.map +1 -1
- package/dist/helpers/notifications.helpers.d.ts +6 -0
- package/dist/helpers/notifications.helpers.d.ts.map +1 -1
- package/dist/helpers/presentation-metadata.d.ts +4 -0
- package/dist/helpers/presentation-metadata.d.ts.map +1 -0
- package/dist/helpers/presentation.helpers.d.ts +1 -1
- package/dist/helpers/presentation.helpers.d.ts.map +1 -1
- package/dist/helpers/profile.helpers.d.ts +2 -0
- package/dist/helpers/profile.helpers.d.ts.map +1 -1
- package/dist/helpers/share-content-client/adapters.d.ts +10 -0
- package/dist/helpers/share-content-client/adapters.d.ts.map +1 -0
- package/dist/helpers/share-content-client/canonical.d.ts +7 -0
- package/dist/helpers/share-content-client/canonical.d.ts.map +1 -0
- package/dist/helpers/share-content-client/client.d.ts +5 -0
- package/dist/helpers/share-content-client/client.d.ts.map +1 -0
- package/dist/helpers/share-content-client/config.d.ts +11 -0
- package/dist/helpers/share-content-client/config.d.ts.map +1 -0
- package/dist/helpers/share-content-client/index.d.ts +6 -0
- package/dist/helpers/share-content-client/index.d.ts.map +1 -0
- package/dist/helpers/share-content-client/responses.d.ts +16 -0
- package/dist/helpers/share-content-client/responses.d.ts.map +1 -0
- package/dist/helpers/share-content-client/types.d.ts +145 -0
- package/dist/helpers/share-content-client/types.d.ts.map +1 -0
- package/dist/helpers/share-link-attachment-access.d.ts +4 -0
- package/dist/helpers/share-link-attachment-access.d.ts.map +1 -0
- package/dist/helpers/share-link-attachment.d.ts +18 -0
- package/dist/helpers/share-link-attachment.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/attachment-stat.d.ts +5 -0
- package/dist/helpers/share-link-coordinator/attachment-stat.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/budget-helpers.d.ts +5 -0
- package/dist/helpers/share-link-coordinator/budget-helpers.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/cleanup-runner.d.ts +3 -0
- package/dist/helpers/share-link-coordinator/cleanup-runner.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/coordinator.d.ts +4 -0
- package/dist/helpers/share-link-coordinator/coordinator.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/index.d.ts +5 -0
- package/dist/helpers/share-link-coordinator/index.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/recovery-runner.d.ts +9 -0
- package/dist/helpers/share-link-coordinator/recovery-runner.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/runtime.d.ts +11 -0
- package/dist/helpers/share-link-coordinator/runtime.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/stat.d.ts +4 -0
- package/dist/helpers/share-link-coordinator/stat.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/types.d.ts +160 -0
- package/dist/helpers/share-link-coordinator/types.d.ts.map +1 -0
- package/dist/helpers/share-link-lifecycle/index.d.ts +5 -0
- package/dist/helpers/share-link-lifecycle/index.d.ts.map +1 -0
- package/dist/helpers/share-link-lifecycle/lease.helpers.d.ts +4 -0
- package/dist/helpers/share-link-lifecycle/lease.helpers.d.ts.map +1 -0
- package/dist/helpers/share-link-lifecycle/recovery.helpers.d.ts +21 -0
- package/dist/helpers/share-link-lifecycle/recovery.helpers.d.ts.map +1 -0
- package/dist/helpers/share-link-lifecycle/request-hash.helpers.d.ts +9 -0
- package/dist/helpers/share-link-lifecycle/request-hash.helpers.d.ts.map +1 -0
- package/dist/helpers/share-link-lifecycle/types.d.ts +14 -0
- package/dist/helpers/share-link-lifecycle/types.d.ts.map +1 -0
- package/dist/helpers/share-link-maintenance/budget.d.ts +12 -0
- package/dist/helpers/share-link-maintenance/budget.d.ts.map +1 -0
- package/dist/helpers/share-link-maintenance/config.d.ts +48 -0
- package/dist/helpers/share-link-maintenance/config.d.ts.map +1 -0
- package/dist/helpers/share-link-maintenance/index.d.ts +8 -0
- package/dist/helpers/share-link-maintenance/index.d.ts.map +1 -0
- package/dist/helpers/share-link-maintenance/runner.d.ts +20 -0
- package/dist/helpers/share-link-maintenance/runner.d.ts.map +1 -0
- package/dist/helpers/share-link-maintenance/runtime.d.ts +38 -0
- package/dist/helpers/share-link-maintenance/runtime.d.ts.map +1 -0
- package/dist/helpers/share-link-maintenance/scheduler.d.ts +18 -0
- package/dist/helpers/share-link-maintenance/scheduler.d.ts.map +1 -0
- package/dist/helpers/share-link-maintenance/telemetry.d.ts +5 -0
- package/dist/helpers/share-link-maintenance/telemetry.d.ts.map +1 -0
- package/dist/helpers/share-link-maintenance/types.d.ts +56 -0
- package/dist/helpers/share-link-maintenance/types.d.ts.map +1 -0
- package/dist/helpers/share-link-owner/config.d.ts +16 -0
- package/dist/helpers/share-link-owner/config.d.ts.map +1 -0
- package/dist/helpers/share-link-owner/diagnostics.d.ts +26 -0
- package/dist/helpers/share-link-owner/diagnostics.d.ts.map +1 -0
- package/dist/helpers/share-link-owner/lazy-initializer.d.ts +2 -0
- package/dist/helpers/share-link-owner/lazy-initializer.d.ts.map +1 -0
- package/dist/helpers/share-link-owner-projection.d.ts +4 -0
- package/dist/helpers/share-link-owner-projection.d.ts.map +1 -0
- package/dist/helpers/share-link-passcode-abuse.d.ts +2 -0
- package/dist/helpers/share-link-passcode-abuse.d.ts.map +1 -0
- package/dist/helpers/share-link-passcode.d.ts +6 -0
- package/dist/helpers/share-link-passcode.d.ts.map +1 -0
- package/dist/helpers/share-link-policy/index.d.ts +4 -0
- package/dist/helpers/share-link-policy/index.d.ts.map +1 -0
- package/dist/helpers/share-link-policy/production.d.ts +11 -0
- package/dist/helpers/share-link-policy/production.d.ts.map +1 -0
- package/dist/helpers/share-link-policy/resolver.d.ts +6 -0
- package/dist/helpers/share-link-policy/resolver.d.ts.map +1 -0
- package/dist/helpers/share-link-policy/types.d.ts +22 -0
- package/dist/helpers/share-link-policy/types.d.ts.map +1 -0
- package/dist/helpers/share-link-public/config.d.ts +13 -0
- package/dist/helpers/share-link-public/config.d.ts.map +1 -0
- package/dist/helpers/share-link-view-notification.d.ts +2 -0
- package/dist/helpers/share-link-view-notification.d.ts.map +1 -0
- package/dist/helpers/signingAuthority.helpers.d.ts.map +1 -1
- package/dist/helpers/smartResume.helpers.d.ts +3 -0
- package/dist/helpers/smartResume.helpers.d.ts.map +1 -0
- package/dist/index.js +2 -2
- package/dist/models/AppManifestVersion.d.ts +20 -0
- package/dist/models/AppManifestVersion.d.ts.map +1 -0
- package/dist/models/AppStoreListing.d.ts +13 -0
- package/dist/models/AppStoreListing.d.ts.map +1 -1
- package/dist/models/ConsentFlowContract.d.ts +13 -2
- package/dist/models/ConsentFlowContract.d.ts.map +1 -1
- package/dist/models/ConsentFlowTerms.d.ts.map +1 -1
- package/dist/models/ConsentFlowTransaction.d.ts.map +1 -1
- package/dist/models/Integration.d.ts +2 -0
- package/dist/models/Integration.d.ts.map +1 -1
- package/dist/models/Presentation.d.ts +2 -0
- package/dist/models/Presentation.d.ts.map +1 -1
- package/dist/models/Profile.d.ts +2 -0
- package/dist/models/Profile.d.ts.map +1 -1
- package/dist/models/ShareLink.d.ts +46 -0
- package/dist/models/ShareLink.d.ts.map +1 -0
- package/dist/models/ShareViewReceipt.d.ts +22 -0
- package/dist/models/ShareViewReceipt.d.ts.map +1 -0
- package/dist/models/index.d.ts +2 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/share-link-constraints.d.ts +3 -0
- package/dist/models/share-link-constraints.d.ts.map +1 -0
- package/dist/openapi.d.ts +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/public-share-link-http.d.ts +4 -0
- package/dist/public-share-link-http.d.ts.map +1 -0
- package/dist/routes/app-store.d.ts +619 -0
- package/dist/routes/app-store.d.ts.map +1 -1
- package/dist/routes/boosts.d.ts +2 -2
- package/dist/routes/boosts.d.ts.map +1 -1
- package/dist/routes/contracts.d.ts +148 -5
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/credentials.d.ts +35 -1
- package/dist/routes/credentials.d.ts.map +1 -1
- package/dist/routes/inbox.d.ts +52 -2
- package/dist/routes/inbox.d.ts.map +1 -1
- package/dist/routes/index.d.ts +153 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/presentations.d.ts +1 -0
- package/dist/routes/presentations.d.ts.map +1 -1
- package/dist/routes/profile-manager.d.ts.map +1 -1
- package/dist/routes/profiles.d.ts.map +1 -1
- package/dist/routes/public-share-links.d.ts +285 -0
- package/dist/routes/public-share-links.d.ts.map +1 -0
- package/dist/routes/share-links.d.ts +1005 -0
- package/dist/routes/share-links.d.ts.map +1 -0
- package/dist/routes/test.d.ts +5 -0
- package/dist/routes/test.d.ts.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/services/delivery/adapters/postmark.adapter.d.ts.map +1 -1
- package/dist/types/app-manifest.d.ts +339 -0
- package/dist/types/app-manifest.d.ts.map +1 -0
- package/dist/types/app-store-listing.d.ts +34 -0
- package/dist/types/app-store-listing.d.ts.map +1 -1
- package/dist/types/consentflowcontract.d.ts +31 -4
- package/dist/types/consentflowcontract.d.ts.map +1 -1
- package/dist/types/credential-refresh.d.ts +1 -1
- package/esbuildPlugins.cjs +1 -0
- package/lambda.ts +49 -192
- package/lambdaApp.ts +203 -0
- package/package.json +25 -17
- package/scripts/export-openapi.ts +20 -0
- package/scripts/offline-schema-environment.ts +18 -0
- package/scripts/seed-demo-persona.ts +425 -0
- package/scripts/verify-python-contracts.ts +72 -0
- package/serverless-local.yml +3 -6
- package/serverless.function-env.cjs +50 -0
- package/serverless.local.yml +0 -1
- package/serverless.yml +44 -55
- package/shareLinkMaintenanceLambda.ts +18 -0
- package/shareLinkMaintenanceLambdaApp.ts +50 -0
- package/src/accesslayer/app-manifest-version/create.ts +57 -0
- package/src/accesslayer/app-manifest-version/read.ts +129 -0
- package/src/accesslayer/app-manifest-version/update.ts +61 -0
- package/src/accesslayer/app-store-listing/read.ts +6 -0
- package/src/accesslayer/app-store-listing/relationships/create.ts +20 -0
- package/src/accesslayer/app-store-listing/relationships/read.ts +24 -1
- package/src/accesslayer/app-store-listing/update.ts +15 -0
- package/src/accesslayer/boost/relationships/create.ts +8 -2
- package/src/accesslayer/consentflowcontract/create.ts +81 -8
- package/src/accesslayer/consentflowcontract/read.ts +84 -10
- package/src/accesslayer/consentflowcontract/relationships/create.ts +125 -109
- package/src/accesslayer/consentflowcontract/relationships/delete.ts +1 -0
- package/src/accesslayer/consentflowcontract/relationships/read.ts +184 -108
- package/src/accesslayer/consentflowcontract/relationships/recipients.ts +125 -0
- package/src/accesslayer/consentflowcontract/relationships/smartResume.ts +125 -0
- package/src/accesslayer/consentflowcontract/relationships/update.ts +255 -217
- package/src/accesslayer/credential/create.test.ts +2 -115
- package/src/accesslayer/credential/create.ts +11 -6
- package/src/accesslayer/credential/relationships/create.ts +17 -10
- package/src/accesslayer/inbox-credential/relationships/create.ts +70 -48
- package/src/accesslayer/inbox-credential/update.ts +4 -2
- package/src/accesslayer/presentation/read.ts +57 -25
- package/src/accesslayer/presentation/relationships/create.ts +54 -11
- package/src/accesslayer/presentation/relationships/read.ts +21 -6
- package/src/accesslayer/share-link/abandon.ts +120 -0
- package/src/accesslayer/share-link/attachment.ts +360 -0
- package/src/accesslayer/share-link/cleanup.ts +271 -0
- package/src/accesslayer/share-link/errors.ts +32 -0
- package/src/accesslayer/share-link/finalize.ts +313 -0
- package/src/accesslayer/share-link/helpers.ts +450 -0
- package/src/accesslayer/share-link/index.ts +11 -0
- package/src/accesslayer/share-link/list.ts +162 -0
- package/src/accesslayer/share-link/read.ts +107 -0
- package/src/accesslayer/share-link/receipt.ts +548 -0
- package/src/accesslayer/share-link/recovery.ts +565 -0
- package/src/accesslayer/share-link/reserve.ts +763 -0
- package/src/accesslayer/share-link/revoke.ts +232 -0
- package/src/accesslayer/share-link/transaction-execution.ts +72 -0
- package/src/accesslayer/share-link/transaction.ts +126 -0
- package/src/accesslayer/share-link/types.ts +606 -0
- package/src/app.ts +6 -0
- package/src/cache/app-store.caches.ts +35 -0
- package/src/config/applyDockerStageConfig.ts +6 -0
- package/src/config/environment.test.ts +17 -12
- package/src/config/environment.ts +15 -0
- package/src/config/serverlessFunctionEnv.test.ts +105 -0
- package/src/config/stageConfig.test.ts +25 -0
- package/src/config/stageConfig.ts +24 -0
- package/src/constants/auth-grant.ts +5 -0
- package/src/docker-entry.ts +81 -0
- package/src/helpers/app-manifest.helpers.ts +185 -0
- package/src/helpers/boost.helpers.ts +4 -31
- package/src/helpers/claim-hooks.helpers.ts +20 -7
- package/src/helpers/consent-referral.helpers.ts +6 -0
- package/src/helpers/consent-scopes.helpers.ts +58 -0
- package/src/helpers/contract-event-maintenance.helpers.ts +43 -0
- package/src/helpers/contract-events.helpers.ts +540 -0
- package/src/helpers/contract-requests.helpers.ts +211 -0
- package/src/helpers/credentialSubject.helpers.test.ts +114 -0
- package/src/helpers/credentialSubject.helpers.ts +40 -0
- package/src/helpers/finalize-inbox.helpers.ts +163 -44
- package/src/helpers/inbox.helpers.ts +58 -70
- package/src/helpers/inline-template.helpers.ts +560 -0
- package/src/helpers/notificationMessages.ts +77 -1
- package/src/helpers/notificationQueue.helpers.ts +23 -5
- package/src/helpers/notifications.helpers.ts +25 -1
- package/src/helpers/presentation-metadata.ts +41 -0
- package/src/helpers/presentation.helpers.ts +27 -20
- package/src/helpers/profile.helpers.ts +13 -0
- package/src/helpers/share-content-client/adapters.ts +55 -0
- package/src/helpers/share-content-client/canonical.ts +25 -0
- package/src/helpers/share-content-client/client.ts +440 -0
- package/src/helpers/share-content-client/config.ts +189 -0
- package/src/helpers/share-content-client/index.ts +27 -0
- package/src/helpers/share-content-client/responses.ts +273 -0
- package/src/helpers/share-content-client/types.ts +253 -0
- package/src/helpers/share-link-attachment-access.ts +87 -0
- package/src/helpers/share-link-attachment.ts +115 -0
- package/src/helpers/share-link-coordinator/attachment-stat.ts +41 -0
- package/src/helpers/share-link-coordinator/budget-helpers.ts +53 -0
- package/src/helpers/share-link-coordinator/cleanup-runner.ts +286 -0
- package/src/helpers/share-link-coordinator/coordinator.ts +727 -0
- package/src/helpers/share-link-coordinator/index.ts +8 -0
- package/src/helpers/share-link-coordinator/recovery-runner.ts +443 -0
- package/src/helpers/share-link-coordinator/runtime.ts +88 -0
- package/src/helpers/share-link-coordinator/stat.ts +30 -0
- package/src/helpers/share-link-coordinator/types.ts +353 -0
- package/src/helpers/share-link-lifecycle/index.ts +4 -0
- package/src/helpers/share-link-lifecycle/lease.helpers.ts +35 -0
- package/src/helpers/share-link-lifecycle/recovery.helpers.ts +173 -0
- package/src/helpers/share-link-lifecycle/request-hash.helpers.ts +130 -0
- package/src/helpers/share-link-lifecycle/types.ts +58 -0
- package/src/helpers/share-link-maintenance/budget.ts +63 -0
- package/src/helpers/share-link-maintenance/config.ts +312 -0
- package/src/helpers/share-link-maintenance/index.ts +24 -0
- package/src/helpers/share-link-maintenance/runner.ts +251 -0
- package/src/helpers/share-link-maintenance/runtime.ts +340 -0
- package/src/helpers/share-link-maintenance/scheduler.ts +126 -0
- package/src/helpers/share-link-maintenance/telemetry.ts +73 -0
- package/src/helpers/share-link-maintenance/types.ts +91 -0
- package/src/helpers/share-link-owner/config.ts +48 -0
- package/src/helpers/share-link-owner/diagnostics.ts +89 -0
- package/src/helpers/share-link-owner/lazy-initializer.ts +29 -0
- package/src/helpers/share-link-owner-projection.ts +54 -0
- package/src/helpers/share-link-passcode-abuse.ts +36 -0
- package/src/helpers/share-link-passcode.ts +47 -0
- package/src/helpers/share-link-policy/index.ts +7 -0
- package/src/helpers/share-link-policy/production.ts +108 -0
- package/src/helpers/share-link-policy/resolver.ts +113 -0
- package/src/helpers/share-link-policy/types.ts +56 -0
- package/src/helpers/share-link-public/config.ts +41 -0
- package/src/helpers/share-link-view-notification.ts +18 -0
- package/src/helpers/signingAuthority.helpers.ts +23 -14
- package/src/helpers/smartResume.helpers.ts +123 -0
- package/src/models/AppManifestVersion.ts +43 -0
- package/src/models/AppStoreListing.ts +32 -0
- package/src/models/ConsentFlowContract.ts +34 -3
- package/src/models/ConsentFlowTerms.ts +10 -0
- package/src/models/ConsentFlowTransaction.ts +3 -0
- package/src/models/Integration.ts +2 -0
- package/src/models/Presentation.ts +2 -2
- package/src/models/Profile.ts +3 -2
- package/src/models/ShareLink.ts +134 -0
- package/src/models/ShareViewReceipt.ts +69 -0
- package/src/models/index.ts +25 -0
- package/src/models/share-link-constraints.ts +98 -0
- package/src/openapi.ts +44 -8
- package/src/public-share-link-http.ts +49 -0
- package/src/routes/app-store.ts +1056 -38
- package/src/routes/boosts.ts +14 -25
- package/src/routes/contracts.ts +384 -273
- package/src/routes/inbox.ts +4 -2
- package/src/routes/index.ts +142 -44
- package/src/routes/presentations.ts +19 -3
- package/src/routes/profile-manager.ts +29 -2
- package/src/routes/profiles.ts +29 -6
- package/src/routes/public-share-links.ts +983 -0
- package/src/routes/share-links.ts +709 -0
- package/src/routes/workflows.ts +3 -2
- package/src/services/delivery/adapters/postmark.adapter.ts +4 -1
- package/src/types/app-manifest.ts +28 -0
- package/src/types/app-store-listing.ts +13 -0
- package/src/types/consentflowcontract.ts +25 -4
- package/test/app-manifest.helpers.spec.ts +170 -0
- package/test/app-manifest.routes.spec.ts +299 -0
- package/test/app-store-listing-updates.spec.ts +236 -0
- package/test/app-store-listing.spec.ts +65 -3
- package/test/consent-data-boundaries.spec.ts +352 -0
- package/test/consent-recipients.spec.ts +513 -0
- package/test/consent-scopes.helpers.spec.ts +67 -0
- package/test/consentflow.spec.ts +63 -2
- package/test/contract-requests.spec.ts +1588 -0
- package/test/credential-storage.neo4j.spec.ts +122 -0
- package/test/dids.spec.ts +10 -1
- package/test/guardian-gated-routes.spec.ts +49 -0
- package/test/helpers/share-link-fixtures.ts +94 -0
- package/test/inbox-security.e2e.ts +26 -10
- package/test/inbox.spec.ts +184 -8
- package/test/inline-template.helpers.spec.ts +49 -0
- package/test/managed-recipient-inbox.spec.ts +152 -0
- package/test/notificationMessages.spec.ts +13 -0
- package/test/openapi.spec.ts +14 -53
- package/test/presentations.spec.ts +54 -6
- package/test/profiles.spec.ts +97 -1
- package/test/share-content-client.contract.spec.ts +365 -0
- package/test/share-content-client.unit.spec.ts +462 -0
- package/test/share-link-abuse.unit.spec.ts +65 -0
- package/test/share-link-attachment.neo4j.spec.ts +262 -0
- package/test/share-link-attachment.unit.spec.ts +244 -0
- package/test/share-link-coordinator.neo4j.spec.ts +684 -0
- package/test/share-link-coordinator.unit.spec.ts +990 -0
- package/test/share-link-dependency-diagnostics.unit.spec.ts +127 -0
- package/test/share-link-lifecycle.neo4j.spec.ts +1411 -0
- package/test/share-link-lifecycle.unit.spec.ts +205 -0
- package/test/share-link-list-cursor.unit.spec.ts +86 -0
- package/test/share-link-list.neo4j.spec.ts +324 -0
- package/test/share-link-maintenance.neo4j.spec.ts +355 -0
- package/test/share-link-maintenance.unit.spec.ts +1140 -0
- package/test/share-link-owner-policy.unit.spec.ts +210 -0
- package/test/share-link-owner-route.unit.spec.ts +820 -0
- package/test/share-link-owner-runtime.unit.spec.ts +102 -0
- package/test/share-link-passcode.unit.spec.ts +29 -0
- package/test/share-link-policy.unit.spec.ts +149 -0
- package/test/share-link-presentation-metadata.unit.spec.ts +49 -0
- package/test/share-link-production-policy.unit.spec.ts +126 -0
- package/test/share-link-public-config.unit.spec.ts +64 -0
- package/test/share-link-public-http-adapter.unit.spec.ts +315 -0
- package/test/share-link-public-route.unit.spec.ts +1079 -0
- package/test/share-link-receipt.neo4j.spec.ts +943 -0
- package/test/share-link-recovery.neo4j.spec.ts +935 -0
- package/test/share-link-recovery.unit.spec.ts +726 -0
- package/test/share-link-service-policy.neo4j.spec.ts +403 -0
- package/test/signing-authority-encryption.spec.ts +75 -0
- package/test/smart-resume-consent.spec.ts +233 -0
- package/test/smart-resume-upload.spec.ts +65 -0
- package/tsconfig.build.json +1 -1
- package/tsconfig.json +1 -0
- package/vitest.config.ts +14 -0
- package/vitest.inbox-e2e.config.ts +2 -0
- package/vitest.share-links-neo4j.config.ts +19 -0
- package/vitest.share-links-unit.config.ts +28 -0
- package/workerLambda.test.ts +100 -0
|
@@ -14,16 +14,27 @@ export type ConsentFlowRelationships = {
|
|
|
14
14
|
{ signingAuthorityEndpoint: string; signingAuthorityName: string; issuer?: string }
|
|
15
15
|
>;
|
|
16
16
|
canWrite: ModelRelatedNodesI<typeof Profile, ProfileInstance>;
|
|
17
|
+
sharesDataWith: ModelRelatedNodesI<typeof Profile, ProfileInstance>;
|
|
17
18
|
relatedTo: ModelRelatedNodesI<typeof Boost, BoostInstance>;
|
|
18
19
|
requestedFor: ModelRelatedNodesI<
|
|
19
20
|
typeof Profile,
|
|
20
21
|
ProfileInstance,
|
|
21
22
|
{
|
|
22
|
-
status: 'pending' | 'accepted' | 'denied';
|
|
23
|
+
status: 'pending' | 'accepted' | 'denied' | 'cancelled';
|
|
24
|
+
requestId?: string;
|
|
25
|
+
requestedBy?: string;
|
|
26
|
+
externalReferenceId?: string;
|
|
27
|
+
message?: string;
|
|
28
|
+
requestedAt?: string;
|
|
23
29
|
readStatus?: 'unseen' | 'seen' | null;
|
|
24
30
|
},
|
|
25
31
|
{
|
|
26
|
-
status: 'pending' | 'accepted' | 'denied';
|
|
32
|
+
status: 'pending' | 'accepted' | 'denied' | 'cancelled';
|
|
33
|
+
requestId?: string;
|
|
34
|
+
requestedBy?: string;
|
|
35
|
+
externalReferenceId?: string;
|
|
36
|
+
message?: string;
|
|
37
|
+
requestedAt?: string;
|
|
27
38
|
readStatus?: 'unseen' | 'seen' | null;
|
|
28
39
|
}
|
|
29
40
|
>;
|
|
@@ -47,6 +58,8 @@ export const ConsentFlowContract = ModelFactory<FlatDbContractType, ConsentFlowR
|
|
|
47
58
|
createdAt: { type: 'string', required: true },
|
|
48
59
|
updatedAt: { type: 'string', required: true },
|
|
49
60
|
expiresAt: { type: 'string', required: false },
|
|
61
|
+
audienceVersion: { type: 'number', required: false },
|
|
62
|
+
hasConsented: { type: 'boolean', required: false },
|
|
50
63
|
} as any,
|
|
51
64
|
relationships: {
|
|
52
65
|
createdBy: { model: Profile, direction: 'out', name: 'CREATED_BY' },
|
|
@@ -70,17 +83,35 @@ export const ConsentFlowContract = ModelFactory<FlatDbContractType, ConsentFlowR
|
|
|
70
83
|
},
|
|
71
84
|
},
|
|
72
85
|
canWrite: { model: Profile, direction: 'out', name: 'CAN_WRITE' },
|
|
86
|
+
sharesDataWith: { model: Profile, direction: 'out', name: 'SHARES_DATA_WITH' },
|
|
73
87
|
relatedTo: { model: Boost, direction: 'out', name: 'RELATED_TO' },
|
|
74
88
|
requestedFor: {
|
|
75
89
|
model: Profile,
|
|
76
90
|
direction: 'out',
|
|
77
91
|
name: 'REQUESTED_FOR',
|
|
78
92
|
properties: {
|
|
93
|
+
requestId: {
|
|
94
|
+
property: 'requestId',
|
|
95
|
+
schema: { type: 'string', required: false },
|
|
96
|
+
},
|
|
97
|
+
requestedBy: {
|
|
98
|
+
property: 'requestedBy',
|
|
99
|
+
schema: { type: 'string', required: false },
|
|
100
|
+
},
|
|
101
|
+
externalReferenceId: {
|
|
102
|
+
property: 'externalReferenceId',
|
|
103
|
+
schema: { type: 'string', required: false },
|
|
104
|
+
},
|
|
105
|
+
message: { property: 'message', schema: { type: 'string', required: false } },
|
|
106
|
+
requestedAt: {
|
|
107
|
+
property: 'requestedAt',
|
|
108
|
+
schema: { type: 'string', required: false },
|
|
109
|
+
},
|
|
79
110
|
status: {
|
|
80
111
|
property: 'status',
|
|
81
112
|
schema: {
|
|
82
113
|
type: 'string',
|
|
83
|
-
enum: ['pending', 'accepted', 'denied'],
|
|
114
|
+
enum: ['pending', 'accepted', 'denied', 'cancelled'],
|
|
84
115
|
required: false,
|
|
85
116
|
},
|
|
86
117
|
},
|
|
@@ -19,10 +19,20 @@ export const ConsentFlowTerms = ModelFactory<FlatDbTermsType, ConsentFlowTermsRe
|
|
|
19
19
|
{
|
|
20
20
|
label: 'ConsentFlowTerms',
|
|
21
21
|
schema: {
|
|
22
|
+
smartResumeFingerprint: { type: 'string', required: false },
|
|
23
|
+
smartResumePublicationStatus: { type: 'string', required: false },
|
|
24
|
+
smartResumeLeaseId: { type: 'string', required: false },
|
|
25
|
+
smartResumeLeaseUntil: { type: 'number', required: false },
|
|
26
|
+
smartResumeMutationVersion: { type: 'number', required: false },
|
|
27
|
+
smartResumeRedirectUrl: { type: 'string', required: false },
|
|
22
28
|
id: { type: 'string', required: true },
|
|
29
|
+
'referral.requestId': { type: 'string', required: false },
|
|
30
|
+
'referral.requestedBy': { type: 'string', required: false },
|
|
31
|
+
'referral.externalReferenceId': { type: 'string', required: false },
|
|
23
32
|
status: { type: 'string', required: true },
|
|
24
33
|
createdAt: { type: 'string', required: false },
|
|
25
34
|
updatedAt: { type: 'string', required: false },
|
|
35
|
+
mutationVersion: { type: 'number', required: false },
|
|
26
36
|
expiresAt: { type: 'string', required: false },
|
|
27
37
|
oneTime: { type: 'boolean', required: false },
|
|
28
38
|
deniedWriters: { type: 'string[]', required: false },
|
|
@@ -21,6 +21,9 @@ export const ConsentFlowTransaction = ModelFactory<
|
|
|
21
21
|
label: 'ConsentFlowTransaction',
|
|
22
22
|
schema: {
|
|
23
23
|
id: { type: 'string', required: true },
|
|
24
|
+
'referral.requestId': { type: 'string', required: false },
|
|
25
|
+
'referral.requestedBy': { type: 'string', required: false },
|
|
26
|
+
'referral.externalReferenceId': { type: 'string', required: false },
|
|
24
27
|
status: { type: 'string', required: true },
|
|
25
28
|
expiresAt: { type: 'string', required: false },
|
|
26
29
|
oneTime: { type: 'boolean', required: false },
|
|
@@ -3,11 +3,13 @@ import { ModelFactory, ModelRelatedNodesI, NeogmaInstance } from 'neogma';
|
|
|
3
3
|
import { neogma } from '@instance';
|
|
4
4
|
|
|
5
5
|
import { Profile, ProfileInstance } from './Profile';
|
|
6
|
+
import type { AppManifestVersion, AppManifestVersionInstance } from './AppManifestVersion';
|
|
6
7
|
import { FlatIntegrationType } from 'types/integration';
|
|
7
8
|
|
|
8
9
|
export type IntegrationRelationships = {
|
|
9
10
|
createdBy: ModelRelatedNodesI<typeof Profile, ProfileInstance>;
|
|
10
11
|
publishesListing: ModelRelatedNodesI<any, any>;
|
|
12
|
+
hasManifestVersion: ModelRelatedNodesI<typeof AppManifestVersion, AppManifestVersionInstance>;
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
export type IntegrationInstance = NeogmaInstance<FlatIntegrationType, IntegrationRelationships>;
|
|
@@ -9,8 +9,8 @@ export type PresentationRelationships = {
|
|
|
9
9
|
presentationReceived: ModelRelatedNodesI<
|
|
10
10
|
{ createOne: (typeof Profile)['createOne'] },
|
|
11
11
|
ProfileInstance,
|
|
12
|
-
{ from: string; date: string },
|
|
13
|
-
{ from: string; date: string }
|
|
12
|
+
{ from: string; date: string; metadata?: Record<string, unknown> },
|
|
13
|
+
{ from: string; date: string; metadata?: Record<string, unknown> }
|
|
14
14
|
>;
|
|
15
15
|
};
|
|
16
16
|
|
package/src/models/Profile.ts
CHANGED
|
@@ -75,8 +75,8 @@ export type ProfileRelationships = {
|
|
|
75
75
|
presentationSent: ModelRelatedNodesI<
|
|
76
76
|
typeof Presentation,
|
|
77
77
|
PresentationInstance,
|
|
78
|
-
{ to: string; date: string },
|
|
79
|
-
{ to: string; date: string }
|
|
78
|
+
{ to: string; date: string; metadata?: Record<string, unknown> },
|
|
79
|
+
{ to: string; date: string; metadata?: Record<string, unknown> }
|
|
80
80
|
>;
|
|
81
81
|
usesSigningAuthority: ModelRelatedNodesI<
|
|
82
82
|
typeof SigningAuthority,
|
|
@@ -238,6 +238,7 @@ export const Profile: any = ModelFactory<FlatProfileType, ProfileRelationships>(
|
|
|
238
238
|
properties: {
|
|
239
239
|
to: { property: 'to', schema: { type: 'string', required: true } },
|
|
240
240
|
date: { property: 'date', schema: { type: 'string', required: true } },
|
|
241
|
+
metadata: { property: 'metadata', schema: { type: 'object', required: false } },
|
|
241
242
|
},
|
|
242
243
|
},
|
|
243
244
|
usesSigningAuthority: {
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { ModelFactory, NeogmaInstance } from 'neogma';
|
|
2
|
+
|
|
3
|
+
import { neogma } from '@instance';
|
|
4
|
+
|
|
5
|
+
/** Lifecycle status of a share. Only `active` is ever served to a recipient. */
|
|
6
|
+
export type ShareLinkStatus = 'pending' | 'active' | 'stopped';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Whether the visible content pointer for a share is committed.
|
|
10
|
+
*
|
|
11
|
+
* `staging` means a reservation exists but the object is not visible yet;
|
|
12
|
+
* `content_missing` means Brain believes content should be visible but LearnCloud
|
|
13
|
+
* does not have it, so the share fails closed and is never served.
|
|
14
|
+
*/
|
|
15
|
+
export type ShareContentState = 'staging' | 'finalized' | 'content_missing';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Persisted ShareLink metadata (LC-2187).
|
|
19
|
+
*
|
|
20
|
+
* This node is the only Brain-side source of truth for the *visible* content
|
|
21
|
+
* pointer. It stores an opaque immutable `activeObjectRef` plus content/recovery
|
|
22
|
+
* hashes and byte counts — never ciphertext, a raw private source URI or a key.
|
|
23
|
+
* The concrete encrypted envelope and owner recovery JWE live together in the
|
|
24
|
+
* dedicated LearnCloud collection keyed by the immutable object reference.
|
|
25
|
+
*
|
|
26
|
+
* `version` is the committed record revision used for optimistic concurrency; a
|
|
27
|
+
* reservation (`staging`) does not change it. `contentVersion` is the visible
|
|
28
|
+
* content revision and changes only when a replacement is finalized.
|
|
29
|
+
*/
|
|
30
|
+
export type ShareLinkRecord = {
|
|
31
|
+
id: string;
|
|
32
|
+
namespace: string;
|
|
33
|
+
ownerProfileId: string;
|
|
34
|
+
version: number;
|
|
35
|
+
contentVersion: number;
|
|
36
|
+
attachmentId?: string | null;
|
|
37
|
+
attachmentChunkCount?: number | null;
|
|
38
|
+
/**
|
|
39
|
+
* Monotonic fence. Bumped on every reservation and on revoke; a worker may
|
|
40
|
+
* only finalize the reservation whose generation still equals this value.
|
|
41
|
+
*/
|
|
42
|
+
generation: number;
|
|
43
|
+
status: ShareLinkStatus;
|
|
44
|
+
contentState: ShareContentState;
|
|
45
|
+
activeObjectRef: string | null;
|
|
46
|
+
activeObjectOperationId: string | null;
|
|
47
|
+
activeContentHash: string | null;
|
|
48
|
+
activeContentBytes: number | null;
|
|
49
|
+
activeRecoveryHash: string | null;
|
|
50
|
+
/** Operation binding: the operation id that produced the visible revision. */
|
|
51
|
+
lastOperationId: string | null;
|
|
52
|
+
/** Operation binding: the create request that first bound this share id. */
|
|
53
|
+
createdByClientRequestId: string | null;
|
|
54
|
+
title: string;
|
|
55
|
+
note: string | null;
|
|
56
|
+
selectedCount: number;
|
|
57
|
+
expiresAt: string | null;
|
|
58
|
+
stoppedAt: string | null;
|
|
59
|
+
viewCount: number;
|
|
60
|
+
lastViewedAt: string | null;
|
|
61
|
+
/** Argon2id PHC string. Plaintext passcodes are never persisted. */
|
|
62
|
+
passcodeHash?: string | null;
|
|
63
|
+
notifyOnView?: boolean;
|
|
64
|
+
minorPolicyIsMinor: boolean | null;
|
|
65
|
+
minorPolicyResolved: boolean;
|
|
66
|
+
minorPolicyDefaultExpiryDays: number;
|
|
67
|
+
minorPolicyViewCountingEnabled: boolean;
|
|
68
|
+
createdAt: string;
|
|
69
|
+
updatedAt: string;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** Neo4j omits null properties; the repository maps missing values back to null. */
|
|
73
|
+
type ShareLinkProperties = { lockTick?: number } & {
|
|
74
|
+
[Key in keyof ShareLinkRecord]:
|
|
75
|
+
| Exclude<ShareLinkRecord[Key], null>
|
|
76
|
+
| (null extends ShareLinkRecord[Key] ? undefined : never);
|
|
77
|
+
};
|
|
78
|
+
export type ShareLinkInstance = NeogmaInstance<ShareLinkProperties, Record<string, never>>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* `:ShareLink` model registration. The repository writes this label with raw
|
|
82
|
+
* parameterized Cypher so it can hold the share write lock across read + write
|
|
83
|
+
* within one transaction; the model exists for schema/typed instance support and
|
|
84
|
+
* constraint registration.
|
|
85
|
+
*/
|
|
86
|
+
export const ShareLink = ModelFactory<ShareLinkProperties, Record<string, never>>(
|
|
87
|
+
{
|
|
88
|
+
label: 'ShareLink',
|
|
89
|
+
schema: {
|
|
90
|
+
id: { type: 'string', required: true },
|
|
91
|
+
namespace: { type: 'string', required: true },
|
|
92
|
+
ownerProfileId: { type: 'string', required: true },
|
|
93
|
+
version: { type: 'number', required: true },
|
|
94
|
+
contentVersion: { type: 'number', required: true },
|
|
95
|
+
attachmentId: { type: 'string', required: false },
|
|
96
|
+
attachmentChunkCount: { type: 'number', required: false },
|
|
97
|
+
generation: { type: 'number', required: true },
|
|
98
|
+
status: { type: 'string', required: true, enum: ['pending', 'active', 'stopped'] },
|
|
99
|
+
contentState: {
|
|
100
|
+
type: 'string',
|
|
101
|
+
required: true,
|
|
102
|
+
enum: ['staging', 'finalized', 'content_missing'],
|
|
103
|
+
},
|
|
104
|
+
activeObjectRef: { type: 'string', required: false },
|
|
105
|
+
activeObjectOperationId: { type: 'string', required: false },
|
|
106
|
+
activeContentHash: { type: 'string', required: false },
|
|
107
|
+
activeContentBytes: { type: 'number', required: false },
|
|
108
|
+
activeRecoveryHash: { type: 'string', required: false },
|
|
109
|
+
lastOperationId: { type: 'string', required: false },
|
|
110
|
+
createdByClientRequestId: { type: 'string', required: false },
|
|
111
|
+
title: { type: 'string', required: true },
|
|
112
|
+
note: { type: 'string', required: false },
|
|
113
|
+
selectedCount: { type: 'number', required: true },
|
|
114
|
+
expiresAt: { type: 'string', required: false },
|
|
115
|
+
stoppedAt: { type: 'string', required: false },
|
|
116
|
+
viewCount: { type: 'number', required: true },
|
|
117
|
+
lastViewedAt: { type: 'string', required: false },
|
|
118
|
+
passcodeHash: { type: 'string', required: false },
|
|
119
|
+
// LC-2187 records created before opt-in alerts may omit this field.
|
|
120
|
+
notifyOnView: { type: 'boolean', required: false },
|
|
121
|
+
minorPolicyIsMinor: { type: 'boolean', required: false },
|
|
122
|
+
minorPolicyResolved: { type: 'boolean', required: true },
|
|
123
|
+
minorPolicyDefaultExpiryDays: { type: 'number', required: true },
|
|
124
|
+
minorPolicyViewCountingEnabled: { type: 'boolean', required: true },
|
|
125
|
+
createdAt: { type: 'string', required: true },
|
|
126
|
+
updatedAt: { type: 'string', required: true },
|
|
127
|
+
lockTick: { type: 'number', required: false },
|
|
128
|
+
},
|
|
129
|
+
primaryKeyField: 'id',
|
|
130
|
+
},
|
|
131
|
+
neogma
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
export default ShareLink;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ModelFactory, NeogmaInstance } from 'neogma';
|
|
2
|
+
|
|
3
|
+
import { neogma } from '@instance';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Persisted, short-lived view receipt (LC-2187 ADR-10).
|
|
7
|
+
*
|
|
8
|
+
* Only the hash of the opaque CSPRNG token is stored — never the token, a viewer
|
|
9
|
+
* identity, an IP, a fingerprint, a credential, a key or any request body. The
|
|
10
|
+
* node is bound to one immutable committed tuple
|
|
11
|
+
* `(namespace, ownerProfileId, shareId, contentVersion, objectRef, operationId)`
|
|
12
|
+
* so a receipt for a superseded revision can never count toward the current one.
|
|
13
|
+
*
|
|
14
|
+
* `consumedAt` is the single-use marker; `lockTick` exists only so a transaction
|
|
15
|
+
* can take a write lock on the receipt AFTER it holds the share write lock.
|
|
16
|
+
* `expiresAt` bounds retention and is indexed for one-shot pruning.
|
|
17
|
+
*/
|
|
18
|
+
export type ShareViewReceiptRecord = {
|
|
19
|
+
receiptHash: string;
|
|
20
|
+
namespace: string;
|
|
21
|
+
ownerProfileId: string;
|
|
22
|
+
shareId: string;
|
|
23
|
+
contentVersion: number;
|
|
24
|
+
objectRef: string;
|
|
25
|
+
operationId: string;
|
|
26
|
+
createdAt: string;
|
|
27
|
+
expiresAt: string;
|
|
28
|
+
consumedAt: string | null;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type ShareViewReceiptProperties = { lockTick?: number } & {
|
|
32
|
+
[Key in keyof ShareViewReceiptRecord]:
|
|
33
|
+
| Exclude<ShareViewReceiptRecord[Key], null>
|
|
34
|
+
| (null extends ShareViewReceiptRecord[Key] ? undefined : never);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type ShareViewReceiptInstance = NeogmaInstance<
|
|
38
|
+
ShareViewReceiptProperties,
|
|
39
|
+
Record<string, never>
|
|
40
|
+
>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* `:ShareViewReceipt` model registration. The repository writes this label with
|
|
44
|
+
* raw parameterized Cypher so consume + increment happen in one transaction with
|
|
45
|
+
* explicit share-then-receipt lock ordering; the model exists for schema and
|
|
46
|
+
* constraint registration.
|
|
47
|
+
*/
|
|
48
|
+
export const ShareViewReceipt = ModelFactory<ShareViewReceiptProperties, Record<string, never>>(
|
|
49
|
+
{
|
|
50
|
+
label: 'ShareViewReceipt',
|
|
51
|
+
schema: {
|
|
52
|
+
receiptHash: { type: 'string', required: true },
|
|
53
|
+
namespace: { type: 'string', required: true },
|
|
54
|
+
ownerProfileId: { type: 'string', required: true },
|
|
55
|
+
shareId: { type: 'string', required: true },
|
|
56
|
+
contentVersion: { type: 'number', required: true },
|
|
57
|
+
objectRef: { type: 'string', required: true },
|
|
58
|
+
operationId: { type: 'string', required: true },
|
|
59
|
+
createdAt: { type: 'string', required: true },
|
|
60
|
+
expiresAt: { type: 'string', required: true },
|
|
61
|
+
consumedAt: { type: 'string', required: false },
|
|
62
|
+
lockTick: { type: 'number', required: false },
|
|
63
|
+
},
|
|
64
|
+
primaryKeyField: 'receiptHash',
|
|
65
|
+
},
|
|
66
|
+
neogma
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export default ShareViewReceipt;
|
package/src/models/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { environment } from '@environment';
|
|
2
2
|
import { neogma } from '@instance';
|
|
3
|
+
import { contractEventMaintenanceSchema } from '@helpers/contract-event-maintenance.helpers';
|
|
3
4
|
|
|
4
5
|
import { Boost } from './Boost';
|
|
5
6
|
import { Profile } from './Profile';
|
|
@@ -11,6 +12,7 @@ import { Skill } from './Skill';
|
|
|
11
12
|
import { Tag } from './Tag';
|
|
12
13
|
import { AppStoreListing } from './AppStoreListing';
|
|
13
14
|
import { Integration } from './Integration';
|
|
15
|
+
import { AppManifestVersion } from './AppManifestVersion';
|
|
14
16
|
import { CredentialActivity } from './CredentialActivity';
|
|
15
17
|
import { CredentialRefresh } from './CredentialRefresh';
|
|
16
18
|
import { StatusList } from './StatusList';
|
|
@@ -69,6 +71,7 @@ Presentation.addRelationships({
|
|
|
69
71
|
properties: {
|
|
70
72
|
from: { property: 'from', schema: { type: 'string', required: true } },
|
|
71
73
|
date: { property: 'date', schema: { type: 'string', required: true } },
|
|
74
|
+
metadata: { property: 'metadata', schema: { type: 'object', required: false } },
|
|
72
75
|
},
|
|
73
76
|
},
|
|
74
77
|
});
|
|
@@ -91,6 +94,19 @@ Integration.addRelationships({
|
|
|
91
94
|
direction: 'out',
|
|
92
95
|
name: 'PUBLISHES_LISTING',
|
|
93
96
|
},
|
|
97
|
+
hasManifestVersion: {
|
|
98
|
+
model: AppManifestVersion,
|
|
99
|
+
direction: 'out',
|
|
100
|
+
name: 'HAS_MANIFEST_VERSION',
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
AppStoreListing.addRelationships({
|
|
105
|
+
usesManifestVersion: {
|
|
106
|
+
model: AppManifestVersion,
|
|
107
|
+
direction: 'out',
|
|
108
|
+
name: 'USES_MANIFEST_VERSION',
|
|
109
|
+
},
|
|
94
110
|
});
|
|
95
111
|
|
|
96
112
|
Profile.addRelationships({
|
|
@@ -127,6 +143,9 @@ const shouldCreateIndices =
|
|
|
127
143
|
environment.NODE_ENV === 'production' || !environment.NEO4J_SKIP_INDICES;
|
|
128
144
|
|
|
129
145
|
const indexQueries = [
|
|
146
|
+
'CREATE CONSTRAINT consent_event_id IF NOT EXISTS FOR (e:ConsentFlowEvent) REQUIRE e.id IS UNIQUE',
|
|
147
|
+
'CREATE CONSTRAINT consent_delivery_id IF NOT EXISTS FOR (d:ConsentFlowEventDelivery) REQUIRE d.id IS UNIQUE',
|
|
148
|
+
...contractEventMaintenanceSchema,
|
|
130
149
|
'CREATE INDEX profileId_idx IF NOT EXISTS FOR (p:Profile) ON (p.profileId)',
|
|
131
150
|
'CREATE INDEX profile_did_idx IF NOT EXISTS FOR (p:Profile) ON (p.did)',
|
|
132
151
|
'CREATE TEXT INDEX profileId_text_idx IF NOT EXISTS FOR (n:Profile) ON (n.profileId)',
|
|
@@ -151,6 +170,10 @@ const indexQueries = [
|
|
|
151
170
|
'CREATE INDEX claim_hook_updated_idx IF NOT EXISTS FOR (c:ClaimHook) ON (c.updatedAt)',
|
|
152
171
|
'CREATE INDEX integration_id_idx IF NOT EXISTS FOR (i:Integration) ON (i.id)',
|
|
153
172
|
'CREATE INDEX integration_publishablekey_idx IF NOT EXISTS FOR (i:Integration) ON (i.publishableKey)',
|
|
173
|
+
'CREATE INDEX app_manifest_version_id_idx IF NOT EXISTS FOR (m:AppManifestVersion) ON (m.id)',
|
|
174
|
+
'CREATE INDEX app_manifest_version_version_idx IF NOT EXISTS FOR (m:AppManifestVersion) ON (m.version)',
|
|
175
|
+
'CREATE INDEX app_manifest_version_hash_idx IF NOT EXISTS FOR (m:AppManifestVersion) ON (m.manifestHash)',
|
|
176
|
+
'CREATE INDEX app_manifest_version_status_idx IF NOT EXISTS FOR (m:AppManifestVersion) ON (m.status)',
|
|
154
177
|
'CREATE INDEX skill_framework_id_idx IF NOT EXISTS FOR (f:SkillFramework) ON (f.id)',
|
|
155
178
|
'CREATE TEXT INDEX skill_framework_name_text_idx IF NOT EXISTS FOR (f:SkillFramework) ON (f.name)',
|
|
156
179
|
'CREATE INDEX skill_id_idx IF NOT EXISTS FOR (s:Skill) ON (s.id)',
|
|
@@ -253,7 +276,9 @@ export * from './SkillFramework';
|
|
|
253
276
|
export * from './Skill';
|
|
254
277
|
export * from './Tag';
|
|
255
278
|
export * from './Integration';
|
|
279
|
+
export * from './AppManifestVersion';
|
|
256
280
|
export * from './AppStoreListing';
|
|
257
281
|
export * from './CredentialActivity';
|
|
258
282
|
export * from './CredentialRefresh';
|
|
283
|
+
export * from './ShareLink';
|
|
259
284
|
export * from './StatusList';
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { neogma } from '@instance';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Uniqueness rules required for the LC-2187 share lifecycle.
|
|
5
|
+
*
|
|
6
|
+
* A uniqueness constraint alone does not serialize two transactions consuming one
|
|
7
|
+
* reservation; the repository additionally holds a `:ShareLink` write lock before
|
|
8
|
+
* reading status/version/reservation state. These rules are the hard backstop that
|
|
9
|
+
* makes the resulting race fail closed instead of forking state.
|
|
10
|
+
*/
|
|
11
|
+
const SHARE_LINK_CONSTRAINT_QUERIES = [
|
|
12
|
+
'CREATE CONSTRAINT share_link_attachment_stage_key_unique IF NOT EXISTS FOR (a:ShareLinkAttachmentStage) REQUIRE (a.key) IS UNIQUE',
|
|
13
|
+
'CREATE CONSTRAINT share_link_attachment_id_unique IF NOT EXISTS FOR (a:ShareLinkAttachmentStage) REQUIRE (a.attachmentId) IS UNIQUE',
|
|
14
|
+
'CREATE CONSTRAINT share_attachment_owner_quota_key_unique IF NOT EXISTS FOR (q:ShareAttachmentOwnerQuota) REQUIRE (q.key) IS UNIQUE',
|
|
15
|
+
// A share id is globally unique across namespaces.
|
|
16
|
+
'CREATE CONSTRAINT share_link_id_unique IF NOT EXISTS FOR (s:ShareLink) REQUIRE (s.id) IS UNIQUE',
|
|
17
|
+
// One idempotency record per (namespace, owner, operation kind, client request).
|
|
18
|
+
'CREATE CONSTRAINT share_link_operation_key_unique IF NOT EXISTS FOR (o:ShareLinkOperation) REQUIRE (o.namespace, o.ownerProfileId, o.opKind, o.clientRequestId) IS UNIQUE',
|
|
19
|
+
// At most one in-flight reservation per share.
|
|
20
|
+
'CREATE CONSTRAINT share_link_reservation_share_unique IF NOT EXISTS FOR (r:ShareLinkReservation) REQUIRE (r.shareId) IS UNIQUE',
|
|
21
|
+
// Cleanup is bound to exactly one immutable object reference.
|
|
22
|
+
'CREATE CONSTRAINT share_content_cleanup_object_unique IF NOT EXISTS FOR (c:ShareContentCleanupJob) REQUIRE (c.objectRef) IS UNIQUE',
|
|
23
|
+
// One persisted receipt node per opaque token hash (the token itself is never stored).
|
|
24
|
+
'CREATE CONSTRAINT share_view_receipt_hash_unique IF NOT EXISTS FOR (v:ShareViewReceipt) REQUIRE (v.receiptHash) IS UNIQUE',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Non-unique indexes that keep the lifecycle queries bounded. Index creation is
|
|
29
|
+
* idempotent and shares the same readiness gate as the constraints.
|
|
30
|
+
*/
|
|
31
|
+
const SHARE_LINK_INDEX_QUERIES = [
|
|
32
|
+
'CREATE INDEX share_attachment_stage_owner_idx IF NOT EXISTS FOR (a:ShareLinkAttachmentStage) ON (a.namespace, a.ownerProfileId, a.status)',
|
|
33
|
+
'CREATE INDEX share_attachment_stage_expiry_idx IF NOT EXISTS FOR (a:ShareLinkAttachmentStage) ON (a.namespace, a.status, a.expiresAt)',
|
|
34
|
+
'CREATE INDEX share_link_ns_owner_idx IF NOT EXISTS FOR (s:ShareLink) ON (s.namespace, s.ownerProfileId)',
|
|
35
|
+
// Bounded owner-list keyset pagination: filters on the leading
|
|
36
|
+
// (namespace, ownerProfileId) prefix and orders by the immutable
|
|
37
|
+
// (createdAt, id) key without a full scan/sort.
|
|
38
|
+
'CREATE INDEX share_link_ns_owner_created_idx IF NOT EXISTS FOR (s:ShareLink) ON (s.namespace, s.ownerProfileId, s.createdAt, s.id)',
|
|
39
|
+
'CREATE INDEX share_link_status_idx IF NOT EXISTS FOR (s:ShareLink) ON (s.status)',
|
|
40
|
+
'CREATE INDEX share_link_operation_operation_id_idx IF NOT EXISTS FOR (o:ShareLinkOperation) ON (o.operationId)',
|
|
41
|
+
'CREATE INDEX share_link_operation_share_id_idx IF NOT EXISTS FOR (o:ShareLinkOperation) ON (o.shareId)',
|
|
42
|
+
'CREATE INDEX share_link_reservation_lease_idx IF NOT EXISTS FOR (r:ShareLinkReservation) ON (r.leaseExpiresAt)',
|
|
43
|
+
// Bounded recovery discovery enumerates expired reservations for one namespace.
|
|
44
|
+
'CREATE INDEX share_link_reservation_ns_lease_idx IF NOT EXISTS FOR (r:ShareLinkReservation) ON (r.namespace, r.leaseExpiresAt)',
|
|
45
|
+
'CREATE INDEX share_content_cleanup_due_idx IF NOT EXISTS FOR (c:ShareContentCleanupJob) ON (c.status, c.nextAttemptAt)',
|
|
46
|
+
// One-shot receipt pruning is bounded by expiry/consumed state.
|
|
47
|
+
'CREATE INDEX share_view_receipt_expiry_idx IF NOT EXISTS FOR (v:ShareViewReceipt) ON (v.expiresAt)',
|
|
48
|
+
'CREATE INDEX share_view_receipt_share_idx IF NOT EXISTS FOR (v:ShareViewReceipt) ON (v.namespace, v.shareId)',
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
type Neo4jSchemaError = {
|
|
52
|
+
code?: string;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const isEquivalentSchemaRuleRace = (error: unknown): boolean =>
|
|
56
|
+
(error as Neo4jSchemaError | undefined)?.code ===
|
|
57
|
+
'Neo.ClientError.Schema.EquivalentSchemaRuleAlreadyExists';
|
|
58
|
+
|
|
59
|
+
const createShareLinkSchema = async (): Promise<void> => {
|
|
60
|
+
for (const query of [...SHARE_LINK_CONSTRAINT_QUERIES, ...SHARE_LINK_INDEX_QUERIES]) {
|
|
61
|
+
try {
|
|
62
|
+
await neogma.queryRunner.run(query);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
// Concurrent service starts can both observe a missing rule before one
|
|
65
|
+
// wins creation. The losing CREATE is equivalent to the desired ready state.
|
|
66
|
+
if (!isEquivalentSchemaRuleRace(error)) throw error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
let constraintReadiness: Promise<void> | undefined;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Ensures the uniqueness rules and indexes required for the share lifecycle.
|
|
75
|
+
*
|
|
76
|
+
* Every public repository method awaits this before its transaction, so a caller
|
|
77
|
+
* can never observe the "constraints not initialized" window. Concurrent callers
|
|
78
|
+
* share one attempt; a failed attempt is cleared so a later request can retry
|
|
79
|
+
* instead of leaving the repository permanently unavailable.
|
|
80
|
+
*/
|
|
81
|
+
export const ensureShareLinkConstraints = (): Promise<void> => {
|
|
82
|
+
if (!constraintReadiness) {
|
|
83
|
+
const pendingReadiness = createShareLinkSchema();
|
|
84
|
+
constraintReadiness = pendingReadiness;
|
|
85
|
+
|
|
86
|
+
void pendingReadiness.catch(() => {
|
|
87
|
+
if (constraintReadiness === pendingReadiness) constraintReadiness = undefined;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return constraintReadiness;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/** Exposed for focused tests that assert the exact schema statements. */
|
|
95
|
+
export const SHARE_LINK_SCHEMA_QUERIES = [
|
|
96
|
+
...SHARE_LINK_CONSTRAINT_QUERIES,
|
|
97
|
+
...SHARE_LINK_INDEX_QUERIES,
|
|
98
|
+
] as const;
|
package/src/openapi.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { generateOpenApiDocument } from 'trpc-to-openapi';
|
|
2
|
-
import express
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import type { Express } from 'express';
|
|
3
4
|
|
|
4
5
|
import { appRouter } from './app';
|
|
5
6
|
|
|
@@ -43,20 +44,55 @@ if (publishRequestBody && !('$ref' in publishRequestBody)) {
|
|
|
43
44
|
const publishSchema = publishRequestBody.content?.['application/json']?.schema;
|
|
44
45
|
|
|
45
46
|
if (publishSchema && !('$ref' in publishSchema)) {
|
|
47
|
+
const properties = publishSchema.properties;
|
|
48
|
+
const signedCredential = properties?.signedCredential;
|
|
49
|
+
const credential = properties?.credential;
|
|
50
|
+
const signingAuthority = properties?.signingAuthority;
|
|
51
|
+
|
|
52
|
+
if (!properties?.refreshId || !signedCredential || !credential || !signingAuthority) {
|
|
53
|
+
throw new Error('Managed refresh publication schema is missing required properties');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const commonProperties = {
|
|
57
|
+
refreshId: properties.refreshId,
|
|
58
|
+
notifyHolder: properties.notifyHolder!,
|
|
59
|
+
updateSummary: properties.updateSummary!,
|
|
60
|
+
idempotencyKey: properties.idempotencyKey!,
|
|
61
|
+
};
|
|
62
|
+
// Generator 7.25.0 loses the OpenAPI 3.1 closed-object flag. Keep the
|
|
63
|
+
// template workaround scoped to these mutually exclusive request branches.
|
|
64
|
+
const closedPublicationBranch = {
|
|
65
|
+
additionalProperties: false,
|
|
66
|
+
'x-python-forbid-extra': true,
|
|
67
|
+
} as const;
|
|
68
|
+
|
|
69
|
+
// Each branch must own its complete shape. Generators do not inherit the
|
|
70
|
+
// parent's properties into oneOf branches; enum also works in the pinned generator.
|
|
46
71
|
publishSchema.oneOf = [
|
|
47
72
|
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
73
|
+
type: 'object',
|
|
74
|
+
properties: {
|
|
75
|
+
...commonProperties,
|
|
76
|
+
mode: { type: 'string', enum: ['issuer-signed'] },
|
|
77
|
+
signedCredential,
|
|
52
78
|
},
|
|
79
|
+
required: ['refreshId', 'mode', 'signedCredential'],
|
|
80
|
+
...closedPublicationBranch,
|
|
53
81
|
},
|
|
54
82
|
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: {
|
|
85
|
+
...commonProperties,
|
|
86
|
+
mode: { type: 'string', enum: ['signing-authority'] },
|
|
87
|
+
credential,
|
|
88
|
+
signingAuthority,
|
|
89
|
+
},
|
|
90
|
+
required: ['refreshId', 'mode', 'credential', 'signingAuthority'],
|
|
91
|
+
...closedPublicationBranch,
|
|
58
92
|
},
|
|
59
93
|
];
|
|
94
|
+
delete publishSchema.properties;
|
|
95
|
+
delete publishSchema.required;
|
|
60
96
|
}
|
|
61
97
|
}
|
|
62
98
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { FastifyInstance } from 'fastify';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* LC-2187 public share-link HTTP adapter seam.
|
|
5
|
+
*
|
|
6
|
+
* The Fastify OpenAPI adapter has no `responseMeta` hook, so the no-store
|
|
7
|
+
* contract for the anonymous public share-link routes is applied at the adapter
|
|
8
|
+
* boundary itself. This module is deliberately free of the server bootstrap
|
|
9
|
+
* (which listens on import) so a real Fastify instance can be exercised in
|
|
10
|
+
* tests without starting the application.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Prefixes that identify a mounted public share-link OpenAPI request.
|
|
15
|
+
*
|
|
16
|
+
* The trpc-to-openapi Fastify adapter rewrites `request.raw.url` by stripping
|
|
17
|
+
* its `/api` base path before the handler runs, so the `onSend` hook sees
|
|
18
|
+
* `/public/share-links/...` even though the client requested
|
|
19
|
+
* `/api/public/share-links/...`. Both forms are matched (with a path-boundary
|
|
20
|
+
* check) so a sibling route such as `/public/share-links-other` is not treated
|
|
21
|
+
* as public.
|
|
22
|
+
*/
|
|
23
|
+
const PUBLIC_SHARE_LINK_PREFIXES = ['/api/public/share-links', '/public/share-links'] as const;
|
|
24
|
+
|
|
25
|
+
/** True for the mounted public share-link OpenAPI route prefix only. */
|
|
26
|
+
export const isPublicShareLinkOpenApiRequestUrl = (url: string | undefined): boolean => {
|
|
27
|
+
if (!url) return false;
|
|
28
|
+
|
|
29
|
+
const path = url.split('?')[0] ?? '';
|
|
30
|
+
|
|
31
|
+
return PUBLIC_SHARE_LINK_PREFIXES.some(
|
|
32
|
+
prefix => path === prefix || path.startsWith(`${prefix}/`)
|
|
33
|
+
);
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Installs the adapter-boundary `Cache-Control: private, no-store` on every
|
|
38
|
+
* public share-link OpenAPI response, independent of any upstream cache layer.
|
|
39
|
+
* It is safe to register on any Fastify instance (tRPC-only test apps included).
|
|
40
|
+
*/
|
|
41
|
+
export const registerPublicShareLinkNoStore = (app: FastifyInstance): void => {
|
|
42
|
+
app.addHook('onSend', async (request, reply, payload) => {
|
|
43
|
+
if (isPublicShareLinkOpenApiRequestUrl(request.raw.url)) {
|
|
44
|
+
reply.header('Cache-Control', 'private, no-store');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return payload;
|
|
48
|
+
});
|
|
49
|
+
};
|