@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
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { getProfileByProfileId } from '@accesslayer/profile/read';
|
|
2
|
+
import { isProfileManaged } from '@accesslayer/profile/relationships/read';
|
|
3
|
+
import type { ShareViewEligibilitySource } from '@accesslayer/share-link/types';
|
|
4
|
+
import type { ShareLinkTransaction } from '@accesslayer/share-link/transaction';
|
|
5
|
+
import {
|
|
6
|
+
isServiceProfileExemptFromGuardianship,
|
|
7
|
+
transformProfileId,
|
|
8
|
+
} from '@helpers/profile.helpers';
|
|
9
|
+
|
|
10
|
+
import { composeShareLinkPolicy } from './resolver';
|
|
11
|
+
import type { CurrentShareLinkPolicy, ShareLinkOwnerAge, ShareLinkPolicySource } from './types';
|
|
12
|
+
|
|
13
|
+
const ADULT_AGE = 18;
|
|
14
|
+
|
|
15
|
+
/** Classify persisted human age without inventing a birthdate for service profiles. */
|
|
16
|
+
export const ageFromPersistedProfile = (
|
|
17
|
+
profile: { dob?: unknown; type?: unknown } | null,
|
|
18
|
+
now: Date = new Date()
|
|
19
|
+
): ShareLinkOwnerAge => {
|
|
20
|
+
if (!profile) return 'unknown';
|
|
21
|
+
if (profile.type === 'child') return 'minor';
|
|
22
|
+
if (typeof profile.dob !== 'string' || !/^\d{4}-\d{2}-\d{2}$/.test(profile.dob)) {
|
|
23
|
+
return 'unknown';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const year = Number(profile.dob.slice(0, 4));
|
|
27
|
+
const month = Number(profile.dob.slice(5, 7));
|
|
28
|
+
const day = Number(profile.dob.slice(8, 10));
|
|
29
|
+
const birthday = new Date(Date.UTC(year, month - 1, day));
|
|
30
|
+
if (
|
|
31
|
+
birthday.getUTCFullYear() !== year ||
|
|
32
|
+
birthday.getUTCMonth() !== month - 1 ||
|
|
33
|
+
birthday.getUTCDate() !== day ||
|
|
34
|
+
birthday.getTime() > now.getTime()
|
|
35
|
+
) {
|
|
36
|
+
return 'unknown';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const age =
|
|
40
|
+
now.getUTCFullYear() -
|
|
41
|
+
year -
|
|
42
|
+
(now.getUTCMonth() + 1 < month ||
|
|
43
|
+
(now.getUTCMonth() + 1 === month && now.getUTCDate() < day)
|
|
44
|
+
? 1
|
|
45
|
+
: 0);
|
|
46
|
+
|
|
47
|
+
return age >= ADULT_AGE ? 'adult' : 'minor';
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Personal profiles require a valid persisted birthdate for tracking. Service
|
|
52
|
+
* profiles are age-exempt, but an explicit child type always keeps protections.
|
|
53
|
+
*/
|
|
54
|
+
export const createProductionShareLinkPolicySource = (): ShareLinkPolicySource => ({
|
|
55
|
+
resolveOwner: async profileId => {
|
|
56
|
+
const profile = await getProfileByProfileId(profileId);
|
|
57
|
+
const isServiceProfile = isServiceProfileExemptFromGuardianship(
|
|
58
|
+
profile?.isServiceProfile,
|
|
59
|
+
profile?.type
|
|
60
|
+
);
|
|
61
|
+
const isManaged = await isProfileManaged(profileId);
|
|
62
|
+
return {
|
|
63
|
+
age: ageFromPersistedProfile(profile),
|
|
64
|
+
isServiceProfile,
|
|
65
|
+
isManaged,
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
/** Read current eligibility within the share lock; no request values or network I/O. */
|
|
71
|
+
export const resolveCurrentShareLinkPolicy = async (
|
|
72
|
+
tx: ShareLinkTransaction,
|
|
73
|
+
ownerProfileId: string,
|
|
74
|
+
now: Date
|
|
75
|
+
): Promise<CurrentShareLinkPolicy> => {
|
|
76
|
+
const result = await tx.run(
|
|
77
|
+
`MATCH (p:Profile {profileId: $profileId})
|
|
78
|
+
OPTIONAL MATCH (p)-[:MANAGED_BY]->(directManager:Profile)
|
|
79
|
+
OPTIONAL MATCH (manager:ProfileManager)-[:MANAGES]->(p)
|
|
80
|
+
RETURN p.dob AS dob, p.type AS profileType,
|
|
81
|
+
p.isServiceProfile AS isServiceProfile,
|
|
82
|
+
(directManager IS NOT NULL OR manager IS NOT NULL) AS isManaged
|
|
83
|
+
LIMIT 1`,
|
|
84
|
+
{ profileId: transformProfileId(ownerProfileId) }
|
|
85
|
+
);
|
|
86
|
+
const record = result.records[0];
|
|
87
|
+
if (!record) return { ...composeShareLinkPolicy('unknown', true), isServiceProfile: false };
|
|
88
|
+
|
|
89
|
+
const profileType = record.get('profileType');
|
|
90
|
+
const isServiceProfile = isServiceProfileExemptFromGuardianship(
|
|
91
|
+
record.get('isServiceProfile'),
|
|
92
|
+
profileType
|
|
93
|
+
);
|
|
94
|
+
return {
|
|
95
|
+
...composeShareLinkPolicy(
|
|
96
|
+
ageFromPersistedProfile({ dob: record.get('dob'), type: profileType }, now),
|
|
97
|
+
record.get('isManaged') !== false,
|
|
98
|
+
isServiceProfile
|
|
99
|
+
),
|
|
100
|
+
isServiceProfile,
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const productionShareViewEligibilitySource: ShareViewEligibilitySource = {
|
|
105
|
+
isEligible: async (tx, input) =>
|
|
106
|
+
(await resolveCurrentShareLinkPolicy(tx, input.ownerProfileId, input.now))
|
|
107
|
+
.viewCountingEnabled,
|
|
108
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { DEFAULT_SHARE_LINK_POLICY } from './types';
|
|
2
|
+
import type {
|
|
3
|
+
ShareLinkOwnerAge,
|
|
4
|
+
ShareLinkPolicyResolver,
|
|
5
|
+
ShareLinkPolicySnapshot,
|
|
6
|
+
ShareLinkPolicySource,
|
|
7
|
+
} from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Pure policy decision table.
|
|
11
|
+
*
|
|
12
|
+
* - personal known minor, managed or unknown age => no views, 30 days
|
|
13
|
+
* - known unmanaged adult => views enabled, 365 days
|
|
14
|
+
* - service profile => views enabled without changing the age-derived expiry
|
|
15
|
+
*/
|
|
16
|
+
export const composeShareLinkPolicy = (
|
|
17
|
+
age: ShareLinkOwnerAge,
|
|
18
|
+
isManaged: boolean,
|
|
19
|
+
isServiceProfile = false
|
|
20
|
+
): ShareLinkPolicySnapshot => {
|
|
21
|
+
// Service age exemption does not establish that the owner is an adult.
|
|
22
|
+
const isMinor = isServiceProfile
|
|
23
|
+
? false
|
|
24
|
+
: age === 'minor'
|
|
25
|
+
? true
|
|
26
|
+
: age === 'adult'
|
|
27
|
+
? false
|
|
28
|
+
: null;
|
|
29
|
+
const policyResolved = isServiceProfile || age !== 'unknown';
|
|
30
|
+
const isUnmanagedAdult = age === 'adult' && !isManaged;
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
isMinor,
|
|
34
|
+
policyResolved,
|
|
35
|
+
defaultExpiryDays: isUnmanagedAdult ? 365 : 30,
|
|
36
|
+
viewCountingEnabled: isServiceProfile || isUnmanagedAdult,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Build an injectable resolver over an authoritative source. Any source failure
|
|
42
|
+
* fails closed to the conservative default rather than assuming adult.
|
|
43
|
+
*/
|
|
44
|
+
export const createShareLinkPolicyResolver = (
|
|
45
|
+
source: ShareLinkPolicySource
|
|
46
|
+
): ShareLinkPolicyResolver => ({
|
|
47
|
+
resolve: async (profileId: string): Promise<ShareLinkPolicySnapshot> => {
|
|
48
|
+
try {
|
|
49
|
+
const { age, isManaged, isServiceProfile } = await source.resolveOwner(profileId);
|
|
50
|
+
|
|
51
|
+
return composeShareLinkPolicy(age, isManaged, isServiceProfile);
|
|
52
|
+
} catch {
|
|
53
|
+
return DEFAULT_SHARE_LINK_POLICY;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Effective expiry: an explicit caller value (including explicit `null`) is
|
|
62
|
+
* preserved; only an omitted value receives the policy default. The default is
|
|
63
|
+
* derived from the policy at first reservation and then persisted, so a retry on
|
|
64
|
+
* a later clock replays the original value.
|
|
65
|
+
*/
|
|
66
|
+
export const resolveShareLinkExpiry = (
|
|
67
|
+
policy: ShareLinkPolicySnapshot,
|
|
68
|
+
expiresAt: string | null | undefined,
|
|
69
|
+
now: Date
|
|
70
|
+
): string | null => {
|
|
71
|
+
if (expiresAt !== undefined) return expiresAt;
|
|
72
|
+
|
|
73
|
+
return new Date(now.getTime() + policy.defaultExpiryDays * DAY_MS).toISOString();
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Conservatively merge a share's currently committed policy with the policy a
|
|
78
|
+
* reservation intends to apply at finalization.
|
|
79
|
+
*
|
|
80
|
+
* A reservation can be created before the owner's authoritative policy changes
|
|
81
|
+
* and then finalized later by a replay or a recovery worker. Applying the stale
|
|
82
|
+
* reservation policy verbatim could re-enable view counting for an owner who has
|
|
83
|
+
* since become managed/minor. The merge therefore only ever tightens:
|
|
84
|
+
*
|
|
85
|
+
* - view counting stays enabled only if BOTH policies allow it;
|
|
86
|
+
* - a known minor on either side is a minor, an unknown on either side is
|
|
87
|
+
* unknown (never inferred adult);
|
|
88
|
+
* - the default expiry is the shorter of the two.
|
|
89
|
+
*
|
|
90
|
+
* Production finalization also rechecks current graph policy under the share
|
|
91
|
+
* lock before an explicit update can replace an old unknown snapshot.
|
|
92
|
+
*/
|
|
93
|
+
export const mergeShareLinkPolicyConservatively = (
|
|
94
|
+
current: ShareLinkPolicySnapshot,
|
|
95
|
+
incoming: ShareLinkPolicySnapshot
|
|
96
|
+
): ShareLinkPolicySnapshot => {
|
|
97
|
+
const isMinor =
|
|
98
|
+
current.isMinor === true || incoming.isMinor === true
|
|
99
|
+
? true
|
|
100
|
+
: current.isMinor === false && incoming.isMinor === false
|
|
101
|
+
? false
|
|
102
|
+
: null;
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
isMinor,
|
|
106
|
+
policyResolved: current.policyResolved && incoming.policyResolved,
|
|
107
|
+
defaultExpiryDays:
|
|
108
|
+
current.defaultExpiryDays <= incoming.defaultExpiryDays
|
|
109
|
+
? current.defaultExpiryDays
|
|
110
|
+
: incoming.defaultExpiryDays,
|
|
111
|
+
viewCountingEnabled: current.viewCountingEnabled && incoming.viewCountingEnabled,
|
|
112
|
+
};
|
|
113
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LC-2187 owner share-link policy types.
|
|
3
|
+
*
|
|
4
|
+
* Policy is always derived server-side from trusted persisted state; nothing in
|
|
5
|
+
* this module reads the request body. The conservative default (unknown age,
|
|
6
|
+
* 30-day expiry, no view counting) is what an unavailable or untrustworthy age
|
|
7
|
+
* source produces — absence of a manager is NOT evidence of adulthood.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Result of consulting the authoritative server-side age source. */
|
|
11
|
+
export type ShareLinkOwnerAge = 'adult' | 'minor' | 'unknown';
|
|
12
|
+
|
|
13
|
+
/** Immutable policy snapshot persisted with the share under the write lock. */
|
|
14
|
+
export type ShareLinkPolicySnapshot = {
|
|
15
|
+
/** `true` known minor, `false` known adult/service profile, `null` unknown. */
|
|
16
|
+
isMinor: boolean | null;
|
|
17
|
+
/** `true` when age is known or a persisted service profile is age-exempt. */
|
|
18
|
+
policyResolved: boolean;
|
|
19
|
+
defaultExpiryDays: 30 | 365;
|
|
20
|
+
viewCountingEnabled: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Fresh graph-local classification; never persisted or inferred from an old snapshot. */
|
|
24
|
+
export type CurrentShareLinkPolicy = ShareLinkPolicySnapshot & {
|
|
25
|
+
isServiceProfile: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Authoritative server-side sources. Implementations must read persisted server
|
|
30
|
+
* state only; no request-derived value may be used as authority.
|
|
31
|
+
*/
|
|
32
|
+
export type ShareLinkPolicySource = {
|
|
33
|
+
/**
|
|
34
|
+
* Read age, service classification and management from persisted state.
|
|
35
|
+
* Service profiles may bypass tracking age checks; explicitly typed children
|
|
36
|
+
* must never be classified as service profiles here.
|
|
37
|
+
*/
|
|
38
|
+
resolveOwner: (profileId: string) => Promise<{
|
|
39
|
+
age: ShareLinkOwnerAge;
|
|
40
|
+
isManaged: boolean;
|
|
41
|
+
isServiceProfile: boolean;
|
|
42
|
+
}>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** Injectable server-side policy resolver used by the coordinator. */
|
|
46
|
+
export type ShareLinkPolicyResolver = {
|
|
47
|
+
resolve: (profileId: string) => Promise<ShareLinkPolicySnapshot>;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/** Fail-closed policy: no views, 30 days, age unknown. */
|
|
51
|
+
export const DEFAULT_SHARE_LINK_POLICY: ShareLinkPolicySnapshot = Object.freeze({
|
|
52
|
+
isMinor: null,
|
|
53
|
+
policyResolved: false,
|
|
54
|
+
defaultExpiryDays: 30,
|
|
55
|
+
viewCountingEnabled: false,
|
|
56
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasShareLinkServiceTransportConfig,
|
|
3
|
+
resolveShareLinkServiceTransportConfig,
|
|
4
|
+
} from '../share-link-maintenance/config';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Available automatically once trusted service configuration is complete.
|
|
8
|
+
* Namespace, origin and audience come only from server configuration. Missing
|
|
9
|
+
* wiring is inactive; partial or invalid wiring fails closed.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export type ShareLinkPublicApiConfigResolution =
|
|
13
|
+
| { status: 'disabled' }
|
|
14
|
+
| { status: 'invalid' }
|
|
15
|
+
| {
|
|
16
|
+
status: 'enabled';
|
|
17
|
+
namespace: string;
|
|
18
|
+
origin: string;
|
|
19
|
+
audience: string;
|
|
20
|
+
allowInsecureLoopback: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const resolveShareLinkPublicApiConfig = (
|
|
24
|
+
raw: unknown
|
|
25
|
+
): ShareLinkPublicApiConfigResolution => {
|
|
26
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) return { status: 'invalid' };
|
|
27
|
+
|
|
28
|
+
const source = raw as Record<string, unknown>;
|
|
29
|
+
if (!hasShareLinkServiceTransportConfig(source)) return { status: 'disabled' };
|
|
30
|
+
|
|
31
|
+
const transport = resolveShareLinkServiceTransportConfig(source);
|
|
32
|
+
if (transport.status !== 'enabled') return { status: 'invalid' };
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
status: 'enabled',
|
|
36
|
+
namespace: transport.config.namespace,
|
|
37
|
+
origin: transport.config.origin,
|
|
38
|
+
audience: transport.config.audience,
|
|
39
|
+
allowInsecureLoopback: transport.config.allowInsecureLoopback,
|
|
40
|
+
};
|
|
41
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import cache from '@cache';
|
|
2
|
+
import { environment } from '@environment';
|
|
3
|
+
|
|
4
|
+
const WINDOW_SECONDS = 10 * 60;
|
|
5
|
+
|
|
6
|
+
/** One owner alert per share per window, claimed atomically across Brain workers. */
|
|
7
|
+
export const claimShareViewNotification = async (
|
|
8
|
+
namespace: string,
|
|
9
|
+
shareId: string
|
|
10
|
+
): Promise<boolean> => {
|
|
11
|
+
if (environment.NODE_ENV === 'production' && !cache.redis) return false;
|
|
12
|
+
const count = await cache.incr(
|
|
13
|
+
`share-link-view-notification:${namespace}:${shareId}`,
|
|
14
|
+
WINDOW_SECONDS
|
|
15
|
+
);
|
|
16
|
+
// A cache failure suppresses alerts, never privacy enforcement or view counts.
|
|
17
|
+
return count === 1;
|
|
18
|
+
};
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { environment } from '@environment';
|
|
2
2
|
import { Agent, fetch as undiciFetch, type Response as UndiciResponse } from 'undici';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createDagJweForRecipients,
|
|
5
|
+
getDidWebLearnCard,
|
|
6
|
+
getLearnCard,
|
|
7
|
+
} from '@helpers/learnCard.helpers';
|
|
4
8
|
import { getDidWeb } from '@helpers/did.helpers';
|
|
5
9
|
import { VCValidator, JWEValidator } from '@learncard/types';
|
|
6
10
|
import type { UnsignedVC, VC, JWE } from '@learncard/types';
|
|
@@ -113,9 +117,17 @@ const getSaAgent = (): Agent => {
|
|
|
113
117
|
return _saAgent;
|
|
114
118
|
};
|
|
115
119
|
|
|
116
|
-
const _mockIssueCredentialWithSigningAuthority = async (
|
|
120
|
+
const _mockIssueCredentialWithSigningAuthority = async (
|
|
121
|
+
credential: UnsignedVC,
|
|
122
|
+
recipients?: string[]
|
|
123
|
+
): Promise<VC | JWE> => {
|
|
117
124
|
const learnCard = await getLearnCard();
|
|
118
|
-
|
|
125
|
+
const signedCredential = await learnCard.invoke.issueCredential({
|
|
126
|
+
...credential,
|
|
127
|
+
issuer: learnCard.id.did(),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return recipients ? createDagJweForRecipients(signedCredential, recipients) : signedCredential;
|
|
119
131
|
};
|
|
120
132
|
|
|
121
133
|
export async function issueCredentialWithSigningAuthority(
|
|
@@ -151,6 +163,10 @@ export async function issueCredentialWithSigningAuthority(
|
|
|
151
163
|
retryable: false,
|
|
152
164
|
});
|
|
153
165
|
}
|
|
166
|
+
// The validation above excludes undefined subject IDs on the encrypted path.
|
|
167
|
+
const encryptionRecipients = encrypt
|
|
168
|
+
? [...new Set([...(subjectIds as string[]), ownerDid, ...additionalEncryptionRecipients])]
|
|
169
|
+
: undefined;
|
|
154
170
|
const credentialToIssue = appendCredentialStatus
|
|
155
171
|
? await appendBitstringStatusListEntries(credential, ownerProfile.profileId, domain)
|
|
156
172
|
: credential;
|
|
@@ -177,7 +193,8 @@ export async function issueCredentialWithSigningAuthority(
|
|
|
177
193
|
try {
|
|
178
194
|
if (IS_TEST_ENVIRONMENT) {
|
|
179
195
|
return await _mockIssueCredentialWithSigningAuthority(
|
|
180
|
-
JSON.parse(serializedCredential)
|
|
196
|
+
JSON.parse(serializedCredential),
|
|
197
|
+
encryptionRecipients
|
|
181
198
|
);
|
|
182
199
|
}
|
|
183
200
|
|
|
@@ -189,16 +206,8 @@ export async function issueCredentialWithSigningAuthority(
|
|
|
189
206
|
perf.mark('initDid');
|
|
190
207
|
|
|
191
208
|
// Brain authenticates the request but must not be able to decrypt the response.
|
|
192
|
-
const encryption =
|
|
193
|
-
? {
|
|
194
|
-
recipients: [
|
|
195
|
-
...new Set([
|
|
196
|
-
...subjectIds,
|
|
197
|
-
ownerDid,
|
|
198
|
-
...additionalEncryptionRecipients,
|
|
199
|
-
]),
|
|
200
|
-
],
|
|
201
|
-
}
|
|
209
|
+
const encryption = encryptionRecipients
|
|
210
|
+
? { recipients: encryptionRecipients }
|
|
202
211
|
: undefined;
|
|
203
212
|
|
|
204
213
|
const didJwt = await traceCrypto('getDidAuthVp', () =>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { environment } from '@environment';
|
|
2
|
+
import { ConsentFlowTermsValidator, type ConsentFlowTerms } from '@learncard/types';
|
|
3
|
+
import { resolveUri } from '@helpers/uri.helpers';
|
|
4
|
+
|
|
5
|
+
/** Publish only the terms returned by the locked consent/publication claim. */
|
|
6
|
+
export const uploadSmartResume = async (
|
|
7
|
+
terms: ConsentFlowTerms,
|
|
8
|
+
did: string,
|
|
9
|
+
recipientToken: string
|
|
10
|
+
): Promise<string | undefined> => {
|
|
11
|
+
const isProduction = !environment.IS_OFFLINE;
|
|
12
|
+
|
|
13
|
+
const srUrl = isProduction ? 'https://my.smartresume.com/' : 'https://mystage.smartresume.com/';
|
|
14
|
+
const clientId = environment.SMART_RESUME_CLIENT_ID;
|
|
15
|
+
const accessKey = environment.SMART_RESUME_ACCESS_KEY;
|
|
16
|
+
|
|
17
|
+
const accessTokenResponse = (await fetch(`${srUrl}api/v1/token`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
signal: AbortSignal.timeout(30_000),
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
22
|
+
Authorization: `Basic ${btoa(`${clientId}:${accessKey}`)}`,
|
|
23
|
+
},
|
|
24
|
+
body: new URLSearchParams({
|
|
25
|
+
grant_type: 'client_credentials',
|
|
26
|
+
scope: 'delete readonly replace',
|
|
27
|
+
}),
|
|
28
|
+
}).then(res => {
|
|
29
|
+
if (!res.ok) throw new Error(`SmartResume token request failed (${res.status})`);
|
|
30
|
+
return res.json();
|
|
31
|
+
})) as { access_token?: string };
|
|
32
|
+
|
|
33
|
+
const accessToken = accessTokenResponse.access_token;
|
|
34
|
+
if (!accessToken) throw new Error('Missing access_token for SmartResume');
|
|
35
|
+
|
|
36
|
+
const parsedTerms = ConsentFlowTermsValidator.parse(terms);
|
|
37
|
+
|
|
38
|
+
const categories = parsedTerms.read.credentials.categories;
|
|
39
|
+
const categoryValues = Object.values(categories) as Array<{ shared?: string[] }>;
|
|
40
|
+
|
|
41
|
+
const allSharedCredentialUris = [
|
|
42
|
+
// filter out duplicates
|
|
43
|
+
...new Set(categoryValues.flatMap(({ shared }) => shared ?? [])),
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const resolvedCredentials = await Promise.all(
|
|
47
|
+
allSharedCredentialUris.map(async uri => {
|
|
48
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
49
|
+
try {
|
|
50
|
+
return await Promise.race([
|
|
51
|
+
resolveUri(uri),
|
|
52
|
+
new Promise<never>((_, reject) => {
|
|
53
|
+
timer = setTimeout(
|
|
54
|
+
() => reject(new Error('Credential resolution timed out')),
|
|
55
|
+
30_000
|
|
56
|
+
);
|
|
57
|
+
}),
|
|
58
|
+
]);
|
|
59
|
+
} finally {
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
type ResolvedCredential = {
|
|
66
|
+
issuer?: string | { id: string };
|
|
67
|
+
id?: string;
|
|
68
|
+
boostCredential?: Record<string, unknown>;
|
|
69
|
+
} & Record<string, unknown>;
|
|
70
|
+
|
|
71
|
+
const credentials = resolvedCredentials
|
|
72
|
+
.filter((cred): cred is ResolvedCredential => typeof cred === 'object' && cred !== null)
|
|
73
|
+
.map(cred =>
|
|
74
|
+
cred.boostCredential && typeof cred.boostCredential === 'object'
|
|
75
|
+
? ({ ...cred.boostCredential, id: cred.id } as ResolvedCredential) // unwrap credential, preserve id
|
|
76
|
+
: cred
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const transformedCredentials = credentials.map(cred => {
|
|
80
|
+
const issuer =
|
|
81
|
+
typeof cred.issuer === 'string' ? { id: cred.issuer } : cred.issuer || { id: '' };
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
...cred,
|
|
85
|
+
issuer,
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const { name, email } = parsedTerms.read.personal;
|
|
90
|
+
|
|
91
|
+
const body = JSON.stringify({
|
|
92
|
+
'@context': [
|
|
93
|
+
'https://www.w3.org/ns/credentials/v2',
|
|
94
|
+
'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
|
|
95
|
+
'https://w3id.org/security/suites/ed25519-2020/v1',
|
|
96
|
+
],
|
|
97
|
+
recipienttoken: recipientToken,
|
|
98
|
+
recipient: {
|
|
99
|
+
id: did,
|
|
100
|
+
givenName: name && name !== 'Anonymous' ? name : '',
|
|
101
|
+
familyName: '', // this is necessary in order for givenName to be respected
|
|
102
|
+
email: email && email !== 'anonymous@hidden.com' ? email : '',
|
|
103
|
+
},
|
|
104
|
+
credentials: transformedCredentials,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const response = await fetch(`${srUrl}api/v1/credentials`, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
signal: AbortSignal.timeout(30_000),
|
|
110
|
+
headers: {
|
|
111
|
+
Authorization: `Bearer ${accessToken}`,
|
|
112
|
+
'Content-Type': 'application/json',
|
|
113
|
+
},
|
|
114
|
+
body,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
throw new Error(`SmartResume upload failed (${response.status})`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const result = (await response.json()) as { redirect_url?: string };
|
|
122
|
+
return result.redirect_url;
|
|
123
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ModelFactory, ModelRelatedNodesI, NeogmaInstance } from 'neogma';
|
|
2
|
+
|
|
3
|
+
import { neogma } from '@instance';
|
|
4
|
+
|
|
5
|
+
import { FlatAppManifestVersionType } from 'types/app-manifest';
|
|
6
|
+
import { Integration, IntegrationInstance } from './Integration';
|
|
7
|
+
import { AppStoreListing, AppStoreListingInstance } from './AppStoreListing';
|
|
8
|
+
|
|
9
|
+
export type AppManifestVersionRelationships = {
|
|
10
|
+
integration: ModelRelatedNodesI<typeof Integration, IntegrationInstance>;
|
|
11
|
+
listing: ModelRelatedNodesI<typeof AppStoreListing, AppStoreListingInstance>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type AppManifestVersionInstance = NeogmaInstance<
|
|
15
|
+
FlatAppManifestVersionType,
|
|
16
|
+
AppManifestVersionRelationships
|
|
17
|
+
>;
|
|
18
|
+
|
|
19
|
+
export const AppManifestVersion = ModelFactory<
|
|
20
|
+
FlatAppManifestVersionType,
|
|
21
|
+
AppManifestVersionRelationships
|
|
22
|
+
>(
|
|
23
|
+
{
|
|
24
|
+
label: 'AppManifestVersion',
|
|
25
|
+
schema: {
|
|
26
|
+
id: { type: 'string', required: true, uniqueItems: true },
|
|
27
|
+
version: { type: 'number', required: true },
|
|
28
|
+
manifestHash: { type: 'string', required: true },
|
|
29
|
+
manifestJson: { type: 'string', required: true },
|
|
30
|
+
status: { type: 'string', enum: ['draft', 'active', 'superseded'], required: true },
|
|
31
|
+
createdAt: { type: 'string', required: true },
|
|
32
|
+
activatedAt: { type: 'string', required: false },
|
|
33
|
+
},
|
|
34
|
+
relationships: {
|
|
35
|
+
integration: { model: Integration, direction: 'in', name: 'HAS_MANIFEST_VERSION' },
|
|
36
|
+
listing: { model: AppStoreListing, direction: 'in', name: 'USES_MANIFEST_VERSION' },
|
|
37
|
+
},
|
|
38
|
+
primaryKeyField: 'id',
|
|
39
|
+
},
|
|
40
|
+
neogma
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export default AppManifestVersion;
|
|
@@ -6,13 +6,16 @@ import { Integration, IntegrationInstance } from './Integration';
|
|
|
6
6
|
import { Profile, ProfileInstance } from './Profile';
|
|
7
7
|
import { Boost, BoostInstance } from './Boost';
|
|
8
8
|
import { Credential, CredentialInstance } from './Credential';
|
|
9
|
+
import { ConsentFlowContract, ConsentFlowInstance } from './ConsentFlowContract';
|
|
9
10
|
import { SigningAuthority, SigningAuthorityInstance } from './SigningAuthority';
|
|
11
|
+
import type { AppManifestVersion, AppManifestVersionInstance } from './AppManifestVersion';
|
|
10
12
|
import {
|
|
11
13
|
FlatAppStoreListingType,
|
|
12
14
|
AppListingStatus,
|
|
13
15
|
LaunchType,
|
|
14
16
|
PromotionLevel,
|
|
15
17
|
AgeRating,
|
|
18
|
+
PendingListingUpdateStatus,
|
|
16
19
|
} from 'types/app-store-listing';
|
|
17
20
|
|
|
18
21
|
export type AppStoreListingRelationships = {
|
|
@@ -73,6 +76,13 @@ export type AppStoreListingRelationships = {
|
|
|
73
76
|
{ name: string; did: string; isPrimary?: boolean },
|
|
74
77
|
{ name: string; did: string; isPrimary?: boolean }
|
|
75
78
|
>;
|
|
79
|
+
hasConsentContract: ModelRelatedNodesI<
|
|
80
|
+
typeof ConsentFlowContract,
|
|
81
|
+
ConsentFlowInstance,
|
|
82
|
+
{ scopeHash: string; createdAt: string },
|
|
83
|
+
{ scopeHash: string; createdAt: string }
|
|
84
|
+
>;
|
|
85
|
+
usesManifestVersion: ModelRelatedNodesI<typeof AppManifestVersion, AppManifestVersionInstance>;
|
|
76
86
|
};
|
|
77
87
|
|
|
78
88
|
export type AppStoreListingInstance = NeogmaInstance<
|
|
@@ -114,6 +124,13 @@ export const AppStoreListing = ModelFactory<FlatAppStoreListingType, AppStoreLis
|
|
|
114
124
|
min_age: { type: 'number', required: false },
|
|
115
125
|
age_rating: { type: 'string', enum: AgeRating.options, required: false },
|
|
116
126
|
contact_email: { type: 'string', required: false },
|
|
127
|
+
pending_update_json: { type: 'string', required: false },
|
|
128
|
+
pending_update_status: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
enum: PendingListingUpdateStatus.options,
|
|
131
|
+
required: false,
|
|
132
|
+
},
|
|
133
|
+
pending_update_submitted_at: { type: 'string', required: false },
|
|
117
134
|
} as any,
|
|
118
135
|
relationships: {
|
|
119
136
|
publishedBy: { model: Integration, direction: 'in', name: 'PUBLISHES_LISTING' },
|
|
@@ -204,6 +221,21 @@ export const AppStoreListing = ModelFactory<FlatAppStoreListingType, AppStoreLis
|
|
|
204
221
|
},
|
|
205
222
|
},
|
|
206
223
|
},
|
|
224
|
+
hasConsentContract: {
|
|
225
|
+
model: ConsentFlowContract,
|
|
226
|
+
direction: 'out',
|
|
227
|
+
name: 'HAS_CONSENT_CONTRACT',
|
|
228
|
+
properties: {
|
|
229
|
+
scopeHash: {
|
|
230
|
+
property: 'scopeHash',
|
|
231
|
+
schema: { type: 'string', required: true },
|
|
232
|
+
},
|
|
233
|
+
createdAt: {
|
|
234
|
+
property: 'createdAt',
|
|
235
|
+
schema: { type: 'string', required: true },
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
},
|
|
207
239
|
},
|
|
208
240
|
primaryKeyField: 'listing_id',
|
|
209
241
|
},
|