@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
|
@@ -1,6 +1,124 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { neogma } from '@instance';
|
|
2
2
|
import { DbContractType } from 'types/consentflowcontract';
|
|
3
|
+
import { TRPCError } from '@trpc/server';
|
|
4
|
+
import { ConsentFlowContractValidator } from '@learncard/types';
|
|
5
|
+
import { diffContractChange, buildContractUpdatePreview } from '@learncard/helpers';
|
|
6
|
+
import { getConsentFlowContractVersionRecord } from './versions';
|
|
7
|
+
import { tryDispatchContractEvent } from '@helpers/contract-events.helpers';
|
|
8
|
+
import { constructUri } from '@helpers/uri.helpers';
|
|
9
|
+
import { environment } from '@environment';
|
|
10
|
+
import { v4 as uuid } from 'uuid';
|
|
3
11
|
|
|
4
|
-
|
|
5
|
-
|
|
12
|
+
/** Retire in place so terms and transaction history remain exportable. */
|
|
13
|
+
export const deleteConsentFlowContract = async (
|
|
14
|
+
contract: DbContractType,
|
|
15
|
+
domain = environment.DOMAIN_NAME ?? 'network.learncard.com',
|
|
16
|
+
appBaseUrl = domain
|
|
17
|
+
): Promise<number> => {
|
|
18
|
+
const contractId = contract.id;
|
|
19
|
+
const currentVersion = contract.currentVersion ?? contract.version ?? 1;
|
|
20
|
+
const snapshot = await getConsentFlowContractVersionRecord(contractId, currentVersion);
|
|
21
|
+
if (!snapshot)
|
|
22
|
+
throw new TRPCError({
|
|
23
|
+
code: 'PRECONDITION_FAILED',
|
|
24
|
+
message: 'Contract version snapshot is missing',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const diff = diffContractChange(snapshot, {
|
|
28
|
+
...snapshot,
|
|
29
|
+
contract: ConsentFlowContractValidator.parse({}),
|
|
30
|
+
});
|
|
31
|
+
const kind = 'relaxed' as const;
|
|
32
|
+
const preview = buildContractUpdatePreview({ name: snapshot.name, kind, diff });
|
|
33
|
+
const createdAt = new Date().toISOString();
|
|
34
|
+
const nextVersion = currentVersion + 1;
|
|
35
|
+
const reviewUrl = `${appBaseUrl.replace(/\/+$/, '')}/consent-flow/review?uri=${encodeURIComponent(constructUri('contract', contractId, domain))}`;
|
|
36
|
+
const eventId = `${contractId}:version:${nextVersion}`;
|
|
37
|
+
const notificationData = {
|
|
38
|
+
contractUri: constructUri('contract', contractId, domain),
|
|
39
|
+
contractName: snapshot.name,
|
|
40
|
+
fromVersion: currentVersion,
|
|
41
|
+
toVersion: nextVersion,
|
|
42
|
+
kind,
|
|
43
|
+
diff,
|
|
44
|
+
reviewUrl,
|
|
45
|
+
preview,
|
|
46
|
+
};
|
|
47
|
+
const result = await neogma.queryRunner.run(
|
|
48
|
+
`MATCH (c:ConsentFlowContract {id:$id})
|
|
49
|
+
WHERE coalesce(c.status,'active') <> 'retired'
|
|
50
|
+
SET c._contractVersionLock=coalesce(c._contractVersionLock,0)+1
|
|
51
|
+
WITH c
|
|
52
|
+
WHERE coalesce(c.currentVersion,1)=$currentVersion
|
|
53
|
+
OPTIONAL MATCH (terms:ConsentFlowTerms)-[:CONSENTS_TO]->(c)
|
|
54
|
+
WHERE terms.status IN ['live','needs_reconsent','suspended','consumed']
|
|
55
|
+
WITH c, collect(DISTINCT terms) AS terms
|
|
56
|
+
MATCH (c)-[:CREATED_BY]->(owner:Profile)
|
|
57
|
+
WITH c, terms, collect(DISTINCT owner.profileId)[0] AS ownerProfileId
|
|
58
|
+
UNWIND CASE WHEN size(terms)=0 THEN [null] ELSE terms END AS term
|
|
59
|
+
OPTIONAL MATCH (term)<-[:CREATED_BY]-(consenter:Profile)
|
|
60
|
+
WITH c, terms, ownerProfileId, collect(DISTINCT consenter.profileId) AS recipientProfileIds
|
|
61
|
+
CREATE (version:ConsentFlowContractVersion {
|
|
62
|
+
id:$versionId, version:$nextVersion, contract:$contractSnapshot,
|
|
63
|
+
autoboosts:$autoboostSnapshot, writers:$writerSnapshot,
|
|
64
|
+
name:$name, subtitle:$subtitle, description:$description,
|
|
65
|
+
reasonForAccessing:$reasonForAccessing, image:$image,
|
|
66
|
+
needsGuardianConsent:$needsGuardianConsent, redirectUrl:$redirectUrl,
|
|
67
|
+
frontDoorBoostUri:$frontDoorBoostUri, expiresAt:$expiresAt,
|
|
68
|
+
kind:$kind, createdAt:$createdAt
|
|
69
|
+
})
|
|
70
|
+
CREATE (c)-[:HAS_VERSION]->(version)
|
|
71
|
+
SET c.currentVersion=$nextVersion, c.status='retired', c.updatedAt=$createdAt,
|
|
72
|
+
c.latestUpdate=$latestUpdate
|
|
73
|
+
REMOVE c._contractVersionLock
|
|
74
|
+
FOREACH (term IN terms |
|
|
75
|
+
SET term.status='withdrawn', term.mutationVersion=coalesce(term.mutationVersion,0)+1, term.updatedAt=$createdAt
|
|
76
|
+
CREATE (transaction:ConsentFlowTransaction {id:randomUUID(), action:'withdraw', date:$createdAt})-[:IS_FOR]->(term))
|
|
77
|
+
CREATE (event:ConsentFlowEvent {
|
|
78
|
+
id:$eventId, contractId:c.id, fromId:ownerProfileId, ownerId:ownerProfileId,
|
|
79
|
+
domain:$eventDomain, kind:'contract_updated', payload:$eventPayload,
|
|
80
|
+
cleanupPending:true, createdAt:$createdAt
|
|
81
|
+
})
|
|
82
|
+
FOREACH (recipientId IN [id IN recipientProfileIds WHERE id IS NOT NULL AND id <> ownerProfileId] |
|
|
83
|
+
CREATE (event)-[:HAS_DELIVERY]->(:ConsentFlowEventDelivery {
|
|
84
|
+
id:event.id + ':' + recipientId, toId:recipientId, state:'pending',
|
|
85
|
+
nextAttemptAt:$createdAt, eventCreatedAt:$createdAt, attempts:0, role:'target'
|
|
86
|
+
}))
|
|
87
|
+
RETURN count(DISTINCT c) AS count`,
|
|
88
|
+
{
|
|
89
|
+
id: contractId,
|
|
90
|
+
currentVersion,
|
|
91
|
+
eventId,
|
|
92
|
+
eventDomain: domain,
|
|
93
|
+
eventPayload: JSON.stringify(notificationData),
|
|
94
|
+
nextVersion,
|
|
95
|
+
versionId: uuid(),
|
|
96
|
+
contractSnapshot: JSON.stringify(snapshot.contract),
|
|
97
|
+
autoboostSnapshot: JSON.stringify(snapshot.autoboosts),
|
|
98
|
+
writerSnapshot: JSON.stringify(snapshot.writers),
|
|
99
|
+
name: snapshot.name,
|
|
100
|
+
subtitle: snapshot.subtitle ?? null,
|
|
101
|
+
description: snapshot.description ?? null,
|
|
102
|
+
reasonForAccessing: snapshot.reasonForAccessing ?? null,
|
|
103
|
+
image: snapshot.image ?? null,
|
|
104
|
+
needsGuardianConsent: snapshot.needsGuardianConsent ?? false,
|
|
105
|
+
redirectUrl: snapshot.redirectUrl ?? null,
|
|
106
|
+
frontDoorBoostUri: snapshot.frontDoorBoostUri ?? null,
|
|
107
|
+
expiresAt: snapshot.expiresAt ?? null,
|
|
108
|
+
kind,
|
|
109
|
+
createdAt,
|
|
110
|
+
latestUpdate: JSON.stringify({
|
|
111
|
+
fromVersion: currentVersion,
|
|
112
|
+
toVersion: nextVersion,
|
|
113
|
+
kind,
|
|
114
|
+
diff,
|
|
115
|
+
createdAt,
|
|
116
|
+
preview,
|
|
117
|
+
}),
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
const record = result.records[0];
|
|
121
|
+
if (!record || Number(record.get('count') ?? 0) === 0) return 0;
|
|
122
|
+
await tryDispatchContractEvent(eventId);
|
|
123
|
+
return Number(record.get('count'));
|
|
6
124
|
};
|
|
@@ -3,21 +3,27 @@ import { QueryBuilder, BindParam } from 'neogma';
|
|
|
3
3
|
|
|
4
4
|
import { getIdFromUri } from '@helpers/uri.helpers';
|
|
5
5
|
import { ConsentFlowContract, ConsentFlowInstance, Profile } from '@models';
|
|
6
|
-
import { DbContractType } from 'types/consentflowcontract';
|
|
6
|
+
import { DbContractType, DbContractValidator } from 'types/consentflowcontract';
|
|
7
7
|
import { inflateObject } from '@helpers/objects.helpers';
|
|
8
8
|
import type { ContractRequestFields } from '@learncard/types';
|
|
9
9
|
import { ProfileType } from 'types/profile';
|
|
10
10
|
|
|
11
11
|
export const getContractById = async (id: string): Promise<DbContractType | null> => {
|
|
12
|
-
|
|
13
|
-
(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
).records[0]?.toObject().contract.properties
|
|
12
|
+
const result = await neogma.queryRunner.run(
|
|
13
|
+
`MATCH (contract:ConsentFlowContract {id:$id})
|
|
14
|
+
OPTIONAL MATCH (contract)-[:HAS_VERSION]->(version:ConsentFlowContractVersion)
|
|
15
|
+
WITH contract, version ORDER BY version.version DESC
|
|
16
|
+
WITH contract, collect(version)[0] AS latest
|
|
17
|
+
RETURN properties(contract) AS contract, properties(latest) AS latest`,
|
|
18
|
+
{ id }
|
|
20
19
|
);
|
|
20
|
+
const record = result.records[0];
|
|
21
|
+
if (!record) return null;
|
|
22
|
+
const contract = DbContractValidator.parse(inflateObject(record.get('contract')));
|
|
23
|
+
const latest = record.get('latest') as Record<string, unknown> | null;
|
|
24
|
+
contract.currentVersion = Number(contract.currentVersion ?? latest?.version ?? 1);
|
|
25
|
+
contract.version = Number(latest?.version ?? contract.currentVersion);
|
|
26
|
+
return contract;
|
|
21
27
|
};
|
|
22
28
|
|
|
23
29
|
export const getContractByUri = async (uri: string): Promise<DbContractType | null> => {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { termsReferralSnapshotCypher } from '@helpers/consent-referral.helpers';
|
|
2
1
|
import { appendConsentEvent, tryDispatchContractEvent } from '@helpers/contract-events.helpers';
|
|
3
2
|
import {
|
|
4
3
|
ConsentFlowTerms as ConsentFlowTermsType,
|
|
@@ -20,7 +19,14 @@ import { DbContractType, FlatDbTermsType } from 'types/consentflowcontract';
|
|
|
20
19
|
import { BoostType } from 'types/boost';
|
|
21
20
|
import { flattenObject, inflateObject } from '@helpers/objects.helpers';
|
|
22
21
|
import { convertQueryResultToPropertiesObjectArray } from '@helpers/neo4j.helpers';
|
|
23
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
reconsentTerms,
|
|
24
|
+
claimAutoBoostTransaction,
|
|
25
|
+
completeAutoBoostTransaction,
|
|
26
|
+
releaseAutoBoostClaim,
|
|
27
|
+
isAutoBoostConsentCurrent,
|
|
28
|
+
} from './update';
|
|
29
|
+
import { getConsentFlowContractVersionRecord } from '@accesslayer/consentflowcontract/versions';
|
|
24
30
|
import { getBoostUri, sendBoost, stampIssuanceDate } from '@helpers/boost.helpers';
|
|
25
31
|
import { setCredentialSubjectIds } from '@helpers/credentialSubject.helpers';
|
|
26
32
|
import { getDidWeb } from '@helpers/did.helpers';
|
|
@@ -85,6 +91,7 @@ export const consentToContract = async (
|
|
|
85
91
|
audienceVersion,
|
|
86
92
|
expectedRequestId,
|
|
87
93
|
smartResumeFingerprint,
|
|
94
|
+
acceptVersion,
|
|
88
95
|
}: {
|
|
89
96
|
terms: ConsentFlowTermsType;
|
|
90
97
|
expiresAt?: string;
|
|
@@ -94,9 +101,11 @@ export const consentToContract = async (
|
|
|
94
101
|
audienceVersion?: number;
|
|
95
102
|
expectedRequestId?: string;
|
|
96
103
|
smartResumeFingerprint?: string;
|
|
104
|
+
acceptVersion?: number;
|
|
97
105
|
},
|
|
98
106
|
domain: string
|
|
99
107
|
) => {
|
|
108
|
+
const expectedContractVersion = Number(contract.currentVersion ?? 1);
|
|
100
109
|
const terms = cloneDeep(_terms);
|
|
101
110
|
const deniedWriters: string[] = terms.deniedWriters ?? [];
|
|
102
111
|
|
|
@@ -143,6 +152,7 @@ export const consentToContract = async (
|
|
|
143
152
|
audienceVersion,
|
|
144
153
|
smartResumeFingerprint,
|
|
145
154
|
expectedRequestId,
|
|
155
|
+
acceptVersion,
|
|
146
156
|
},
|
|
147
157
|
domain
|
|
148
158
|
);
|
|
@@ -174,6 +184,7 @@ export const consentToContract = async (
|
|
|
174
184
|
: {}),
|
|
175
185
|
...(guardianApproval ? { guardianApproval } : {}),
|
|
176
186
|
}),
|
|
187
|
+
expectedContractVersion,
|
|
177
188
|
audienceVersion: audienceVersion ?? null,
|
|
178
189
|
expectedRequestId: expectedRequestId ?? null,
|
|
179
190
|
consenterProfileId: consenter.profileId,
|
|
@@ -181,7 +192,9 @@ export const consentToContract = async (
|
|
|
181
192
|
),
|
|
182
193
|
contract.id
|
|
183
194
|
)
|
|
184
|
-
.where(
|
|
195
|
+
.where(
|
|
196
|
+
`${audienceVersionWhere} AND ${consentMutationWhere} AND coalesce(contract.currentVersion, 1) = $expectedContractVersion AND coalesce(contract.status, 'active') <> 'retired'`
|
|
197
|
+
)
|
|
185
198
|
.set('contract.hasConsented = true')
|
|
186
199
|
.with('contract')
|
|
187
200
|
.match({
|
|
@@ -209,7 +222,9 @@ export const consentToContract = async (
|
|
|
209
222
|
model: ConsentFlowTerms,
|
|
210
223
|
properties: {
|
|
211
224
|
id: termsId,
|
|
212
|
-
status: oneTime ? '
|
|
225
|
+
status: oneTime ? 'consumed' : 'live',
|
|
226
|
+
consentedVersion: contract.currentVersion ?? 1,
|
|
227
|
+
lastReviewedVersion: contract.currentVersion ?? 1,
|
|
213
228
|
createdAt: transaction.date,
|
|
214
229
|
updatedAt: transaction.date,
|
|
215
230
|
...(expiresAt ? { expiresAt } : {}),
|
|
@@ -248,23 +263,31 @@ export const consentToContract = async (
|
|
|
248
263
|
);
|
|
249
264
|
assertAudienceMutation(result.records.length);
|
|
250
265
|
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
266
|
+
const versionSnapshot = await getConsentFlowContractVersionRecord(
|
|
267
|
+
contract.id,
|
|
268
|
+
Number(contract.currentVersion ?? 1)
|
|
269
|
+
);
|
|
270
|
+
const configuredAutoBoosts = new Map(
|
|
271
|
+
(versionSnapshot?.autoboosts ?? []).map(config => [config.id, config])
|
|
272
|
+
);
|
|
273
|
+
const autoBoosts = (
|
|
274
|
+
await ConsentFlowContract.findRelationships({
|
|
275
|
+
alias: 'autoReceive',
|
|
276
|
+
where: { source: { id: contract.id } },
|
|
277
|
+
})
|
|
278
|
+
).filter(boost => configuredAutoBoosts.has(boost.target.id));
|
|
255
279
|
|
|
256
280
|
if (autoBoosts.length > 0) {
|
|
257
281
|
await Promise.all(
|
|
258
282
|
autoBoosts.map(async boost => {
|
|
283
|
+
let claimId: string | undefined;
|
|
284
|
+
let sendStarted = false;
|
|
259
285
|
try {
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
const signingAuthorityName =
|
|
263
|
-
boost.relationship?.signingAuthorityName || 'default';
|
|
264
|
-
|
|
286
|
+
const config = configuredAutoBoosts.get(boost.target.id)!;
|
|
287
|
+
const signingAuthorityEndpoint = config.signingAuthorityEndpoint || 'default';
|
|
288
|
+
const signingAuthorityName = config.signingAuthorityName || 'default';
|
|
265
289
|
const issuer =
|
|
266
|
-
(
|
|
267
|
-
(await getProfileByProfileId(boost.relationship.issuer))) ||
|
|
290
|
+
(config.issuer && (await getProfileByProfileId(config.issuer))) ||
|
|
268
291
|
contractOwner;
|
|
269
292
|
|
|
270
293
|
if (terms.deniedWriters?.includes(issuer.profileId)) return;
|
|
@@ -278,6 +301,14 @@ export const consentToContract = async (
|
|
|
278
301
|
|
|
279
302
|
if (categoryWritePermission !== true) return;
|
|
280
303
|
}
|
|
304
|
+
claimId =
|
|
305
|
+
(await claimAutoBoostTransaction(
|
|
306
|
+
contract.id,
|
|
307
|
+
termsId,
|
|
308
|
+
String(boost.target.id),
|
|
309
|
+
Boolean(oneTime)
|
|
310
|
+
)) ?? undefined;
|
|
311
|
+
if (!claimId) return;
|
|
281
312
|
|
|
282
313
|
const contractOwnerSigningAuthority = await getSigningAuthorityForUserByName(
|
|
283
314
|
issuer,
|
|
@@ -286,6 +317,8 @@ export const consentToContract = async (
|
|
|
286
317
|
);
|
|
287
318
|
|
|
288
319
|
if (!contractOwnerSigningAuthority) {
|
|
320
|
+
await releaseAutoBoostClaim(claimId);
|
|
321
|
+
claimId = undefined;
|
|
289
322
|
console.error(
|
|
290
323
|
`Signing authority "${signingAuthorityName}" at endpoint "${signingAuthorityEndpoint}" not found for contract owner`
|
|
291
324
|
);
|
|
@@ -325,36 +358,24 @@ export const consentToContract = async (
|
|
|
325
358
|
[getDidWeb(domain, contractOwner.profileId)]
|
|
326
359
|
);
|
|
327
360
|
|
|
328
|
-
const boostTransaction = {
|
|
329
|
-
id: uuid(),
|
|
330
|
-
action: 'write',
|
|
331
|
-
date: new Date().toISOString(),
|
|
332
|
-
} as const satisfies ConsentFlowTransaction;
|
|
333
|
-
|
|
334
361
|
const termsResult = await new QueryBuilder()
|
|
335
362
|
.match({
|
|
336
363
|
identifier: 'terms',
|
|
337
364
|
model: ConsentFlowTerms,
|
|
338
365
|
where: { id: termsId },
|
|
339
366
|
})
|
|
340
|
-
.create({
|
|
341
|
-
related: [
|
|
342
|
-
{
|
|
343
|
-
identifier: 'boostTransaction',
|
|
344
|
-
model: ConsentFlowTransactionModel,
|
|
345
|
-
properties: boostTransaction,
|
|
346
|
-
},
|
|
347
|
-
ConsentFlowTransactionModel.getRelationshipByAlias('isFor'),
|
|
348
|
-
{ identifier: 'terms' },
|
|
349
|
-
],
|
|
350
|
-
})
|
|
351
|
-
.raw(termsReferralSnapshotCypher('boostTransaction'))
|
|
352
367
|
.return('terms')
|
|
353
368
|
.run();
|
|
354
|
-
|
|
355
369
|
const updatedTerms = termsResult.records[0]?.get('terms')
|
|
356
370
|
.properties as FlatDbTermsType;
|
|
357
|
-
|
|
371
|
+
if (
|
|
372
|
+
!(await isAutoBoostConsentCurrent(contract.id, termsId, Boolean(oneTime)))
|
|
373
|
+
) {
|
|
374
|
+
await releaseAutoBoostClaim(claimId);
|
|
375
|
+
claimId = undefined;
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
sendStarted = true;
|
|
358
379
|
await sendBoost({
|
|
359
380
|
from: { type: 'profile', profile: contractOwner },
|
|
360
381
|
to: consenter,
|
|
@@ -364,9 +385,22 @@ export const consentToContract = async (
|
|
|
364
385
|
skipNotification: true,
|
|
365
386
|
autoAcceptCredential: false,
|
|
366
387
|
contractTerms: inflateObject(updatedTerms),
|
|
388
|
+
contractWriterProfileId: issuer.profileId,
|
|
389
|
+
allowConsumedOneTime: Boolean(oneTime),
|
|
367
390
|
});
|
|
391
|
+
await completeAutoBoostTransaction(claimId, termsId, String(boost.target.id));
|
|
392
|
+
claimId = undefined;
|
|
368
393
|
} catch (error) {
|
|
369
|
-
|
|
394
|
+
if (claimId && sendStarted) {
|
|
395
|
+
console.error(
|
|
396
|
+
'Auto-boost claim send failed; delivery may be ambiguous',
|
|
397
|
+
{ claimId, termsId, boostId: String(boost.target.id) },
|
|
398
|
+
error
|
|
399
|
+
);
|
|
400
|
+
} else {
|
|
401
|
+
console.error('Error processing auto-boost:', error);
|
|
402
|
+
}
|
|
403
|
+
if (claimId && !sendStarted) await releaseAutoBoostClaim(claimId);
|
|
370
404
|
}
|
|
371
405
|
})
|
|
372
406
|
);
|