@learncard/network-brain-service 4.1.3 → 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 +143 -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
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { v4 as uuid } from 'uuid';
|
|
2
|
+
import { getConsentFlowContractVersionRecord } from '@accesslayer/consentflowcontract/versions';
|
|
1
3
|
import { termsReferralSnapshotCypher } from '@helpers/consent-referral.helpers';
|
|
2
4
|
import { appendConsentEvent, tryDispatchContractEvent } from '@helpers/contract-events.helpers';
|
|
3
5
|
import { QueryBuilder, BindParam } from 'neogma';
|
|
4
6
|
import { TRPCError } from '@trpc/server';
|
|
5
|
-
import { v4 as uuid } from 'uuid';
|
|
6
7
|
import {
|
|
7
8
|
ConsentFlowTerms as ConsentFlowTermsType,
|
|
8
9
|
ConsentFlowTransaction as ConsentFlowTransactionType,
|
|
@@ -31,6 +32,78 @@ import {
|
|
|
31
32
|
runAudienceMutation,
|
|
32
33
|
} from './recipients';
|
|
33
34
|
|
|
35
|
+
export const claimAutoBoostTransaction = async (
|
|
36
|
+
contractId: string,
|
|
37
|
+
termsId: string,
|
|
38
|
+
boostId: string,
|
|
39
|
+
allowConsumedOneTime = false
|
|
40
|
+
) => {
|
|
41
|
+
const id = uuid();
|
|
42
|
+
const result = await neogma.queryRunner.run(
|
|
43
|
+
`MATCH (contract:ConsentFlowContract {id:$contractId})
|
|
44
|
+
SET contract.autoBoostClaimLock = coalesce(contract.autoBoostClaimLock, 0) + 1
|
|
45
|
+
WITH contract
|
|
46
|
+
MATCH (terms:ConsentFlowTerms {id:$termsId})-[:CONSENTS_TO]->(contract)
|
|
47
|
+
WHERE coalesce(contract.status, 'active') <> 'retired'
|
|
48
|
+
AND (terms.status = 'live' OR
|
|
49
|
+
($allowConsumedOneTime AND terms.status = 'consumed' AND terms.oneTime = true))
|
|
50
|
+
AND coalesce(terms.consentedVersion, 1) = coalesce(contract.currentVersion, 1)
|
|
51
|
+
SET terms.autoBoostClaimLock = coalesce(terms.autoBoostClaimLock, 0) + 1
|
|
52
|
+
WITH terms
|
|
53
|
+
OPTIONAL MATCH (terms)<-[:IS_FOR]-(existing:ConsentFlowTransaction {boostId:$boostId})
|
|
54
|
+
OPTIONAL MATCH (terms)<-[:IS_FOR]-(legacy:ConsentFlowTransaction)-[:ISSUED_VIA_TRANSACTION]-
|
|
55
|
+
(credential:Credential)-[:INSTANCE_OF]->(:Boost {id:$boostId})
|
|
56
|
+
OPTIONAL MATCH (claim:ConsentFlowAutoBoostClaim {termsId:$termsId, boostId:$boostId})
|
|
57
|
+
WITH terms, existing, legacy, claim
|
|
58
|
+
WHERE existing IS NULL AND legacy IS NULL AND claim IS NULL
|
|
59
|
+
CREATE (:ConsentFlowAutoBoostClaim {id:$id, termsId:$termsId, boostId:$boostId})
|
|
60
|
+
RETURN $id AS id`,
|
|
61
|
+
{ contractId, termsId, boostId, id, allowConsumedOneTime }
|
|
62
|
+
);
|
|
63
|
+
const created = result.records[0]?.get('id');
|
|
64
|
+
return created ? String(created) : null;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const completeAutoBoostTransaction = async (
|
|
68
|
+
claimId: string,
|
|
69
|
+
termsId: string,
|
|
70
|
+
boostId: string
|
|
71
|
+
) => {
|
|
72
|
+
await neogma.queryRunner.run(
|
|
73
|
+
`MATCH (terms:ConsentFlowTerms {id:$termsId})
|
|
74
|
+
MATCH (claim:ConsentFlowAutoBoostClaim {id:$claimId})
|
|
75
|
+
MATCH (terms)<-[:IS_FOR]-(transaction:ConsentFlowTransaction)
|
|
76
|
+
<-[:ISSUED_VIA_TRANSACTION]-(credential:Credential)-[:INSTANCE_OF]->(:Boost {id:$boostId})
|
|
77
|
+
WITH claim, collect(DISTINCT transaction) AS transactions
|
|
78
|
+
FOREACH (transaction IN transactions | SET transaction.boostId = $boostId)
|
|
79
|
+
DETACH DELETE claim`,
|
|
80
|
+
{ termsId, claimId, boostId }
|
|
81
|
+
);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const releaseAutoBoostClaim = async (claimId: string) => {
|
|
85
|
+
await neogma.queryRunner.run(
|
|
86
|
+
`MATCH (claim:ConsentFlowAutoBoostClaim {id:$claimId}) DETACH DELETE claim`,
|
|
87
|
+
{ claimId }
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
export const isAutoBoostConsentCurrent = async (
|
|
91
|
+
contractId: string,
|
|
92
|
+
termsId: string,
|
|
93
|
+
allowConsumedOneTime = false
|
|
94
|
+
) => {
|
|
95
|
+
const result = await neogma.queryRunner.run(
|
|
96
|
+
`MATCH (contract:ConsentFlowContract {id:$contractId})
|
|
97
|
+
MATCH (terms:ConsentFlowTerms {id:$termsId})-[:CONSENTS_TO]->(contract)
|
|
98
|
+
RETURN coalesce(contract.status, 'active') <> 'retired'
|
|
99
|
+
AND (terms.status = 'live' OR
|
|
100
|
+
($allowConsumedOneTime AND terms.status = 'consumed' AND terms.oneTime = true))
|
|
101
|
+
AND coalesce(terms.consentedVersion, 1) = coalesce(contract.currentVersion, 1) AS current`,
|
|
102
|
+
{ contractId, termsId, allowConsumedOneTime }
|
|
103
|
+
);
|
|
104
|
+
return result.records[0]?.get('current') === true;
|
|
105
|
+
};
|
|
106
|
+
|
|
34
107
|
export const reconsentTerms = async (
|
|
35
108
|
relationship: {
|
|
36
109
|
terms: DbTermsType;
|
|
@@ -46,6 +119,7 @@ export const reconsentTerms = async (
|
|
|
46
119
|
audienceVersion,
|
|
47
120
|
expectedRequestId,
|
|
48
121
|
smartResumeFingerprint,
|
|
122
|
+
acceptVersion,
|
|
49
123
|
}: {
|
|
50
124
|
terms: ConsentFlowTermsType;
|
|
51
125
|
expiresAt?: string;
|
|
@@ -54,12 +128,23 @@ export const reconsentTerms = async (
|
|
|
54
128
|
audienceVersion?: number;
|
|
55
129
|
expectedRequestId?: string;
|
|
56
130
|
smartResumeFingerprint?: string;
|
|
131
|
+
acceptVersion?: number;
|
|
57
132
|
},
|
|
58
133
|
domain: string
|
|
59
134
|
): Promise<boolean> => {
|
|
135
|
+
const currentVersion = Number(relationship.contract.currentVersion ?? 1);
|
|
136
|
+
const version = acceptVersion ?? currentVersion;
|
|
137
|
+
if (!Number.isInteger(version) || version !== currentVersion) {
|
|
138
|
+
throw new TRPCError({
|
|
139
|
+
code: 'CONFLICT',
|
|
140
|
+
message: 'Only the latest contract version can be accepted',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
const effectiveOneTime = oneTime ?? relationship.terms.oneTime ?? false;
|
|
144
|
+
|
|
60
145
|
const transaction = {
|
|
61
146
|
id: uuid(),
|
|
62
|
-
action: '
|
|
147
|
+
action: 'reconsent',
|
|
63
148
|
date: new Date().toISOString(),
|
|
64
149
|
...(typeof expiresAt === 'string' ? { expiresAt } : {}),
|
|
65
150
|
...(typeof oneTime === 'boolean' ? { oneTime } : {}),
|
|
@@ -81,6 +166,7 @@ export const reconsentTerms = async (
|
|
|
81
166
|
lockContractAudience(
|
|
82
167
|
new QueryBuilder(
|
|
83
168
|
new BindParam({
|
|
169
|
+
expectedContractVersion: version,
|
|
84
170
|
audienceVersion: audienceVersion ?? null,
|
|
85
171
|
expectedRequestId: expectedRequestId ?? null,
|
|
86
172
|
consenterProfileId: relationship.consenter.profileId,
|
|
@@ -100,7 +186,12 @@ export const reconsentTerms = async (
|
|
|
100
186
|
}
|
|
101
187
|
: {}),
|
|
102
188
|
updatedAt: transaction.date,
|
|
103
|
-
status:
|
|
189
|
+
status: effectiveOneTime ? 'consumed' : 'live',
|
|
190
|
+
|
|
191
|
+
consentedVersion: version,
|
|
192
|
+
lastReviewedVersion: version,
|
|
193
|
+
reconsentDeadline: null,
|
|
194
|
+
newOptionsUntil: null,
|
|
104
195
|
...(typeof expiresAt === 'string' ? { expiresAt } : {}),
|
|
105
196
|
...(typeof oneTime === 'boolean' ? { oneTime } : {}),
|
|
106
197
|
},
|
|
@@ -108,7 +199,9 @@ export const reconsentTerms = async (
|
|
|
108
199
|
),
|
|
109
200
|
relationship.contract.id
|
|
110
201
|
)
|
|
111
|
-
.where(
|
|
202
|
+
.where(
|
|
203
|
+
`${audienceVersionWhere} AND ${consentMutationWhere} AND coalesce(contract.status, 'active') <> 'retired' AND coalesce(contract.currentVersion, 1) = $expectedContractVersion`
|
|
204
|
+
)
|
|
112
205
|
.set('contract.hasConsented = true')
|
|
113
206
|
.with('contract')
|
|
114
207
|
.match({
|
|
@@ -143,28 +236,34 @@ export const reconsentTerms = async (
|
|
|
143
236
|
);
|
|
144
237
|
assertAudienceMutation(result.records.length);
|
|
145
238
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
239
|
+
const versionSnapshot = await getConsentFlowContractVersionRecord(
|
|
240
|
+
relationship.contract.id,
|
|
241
|
+
version
|
|
242
|
+
);
|
|
243
|
+
const configuredAutoBoosts = new Map(
|
|
244
|
+
(versionSnapshot?.autoboosts ?? []).map(config => [config.id, config])
|
|
245
|
+
);
|
|
246
|
+
const autoBoostsResult = (
|
|
247
|
+
await ConsentFlowContract.findRelationships({
|
|
248
|
+
alias: 'autoReceive',
|
|
249
|
+
where: { source: { id: relationship.contract.id } },
|
|
250
|
+
})
|
|
251
|
+
).filter(boost => configuredAutoBoosts.has(boost.target.id));
|
|
151
252
|
|
|
152
253
|
if (autoBoostsResult.length > 0) {
|
|
153
254
|
// For each auto-boost, issue it to the consenter
|
|
154
255
|
await Promise.all(
|
|
155
256
|
autoBoostsResult.map(async boostRel => {
|
|
257
|
+
let claimId: string | undefined;
|
|
258
|
+
let sendStarted = false;
|
|
156
259
|
try {
|
|
157
260
|
const boost = boostRel.target;
|
|
158
261
|
|
|
159
|
-
|
|
160
|
-
const signingAuthorityEndpoint =
|
|
161
|
-
|
|
162
|
-
const signingAuthorityName =
|
|
163
|
-
boostRel.relationship?.signingAuthorityName || 'default';
|
|
164
|
-
|
|
262
|
+
const config = configuredAutoBoosts.get(boost.id)!;
|
|
263
|
+
const signingAuthorityEndpoint = config.signingAuthorityEndpoint || 'default';
|
|
264
|
+
const signingAuthorityName = config.signingAuthorityName || 'default';
|
|
165
265
|
const issuer =
|
|
166
|
-
(
|
|
167
|
-
(await getProfileByProfileId(boostRel.relationship.issuer))) ||
|
|
266
|
+
(config.issuer && (await getProfileByProfileId(config.issuer))) ||
|
|
168
267
|
relationship.contractOwner;
|
|
169
268
|
|
|
170
269
|
if (terms.deniedWriters?.includes(issuer.profileId)) return;
|
|
@@ -195,6 +294,14 @@ export const reconsentTerms = async (
|
|
|
195
294
|
// Only issue autoboost if write permission is explicitly granted (true)
|
|
196
295
|
if (categoryWritePermission !== true) return;
|
|
197
296
|
}
|
|
297
|
+
claimId =
|
|
298
|
+
(await claimAutoBoostTransaction(
|
|
299
|
+
relationship.contract.id,
|
|
300
|
+
relationship.terms.id,
|
|
301
|
+
String(boost.dataValues.id),
|
|
302
|
+
effectiveOneTime
|
|
303
|
+
)) ?? undefined;
|
|
304
|
+
if (!claimId) return;
|
|
198
305
|
// Get boost instance
|
|
199
306
|
const boostCredential = JSON.parse(boost.dataValues?.boost) as UnsignedVC | VC;
|
|
200
307
|
|
|
@@ -230,35 +337,19 @@ export const reconsentTerms = async (
|
|
|
230
337
|
[getDidWeb(domain, relationship.contractOwner.profileId)]
|
|
231
338
|
);
|
|
232
339
|
|
|
233
|
-
// Create transaction to record the boost issuance
|
|
234
|
-
const boostTransaction = {
|
|
235
|
-
id: uuid(),
|
|
236
|
-
action: 'write',
|
|
237
|
-
date: new Date().toISOString(),
|
|
238
|
-
} as const satisfies ConsentFlowTransactionType;
|
|
239
|
-
|
|
240
|
-
// Create the transaction in the database
|
|
241
|
-
await new QueryBuilder()
|
|
242
|
-
.match({
|
|
243
|
-
model: ConsentFlowTerms,
|
|
244
|
-
where: { id: relationship.terms.id },
|
|
245
|
-
identifier: 'terms',
|
|
246
|
-
})
|
|
247
|
-
.create({
|
|
248
|
-
related: [
|
|
249
|
-
{
|
|
250
|
-
identifier: 'boostTransaction',
|
|
251
|
-
model: ConsentFlowTransaction,
|
|
252
|
-
properties: boostTransaction,
|
|
253
|
-
},
|
|
254
|
-
ConsentFlowTransaction.getRelationshipByAlias('isFor'),
|
|
255
|
-
{ identifier: 'terms' },
|
|
256
|
-
],
|
|
257
|
-
})
|
|
258
|
-
.raw(termsReferralSnapshotCypher('boostTransaction'))
|
|
259
|
-
.run();
|
|
260
|
-
|
|
261
340
|
// Send the boost to the consenter
|
|
341
|
+
if (
|
|
342
|
+
!(await isAutoBoostConsentCurrent(
|
|
343
|
+
relationship.contract.id,
|
|
344
|
+
relationship.terms.id,
|
|
345
|
+
effectiveOneTime
|
|
346
|
+
))
|
|
347
|
+
) {
|
|
348
|
+
await releaseAutoBoostClaim(claimId);
|
|
349
|
+
claimId = undefined;
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
sendStarted = true;
|
|
262
353
|
await sendBoost({
|
|
263
354
|
from: { type: 'profile', profile: relationship.contractOwner },
|
|
264
355
|
to: relationship.consenter,
|
|
@@ -267,15 +358,41 @@ export const reconsentTerms = async (
|
|
|
267
358
|
domain,
|
|
268
359
|
skipNotification: true,
|
|
269
360
|
autoAcceptCredential: false,
|
|
270
|
-
|
|
361
|
+
allowConsumedOneTime: effectiveOneTime,
|
|
362
|
+
contractTerms: {
|
|
363
|
+
...relationship.terms,
|
|
364
|
+
terms,
|
|
365
|
+
oneTime: oneTime ?? relationship.terms.oneTime,
|
|
366
|
+
consentedVersion: version,
|
|
367
|
+
status: effectiveOneTime ? 'consumed' : 'live',
|
|
368
|
+
},
|
|
369
|
+
contractWriterProfileId: issuer.profileId,
|
|
271
370
|
});
|
|
371
|
+
await completeAutoBoostTransaction(
|
|
372
|
+
claimId,
|
|
373
|
+
relationship.terms.id,
|
|
374
|
+
String(boost.dataValues.id)
|
|
375
|
+
);
|
|
376
|
+
claimId = undefined;
|
|
272
377
|
} catch (error) {
|
|
273
|
-
|
|
378
|
+
if (claimId && sendStarted) {
|
|
379
|
+
console.error(
|
|
380
|
+
'Auto-boost claim send failed; delivery may be ambiguous',
|
|
381
|
+
{
|
|
382
|
+
claimId,
|
|
383
|
+
termsId: relationship.terms.id,
|
|
384
|
+
boostId: String(boostRel.target.dataValues.id),
|
|
385
|
+
},
|
|
386
|
+
error
|
|
387
|
+
);
|
|
388
|
+
} else {
|
|
389
|
+
console.error('Error processing auto-boost:', error);
|
|
390
|
+
}
|
|
391
|
+
if (claimId && !sendStarted) await releaseAutoBoostClaim(claimId);
|
|
274
392
|
}
|
|
275
393
|
})
|
|
276
394
|
);
|
|
277
395
|
}
|
|
278
|
-
|
|
279
396
|
await tryDispatchContractEvent(transaction.id);
|
|
280
397
|
|
|
281
398
|
return result.summary.counters.containsUpdates();
|
|
@@ -303,6 +420,17 @@ export const updateTerms = async (
|
|
|
303
420
|
},
|
|
304
421
|
domain: string
|
|
305
422
|
): Promise<boolean> => {
|
|
423
|
+
if (
|
|
424
|
+
relationship.terms.status === 'needs_reconsent' ||
|
|
425
|
+
relationship.terms.status === 'suspended'
|
|
426
|
+
) {
|
|
427
|
+
throw new TRPCError({
|
|
428
|
+
code: 'FORBIDDEN',
|
|
429
|
+
message: 'User has not yet approved the latest version of this contract',
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
const effectiveOneTime = oneTime ?? relationship.terms.oneTime ?? false;
|
|
433
|
+
|
|
306
434
|
const transaction = {
|
|
307
435
|
id: uuid(),
|
|
308
436
|
action: 'update',
|
|
@@ -332,10 +460,13 @@ export const updateTerms = async (
|
|
|
332
460
|
const paramsForSet = {
|
|
333
461
|
...newFlatInner,
|
|
334
462
|
updatedAt: transaction.date,
|
|
335
|
-
status:
|
|
463
|
+
status: effectiveOneTime ? 'consumed' : 'live',
|
|
464
|
+
|
|
465
|
+
lastReviewedVersion: Number(relationship.contract.currentVersion ?? 1),
|
|
336
466
|
...(typeof expiresAt === 'string' ? { expiresAt } : {}),
|
|
337
467
|
...(typeof oneTime === 'boolean' ? { oneTime } : {}),
|
|
338
|
-
|
|
468
|
+
newOptionsUntil: null,
|
|
469
|
+
...Object.fromEntries(keysToRemove.map(k => [k, null])),
|
|
339
470
|
};
|
|
340
471
|
|
|
341
472
|
const result = await runAudienceMutation(
|
|
@@ -344,13 +475,16 @@ export const updateTerms = async (
|
|
|
344
475
|
new QueryBuilder(
|
|
345
476
|
new BindParam({
|
|
346
477
|
params: paramsForSet,
|
|
478
|
+
expectedContractVersion: Number(relationship.contract.currentVersion ?? 1),
|
|
347
479
|
audienceVersion: audienceVersion ?? null,
|
|
348
480
|
termsMutationVersion: Number(relationship.terms.mutationVersion ?? 0),
|
|
349
481
|
})
|
|
350
482
|
),
|
|
351
483
|
relationship.contract.id
|
|
352
484
|
)
|
|
353
|
-
.where(
|
|
485
|
+
.where(
|
|
486
|
+
`${audienceVersionWhere} AND coalesce(contract.status, 'active') <> 'retired' AND coalesce(contract.currentVersion, 1) = $expectedContractVersion`
|
|
487
|
+
)
|
|
354
488
|
.set('contract.hasConsented = true')
|
|
355
489
|
.with('contract')
|
|
356
490
|
.match({
|
|
@@ -385,26 +519,33 @@ export const updateTerms = async (
|
|
|
385
519
|
);
|
|
386
520
|
assertAudienceMutation(result.records.length);
|
|
387
521
|
|
|
388
|
-
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
522
|
+
const latestVersion = Number(relationship.contract.currentVersion ?? 1);
|
|
523
|
+
const versionSnapshot = await getConsentFlowContractVersionRecord(
|
|
524
|
+
relationship.contract.id,
|
|
525
|
+
latestVersion
|
|
526
|
+
);
|
|
527
|
+
const configuredAutoBoosts = new Map(
|
|
528
|
+
(versionSnapshot?.autoboosts ?? []).map(config => [config.id, config])
|
|
529
|
+
);
|
|
530
|
+
const autoBoosts = (
|
|
531
|
+
await ConsentFlowContract.findRelationships({
|
|
532
|
+
alias: 'autoReceive',
|
|
533
|
+
where: { source: { id: relationship.contract.id } },
|
|
534
|
+
})
|
|
535
|
+
).filter(boost => configuredAutoBoosts.has(boost.target.id));
|
|
393
536
|
|
|
394
537
|
if (autoBoosts.length > 0) {
|
|
395
538
|
// For each auto-boost, issue it to the consenter
|
|
396
539
|
await Promise.all(
|
|
397
540
|
autoBoosts.map(async boost => {
|
|
541
|
+
let claimId: string | undefined;
|
|
542
|
+
let sendStarted = false;
|
|
398
543
|
try {
|
|
399
|
-
|
|
400
|
-
const signingAuthorityEndpoint =
|
|
401
|
-
|
|
402
|
-
const signingAuthorityName =
|
|
403
|
-
boost.relationship?.signingAuthorityName || 'default';
|
|
404
|
-
|
|
544
|
+
const config = configuredAutoBoosts.get(boost.target.id)!;
|
|
545
|
+
const signingAuthorityEndpoint = config.signingAuthorityEndpoint || 'default';
|
|
546
|
+
const signingAuthorityName = config.signingAuthorityName || 'default';
|
|
405
547
|
const issuer =
|
|
406
|
-
(
|
|
407
|
-
(await getProfileByProfileId(boost.relationship.issuer))) ||
|
|
548
|
+
(config.issuer && (await getProfileByProfileId(config.issuer))) ||
|
|
408
549
|
relationship.contractOwner;
|
|
409
550
|
|
|
410
551
|
if (terms.deniedWriters?.includes(issuer.profileId)) return;
|
|
@@ -434,6 +575,14 @@ export const updateTerms = async (
|
|
|
434
575
|
// Only issue autoboost if write permission is explicitly granted (true)
|
|
435
576
|
if (categoryWritePermission !== true) return;
|
|
436
577
|
}
|
|
578
|
+
claimId =
|
|
579
|
+
(await claimAutoBoostTransaction(
|
|
580
|
+
relationship.contract.id,
|
|
581
|
+
relationship.terms.id,
|
|
582
|
+
String(boost.target.id),
|
|
583
|
+
effectiveOneTime
|
|
584
|
+
)) ?? undefined;
|
|
585
|
+
if (!claimId) return;
|
|
437
586
|
|
|
438
587
|
// Get boost instance
|
|
439
588
|
const boostCredential = JSON.parse(boost.target.boost) as UnsignedVC | VC;
|
|
@@ -470,47 +619,57 @@ export const updateTerms = async (
|
|
|
470
619
|
[getDidWeb(domain, relationship.contractOwner.profileId)]
|
|
471
620
|
);
|
|
472
621
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
identifier: 'terms',
|
|
486
|
-
})
|
|
487
|
-
.create({
|
|
488
|
-
related: [
|
|
489
|
-
{
|
|
490
|
-
identifier: 'boostTransaction',
|
|
491
|
-
model: ConsentFlowTransaction,
|
|
492
|
-
properties: boostTransaction,
|
|
493
|
-
},
|
|
494
|
-
ConsentFlowTransaction.getRelationshipByAlias('isFor'),
|
|
495
|
-
{ identifier: 'terms' },
|
|
496
|
-
],
|
|
497
|
-
})
|
|
498
|
-
.raw(termsReferralSnapshotCypher('boostTransaction'))
|
|
499
|
-
.run();
|
|
500
|
-
|
|
501
|
-
// Send the boost to the consenter
|
|
622
|
+
if (
|
|
623
|
+
!(await isAutoBoostConsentCurrent(
|
|
624
|
+
relationship.contract.id,
|
|
625
|
+
relationship.terms.id,
|
|
626
|
+
effectiveOneTime
|
|
627
|
+
))
|
|
628
|
+
) {
|
|
629
|
+
await releaseAutoBoostClaim(claimId);
|
|
630
|
+
claimId = undefined;
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
sendStarted = true;
|
|
502
634
|
await sendBoost({
|
|
503
635
|
from: { type: 'profile', profile: relationship.contractOwner },
|
|
504
636
|
to: relationship.consenter,
|
|
505
637
|
boost: boost.target,
|
|
506
638
|
credential: vc,
|
|
507
639
|
domain,
|
|
508
|
-
skipNotification:
|
|
509
|
-
autoAcceptCredential:
|
|
510
|
-
|
|
640
|
+
skipNotification: true,
|
|
641
|
+
autoAcceptCredential: false,
|
|
642
|
+
allowConsumedOneTime: effectiveOneTime,
|
|
643
|
+
contractTerms: {
|
|
644
|
+
...relationship.terms,
|
|
645
|
+
terms,
|
|
646
|
+
oneTime: oneTime ?? relationship.terms.oneTime,
|
|
647
|
+
consentedVersion: latestVersion,
|
|
648
|
+
status: effectiveOneTime ? 'consumed' : 'live',
|
|
649
|
+
},
|
|
650
|
+
contractWriterProfileId: issuer.profileId,
|
|
511
651
|
});
|
|
652
|
+
await completeAutoBoostTransaction(
|
|
653
|
+
claimId,
|
|
654
|
+
relationship.terms.id,
|
|
655
|
+
String(boost.target.id)
|
|
656
|
+
);
|
|
657
|
+
claimId = undefined;
|
|
512
658
|
} catch (error) {
|
|
513
|
-
|
|
659
|
+
if (claimId && sendStarted) {
|
|
660
|
+
console.error(
|
|
661
|
+
'Auto-boost claim send failed; delivery may be ambiguous',
|
|
662
|
+
{
|
|
663
|
+
claimId,
|
|
664
|
+
termsId: relationship.terms.id,
|
|
665
|
+
boostId: String(boost.target.id),
|
|
666
|
+
},
|
|
667
|
+
error
|
|
668
|
+
);
|
|
669
|
+
} else {
|
|
670
|
+
console.error('Error processing auto-boost:', error);
|
|
671
|
+
}
|
|
672
|
+
if (claimId && !sendStarted) await releaseAutoBoostClaim(claimId);
|
|
514
673
|
}
|
|
515
674
|
})
|
|
516
675
|
);
|
|
@@ -593,6 +752,15 @@ export const syncCredentialsToContract = async (
|
|
|
593
752
|
audienceVersion?: number,
|
|
594
753
|
domain?: string
|
|
595
754
|
): Promise<boolean> => {
|
|
755
|
+
if (
|
|
756
|
+
relationship.terms.status === 'needs_reconsent' ||
|
|
757
|
+
relationship.terms.status === 'suspended'
|
|
758
|
+
) {
|
|
759
|
+
throw new TRPCError({
|
|
760
|
+
code: 'FORBIDDEN',
|
|
761
|
+
message: 'User has not yet approved the latest version of this contract',
|
|
762
|
+
});
|
|
763
|
+
}
|
|
596
764
|
// First define the transaction with sync terms data
|
|
597
765
|
// Create a structure that matches the terms format with multiple categories
|
|
598
766
|
const syncTerms: ConsentFlowTermsType = {
|
|
@@ -659,6 +827,7 @@ export const syncCredentialsToContract = async (
|
|
|
659
827
|
lockContractAudience(
|
|
660
828
|
new QueryBuilder(
|
|
661
829
|
new BindParam({
|
|
830
|
+
expectedContractVersion: Number(relationship.contract.currentVersion ?? 1),
|
|
662
831
|
audienceVersion: audienceVersion ?? null,
|
|
663
832
|
termsMutationVersion: Number(relationship.terms.mutationVersion ?? 0),
|
|
664
833
|
now: new Date().toISOString(),
|
|
@@ -671,7 +840,9 @@ export const syncCredentialsToContract = async (
|
|
|
671
840
|
),
|
|
672
841
|
relationship.contract.id
|
|
673
842
|
)
|
|
674
|
-
.where(
|
|
843
|
+
.where(
|
|
844
|
+
`${audienceVersionWhere} AND coalesce(contract.status, 'active') <> 'retired' AND coalesce(contract.currentVersion, 1) = $expectedContractVersion`
|
|
845
|
+
)
|
|
675
846
|
.match({
|
|
676
847
|
model: ConsentFlowTerms,
|
|
677
848
|
where: { id: relationship.terms.id },
|