@learncard/network-brain-service 4.1.2 → 5.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 +14 -0
- package/CHANGELOG.md +164 -0
- package/README.md +27 -1
- package/bootstrapLambda.test.ts +70 -32
- package/config/config.dev.json +1 -0
- package/config/config.example.json +2 -1
- package/config/config.production.json +1 -0
- package/config/config.scouts.dev.json +1 -0
- package/config/config.scouts.production.json +1 -0
- package/consentFlowDeadlineLambda.test.ts +108 -0
- package/consentFlowDeadlineLambda.ts +18 -0
- package/consentFlowDeadlineLambdaApp.ts +14 -0
- package/dist/accesslayer/boost/create.d.ts +8 -2
- package/dist/accesslayer/boost/create.d.ts.map +1 -1
- package/dist/accesslayer/campaign/audience.d.ts +4 -4
- package/dist/accesslayer/campaign/audience.d.ts.map +1 -1
- package/dist/accesslayer/campaign/create.d.ts +1 -1
- package/dist/accesslayer/campaign/create.d.ts.map +1 -1
- package/dist/accesslayer/campaign/delivery.d.ts +5 -0
- package/dist/accesslayer/campaign/delivery.d.ts.map +1 -0
- package/dist/accesslayer/campaign/dispatch.d.ts +5 -0
- package/dist/accesslayer/campaign/dispatch.d.ts.map +1 -0
- package/dist/accesslayer/campaign/dispatch.test.d.ts +2 -0
- package/dist/accesslayer/campaign/dispatch.test.d.ts.map +1 -0
- package/dist/accesslayer/campaign/email.d.ts +10 -0
- package/dist/accesslayer/campaign/email.d.ts.map +1 -0
- package/dist/accesslayer/campaign/email.test.d.ts +2 -0
- package/dist/accesslayer/campaign/email.test.d.ts.map +1 -0
- package/dist/accesslayer/campaign/preferences.d.ts +5 -0
- package/dist/accesslayer/campaign/preferences.d.ts.map +1 -0
- package/dist/accesslayer/campaign/read.d.ts.map +1 -1
- package/dist/accesslayer/campaign/test.d.ts +5 -0
- package/dist/accesslayer/campaign/test.d.ts.map +1 -0
- package/dist/accesslayer/campaign/test.test.d.ts +2 -0
- package/dist/accesslayer/campaign/test.test.d.ts.map +1 -0
- package/dist/accesslayer/campaign/update.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/delete.d.ts +1 -1
- package/dist/accesslayer/consentflowcontract/delete.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/read.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/create.d.ts +2 -1
- package/dist/accesslayer/consentflowcontract/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/read.d.ts +19 -4
- package/dist/accesslayer/consentflowcontract/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/update.d.ts +6 -1
- package/dist/accesslayer/consentflowcontract/relationships/update.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/versions.d.ts +68 -0
- package/dist/accesslayer/consentflowcontract/versions.d.ts.map +1 -0
- package/dist/accesslayer/credential/create.d.ts +3 -1
- package/dist/accesslayer/credential/create.d.ts.map +1 -1
- package/dist/accesslayer/credential/delete.d.ts +1 -0
- package/dist/accesslayer/credential/delete.d.ts.map +1 -1
- package/dist/accesslayer/credential/relationships/create.d.ts +15 -3
- package/dist/accesslayer/credential/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/credential/relationships/read.d.ts +2 -0
- package/dist/accesslayer/credential/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/credential/relationships/update.d.ts.map +1 -1
- package/dist/accesslayer/credential-refresh/read.d.ts +1 -0
- package/dist/accesslayer/credential-refresh/read.d.ts.map +1 -1
- package/dist/accesslayer/credential-refresh/update.d.ts.map +1 -1
- package/dist/accesslayer/inbox-credential/create.d.ts +1 -0
- package/dist/accesslayer/inbox-credential/create.d.ts.map +1 -1
- package/dist/accesslayer/inbox-credential/refresh.d.ts +7 -0
- package/dist/accesslayer/inbox-credential/refresh.d.ts.map +1 -1
- package/dist/app.d.ts +11 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/cache/app-store.caches.d.ts +61 -1
- package/dist/cache/app-store.caches.d.ts.map +1 -1
- package/dist/campaign-unsubscribe.d.ts +7 -0
- package/dist/campaign-unsubscribe.d.ts.map +1 -0
- package/dist/campaign-unsubscribe.test.d.ts +2 -0
- package/dist/campaign-unsubscribe.test.d.ts.map +1 -0
- package/dist/config/environment.d.ts +42 -0
- package/dist/config/environment.d.ts.map +1 -1
- package/dist/config/stageConfig.d.ts +4 -0
- package/dist/config/stageConfig.d.ts.map +1 -1
- package/dist/credential-refresh.d.ts.map +1 -1
- package/dist/helpers/boost.helpers.d.ts +4 -1
- package/dist/helpers/boost.helpers.d.ts.map +1 -1
- package/dist/helpers/campaign-app-origin.helpers.d.ts +2 -0
- package/dist/helpers/campaign-app-origin.helpers.d.ts.map +1 -0
- package/dist/helpers/campaign-email.helpers.d.ts +13 -0
- package/dist/helpers/campaign-email.helpers.d.ts.map +1 -0
- package/dist/helpers/campaign-notifications.helpers.d.ts +7 -0
- package/dist/helpers/campaign-notifications.helpers.d.ts.map +1 -0
- package/dist/helpers/campaign-queue.helpers.d.ts +7 -0
- package/dist/helpers/campaign-queue.helpers.d.ts.map +1 -0
- package/dist/helpers/campaign-queue.helpers.test.d.ts +2 -0
- package/dist/helpers/campaign-queue.helpers.test.d.ts.map +1 -0
- package/dist/helpers/campaign-unsubscribe-page.d.ts +2 -0
- package/dist/helpers/campaign-unsubscribe-page.d.ts.map +1 -0
- package/dist/helpers/campaign-unsubscribe.helpers.d.ts +7 -0
- package/dist/helpers/campaign-unsubscribe.helpers.d.ts.map +1 -0
- package/dist/helpers/campaign-webhook.helpers.test.d.ts +2 -0
- package/dist/helpers/campaign-webhook.helpers.test.d.ts.map +1 -0
- package/dist/helpers/consentflow-deadline.helpers.d.ts +5 -0
- package/dist/helpers/consentflow-deadline.helpers.d.ts.map +1 -0
- package/dist/helpers/consentflow-legacy-migration.helpers.d.ts +2 -0
- package/dist/helpers/consentflow-legacy-migration.helpers.d.ts.map +1 -0
- package/dist/helpers/contract-events.helpers.d.ts.map +1 -1
- package/dist/helpers/contract.helpers.d.ts +1 -1
- package/dist/helpers/contract.helpers.d.ts.map +1 -1
- package/dist/helpers/credential-display.helpers.d.ts +5 -0
- package/dist/helpers/credential-display.helpers.d.ts.map +1 -0
- package/dist/helpers/credential-display.helpers.test.d.ts +2 -0
- package/dist/helpers/credential-display.helpers.test.d.ts.map +1 -0
- package/dist/helpers/credential-refresh-email.helpers.d.ts.map +1 -1
- package/dist/helpers/credential-refresh-materiality.helpers.d.ts +4 -0
- package/dist/helpers/credential-refresh-materiality.helpers.d.ts.map +1 -1
- package/dist/helpers/credential-refresh.helpers.d.ts +30 -1
- package/dist/helpers/credential-refresh.helpers.d.ts.map +1 -1
- package/dist/helpers/credential-status-mutation.helpers.d.ts +5 -0
- package/dist/helpers/credential-status-mutation.helpers.d.ts.map +1 -0
- package/dist/helpers/credential-status-mutation.helpers.test.d.ts +2 -0
- package/dist/helpers/credential-status-mutation.helpers.test.d.ts.map +1 -0
- package/dist/helpers/credential.helpers.d.ts +1 -1
- package/dist/helpers/credential.helpers.d.ts.map +1 -1
- package/dist/helpers/inbox-refresh.helpers.d.ts +4 -2
- package/dist/helpers/inbox-refresh.helpers.d.ts.map +1 -1
- package/dist/helpers/inbox.helpers.d.ts +1 -0
- package/dist/helpers/inbox.helpers.d.ts.map +1 -1
- package/dist/helpers/learnCard.helpers.d.ts +1 -0
- package/dist/helpers/learnCard.helpers.d.ts.map +1 -1
- package/dist/helpers/managed-status.helpers.d.ts +7 -0
- package/dist/helpers/managed-status.helpers.d.ts.map +1 -0
- package/dist/helpers/managed-status.helpers.test.d.ts +2 -0
- package/dist/helpers/managed-status.helpers.test.d.ts.map +1 -0
- package/dist/helpers/notification-delivery-boundary.helpers.test.d.ts +2 -0
- package/dist/helpers/notification-delivery-boundary.helpers.test.d.ts.map +1 -0
- package/dist/helpers/notification-webhook-fetch.helpers.d.ts +13 -0
- package/dist/helpers/notification-webhook-fetch.helpers.d.ts.map +1 -0
- package/dist/helpers/notification-webhook-fetch.helpers.test.d.ts +2 -0
- package/dist/helpers/notification-webhook-fetch.helpers.test.d.ts.map +1 -0
- package/dist/helpers/notificationQueue.helpers.d.ts.map +1 -1
- package/dist/helpers/notifications.helpers.d.ts.map +1 -1
- package/dist/helpers/refresh-send-intent.helpers.d.ts +13 -5
- package/dist/helpers/refresh-send-intent.helpers.d.ts.map +1 -1
- package/dist/helpers/refresh-send-intent.helpers.test.d.ts +2 -0
- package/dist/helpers/refresh-send-intent.helpers.test.d.ts.map +1 -0
- package/dist/helpers/send-contract.helpers.d.ts +11 -0
- package/dist/helpers/send-contract.helpers.d.ts.map +1 -0
- package/dist/helpers/status-list.helpers.d.ts +12 -1
- package/dist/helpers/status-list.helpers.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/models/ConsentFlowContract.d.ts.map +1 -1
- package/dist/models/ConsentFlowContractVersion.d.ts +12 -0
- package/dist/models/ConsentFlowContractVersion.d.ts.map +1 -0
- package/dist/models/ConsentFlowTerms.d.ts.map +1 -1
- package/dist/models/Credential.d.ts +2 -0
- package/dist/models/Credential.d.ts.map +1 -1
- package/dist/models/CredentialRefresh.d.ts +5 -0
- package/dist/models/CredentialRefresh.d.ts.map +1 -1
- package/dist/models/Integration.d.ts +1 -1
- package/dist/models/Profile.d.ts.map +1 -1
- package/dist/models/campaign-constraints.d.ts.map +1 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/publish-metafile.json +1 -1
- package/dist/routes/activity.d.ts +15 -5
- package/dist/routes/activity.d.ts.map +1 -1
- package/dist/routes/app-store.d.ts +15 -5
- package/dist/routes/app-store.d.ts.map +1 -1
- package/dist/routes/auth-grants.d.ts +12 -2
- package/dist/routes/auth-grants.d.ts.map +1 -1
- package/dist/routes/bench.d.ts +11 -1
- package/dist/routes/bench.d.ts.map +1 -1
- package/dist/routes/boosts.d.ts +70 -15
- package/dist/routes/boosts.d.ts.map +1 -1
- package/dist/routes/campaigns.d.ts +183 -51
- package/dist/routes/campaigns.d.ts.map +1 -1
- package/dist/routes/claim-hooks.d.ts +11 -1
- package/dist/routes/claim-hooks.d.ts.map +1 -1
- package/dist/routes/contact-methods.d.ts +11 -1
- package/dist/routes/contact-methods.d.ts.map +1 -1
- package/dist/routes/contracts.d.ts +374 -8
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/credential-input-privacy.test.d.ts +2 -0
- package/dist/routes/credential-input-privacy.test.d.ts.map +1 -0
- package/dist/routes/credential-refreshes.d.ts +210 -1
- package/dist/routes/credential-refreshes.d.ts.map +1 -1
- package/dist/routes/credential-share-previews.d.ts +11 -1
- package/dist/routes/credential-share-previews.d.ts.map +1 -1
- package/dist/routes/credentials.d.ts +132 -3
- package/dist/routes/credentials.d.ts.map +1 -1
- package/dist/routes/did-metadata.d.ts +11 -1
- package/dist/routes/did-metadata.d.ts.map +1 -1
- package/dist/routes/federation.d.ts +11 -1
- package/dist/routes/federation.d.ts.map +1 -1
- package/dist/routes/inbox.d.ts +54 -19
- package/dist/routes/inbox.d.ts.map +1 -1
- package/dist/routes/index.d.ts +100 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/integrations.d.ts +14 -4
- package/dist/routes/integrations.d.ts.map +1 -1
- package/dist/routes/presentations.d.ts +11 -1
- package/dist/routes/presentations.d.ts.map +1 -1
- package/dist/routes/profile-manager.d.ts +11 -1
- package/dist/routes/profile-manager.d.ts.map +1 -1
- package/dist/routes/profiles.d.ts +11 -1
- package/dist/routes/profiles.d.ts.map +1 -1
- package/dist/routes/public-share-links.d.ts +22 -2
- package/dist/routes/public-share-links.d.ts.map +1 -1
- package/dist/routes/share-links.d.ts +36 -16
- package/dist/routes/share-links.d.ts.map +1 -1
- package/dist/routes/skill-frameworks.d.ts +11 -1
- package/dist/routes/skill-frameworks.d.ts.map +1 -1
- package/dist/routes/skills.d.ts +11 -1
- package/dist/routes/skills.d.ts.map +1 -1
- package/dist/routes/storage.d.ts +37 -23
- package/dist/routes/storage.d.ts.map +1 -1
- package/dist/routes/test.d.ts +79 -3
- package/dist/routes/test.d.ts.map +1 -1
- package/dist/routes/utilities.d.ts +11 -1
- package/dist/routes/utilities.d.ts.map +1 -1
- package/dist/routes/workflows.d.ts +11 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/services/delivery/adapters/postmark.adapter.d.ts +3 -0
- package/dist/services/delivery/adapters/postmark.adapter.d.ts.map +1 -1
- package/dist/services/delivery/delivery.service.d.ts +10 -0
- package/dist/services/delivery/delivery.service.d.ts.map +1 -1
- package/dist/types/activity.d.ts +3 -3
- package/dist/types/app-manifest.d.ts +10 -10
- package/dist/types/campaign.d.ts +13 -1
- package/dist/types/campaign.d.ts.map +1 -1
- package/dist/types/consentflowcontract.d.ts +175 -7
- package/dist/types/consentflowcontract.d.ts.map +1 -1
- package/dist/types/credential-refresh.d.ts +27 -0
- package/dist/types/credential-refresh.d.ts.map +1 -1
- package/dist/types/credential.d.ts +5 -0
- package/dist/types/credential.d.ts.map +1 -1
- package/dist/types/integration.d.ts +3 -3
- package/lambda.ts +44 -14
- package/lambdaApp.ts +20 -0
- package/package.json +20 -19
- package/project.json +5 -0
- package/scripts/migrate-consent-flow-versions.ts +9 -0
- package/scripts/report-send-template-exposure.ts +47 -0
- package/scripts/verify-python-contracts.ts +16 -1
- package/serverless-local.yml +15 -2
- package/serverless.function-env.cjs +4 -0
- package/serverless.local.yml +12 -0
- package/serverless.yml +48 -3
- package/src/accesslayer/boost/create.ts +62 -7
- package/src/accesslayer/campaign/README.md +275 -6
- package/src/accesslayer/campaign/audience.ts +39 -7
- package/src/accesslayer/campaign/create.ts +4 -2
- package/src/accesslayer/campaign/delivery.ts +66 -0
- package/src/accesslayer/campaign/dispatch.test.ts +59 -0
- package/src/accesslayer/campaign/dispatch.ts +172 -0
- package/src/accesslayer/campaign/email.test.ts +73 -0
- package/src/accesslayer/campaign/email.ts +91 -0
- package/src/accesslayer/campaign/preferences.ts +53 -0
- package/src/accesslayer/campaign/read.ts +3 -1
- package/src/accesslayer/campaign/state.ts +1 -1
- package/src/accesslayer/campaign/test.test.ts +31 -0
- package/src/accesslayer/campaign/test.ts +75 -0
- package/src/accesslayer/campaign/update.ts +15 -4
- package/src/accesslayer/consentflowcontract/create.ts +20 -1
- package/src/accesslayer/consentflowcontract/delete.ts +121 -3
- package/src/accesslayer/consentflowcontract/read.ts +15 -9
- package/src/accesslayer/consentflowcontract/relationships/create.ts +70 -36
- package/src/accesslayer/consentflowcontract/relationships/read.ts +305 -73
- package/src/accesslayer/consentflowcontract/relationships/smartResume.ts +1 -1
- package/src/accesslayer/consentflowcontract/relationships/update.ts +269 -98
- package/src/accesslayer/consentflowcontract/versions.ts +790 -0
- package/src/accesslayer/credential/create.ts +33 -9
- package/src/accesslayer/credential/delete.ts +45 -0
- package/src/accesslayer/credential/relationships/create.ts +102 -47
- package/src/accesslayer/credential/relationships/update.ts +8 -116
- package/src/accesslayer/credential-refresh/read.ts +26 -2
- package/src/accesslayer/credential-refresh/update.ts +6 -2
- package/src/accesslayer/inbox-credential/create.ts +7 -1
- package/src/accesslayer/inbox-credential/refresh.ts +14 -4
- package/src/campaign-unsubscribe.test.ts +158 -0
- package/src/campaign-unsubscribe.ts +86 -0
- package/src/config/environment.test.ts +52 -0
- package/src/config/environment.ts +58 -0
- package/src/config/serverlessFunctionEnv.test.ts +59 -0
- package/src/credential-refresh.ts +1 -0
- package/src/docker-entry.ts +26 -1
- package/src/helpers/boost-storage.helpers.test.ts +107 -41
- package/src/helpers/boost.helpers.ts +88 -40
- package/src/helpers/campaign-app-origin.helpers.ts +25 -0
- package/src/helpers/campaign-email.helpers.ts +113 -0
- package/src/helpers/campaign-notifications.helpers.ts +127 -0
- package/src/helpers/campaign-queue.helpers.test.ts +442 -0
- package/src/helpers/campaign-queue.helpers.ts +122 -0
- package/src/helpers/campaign-unsubscribe-page.ts +107 -0
- package/src/helpers/campaign-unsubscribe.helpers.ts +56 -0
- package/src/helpers/campaign-webhook.helpers.test.ts +137 -0
- package/src/helpers/consentflow-deadline.helpers.ts +22 -0
- package/src/helpers/consentflow-legacy-migration.helpers.ts +179 -0
- package/src/helpers/contract-events.helpers.ts +35 -3
- package/src/helpers/contract-requests.helpers.ts +1 -1
- package/src/helpers/contract.helpers.ts +5 -1
- package/src/helpers/credential-display.helpers.test.ts +68 -0
- package/src/helpers/credential-display.helpers.ts +15 -0
- package/src/helpers/credential-refresh-email.helpers.ts +5 -12
- package/src/helpers/credential-refresh-materiality.helpers.test.ts +138 -1
- package/src/helpers/credential-refresh-materiality.helpers.ts +62 -1
- package/src/helpers/credential-refresh-proof.helpers.test.ts +1 -1
- package/src/helpers/credential-refresh-proof.helpers.ts +2 -2
- package/src/helpers/credential-refresh.helpers.ts +1166 -376
- package/src/helpers/credential-status-mutation.helpers.test.ts +155 -0
- package/src/helpers/credential-status-mutation.helpers.ts +166 -0
- package/src/helpers/credential.helpers.ts +19 -11
- package/src/helpers/finalize-inbox.helpers.ts +1 -1
- package/src/helpers/inbox-refresh.helpers.ts +34 -8
- package/src/helpers/inbox.helpers.ts +2 -0
- package/src/helpers/learnCard.helpers.ts +23 -0
- package/src/helpers/managed-status.helpers.test.ts +101 -0
- package/src/helpers/managed-status.helpers.ts +147 -0
- package/src/helpers/notification-delivery-boundary.helpers.test.ts +114 -0
- package/src/helpers/notification-webhook-fetch.helpers.test.ts +228 -0
- package/src/helpers/notification-webhook-fetch.helpers.ts +166 -0
- package/src/helpers/notificationQueue.helpers.ts +5 -0
- package/src/helpers/notifications.helpers.ts +19 -12
- package/src/helpers/refresh-send-intent.helpers.test.ts +60 -0
- package/src/helpers/refresh-send-intent.helpers.ts +81 -18
- package/src/helpers/send-contract.helpers.ts +36 -0
- package/src/helpers/status-list.helpers.test.ts +29 -12
- package/src/helpers/status-list.helpers.ts +329 -20
- package/src/models/ConsentFlowContract.ts +3 -0
- package/src/models/ConsentFlowContractVersion.ts +50 -0
- package/src/models/ConsentFlowTerms.ts +4 -0
- package/src/models/Credential.ts +2 -0
- package/src/models/CredentialRefresh.ts +2 -0
- package/src/models/Profile.ts +2 -0
- package/src/models/campaign-constraints.ts +13 -8
- package/src/models/index.ts +2 -0
- package/src/openapi.ts +21 -0
- package/src/routes/app-store.ts +2 -1
- package/src/routes/boosts.ts +219 -137
- package/src/routes/campaigns.ts +98 -19
- package/src/routes/contracts.ts +433 -115
- package/src/routes/credential-input-privacy.test.ts +92 -0
- package/src/routes/credential-refreshes.ts +273 -2
- package/src/routes/federation.ts +7 -2
- package/src/routes/inbox.ts +6 -1
- package/src/routes/index.ts +31 -2
- package/src/routes/workflows.ts +61 -46
- package/src/services/delivery/adapters/postmark.adapter.test.ts +70 -1
- package/src/services/delivery/adapters/postmark.adapter.ts +84 -11
- package/src/services/delivery/delivery.service.ts +4 -0
- package/src/types/campaign.ts +14 -1
- package/src/types/consentflowcontract.ts +43 -2
- package/src/types/credential-refresh.ts +11 -1
- package/src/types/credential.ts +2 -0
- package/test/boost-status-cleanup.spec.ts +123 -0
- package/test/campaigns-email.unit.spec.ts +268 -0
- package/test/campaigns.spec.ts +804 -30
- package/test/consent-autoboost-idempotency.spec.ts +432 -0
- package/test/consent-data-boundaries.spec.ts +322 -26
- package/test/consent-legacy-migration.spec.ts +315 -0
- package/test/consent-recipients.spec.ts +7 -7
- package/test/consent-version-updates.spec.ts +761 -0
- package/test/consentflow.spec.ts +698 -226
- package/test/contract-requests.spec.ts +55 -9
- package/test/credential-refresh-allocation.spec.ts +212 -14
- package/test/credential-refresh-email.spec.ts +6 -10
- package/test/credential-refresh-endpoint.spec.ts +3 -0
- package/test/credential-refresh-publication.spec.ts +52 -15
- package/test/credential-storage.neo4j.spec.ts +33 -6
- package/test/helpers/legacy-autoboost.ts +48 -0
- package/test/holder-mode-send.spec.ts +710 -0
- package/test/inbox-refresh.spec.ts +105 -0
- package/test/inbox-security.e2e.ts +18 -22
- package/test/managed-status-revocation.spec.ts +970 -0
- package/test/notifications-worker.spec.ts +31 -25
- package/test/refresh-send.spec.ts +334 -5
- package/test/smart-resume-consent.spec.ts +1 -1
- package/test/verification/campaigns.ts +40 -0
- package/vitest.campaigns.config.ts +2 -0
- package/vitest.config.ts +14 -0
package/src/routes/boosts.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
assertInboxRefreshEnabled,
|
|
3
3
|
inboxRefreshRequestDigest,
|
|
4
|
+
getInboxRefreshRequestDigestCandidates,
|
|
4
5
|
getInboxRefreshReplay,
|
|
5
6
|
getInboxRefreshReceipt,
|
|
6
7
|
resumeInboxRefreshDelivery,
|
|
@@ -41,6 +42,7 @@ import {
|
|
|
41
42
|
PrepareRefreshableSendResult,
|
|
42
43
|
AllocateCredentialStatusInputValidator,
|
|
43
44
|
AllocatedBitstringStatusListEntryValidator,
|
|
45
|
+
ManagedCredentialRefreshBindingValidator,
|
|
44
46
|
} from '@learncard/types';
|
|
45
47
|
import {
|
|
46
48
|
isVC2Format,
|
|
@@ -58,7 +60,7 @@ import {
|
|
|
58
60
|
logCredentialFailed,
|
|
59
61
|
} from '@helpers/activity.helpers';
|
|
60
62
|
|
|
61
|
-
import { t, profileRoute } from '@routes';
|
|
63
|
+
import { t, profileRoute, credentialProfileRoute } from '@routes';
|
|
62
64
|
|
|
63
65
|
import {
|
|
64
66
|
getBoostByUri,
|
|
@@ -133,7 +135,11 @@ import {
|
|
|
133
135
|
buildObv3AlignmentsForBoost,
|
|
134
136
|
normalizeCredentialAlignments,
|
|
135
137
|
} from '@services/skills-provider/inject';
|
|
136
|
-
import {
|
|
138
|
+
import {
|
|
139
|
+
createBoost,
|
|
140
|
+
createDisplayOnlyBoost,
|
|
141
|
+
normalizePublicDisplay,
|
|
142
|
+
} from '@accesslayer/boost/create';
|
|
137
143
|
import { getBoostOwner } from '@accesslayer/boost/relationships/read';
|
|
138
144
|
import { BoostInstance } from '@models';
|
|
139
145
|
import { getProfileByProfileId } from '@accesslayer/profile/read';
|
|
@@ -145,12 +151,7 @@ import {
|
|
|
145
151
|
getSigningAuthorityForUserByName,
|
|
146
152
|
getPrimarySigningAuthorityForUser,
|
|
147
153
|
} from '@accesslayer/signing-authority/relationships/read';
|
|
148
|
-
import {
|
|
149
|
-
getContractDetailsByUri,
|
|
150
|
-
getContractTermsForProfile,
|
|
151
|
-
getWritersForContract,
|
|
152
|
-
} from '@accesslayer/consentflowcontract/relationships/read';
|
|
153
|
-
import { setRelatedBoostForContract } from '@accesslayer/consentflowcontract/relationships/create';
|
|
154
|
+
import { resolveContractForSend } from '@helpers/send-contract.helpers';
|
|
154
155
|
|
|
155
156
|
import {
|
|
156
157
|
isClaimLinkAlreadySetForBoost,
|
|
@@ -198,12 +199,14 @@ import {
|
|
|
198
199
|
extractManagedRefreshHandoff,
|
|
199
200
|
getBoundRefreshBoostId,
|
|
200
201
|
getCredentialRefreshServiceUrl,
|
|
202
|
+
getHolderEncryptionRecipientKeyIds,
|
|
201
203
|
peekCredentialRefreshInitialBinding,
|
|
202
204
|
sendRefreshableCredential,
|
|
203
205
|
} from '@helpers/credential-refresh.helpers';
|
|
204
206
|
import {
|
|
205
207
|
claimRefreshSendIntent,
|
|
206
208
|
computeRefreshSendRequestDigest,
|
|
209
|
+
getRefreshSendRequestDigestCandidates,
|
|
207
210
|
getRefreshSendIntent,
|
|
208
211
|
markRefreshSendIntentDelivered,
|
|
209
212
|
reconcileBoundRefreshSendIntent,
|
|
@@ -212,6 +215,10 @@ import {
|
|
|
212
215
|
type RefreshSendIntent,
|
|
213
216
|
} from '@helpers/refresh-send-intent.helpers';
|
|
214
217
|
import { getCredentialRefreshRuntimeEnvironment } from '@environment';
|
|
218
|
+
import { getCredentialRefresh } from '@accesslayer/credential-refresh';
|
|
219
|
+
import { prepareRefreshStatusEntries } from '@helpers/managed-status.helpers';
|
|
220
|
+
import { getCredentialStatusRootId, getStatusManagement } from '@helpers/status-list.helpers';
|
|
221
|
+
import { getBitstringStatusListEntries } from '@learncard/helpers';
|
|
215
222
|
import { ensureCredentialRefreshConstraints } from '../models/credential-refresh-constraints';
|
|
216
223
|
import { userHasRequiredScopes } from '@helpers/auth-grant.helpers';
|
|
217
224
|
import { AUTH_GRANT_NO_ACCESS_SCOPE } from 'src/constants/auth-grant';
|
|
@@ -252,12 +259,16 @@ const resolveBoostCredentialInstance = async ({
|
|
|
252
259
|
}) => {
|
|
253
260
|
const {
|
|
254
261
|
getCredentialByUri,
|
|
262
|
+
getCredentialById,
|
|
255
263
|
getCredentialInstanceForBoostAndProfile,
|
|
256
264
|
isCredentialInstanceOfBoost,
|
|
257
265
|
} = await import('@accesslayer/credential/read');
|
|
258
266
|
|
|
259
267
|
if (credentialUri) {
|
|
260
|
-
const
|
|
268
|
+
const version = await getCredentialByUri(decodeURIComponent(credentialUri));
|
|
269
|
+
const resolvedCredential = version
|
|
270
|
+
? await getCredentialById(await getCredentialStatusRootId(version.id))
|
|
271
|
+
: null;
|
|
261
272
|
|
|
262
273
|
if (!resolvedCredential) {
|
|
263
274
|
throw new TRPCError({
|
|
@@ -281,63 +292,6 @@ const resolveBoostCredentialInstance = async ({
|
|
|
281
292
|
return getCredentialInstanceForBoostAndProfile(boostId, recipientProfileId);
|
|
282
293
|
};
|
|
283
294
|
|
|
284
|
-
/**
|
|
285
|
-
* Resolves the approved consent-flow contract terms for a unified send, and links a
|
|
286
|
-
* newly created boost to the contract. Shared by the normal and managed-refresh send
|
|
287
|
-
* paths so contract linkage semantics stay identical.
|
|
288
|
-
*/
|
|
289
|
-
const resolveContractForSend = async (params: {
|
|
290
|
-
profile: ProfileType;
|
|
291
|
-
targetProfile: ProfileType;
|
|
292
|
-
boost: BoostInstance;
|
|
293
|
-
boostCreated: boolean;
|
|
294
|
-
contractUri?: string;
|
|
295
|
-
}) => {
|
|
296
|
-
const { profile, targetProfile, boost, boostCreated, contractUri } = params;
|
|
297
|
-
|
|
298
|
-
let contractTerms = null as Awaited<ReturnType<typeof getContractTermsForProfile>> | null;
|
|
299
|
-
let contractDetails: Awaited<ReturnType<typeof getContractDetailsByUri>> | null = null;
|
|
300
|
-
|
|
301
|
-
if (contractUri) {
|
|
302
|
-
const decodedContractUri = decodeURIComponent(contractUri);
|
|
303
|
-
contractDetails = await traceDb('getContractDetailsByUri', () =>
|
|
304
|
-
getContractDetailsByUri(decodedContractUri)
|
|
305
|
-
);
|
|
306
|
-
|
|
307
|
-
if (!contractDetails) {
|
|
308
|
-
throw new TRPCError({
|
|
309
|
-
code: 'NOT_FOUND',
|
|
310
|
-
message: 'Could not find contract',
|
|
311
|
-
});
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const terms = await traceDb('getContractTermsForProfile', () =>
|
|
315
|
-
getContractTermsForProfile(targetProfile, contractDetails!.contract)
|
|
316
|
-
);
|
|
317
|
-
|
|
318
|
-
const writers = await traceDb('getWritersForContract', () =>
|
|
319
|
-
getWritersForContract(contractDetails!.contract)
|
|
320
|
-
);
|
|
321
|
-
const isWriter = writers.some(writer => writer.profileId === profile.profileId);
|
|
322
|
-
const isDenied = terms?.terms.deniedWriters?.includes(profile.profileId) ?? false;
|
|
323
|
-
const categoryAllowed = boost.category
|
|
324
|
-
? terms?.terms.write?.credentials?.categories?.[boost.category] === true
|
|
325
|
-
: true;
|
|
326
|
-
|
|
327
|
-
if (terms && isWriter && !isDenied && categoryAllowed) {
|
|
328
|
-
contractTerms = terms;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
if (boostCreated && contractDetails) {
|
|
333
|
-
await traceDb('setRelatedBoostForContract', () =>
|
|
334
|
-
setRelatedBoostForContract(contractDetails!.contract, boost)
|
|
335
|
-
);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
return contractTerms;
|
|
339
|
-
};
|
|
340
|
-
|
|
341
295
|
/** Validate managed send support and recipient before creating any send state. */
|
|
342
296
|
const validateRefreshSendRecipient = async ({
|
|
343
297
|
profile,
|
|
@@ -447,50 +401,85 @@ const managedRefreshServiceFor = (refreshId: string, domain: string) => ({
|
|
|
447
401
|
* retried call reuses the same boost/allocation, or returns the completed result.
|
|
448
402
|
*/
|
|
449
403
|
const prepareManagedRefreshSend = async (params: {
|
|
404
|
+
statusBinding?: 'server';
|
|
405
|
+
/** Internal signing already owns allocation; preserve its existing request digest. */
|
|
406
|
+
serverSigning?: boolean;
|
|
407
|
+
statusPurposes?: ('revocation' | 'suspension')[];
|
|
450
408
|
profile: ProfileType;
|
|
451
409
|
/** Returned by validateRefreshSendRecipient in this request, before any mutation. */
|
|
452
410
|
targetProfile: ProfileType;
|
|
453
411
|
domain: string;
|
|
454
412
|
templateUri?: string;
|
|
455
413
|
template?: z.infer<typeof SendBoostTemplateValidator>;
|
|
414
|
+
display?: import('@learncard/types').CredentialDisplay;
|
|
456
415
|
contractUri?: string;
|
|
457
416
|
credentialId?: string;
|
|
458
417
|
templateData?: Record<string, unknown>;
|
|
459
418
|
integrationId?: string;
|
|
460
419
|
idempotencyKey?: string;
|
|
420
|
+
/** `'holder'` requests student-only encryption (LC-2345); default `'network'`. */
|
|
421
|
+
encryption?: 'network' | 'holder';
|
|
461
422
|
}): Promise<PrepareRefreshableSendResult & { intent?: RefreshSendIntent }> => {
|
|
462
423
|
const { profile, targetProfile, domain, templateUri, template, contractUri } = params;
|
|
463
424
|
// Local recipients authenticate refresh requests as their network profile DID,
|
|
464
425
|
// including when the caller addressed them by their controller did:key.
|
|
465
426
|
const holderDid = getDidWeb(domain, targetProfile.profileId);
|
|
427
|
+
const holderMode = params.encryption === 'holder';
|
|
428
|
+
// Holder and network sends share the same explicit status-allocation contract.
|
|
429
|
+
let preallocateStatus =
|
|
430
|
+
(params.serverSigning && !template?.credential.credentialStatus) ||
|
|
431
|
+
params.statusBinding === 'server';
|
|
432
|
+
// Computed once and reused for both the request digest and anchor creation below,
|
|
433
|
+
// so a retried/keyed request can never digest a different display than the one
|
|
434
|
+
// actually stored on the anchor.
|
|
435
|
+
const normalizedDisplay = normalizePublicDisplay(params.display, template);
|
|
466
436
|
|
|
467
437
|
let intent: RefreshSendIntent | undefined;
|
|
468
438
|
|
|
469
|
-
if (params.idempotencyKey) {
|
|
439
|
+
if (params.idempotencyKey || holderMode) {
|
|
440
|
+
const request = {
|
|
441
|
+
recipientProfileId: targetProfile.profileId,
|
|
442
|
+
holderDid,
|
|
443
|
+
templateUri,
|
|
444
|
+
display: normalizedDisplay,
|
|
445
|
+
contractUri,
|
|
446
|
+
integrationId: params.integrationId,
|
|
447
|
+
credentialId: params.credentialId,
|
|
448
|
+
statusPurposes: params.statusPurposes,
|
|
449
|
+
encryption: params.encryption,
|
|
450
|
+
statusBinding: params.statusBinding,
|
|
451
|
+
};
|
|
470
452
|
const claim = await claimRefreshSendIntent({
|
|
471
453
|
issuerProfileId: profile.profileId,
|
|
472
|
-
idempotencyKey: params.idempotencyKey,
|
|
473
|
-
requestDigest: computeRefreshSendRequestDigest(
|
|
474
|
-
|
|
475
|
-
holderDid,
|
|
476
|
-
templateUri,
|
|
477
|
-
template,
|
|
478
|
-
contractUri,
|
|
479
|
-
templateData: params.templateData,
|
|
480
|
-
integrationId: params.integrationId,
|
|
481
|
-
credentialId: params.credentialId,
|
|
482
|
-
}),
|
|
454
|
+
idempotencyKey: params.idempotencyKey ?? uuid(),
|
|
455
|
+
requestDigest: computeRefreshSendRequestDigest(request),
|
|
456
|
+
requestDigestCandidates: getRefreshSendRequestDigestCandidates(request),
|
|
483
457
|
});
|
|
484
458
|
|
|
485
459
|
intent = claim.intent;
|
|
486
460
|
|
|
487
461
|
if (claim.kind !== 'owned') {
|
|
462
|
+
const refresh = await getCredentialRefresh(intent.refreshId!);
|
|
488
463
|
const prepared = {
|
|
464
|
+
...(preallocateStatus && refresh?.statusEntries
|
|
465
|
+
? {
|
|
466
|
+
statusEntries: JSON.parse(refresh.statusEntries),
|
|
467
|
+
statusManagement: getStatusManagement(
|
|
468
|
+
JSON.parse(refresh.statusEntries),
|
|
469
|
+
domain
|
|
470
|
+
),
|
|
471
|
+
}
|
|
472
|
+
: {}),
|
|
489
473
|
boostUri: intent.boostUri!,
|
|
490
474
|
credentialId: intent.credentialId!,
|
|
491
475
|
refreshId: intent.refreshId!,
|
|
492
476
|
refreshService: managedRefreshServiceFor(intent.refreshId!, domain),
|
|
493
477
|
holderDid: intent.holderDid!,
|
|
478
|
+
// Recomputed fresh (never cached on the intent): a manager change
|
|
479
|
+
// between prepare calls must be reflected immediately.
|
|
480
|
+
...(refresh?.encryptionMode === 'holder'
|
|
481
|
+
? { recipientKeyIds: await getHolderEncryptionRecipientKeyIds(targetProfile) }
|
|
482
|
+
: {}),
|
|
494
483
|
intent,
|
|
495
484
|
};
|
|
496
485
|
const completed =
|
|
@@ -517,7 +506,7 @@ const prepareManagedRefreshSend = async (params: {
|
|
|
517
506
|
|
|
518
507
|
if (!boost) throw new TRPCError({ code: 'NOT_FOUND', message: 'Could not find boost' });
|
|
519
508
|
} else {
|
|
520
|
-
boost = await
|
|
509
|
+
boost = await createDisplayOnlyBoost(normalizedDisplay, profile, domain);
|
|
521
510
|
boostUri = getBoostUri(boost.id, domain);
|
|
522
511
|
|
|
523
512
|
if (intent) intent = await recordRefreshSendIntent(intent, { boostUri });
|
|
@@ -560,28 +549,57 @@ const prepareManagedRefreshSend = async (params: {
|
|
|
560
549
|
holderDid,
|
|
561
550
|
credentialId,
|
|
562
551
|
domain,
|
|
552
|
+
...(holderMode ? { encryptionMode: 'holder' as const } : {}),
|
|
563
553
|
})
|
|
564
554
|
);
|
|
565
555
|
|
|
566
556
|
refreshId = allocation.refreshId;
|
|
567
557
|
}
|
|
568
558
|
|
|
559
|
+
// Older clients allocate their own coordinates after preparation. Bind those
|
|
560
|
+
// only at the signed handoff, where ownership and index reuse are validated.
|
|
561
|
+
const templateCredential = JSON.parse(boost.dataValues.boost) as UnsignedVC;
|
|
562
|
+
if (params.serverSigning && templateCredential.credentialStatus) preallocateStatus = false;
|
|
563
|
+
const statusEntries = preallocateStatus
|
|
564
|
+
? await prepareRefreshStatusEntries(
|
|
565
|
+
refreshId,
|
|
566
|
+
profile.profileId,
|
|
567
|
+
domain,
|
|
568
|
+
params.statusPurposes
|
|
569
|
+
)
|
|
570
|
+
: undefined;
|
|
569
571
|
if (intent) {
|
|
570
572
|
intent = await recordRefreshSendIntent(intent, {
|
|
571
573
|
boostUri,
|
|
572
574
|
credentialId,
|
|
573
575
|
refreshId,
|
|
574
576
|
holderDid,
|
|
577
|
+
contractUri,
|
|
578
|
+
integrationId: params.integrationId,
|
|
575
579
|
state: 'prepared',
|
|
576
580
|
});
|
|
577
581
|
}
|
|
578
582
|
|
|
579
583
|
return {
|
|
580
584
|
boostUri,
|
|
585
|
+
...(statusEntries
|
|
586
|
+
? { statusEntries, statusManagement: getStatusManagement(statusEntries, domain) }
|
|
587
|
+
: templateCredential.credentialStatus
|
|
588
|
+
? {
|
|
589
|
+
statusManagement: getStatusManagement(
|
|
590
|
+
getBitstringStatusListEntries(templateCredential),
|
|
591
|
+
domain
|
|
592
|
+
),
|
|
593
|
+
}
|
|
594
|
+
: {}),
|
|
581
595
|
credentialId,
|
|
582
596
|
refreshId,
|
|
583
597
|
refreshService: managedRefreshServiceFor(refreshId, domain),
|
|
584
598
|
holderDid,
|
|
599
|
+
// Recomputed every call (never persisted): see getHolderEncryptionRecipientKeyIds.
|
|
600
|
+
...(holderMode
|
|
601
|
+
? { recipientKeyIds: await getHolderEncryptionRecipientKeyIds(targetProfile) }
|
|
602
|
+
: {}),
|
|
585
603
|
...(intent ? { intent } : {}),
|
|
586
604
|
};
|
|
587
605
|
};
|
|
@@ -590,7 +608,7 @@ export const boostsRouter = t.router({
|
|
|
590
608
|
// SDK preparation only: guards, boost anchor and refresh allocation. Never signs or
|
|
591
609
|
// delivers. With an idempotencyKey a retried call reuses the same boost/allocation,
|
|
592
610
|
// or returns `completed` when that key already delivered.
|
|
593
|
-
prepareRefreshableSend:
|
|
611
|
+
prepareRefreshableSend: credentialProfileRoute
|
|
594
612
|
.meta({ requiredScope: 'boosts:write' })
|
|
595
613
|
.input(PrepareRefreshableSendInputValidator)
|
|
596
614
|
.output(PrepareRefreshableSendResultValidator)
|
|
@@ -1081,7 +1099,7 @@ export const boostsRouter = t.router({
|
|
|
1081
1099
|
return credentialUri;
|
|
1082
1100
|
}),
|
|
1083
1101
|
|
|
1084
|
-
send:
|
|
1102
|
+
send: credentialProfileRoute
|
|
1085
1103
|
.meta({
|
|
1086
1104
|
openapi: {
|
|
1087
1105
|
protect: true,
|
|
@@ -1131,6 +1149,8 @@ export const boostsRouter = t.router({
|
|
|
1131
1149
|
issuerProfileId: profile.profileId,
|
|
1132
1150
|
idempotencyKey: input.idempotencyKey,
|
|
1133
1151
|
requestDigest: inboxDigest!,
|
|
1152
|
+
requestDigestCandidates:
|
|
1153
|
+
getInboxRefreshRequestDigestCandidates(input),
|
|
1134
1154
|
});
|
|
1135
1155
|
if (claim.kind === 'delivered' && claim.intent.result)
|
|
1136
1156
|
return claim.intent.result;
|
|
@@ -1138,7 +1158,8 @@ export const boostsRouter = t.router({
|
|
|
1138
1158
|
const replay = await getInboxRefreshReplay(
|
|
1139
1159
|
profile.profileId,
|
|
1140
1160
|
inboxKey,
|
|
1141
|
-
inboxDigest
|
|
1161
|
+
inboxDigest!,
|
|
1162
|
+
getInboxRefreshRequestDigestCandidates(input)
|
|
1142
1163
|
);
|
|
1143
1164
|
if (
|
|
1144
1165
|
replay &&
|
|
@@ -1229,23 +1250,45 @@ export const boostsRouter = t.router({
|
|
|
1229
1250
|
// Keyed managed send without a pre-signed credential: preparation (boost +
|
|
1230
1251
|
// allocation) goes through the idempotency intent instead of the generic
|
|
1231
1252
|
// boost creation below.
|
|
1253
|
+
if (input.template?.status === 'DRAFT') {
|
|
1254
|
+
throw new TRPCError({
|
|
1255
|
+
code: 'FORBIDDEN',
|
|
1256
|
+
message:
|
|
1257
|
+
'Draft Boosts can not be sent. Only Published Boosts can be sent.',
|
|
1258
|
+
});
|
|
1259
|
+
}
|
|
1232
1260
|
const keyedPrepared =
|
|
1233
1261
|
refreshRequested && input.idempotencyKey && !input.signedCredential
|
|
1234
1262
|
? await prepareManagedRefreshSend({
|
|
1263
|
+
serverSigning: true,
|
|
1235
1264
|
profile,
|
|
1236
1265
|
targetProfile: refreshTargetProfile!,
|
|
1237
1266
|
domain,
|
|
1238
1267
|
templateUri: input.templateUri,
|
|
1239
1268
|
template: input.templateUri ? undefined : input.template,
|
|
1269
|
+
display: input.display,
|
|
1240
1270
|
contractUri,
|
|
1241
1271
|
templateData: input.templateData,
|
|
1242
1272
|
integrationId: input.integrationId,
|
|
1243
1273
|
idempotencyKey: input.idempotencyKey,
|
|
1274
|
+
statusPurposes: input.statusPurposes,
|
|
1244
1275
|
})
|
|
1245
1276
|
: undefined;
|
|
1246
1277
|
|
|
1247
1278
|
if (keyedPrepared?.completed) return keyedPrepared.completed;
|
|
1248
1279
|
|
|
1280
|
+
// boost.send only ever builds a plaintext credential (signedCredential
|
|
1281
|
+
// input or a server/signing-authority-signed one below); a holder-mode
|
|
1282
|
+
// prepare (recipientKeyIds present) must deliver its encrypted handoff
|
|
1283
|
+
// through credentialRefresh.sendHolderEncryptedRefreshable instead.
|
|
1284
|
+
if (keyedPrepared?.recipientKeyIds) {
|
|
1285
|
+
throw new TRPCError({
|
|
1286
|
+
code: 'BAD_REQUEST',
|
|
1287
|
+
message:
|
|
1288
|
+
'This credential refresh uses holder-mode encryption; send the encrypted handoff via credentialRefresh.sendHolderEncryptedRefreshable instead.',
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1249
1292
|
// Check if recipient is email/phone (routes to Universal Inbox)
|
|
1250
1293
|
const inboxRecipient = isInboxRecipient(input.recipient);
|
|
1251
1294
|
|
|
@@ -1282,7 +1325,15 @@ export const boostsRouter = t.router({
|
|
|
1282
1325
|
boost = resolved;
|
|
1283
1326
|
boostUri = input.templateUri;
|
|
1284
1327
|
} else if (input.template) {
|
|
1285
|
-
boost =
|
|
1328
|
+
boost =
|
|
1329
|
+
input.refresh || input.signedCredential
|
|
1330
|
+
? await createDisplayOnlyBoost(
|
|
1331
|
+
input.display,
|
|
1332
|
+
profile,
|
|
1333
|
+
domain,
|
|
1334
|
+
input.template
|
|
1335
|
+
)
|
|
1336
|
+
: await createInlineBoostForSend(input.template, profile, domain);
|
|
1286
1337
|
|
|
1287
1338
|
boostUri = getBoostUri(boost.id, domain);
|
|
1288
1339
|
boostCreated = true;
|
|
@@ -1328,26 +1379,11 @@ export const boostsRouter = t.router({
|
|
|
1328
1379
|
boost = preparedBoost;
|
|
1329
1380
|
boostUri = preparedBoostUri;
|
|
1330
1381
|
} else {
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
input.
|
|
1336
|
-
const name =
|
|
1337
|
-
typeof templateCredential.name === 'string'
|
|
1338
|
-
? templateCredential.name
|
|
1339
|
-
: undefined;
|
|
1340
|
-
|
|
1341
|
-
boost = await traceDb('createBoost:fromSignedCredential', () =>
|
|
1342
|
-
createBoost(
|
|
1343
|
-
(refreshRequested
|
|
1344
|
-
? templateCredential
|
|
1345
|
-
: input.signedCredential!) as typeof input.signedCredential &
|
|
1346
|
-
object,
|
|
1347
|
-
profile,
|
|
1348
|
-
{ ...(name ? { name } : {}) },
|
|
1349
|
-
domain
|
|
1350
|
-
)
|
|
1382
|
+
boost = await createDisplayOnlyBoost(
|
|
1383
|
+
input.display,
|
|
1384
|
+
profile,
|
|
1385
|
+
domain,
|
|
1386
|
+
input.template
|
|
1351
1387
|
);
|
|
1352
1388
|
|
|
1353
1389
|
boostUri = getBoostUri(boost.id, domain);
|
|
@@ -1468,17 +1504,18 @@ export const boostsRouter = t.router({
|
|
|
1468
1504
|
);
|
|
1469
1505
|
|
|
1470
1506
|
if (binding.bound) {
|
|
1471
|
-
const { uri, receipt } =
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1507
|
+
const { uri, receipt, statusManagement } =
|
|
1508
|
+
await sendRefreshableCredential({
|
|
1509
|
+
issuerProfile: profile,
|
|
1510
|
+
refreshId,
|
|
1511
|
+
credential: signedVc,
|
|
1512
|
+
boostUri,
|
|
1513
|
+
skipNotification,
|
|
1514
|
+
domain,
|
|
1515
|
+
activityId: binding.activityId,
|
|
1516
|
+
integrationId: input.integrationId,
|
|
1517
|
+
contractTerms: contractTerms ?? undefined,
|
|
1518
|
+
});
|
|
1482
1519
|
|
|
1483
1520
|
const response = {
|
|
1484
1521
|
type: 'boost' as const,
|
|
@@ -1486,6 +1523,7 @@ export const boostsRouter = t.router({
|
|
|
1486
1523
|
uri: boostUri,
|
|
1487
1524
|
activityId: binding.activityId ?? '',
|
|
1488
1525
|
refresh: receipt,
|
|
1526
|
+
statusManagement,
|
|
1489
1527
|
};
|
|
1490
1528
|
|
|
1491
1529
|
if (intent)
|
|
@@ -1523,6 +1561,7 @@ export const boostsRouter = t.router({
|
|
|
1523
1561
|
'prepareCredentialFromBoost:refresh',
|
|
1524
1562
|
() =>
|
|
1525
1563
|
prepareCredentialFromBoost(boost!, boostUri, domain, {
|
|
1564
|
+
credential: input.template?.credential,
|
|
1526
1565
|
templateData: input.templateData as Record<
|
|
1527
1566
|
string,
|
|
1528
1567
|
unknown
|
|
@@ -1534,8 +1573,10 @@ export const boostsRouter = t.router({
|
|
|
1534
1573
|
recipientName: targetProfile.displayName,
|
|
1535
1574
|
})
|
|
1536
1575
|
);
|
|
1537
|
-
} catch (
|
|
1538
|
-
|
|
1576
|
+
} catch (error) {
|
|
1577
|
+
if (error instanceof TRPCError && error.code === 'BAD_REQUEST')
|
|
1578
|
+
throw error;
|
|
1579
|
+
console.error('CREDENTIAL_PREPARATION_FAILED');
|
|
1539
1580
|
throw new TRPCError({
|
|
1540
1581
|
code: 'INTERNAL_SERVER_ERROR',
|
|
1541
1582
|
message: 'Failed to prepare boost credential',
|
|
@@ -1569,6 +1610,21 @@ export const boostsRouter = t.router({
|
|
|
1569
1610
|
|
|
1570
1611
|
refreshId = allocation.refreshId;
|
|
1571
1612
|
|
|
1613
|
+
const statusEntries = unsignedVc.credentialStatus
|
|
1614
|
+
? undefined
|
|
1615
|
+
: await prepareRefreshStatusEntries(
|
|
1616
|
+
refreshId,
|
|
1617
|
+
profile.profileId,
|
|
1618
|
+
domain,
|
|
1619
|
+
input.statusPurposes
|
|
1620
|
+
);
|
|
1621
|
+
if (statusEntries)
|
|
1622
|
+
unsignedVc.credentialStatus =
|
|
1623
|
+
statusEntries.length === 1 &&
|
|
1624
|
+
!Array.isArray(unsignedVc.credentialStatus)
|
|
1625
|
+
? statusEntries[0]
|
|
1626
|
+
: statusEntries;
|
|
1627
|
+
|
|
1572
1628
|
const prepared = injectManagedRefreshService(
|
|
1573
1629
|
unsignedVc,
|
|
1574
1630
|
allocation.refreshService
|
|
@@ -1583,6 +1639,8 @@ export const boostsRouter = t.router({
|
|
|
1583
1639
|
prepared,
|
|
1584
1640
|
signingAuthority,
|
|
1585
1641
|
domain,
|
|
1642
|
+
false,
|
|
1643
|
+
undefined,
|
|
1586
1644
|
false
|
|
1587
1645
|
)
|
|
1588
1646
|
).credential as VC
|
|
@@ -1609,7 +1667,10 @@ export const boostsRouter = t.router({
|
|
|
1609
1667
|
intent,
|
|
1610
1668
|
{
|
|
1611
1669
|
refreshId,
|
|
1612
|
-
refreshService:
|
|
1670
|
+
refreshService:
|
|
1671
|
+
ManagedCredentialRefreshBindingValidator.parse(
|
|
1672
|
+
signedVc.refreshService
|
|
1673
|
+
),
|
|
1613
1674
|
credentialId: signedVc.id as string,
|
|
1614
1675
|
issuerDid:
|
|
1615
1676
|
getCredentialIssuerId(signedVc) ??
|
|
@@ -1626,17 +1687,18 @@ export const boostsRouter = t.router({
|
|
|
1626
1687
|
}
|
|
1627
1688
|
|
|
1628
1689
|
try {
|
|
1629
|
-
const { uri, receipt } =
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1690
|
+
const { uri, receipt, statusManagement } =
|
|
1691
|
+
await sendRefreshableCredential({
|
|
1692
|
+
issuerProfile: profile,
|
|
1693
|
+
refreshId,
|
|
1694
|
+
credential: signedVc,
|
|
1695
|
+
boostUri,
|
|
1696
|
+
skipNotification,
|
|
1697
|
+
domain,
|
|
1698
|
+
activityId,
|
|
1699
|
+
integrationId: input.integrationId,
|
|
1700
|
+
contractTerms: contractTerms ?? undefined,
|
|
1701
|
+
});
|
|
1640
1702
|
|
|
1641
1703
|
const response = {
|
|
1642
1704
|
type: 'boost' as const,
|
|
@@ -1644,6 +1706,7 @@ export const boostsRouter = t.router({
|
|
|
1644
1706
|
uri: boostUri,
|
|
1645
1707
|
activityId,
|
|
1646
1708
|
refresh: receipt,
|
|
1709
|
+
statusManagement,
|
|
1647
1710
|
};
|
|
1648
1711
|
|
|
1649
1712
|
if (intent) await markRefreshSendIntentDelivered(intent, response);
|
|
@@ -1714,6 +1777,9 @@ export const boostsRouter = t.router({
|
|
|
1714
1777
|
'prepareCredentialFromBoost:inbox',
|
|
1715
1778
|
() =>
|
|
1716
1779
|
prepareCredentialFromBoost(boost!, boostUri, domain, {
|
|
1780
|
+
credential: input.refresh
|
|
1781
|
+
? input.template?.credential
|
|
1782
|
+
: undefined,
|
|
1717
1783
|
templateData: input.templateData as Record<
|
|
1718
1784
|
string,
|
|
1719
1785
|
unknown
|
|
@@ -1722,8 +1788,10 @@ export const boostsRouter = t.router({
|
|
|
1722
1788
|
recipientName: inboxRecipientName,
|
|
1723
1789
|
})
|
|
1724
1790
|
);
|
|
1725
|
-
} catch (
|
|
1726
|
-
|
|
1791
|
+
} catch (error) {
|
|
1792
|
+
if (error instanceof TRPCError && error.code === 'BAD_REQUEST')
|
|
1793
|
+
throw error;
|
|
1794
|
+
console.error('INBOX_CREDENTIAL_PREPARATION_FAILED');
|
|
1727
1795
|
throw new TRPCError({
|
|
1728
1796
|
code: 'INTERNAL_SERVER_ERROR',
|
|
1729
1797
|
message: 'Failed to prepare boost credential',
|
|
@@ -1749,7 +1817,10 @@ export const boostsRouter = t.router({
|
|
|
1749
1817
|
boostUri,
|
|
1750
1818
|
source: 'send',
|
|
1751
1819
|
integrationId: input.integrationId,
|
|
1752
|
-
metadata:
|
|
1820
|
+
metadata:
|
|
1821
|
+
input.refresh || input.signedCredential
|
|
1822
|
+
? undefined
|
|
1823
|
+
: { templateData: input.templateData },
|
|
1753
1824
|
})
|
|
1754
1825
|
);
|
|
1755
1826
|
|
|
@@ -1766,6 +1837,9 @@ export const boostsRouter = t.router({
|
|
|
1766
1837
|
refresh: inboxRefreshRequested,
|
|
1767
1838
|
idempotencyKey: inboxKey,
|
|
1768
1839
|
refreshRequestDigest: inboxDigest,
|
|
1840
|
+
refreshRequestDigestCandidates: inboxRefreshRequested
|
|
1841
|
+
? getInboxRefreshRequestDigestCandidates(input)
|
|
1842
|
+
: undefined,
|
|
1769
1843
|
activityId,
|
|
1770
1844
|
integrationId: input.integrationId,
|
|
1771
1845
|
},
|
|
@@ -1858,8 +1932,10 @@ export const boostsRouter = t.router({
|
|
|
1858
1932
|
recipientDid: input.recipient,
|
|
1859
1933
|
})
|
|
1860
1934
|
);
|
|
1861
|
-
} catch (
|
|
1862
|
-
|
|
1935
|
+
} catch (error) {
|
|
1936
|
+
if (error instanceof TRPCError && error.code === 'BAD_REQUEST')
|
|
1937
|
+
throw error;
|
|
1938
|
+
console.error('CREDENTIAL_PREPARATION_FAILED');
|
|
1863
1939
|
throw new TRPCError({
|
|
1864
1940
|
code: 'INTERNAL_SERVER_ERROR',
|
|
1865
1941
|
message: 'Failed to prepare boost credential',
|
|
@@ -1895,7 +1971,9 @@ export const boostsRouter = t.router({
|
|
|
1895
1971
|
boostUri,
|
|
1896
1972
|
source: 'send',
|
|
1897
1973
|
integrationId: input.integrationId,
|
|
1898
|
-
metadata:
|
|
1974
|
+
metadata: input.signedCredential
|
|
1975
|
+
? undefined
|
|
1976
|
+
: { templateData: input.templateData },
|
|
1899
1977
|
})
|
|
1900
1978
|
);
|
|
1901
1979
|
|
|
@@ -2029,8 +2107,10 @@ export const boostsRouter = t.router({
|
|
|
2029
2107
|
recipientName: targetProfile.displayName,
|
|
2030
2108
|
})
|
|
2031
2109
|
);
|
|
2032
|
-
} catch (
|
|
2033
|
-
|
|
2110
|
+
} catch (error) {
|
|
2111
|
+
if (error instanceof TRPCError && error.code === 'BAD_REQUEST')
|
|
2112
|
+
throw error;
|
|
2113
|
+
console.error('CREDENTIAL_PREPARATION_FAILED');
|
|
2034
2114
|
throw new TRPCError({
|
|
2035
2115
|
code: 'INTERNAL_SERVER_ERROR',
|
|
2036
2116
|
message: 'Failed to prepare boost credential',
|
|
@@ -2066,7 +2146,9 @@ export const boostsRouter = t.router({
|
|
|
2066
2146
|
boostUri,
|
|
2067
2147
|
source: 'send',
|
|
2068
2148
|
integrationId: input.integrationId,
|
|
2069
|
-
metadata:
|
|
2149
|
+
metadata: input.signedCredential
|
|
2150
|
+
? undefined
|
|
2151
|
+
: { templateData: input.templateData },
|
|
2070
2152
|
})
|
|
2071
2153
|
);
|
|
2072
2154
|
|