@learncard/network-brain-service 3.19.1 → 4.0.1
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 +44 -111
- package/AGENTS.md +52 -0
- package/CHANGELOG.md +120 -0
- package/README.md +9 -2
- package/bootstrapLambda.test.ts +72 -0
- package/bundle.mjs +9 -1
- package/config/config.dev.json +29 -0
- package/config/config.example.json +29 -0
- package/config/config.json +1 -0
- package/config/config.production.json +29 -0
- package/config/config.scouts.dev.json +24 -0
- package/config/config.scouts.production.json +24 -0
- package/contractEventsLambda.ts +18 -0
- package/contractEventsLambdaApp.ts +19 -0
- package/didWebLambda.ts +13 -18
- package/didWebLambdaApp.ts +22 -0
- package/dist/accesslayer/app-manifest-version/create.d.ts +10 -0
- package/dist/accesslayer/app-manifest-version/create.d.ts.map +1 -0
- package/dist/accesslayer/app-manifest-version/read.d.ts +11 -0
- package/dist/accesslayer/app-manifest-version/read.d.ts.map +1 -0
- package/dist/accesslayer/app-manifest-version/update.d.ts +7 -0
- package/dist/accesslayer/app-manifest-version/update.d.ts.map +1 -0
- package/dist/accesslayer/app-store-listing/read.d.ts +2 -1
- package/dist/accesslayer/app-store-listing/read.d.ts.map +1 -1
- package/dist/accesslayer/app-store-listing/relationships/create.d.ts +1 -0
- package/dist/accesslayer/app-store-listing/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/app-store-listing/relationships/read.d.ts +2 -0
- package/dist/accesslayer/app-store-listing/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/app-store-listing/update.d.ts +1 -0
- package/dist/accesslayer/app-store-listing/update.d.ts.map +1 -1
- package/dist/accesslayer/boost/relationships/create.d.ts +2 -1
- package/dist/accesslayer/boost/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/create.d.ts +9 -1
- package/dist/accesslayer/consentflowcontract/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/read.d.ts +34 -3
- package/dist/accesslayer/consentflowcontract/read.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/create.d.ts +4 -1
- package/dist/accesslayer/consentflowcontract/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/delete.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/read.d.ts +3 -2
- package/dist/accesslayer/consentflowcontract/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/recipients.d.ts +12 -0
- package/dist/accesslayer/consentflowcontract/relationships/recipients.d.ts.map +1 -0
- package/dist/accesslayer/consentflowcontract/relationships/smartResume.d.ts +12 -0
- package/dist/accesslayer/consentflowcontract/relationships/smartResume.d.ts.map +1 -0
- package/dist/accesslayer/consentflowcontract/relationships/update.d.ts +8 -5
- package/dist/accesslayer/consentflowcontract/relationships/update.d.ts.map +1 -1
- package/dist/accesslayer/credential/create.d.ts +2 -1
- package/dist/accesslayer/credential/create.d.ts.map +1 -1
- package/dist/accesslayer/credential/relationships/create.d.ts +4 -3
- package/dist/accesslayer/credential/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/inbox-credential/relationships/create.d.ts +2 -1
- package/dist/accesslayer/inbox-credential/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/inbox-credential/update.d.ts +2 -1
- package/dist/accesslayer/inbox-credential/update.d.ts.map +1 -1
- package/dist/accesslayer/share-link/abandon.d.ts.map +1 -1
- package/dist/accesslayer/share-link/attachment.d.ts +37 -0
- package/dist/accesslayer/share-link/attachment.d.ts.map +1 -0
- package/dist/accesslayer/share-link/finalize.d.ts.map +1 -1
- package/dist/accesslayer/share-link/helpers.d.ts +3 -0
- package/dist/accesslayer/share-link/helpers.d.ts.map +1 -1
- package/dist/accesslayer/share-link/recovery.d.ts.map +1 -1
- package/dist/accesslayer/share-link/reserve.d.ts.map +1 -1
- package/dist/accesslayer/share-link/revoke.d.ts.map +1 -1
- package/dist/accesslayer/share-link/types.d.ts +8 -3
- package/dist/accesslayer/share-link/types.d.ts.map +1 -1
- package/dist/cache/app-store.caches.d.ts +49 -0
- package/dist/cache/app-store.caches.d.ts.map +1 -1
- package/dist/config/applyDockerStageConfig.d.ts +2 -0
- package/dist/config/applyDockerStageConfig.d.ts.map +1 -0
- package/dist/config/environment.d.ts +5 -0
- package/dist/config/environment.d.ts.map +1 -1
- package/dist/config/serverlessFunctionEnv.test.d.ts +2 -0
- package/dist/config/serverlessFunctionEnv.test.d.ts.map +1 -0
- package/dist/config/stageConfig.d.ts +112 -0
- package/dist/config/stageConfig.d.ts.map +1 -0
- package/dist/config/stageConfig.test.d.ts +2 -0
- package/dist/config/stageConfig.test.d.ts.map +1 -0
- package/dist/didkit_wasm_bg.wasm +0 -0
- package/dist/docker-entry.d.ts +1 -1
- package/dist/docker-entry.d.ts.map +1 -1
- package/dist/helpers/app-manifest.helpers.d.ts +5 -0
- package/dist/helpers/app-manifest.helpers.d.ts.map +1 -0
- package/dist/helpers/claim-hooks.helpers.d.ts +2 -1
- package/dist/helpers/claim-hooks.helpers.d.ts.map +1 -1
- package/dist/helpers/consent-referral.helpers.d.ts +2 -0
- package/dist/helpers/consent-referral.helpers.d.ts.map +1 -0
- package/dist/helpers/consent-scopes.helpers.d.ts +7 -0
- package/dist/helpers/consent-scopes.helpers.d.ts.map +1 -0
- package/dist/helpers/contract-event-maintenance.helpers.d.ts +3 -0
- package/dist/helpers/contract-event-maintenance.helpers.d.ts.map +1 -0
- package/dist/helpers/contract-events.helpers.d.ts +25 -0
- package/dist/helpers/contract-events.helpers.d.ts.map +1 -0
- package/dist/helpers/contract-requests.helpers.d.ts +19 -0
- package/dist/helpers/contract-requests.helpers.d.ts.map +1 -0
- package/dist/helpers/finalize-inbox.helpers.d.ts +3 -3
- package/dist/helpers/finalize-inbox.helpers.d.ts.map +1 -1
- package/dist/helpers/inbox.helpers.d.ts.map +1 -1
- package/dist/helpers/inline-template.helpers.d.ts +45 -0
- package/dist/helpers/inline-template.helpers.d.ts.map +1 -0
- package/dist/helpers/notificationMessages.d.ts +1 -1
- package/dist/helpers/notificationMessages.d.ts.map +1 -1
- package/dist/helpers/notificationQueue.helpers.d.ts.map +1 -1
- package/dist/helpers/notifications.helpers.d.ts +6 -0
- package/dist/helpers/notifications.helpers.d.ts.map +1 -1
- package/dist/helpers/profile.helpers.d.ts +1 -0
- package/dist/helpers/profile.helpers.d.ts.map +1 -1
- package/dist/helpers/share-link-attachment-access.d.ts +4 -0
- package/dist/helpers/share-link-attachment-access.d.ts.map +1 -0
- package/dist/helpers/share-link-attachment.d.ts +18 -0
- package/dist/helpers/share-link-attachment.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/attachment-stat.d.ts +5 -0
- package/dist/helpers/share-link-coordinator/attachment-stat.d.ts.map +1 -0
- package/dist/helpers/share-link-coordinator/coordinator.d.ts.map +1 -1
- package/dist/helpers/share-link-coordinator/recovery-runner.d.ts.map +1 -1
- package/dist/helpers/share-link-maintenance/runner.d.ts +1 -0
- package/dist/helpers/share-link-maintenance/runner.d.ts.map +1 -1
- package/dist/helpers/share-link-maintenance/runtime.d.ts +2 -0
- package/dist/helpers/share-link-maintenance/runtime.d.ts.map +1 -1
- package/dist/helpers/share-link-maintenance/telemetry.d.ts.map +1 -1
- package/dist/helpers/share-link-maintenance/types.d.ts +4 -1
- package/dist/helpers/share-link-maintenance/types.d.ts.map +1 -1
- package/dist/helpers/share-link-owner-projection.d.ts.map +1 -1
- package/dist/helpers/share-link-policy/production.d.ts +3 -5
- package/dist/helpers/share-link-policy/production.d.ts.map +1 -1
- package/dist/helpers/share-link-policy/resolver.d.ts +1 -1
- package/dist/helpers/share-link-policy/resolver.d.ts.map +1 -1
- package/dist/helpers/share-link-policy/types.d.ts +8 -2
- package/dist/helpers/share-link-policy/types.d.ts.map +1 -1
- package/dist/helpers/signingAuthority.helpers.d.ts.map +1 -1
- package/dist/helpers/smartResume.helpers.d.ts +3 -0
- package/dist/helpers/smartResume.helpers.d.ts.map +1 -0
- package/dist/index.js +2 -2
- package/dist/models/AppManifestVersion.d.ts +20 -0
- package/dist/models/AppManifestVersion.d.ts.map +1 -0
- package/dist/models/AppStoreListing.d.ts +13 -0
- package/dist/models/AppStoreListing.d.ts.map +1 -1
- package/dist/models/ConsentFlowContract.d.ts +13 -2
- package/dist/models/ConsentFlowContract.d.ts.map +1 -1
- package/dist/models/ConsentFlowTerms.d.ts.map +1 -1
- package/dist/models/ConsentFlowTransaction.d.ts.map +1 -1
- package/dist/models/Integration.d.ts +2 -0
- package/dist/models/Integration.d.ts.map +1 -1
- package/dist/models/ShareLink.d.ts +2 -0
- package/dist/models/ShareLink.d.ts.map +1 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/share-link-constraints.d.ts.map +1 -1
- package/dist/openapi.d.ts +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/publish-metafile.json +1 -0
- package/dist/routes/app-store.d.ts +619 -0
- package/dist/routes/app-store.d.ts.map +1 -1
- package/dist/routes/boosts.d.ts +2 -2
- package/dist/routes/boosts.d.ts.map +1 -1
- package/dist/routes/contracts.d.ts +146 -3
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/credentials.d.ts +34 -0
- package/dist/routes/credentials.d.ts.map +1 -1
- package/dist/routes/inbox.d.ts +52 -2
- package/dist/routes/inbox.d.ts.map +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/profile-manager.d.ts.map +1 -1
- package/dist/routes/profiles.d.ts.map +1 -1
- package/dist/routes/public-share-links.d.ts +55 -0
- package/dist/routes/public-share-links.d.ts.map +1 -1
- package/dist/routes/share-links.d.ts +175 -14
- package/dist/routes/share-links.d.ts.map +1 -1
- package/dist/routes/test.d.ts +5 -0
- package/dist/routes/test.d.ts.map +1 -1
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/types/app-manifest.d.ts +339 -0
- package/dist/types/app-manifest.d.ts.map +1 -0
- package/dist/types/app-store-listing.d.ts +34 -0
- package/dist/types/app-store-listing.d.ts.map +1 -1
- package/dist/types/consentflowcontract.d.ts +30 -3
- package/dist/types/consentflowcontract.d.ts.map +1 -1
- package/dist/types/credential-refresh.d.ts +1 -1
- package/esbuildPlugins.cjs +1 -0
- package/lambda.ts +49 -195
- package/lambdaApp.ts +203 -0
- package/package.json +20 -19
- package/project.json +8 -1
- package/scripts/export-openapi.ts +20 -0
- package/scripts/offline-schema-environment.ts +18 -0
- package/scripts/verify-python-contracts.ts +72 -0
- package/serverless-local.yml +3 -6
- package/serverless.function-env.cjs +50 -0
- package/serverless.local.yml +0 -1
- package/serverless.yml +29 -74
- package/shareLinkMaintenanceLambda.ts +13 -44
- package/shareLinkMaintenanceLambdaApp.ts +50 -0
- package/src/accesslayer/app-manifest-version/create.ts +57 -0
- package/src/accesslayer/app-manifest-version/read.ts +129 -0
- package/src/accesslayer/app-manifest-version/update.ts +61 -0
- package/src/accesslayer/app-store-listing/read.ts +6 -0
- package/src/accesslayer/app-store-listing/relationships/create.ts +20 -0
- package/src/accesslayer/app-store-listing/relationships/read.ts +24 -1
- package/src/accesslayer/app-store-listing/update.ts +15 -0
- package/src/accesslayer/boost/relationships/create.ts +8 -2
- package/src/accesslayer/consentflowcontract/create.ts +81 -8
- package/src/accesslayer/consentflowcontract/read.ts +84 -10
- package/src/accesslayer/consentflowcontract/relationships/create.ts +116 -93
- package/src/accesslayer/consentflowcontract/relationships/delete.ts +1 -0
- package/src/accesslayer/consentflowcontract/relationships/read.ts +184 -108
- package/src/accesslayer/consentflowcontract/relationships/recipients.ts +125 -0
- package/src/accesslayer/consentflowcontract/relationships/smartResume.ts +125 -0
- package/src/accesslayer/consentflowcontract/relationships/update.ts +240 -189
- package/src/accesslayer/credential/create.test.ts +2 -115
- package/src/accesslayer/credential/create.ts +11 -6
- package/src/accesslayer/credential/relationships/create.ts +17 -10
- package/src/accesslayer/inbox-credential/relationships/create.ts +70 -48
- package/src/accesslayer/inbox-credential/update.ts +4 -2
- package/src/accesslayer/share-link/abandon.ts +20 -0
- package/src/accesslayer/share-link/attachment.ts +360 -0
- package/src/accesslayer/share-link/finalize.ts +55 -7
- package/src/accesslayer/share-link/helpers.ts +33 -2
- package/src/accesslayer/share-link/recovery.ts +20 -0
- package/src/accesslayer/share-link/reserve.ts +85 -6
- package/src/accesslayer/share-link/revoke.ts +35 -0
- package/src/accesslayer/share-link/types.ts +9 -4
- package/src/cache/app-store.caches.ts +35 -0
- package/src/config/applyDockerStageConfig.ts +6 -0
- package/src/config/environment.test.ts +17 -12
- package/src/config/environment.ts +1 -0
- package/src/config/serverlessFunctionEnv.test.ts +105 -0
- package/src/config/stageConfig.test.ts +25 -0
- package/src/config/stageConfig.ts +24 -0
- package/src/docker-entry.ts +24 -0
- package/src/helpers/app-manifest.helpers.ts +185 -0
- package/src/helpers/claim-hooks.helpers.ts +20 -7
- package/src/helpers/consent-referral.helpers.ts +6 -0
- package/src/helpers/consent-scopes.helpers.ts +58 -0
- package/src/helpers/contract-event-maintenance.helpers.ts +43 -0
- package/src/helpers/contract-events.helpers.ts +540 -0
- package/src/helpers/contract-requests.helpers.ts +211 -0
- package/src/helpers/finalize-inbox.helpers.ts +163 -44
- package/src/helpers/inbox.helpers.ts +51 -66
- package/src/helpers/inline-template.helpers.ts +560 -0
- package/src/helpers/notificationMessages.ts +59 -0
- package/src/helpers/notificationQueue.helpers.ts +23 -5
- package/src/helpers/notifications.helpers.ts +25 -1
- package/src/helpers/profile.helpers.ts +6 -0
- package/src/helpers/share-link-attachment-access.ts +87 -0
- package/src/helpers/share-link-attachment.ts +115 -0
- package/src/helpers/share-link-coordinator/attachment-stat.ts +41 -0
- package/src/helpers/share-link-coordinator/coordinator.ts +15 -2
- package/src/helpers/share-link-coordinator/recovery-runner.ts +15 -0
- package/src/helpers/share-link-maintenance/runner.ts +28 -0
- package/src/helpers/share-link-maintenance/runtime.ts +6 -0
- package/src/helpers/share-link-maintenance/telemetry.ts +3 -0
- package/src/helpers/share-link-maintenance/types.ts +2 -0
- package/src/helpers/share-link-owner-projection.ts +2 -0
- package/src/helpers/share-link-policy/production.ts +37 -17
- package/src/helpers/share-link-policy/resolver.ts +16 -11
- package/src/helpers/share-link-policy/types.ts +15 -7
- package/src/helpers/signingAuthority.helpers.ts +23 -14
- package/src/helpers/smartResume.helpers.ts +123 -0
- package/src/models/AppManifestVersion.ts +43 -0
- package/src/models/AppStoreListing.ts +32 -0
- package/src/models/ConsentFlowContract.ts +34 -3
- package/src/models/ConsentFlowTerms.ts +10 -0
- package/src/models/ConsentFlowTransaction.ts +3 -0
- package/src/models/Integration.ts +2 -0
- package/src/models/ShareLink.ts +4 -0
- package/src/models/index.ts +23 -0
- package/src/models/share-link-constraints.ts +5 -0
- package/src/openapi.ts +44 -8
- package/src/routes/app-store.ts +1054 -27
- package/src/routes/boosts.ts +12 -14
- package/src/routes/contracts.ts +382 -262
- package/src/routes/inbox.ts +4 -2
- package/src/routes/index.ts +4 -1
- package/src/routes/profile-manager.ts +19 -0
- package/src/routes/profiles.ts +12 -0
- package/src/routes/public-share-links.ts +169 -0
- package/src/routes/share-links.ts +69 -0
- package/src/routes/workflows.ts +3 -2
- package/src/types/app-manifest.ts +28 -0
- package/src/types/app-store-listing.ts +13 -0
- package/src/types/consentflowcontract.ts +25 -4
- package/test/app-manifest.helpers.spec.ts +170 -0
- package/test/app-manifest.routes.spec.ts +299 -0
- package/test/app-store-listing-updates.spec.ts +236 -0
- package/test/app-store-listing.spec.ts +65 -3
- package/test/consent-data-boundaries.spec.ts +352 -0
- package/test/consent-recipients.spec.ts +513 -0
- package/test/consent-scopes.helpers.spec.ts +67 -0
- package/test/consentflow.spec.ts +63 -2
- package/test/contract-requests.spec.ts +1588 -0
- package/test/credential-storage.neo4j.spec.ts +122 -0
- package/test/guardian-gated-routes.spec.ts +36 -0
- package/test/inbox-security.e2e.ts +26 -10
- package/test/inbox.spec.ts +184 -8
- package/test/inline-template.helpers.spec.ts +49 -0
- package/test/managed-recipient-inbox.spec.ts +24 -2
- package/test/openapi.spec.ts +14 -73
- package/test/profiles.spec.ts +30 -0
- package/test/share-link-attachment.neo4j.spec.ts +262 -0
- package/test/share-link-attachment.unit.spec.ts +244 -0
- package/test/share-link-lifecycle.neo4j.spec.ts +145 -2
- package/test/share-link-maintenance.unit.spec.ts +32 -5
- package/test/share-link-owner-route.unit.spec.ts +70 -2
- package/test/share-link-policy.unit.spec.ts +18 -4
- package/test/share-link-production-policy.unit.spec.ts +58 -9
- package/test/share-link-public-route.unit.spec.ts +279 -0
- package/test/share-link-service-policy.neo4j.spec.ts +403 -0
- package/test/signing-authority-encryption.spec.ts +75 -0
- package/test/smart-resume-consent.spec.ts +233 -0
- package/test/smart-resume-upload.spec.ts +65 -0
- package/tsconfig.build.json +1 -1
- package/tsconfig.json +1 -0
- package/vitest.config.ts +13 -0
- package/vitest.inbox-e2e.config.ts +2 -0
- package/workerLambda.test.ts +100 -0
|
@@ -9,23 +9,31 @@ import type {
|
|
|
9
9
|
/**
|
|
10
10
|
* Pure policy decision table.
|
|
11
11
|
*
|
|
12
|
-
* - known minor, managed or unknown age => no views, 30 days
|
|
12
|
+
* - personal known minor, managed or unknown age => no views, 30 days
|
|
13
13
|
* - known unmanaged adult => views enabled, 365 days
|
|
14
|
-
*
|
|
14
|
+
* - service profile => views enabled without changing the age-derived expiry
|
|
15
15
|
*/
|
|
16
16
|
export const composeShareLinkPolicy = (
|
|
17
17
|
age: ShareLinkOwnerAge,
|
|
18
|
-
isManaged: boolean
|
|
18
|
+
isManaged: boolean,
|
|
19
|
+
isServiceProfile = false
|
|
19
20
|
): ShareLinkPolicySnapshot => {
|
|
20
|
-
|
|
21
|
-
const
|
|
21
|
+
// Service age exemption does not establish that the owner is an adult.
|
|
22
|
+
const isMinor = isServiceProfile
|
|
23
|
+
? false
|
|
24
|
+
: age === 'minor'
|
|
25
|
+
? true
|
|
26
|
+
: age === 'adult'
|
|
27
|
+
? false
|
|
28
|
+
: null;
|
|
29
|
+
const policyResolved = isServiceProfile || age !== 'unknown';
|
|
22
30
|
const isUnmanagedAdult = age === 'adult' && !isManaged;
|
|
23
31
|
|
|
24
32
|
return {
|
|
25
33
|
isMinor,
|
|
26
34
|
policyResolved,
|
|
27
35
|
defaultExpiryDays: isUnmanagedAdult ? 365 : 30,
|
|
28
|
-
viewCountingEnabled: isUnmanagedAdult,
|
|
36
|
+
viewCountingEnabled: isServiceProfile || isUnmanagedAdult,
|
|
29
37
|
};
|
|
30
38
|
};
|
|
31
39
|
|
|
@@ -38,12 +46,9 @@ export const createShareLinkPolicyResolver = (
|
|
|
38
46
|
): ShareLinkPolicyResolver => ({
|
|
39
47
|
resolve: async (profileId: string): Promise<ShareLinkPolicySnapshot> => {
|
|
40
48
|
try {
|
|
41
|
-
const
|
|
42
|
-
source.resolveOwnerAge(profileId),
|
|
43
|
-
source.isManaged(profileId),
|
|
44
|
-
]);
|
|
49
|
+
const { age, isManaged, isServiceProfile } = await source.resolveOwner(profileId);
|
|
45
50
|
|
|
46
|
-
return composeShareLinkPolicy(age, isManaged);
|
|
51
|
+
return composeShareLinkPolicy(age, isManaged, isServiceProfile);
|
|
47
52
|
} catch {
|
|
48
53
|
return DEFAULT_SHARE_LINK_POLICY;
|
|
49
54
|
}
|
|
@@ -12,26 +12,34 @@ export type ShareLinkOwnerAge = 'adult' | 'minor' | 'unknown';
|
|
|
12
12
|
|
|
13
13
|
/** Immutable policy snapshot persisted with the share under the write lock. */
|
|
14
14
|
export type ShareLinkPolicySnapshot = {
|
|
15
|
-
/** `true` known minor, `false` known adult, `null` unknown. */
|
|
15
|
+
/** `true` known minor, `false` known adult/service profile, `null` unknown. */
|
|
16
16
|
isMinor: boolean | null;
|
|
17
|
-
/** `true`
|
|
17
|
+
/** `true` when age is known or a persisted service profile is age-exempt. */
|
|
18
18
|
policyResolved: boolean;
|
|
19
19
|
defaultExpiryDays: 30 | 365;
|
|
20
20
|
viewCountingEnabled: boolean;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
|
+
/** Fresh graph-local classification; never persisted or inferred from an old snapshot. */
|
|
24
|
+
export type CurrentShareLinkPolicy = ShareLinkPolicySnapshot & {
|
|
25
|
+
isServiceProfile: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
23
28
|
/**
|
|
24
29
|
* Authoritative server-side sources. Implementations must read persisted server
|
|
25
30
|
* state only; no request-derived value may be used as authority.
|
|
26
31
|
*/
|
|
27
32
|
export type ShareLinkPolicySource = {
|
|
28
33
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
34
|
+
* Read age, service classification and management from persisted state.
|
|
35
|
+
* Service profiles may bypass tracking age checks; explicitly typed children
|
|
36
|
+
* must never be classified as service profiles here.
|
|
31
37
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
38
|
+
resolveOwner: (profileId: string) => Promise<{
|
|
39
|
+
age: ShareLinkOwnerAge;
|
|
40
|
+
isManaged: boolean;
|
|
41
|
+
isServiceProfile: boolean;
|
|
42
|
+
}>;
|
|
35
43
|
};
|
|
36
44
|
|
|
37
45
|
/** Injectable server-side policy resolver used by the coordinator. */
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { environment } from '@environment';
|
|
2
2
|
import { Agent, fetch as undiciFetch, type Response as UndiciResponse } from 'undici';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createDagJweForRecipients,
|
|
5
|
+
getDidWebLearnCard,
|
|
6
|
+
getLearnCard,
|
|
7
|
+
} from '@helpers/learnCard.helpers';
|
|
4
8
|
import { getDidWeb } from '@helpers/did.helpers';
|
|
5
9
|
import { VCValidator, JWEValidator } from '@learncard/types';
|
|
6
10
|
import type { UnsignedVC, VC, JWE } from '@learncard/types';
|
|
@@ -113,9 +117,17 @@ const getSaAgent = (): Agent => {
|
|
|
113
117
|
return _saAgent;
|
|
114
118
|
};
|
|
115
119
|
|
|
116
|
-
const _mockIssueCredentialWithSigningAuthority = async (
|
|
120
|
+
const _mockIssueCredentialWithSigningAuthority = async (
|
|
121
|
+
credential: UnsignedVC,
|
|
122
|
+
recipients?: string[]
|
|
123
|
+
): Promise<VC | JWE> => {
|
|
117
124
|
const learnCard = await getLearnCard();
|
|
118
|
-
|
|
125
|
+
const signedCredential = await learnCard.invoke.issueCredential({
|
|
126
|
+
...credential,
|
|
127
|
+
issuer: learnCard.id.did(),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return recipients ? createDagJweForRecipients(signedCredential, recipients) : signedCredential;
|
|
119
131
|
};
|
|
120
132
|
|
|
121
133
|
export async function issueCredentialWithSigningAuthority(
|
|
@@ -151,6 +163,10 @@ export async function issueCredentialWithSigningAuthority(
|
|
|
151
163
|
retryable: false,
|
|
152
164
|
});
|
|
153
165
|
}
|
|
166
|
+
// The validation above excludes undefined subject IDs on the encrypted path.
|
|
167
|
+
const encryptionRecipients = encrypt
|
|
168
|
+
? [...new Set([...(subjectIds as string[]), ownerDid, ...additionalEncryptionRecipients])]
|
|
169
|
+
: undefined;
|
|
154
170
|
const credentialToIssue = appendCredentialStatus
|
|
155
171
|
? await appendBitstringStatusListEntries(credential, ownerProfile.profileId, domain)
|
|
156
172
|
: credential;
|
|
@@ -177,7 +193,8 @@ export async function issueCredentialWithSigningAuthority(
|
|
|
177
193
|
try {
|
|
178
194
|
if (IS_TEST_ENVIRONMENT) {
|
|
179
195
|
return await _mockIssueCredentialWithSigningAuthority(
|
|
180
|
-
JSON.parse(serializedCredential)
|
|
196
|
+
JSON.parse(serializedCredential),
|
|
197
|
+
encryptionRecipients
|
|
181
198
|
);
|
|
182
199
|
}
|
|
183
200
|
|
|
@@ -189,16 +206,8 @@ export async function issueCredentialWithSigningAuthority(
|
|
|
189
206
|
perf.mark('initDid');
|
|
190
207
|
|
|
191
208
|
// Brain authenticates the request but must not be able to decrypt the response.
|
|
192
|
-
const encryption =
|
|
193
|
-
? {
|
|
194
|
-
recipients: [
|
|
195
|
-
...new Set([
|
|
196
|
-
...subjectIds,
|
|
197
|
-
ownerDid,
|
|
198
|
-
...additionalEncryptionRecipients,
|
|
199
|
-
]),
|
|
200
|
-
],
|
|
201
|
-
}
|
|
209
|
+
const encryption = encryptionRecipients
|
|
210
|
+
? { recipients: encryptionRecipients }
|
|
202
211
|
: undefined;
|
|
203
212
|
|
|
204
213
|
const didJwt = await traceCrypto('getDidAuthVp', () =>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { environment } from '@environment';
|
|
2
|
+
import { ConsentFlowTermsValidator, type ConsentFlowTerms } from '@learncard/types';
|
|
3
|
+
import { resolveUri } from '@helpers/uri.helpers';
|
|
4
|
+
|
|
5
|
+
/** Publish only the terms returned by the locked consent/publication claim. */
|
|
6
|
+
export const uploadSmartResume = async (
|
|
7
|
+
terms: ConsentFlowTerms,
|
|
8
|
+
did: string,
|
|
9
|
+
recipientToken: string
|
|
10
|
+
): Promise<string | undefined> => {
|
|
11
|
+
const isProduction = !environment.IS_OFFLINE;
|
|
12
|
+
|
|
13
|
+
const srUrl = isProduction ? 'https://my.smartresume.com/' : 'https://mystage.smartresume.com/';
|
|
14
|
+
const clientId = environment.SMART_RESUME_CLIENT_ID;
|
|
15
|
+
const accessKey = environment.SMART_RESUME_ACCESS_KEY;
|
|
16
|
+
|
|
17
|
+
const accessTokenResponse = (await fetch(`${srUrl}api/v1/token`, {
|
|
18
|
+
method: 'POST',
|
|
19
|
+
signal: AbortSignal.timeout(30_000),
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
22
|
+
Authorization: `Basic ${btoa(`${clientId}:${accessKey}`)}`,
|
|
23
|
+
},
|
|
24
|
+
body: new URLSearchParams({
|
|
25
|
+
grant_type: 'client_credentials',
|
|
26
|
+
scope: 'delete readonly replace',
|
|
27
|
+
}),
|
|
28
|
+
}).then(res => {
|
|
29
|
+
if (!res.ok) throw new Error(`SmartResume token request failed (${res.status})`);
|
|
30
|
+
return res.json();
|
|
31
|
+
})) as { access_token?: string };
|
|
32
|
+
|
|
33
|
+
const accessToken = accessTokenResponse.access_token;
|
|
34
|
+
if (!accessToken) throw new Error('Missing access_token for SmartResume');
|
|
35
|
+
|
|
36
|
+
const parsedTerms = ConsentFlowTermsValidator.parse(terms);
|
|
37
|
+
|
|
38
|
+
const categories = parsedTerms.read.credentials.categories;
|
|
39
|
+
const categoryValues = Object.values(categories) as Array<{ shared?: string[] }>;
|
|
40
|
+
|
|
41
|
+
const allSharedCredentialUris = [
|
|
42
|
+
// filter out duplicates
|
|
43
|
+
...new Set(categoryValues.flatMap(({ shared }) => shared ?? [])),
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const resolvedCredentials = await Promise.all(
|
|
47
|
+
allSharedCredentialUris.map(async uri => {
|
|
48
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
49
|
+
try {
|
|
50
|
+
return await Promise.race([
|
|
51
|
+
resolveUri(uri),
|
|
52
|
+
new Promise<never>((_, reject) => {
|
|
53
|
+
timer = setTimeout(
|
|
54
|
+
() => reject(new Error('Credential resolution timed out')),
|
|
55
|
+
30_000
|
|
56
|
+
);
|
|
57
|
+
}),
|
|
58
|
+
]);
|
|
59
|
+
} finally {
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
type ResolvedCredential = {
|
|
66
|
+
issuer?: string | { id: string };
|
|
67
|
+
id?: string;
|
|
68
|
+
boostCredential?: Record<string, unknown>;
|
|
69
|
+
} & Record<string, unknown>;
|
|
70
|
+
|
|
71
|
+
const credentials = resolvedCredentials
|
|
72
|
+
.filter((cred): cred is ResolvedCredential => typeof cred === 'object' && cred !== null)
|
|
73
|
+
.map(cred =>
|
|
74
|
+
cred.boostCredential && typeof cred.boostCredential === 'object'
|
|
75
|
+
? ({ ...cred.boostCredential, id: cred.id } as ResolvedCredential) // unwrap credential, preserve id
|
|
76
|
+
: cred
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const transformedCredentials = credentials.map(cred => {
|
|
80
|
+
const issuer =
|
|
81
|
+
typeof cred.issuer === 'string' ? { id: cred.issuer } : cred.issuer || { id: '' };
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
...cred,
|
|
85
|
+
issuer,
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const { name, email } = parsedTerms.read.personal;
|
|
90
|
+
|
|
91
|
+
const body = JSON.stringify({
|
|
92
|
+
'@context': [
|
|
93
|
+
'https://www.w3.org/ns/credentials/v2',
|
|
94
|
+
'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
|
|
95
|
+
'https://w3id.org/security/suites/ed25519-2020/v1',
|
|
96
|
+
],
|
|
97
|
+
recipienttoken: recipientToken,
|
|
98
|
+
recipient: {
|
|
99
|
+
id: did,
|
|
100
|
+
givenName: name && name !== 'Anonymous' ? name : '',
|
|
101
|
+
familyName: '', // this is necessary in order for givenName to be respected
|
|
102
|
+
email: email && email !== 'anonymous@hidden.com' ? email : '',
|
|
103
|
+
},
|
|
104
|
+
credentials: transformedCredentials,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const response = await fetch(`${srUrl}api/v1/credentials`, {
|
|
108
|
+
method: 'POST',
|
|
109
|
+
signal: AbortSignal.timeout(30_000),
|
|
110
|
+
headers: {
|
|
111
|
+
Authorization: `Bearer ${accessToken}`,
|
|
112
|
+
'Content-Type': 'application/json',
|
|
113
|
+
},
|
|
114
|
+
body,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
throw new Error(`SmartResume upload failed (${response.status})`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const result = (await response.json()) as { redirect_url?: string };
|
|
122
|
+
return result.redirect_url;
|
|
123
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ModelFactory, ModelRelatedNodesI, NeogmaInstance } from 'neogma';
|
|
2
|
+
|
|
3
|
+
import { neogma } from '@instance';
|
|
4
|
+
|
|
5
|
+
import { FlatAppManifestVersionType } from 'types/app-manifest';
|
|
6
|
+
import { Integration, IntegrationInstance } from './Integration';
|
|
7
|
+
import { AppStoreListing, AppStoreListingInstance } from './AppStoreListing';
|
|
8
|
+
|
|
9
|
+
export type AppManifestVersionRelationships = {
|
|
10
|
+
integration: ModelRelatedNodesI<typeof Integration, IntegrationInstance>;
|
|
11
|
+
listing: ModelRelatedNodesI<typeof AppStoreListing, AppStoreListingInstance>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type AppManifestVersionInstance = NeogmaInstance<
|
|
15
|
+
FlatAppManifestVersionType,
|
|
16
|
+
AppManifestVersionRelationships
|
|
17
|
+
>;
|
|
18
|
+
|
|
19
|
+
export const AppManifestVersion = ModelFactory<
|
|
20
|
+
FlatAppManifestVersionType,
|
|
21
|
+
AppManifestVersionRelationships
|
|
22
|
+
>(
|
|
23
|
+
{
|
|
24
|
+
label: 'AppManifestVersion',
|
|
25
|
+
schema: {
|
|
26
|
+
id: { type: 'string', required: true, uniqueItems: true },
|
|
27
|
+
version: { type: 'number', required: true },
|
|
28
|
+
manifestHash: { type: 'string', required: true },
|
|
29
|
+
manifestJson: { type: 'string', required: true },
|
|
30
|
+
status: { type: 'string', enum: ['draft', 'active', 'superseded'], required: true },
|
|
31
|
+
createdAt: { type: 'string', required: true },
|
|
32
|
+
activatedAt: { type: 'string', required: false },
|
|
33
|
+
},
|
|
34
|
+
relationships: {
|
|
35
|
+
integration: { model: Integration, direction: 'in', name: 'HAS_MANIFEST_VERSION' },
|
|
36
|
+
listing: { model: AppStoreListing, direction: 'in', name: 'USES_MANIFEST_VERSION' },
|
|
37
|
+
},
|
|
38
|
+
primaryKeyField: 'id',
|
|
39
|
+
},
|
|
40
|
+
neogma
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export default AppManifestVersion;
|
|
@@ -6,13 +6,16 @@ import { Integration, IntegrationInstance } from './Integration';
|
|
|
6
6
|
import { Profile, ProfileInstance } from './Profile';
|
|
7
7
|
import { Boost, BoostInstance } from './Boost';
|
|
8
8
|
import { Credential, CredentialInstance } from './Credential';
|
|
9
|
+
import { ConsentFlowContract, ConsentFlowInstance } from './ConsentFlowContract';
|
|
9
10
|
import { SigningAuthority, SigningAuthorityInstance } from './SigningAuthority';
|
|
11
|
+
import type { AppManifestVersion, AppManifestVersionInstance } from './AppManifestVersion';
|
|
10
12
|
import {
|
|
11
13
|
FlatAppStoreListingType,
|
|
12
14
|
AppListingStatus,
|
|
13
15
|
LaunchType,
|
|
14
16
|
PromotionLevel,
|
|
15
17
|
AgeRating,
|
|
18
|
+
PendingListingUpdateStatus,
|
|
16
19
|
} from 'types/app-store-listing';
|
|
17
20
|
|
|
18
21
|
export type AppStoreListingRelationships = {
|
|
@@ -73,6 +76,13 @@ export type AppStoreListingRelationships = {
|
|
|
73
76
|
{ name: string; did: string; isPrimary?: boolean },
|
|
74
77
|
{ name: string; did: string; isPrimary?: boolean }
|
|
75
78
|
>;
|
|
79
|
+
hasConsentContract: ModelRelatedNodesI<
|
|
80
|
+
typeof ConsentFlowContract,
|
|
81
|
+
ConsentFlowInstance,
|
|
82
|
+
{ scopeHash: string; createdAt: string },
|
|
83
|
+
{ scopeHash: string; createdAt: string }
|
|
84
|
+
>;
|
|
85
|
+
usesManifestVersion: ModelRelatedNodesI<typeof AppManifestVersion, AppManifestVersionInstance>;
|
|
76
86
|
};
|
|
77
87
|
|
|
78
88
|
export type AppStoreListingInstance = NeogmaInstance<
|
|
@@ -114,6 +124,13 @@ export const AppStoreListing = ModelFactory<FlatAppStoreListingType, AppStoreLis
|
|
|
114
124
|
min_age: { type: 'number', required: false },
|
|
115
125
|
age_rating: { type: 'string', enum: AgeRating.options, required: false },
|
|
116
126
|
contact_email: { type: 'string', required: false },
|
|
127
|
+
pending_update_json: { type: 'string', required: false },
|
|
128
|
+
pending_update_status: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
enum: PendingListingUpdateStatus.options,
|
|
131
|
+
required: false,
|
|
132
|
+
},
|
|
133
|
+
pending_update_submitted_at: { type: 'string', required: false },
|
|
117
134
|
} as any,
|
|
118
135
|
relationships: {
|
|
119
136
|
publishedBy: { model: Integration, direction: 'in', name: 'PUBLISHES_LISTING' },
|
|
@@ -204,6 +221,21 @@ export const AppStoreListing = ModelFactory<FlatAppStoreListingType, AppStoreLis
|
|
|
204
221
|
},
|
|
205
222
|
},
|
|
206
223
|
},
|
|
224
|
+
hasConsentContract: {
|
|
225
|
+
model: ConsentFlowContract,
|
|
226
|
+
direction: 'out',
|
|
227
|
+
name: 'HAS_CONSENT_CONTRACT',
|
|
228
|
+
properties: {
|
|
229
|
+
scopeHash: {
|
|
230
|
+
property: 'scopeHash',
|
|
231
|
+
schema: { type: 'string', required: true },
|
|
232
|
+
},
|
|
233
|
+
createdAt: {
|
|
234
|
+
property: 'createdAt',
|
|
235
|
+
schema: { type: 'string', required: true },
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
},
|
|
207
239
|
},
|
|
208
240
|
primaryKeyField: 'listing_id',
|
|
209
241
|
},
|
|
@@ -14,16 +14,27 @@ export type ConsentFlowRelationships = {
|
|
|
14
14
|
{ signingAuthorityEndpoint: string; signingAuthorityName: string; issuer?: string }
|
|
15
15
|
>;
|
|
16
16
|
canWrite: ModelRelatedNodesI<typeof Profile, ProfileInstance>;
|
|
17
|
+
sharesDataWith: ModelRelatedNodesI<typeof Profile, ProfileInstance>;
|
|
17
18
|
relatedTo: ModelRelatedNodesI<typeof Boost, BoostInstance>;
|
|
18
19
|
requestedFor: ModelRelatedNodesI<
|
|
19
20
|
typeof Profile,
|
|
20
21
|
ProfileInstance,
|
|
21
22
|
{
|
|
22
|
-
status: 'pending' | 'accepted' | 'denied';
|
|
23
|
+
status: 'pending' | 'accepted' | 'denied' | 'cancelled';
|
|
24
|
+
requestId?: string;
|
|
25
|
+
requestedBy?: string;
|
|
26
|
+
externalReferenceId?: string;
|
|
27
|
+
message?: string;
|
|
28
|
+
requestedAt?: string;
|
|
23
29
|
readStatus?: 'unseen' | 'seen' | null;
|
|
24
30
|
},
|
|
25
31
|
{
|
|
26
|
-
status: 'pending' | 'accepted' | 'denied';
|
|
32
|
+
status: 'pending' | 'accepted' | 'denied' | 'cancelled';
|
|
33
|
+
requestId?: string;
|
|
34
|
+
requestedBy?: string;
|
|
35
|
+
externalReferenceId?: string;
|
|
36
|
+
message?: string;
|
|
37
|
+
requestedAt?: string;
|
|
27
38
|
readStatus?: 'unseen' | 'seen' | null;
|
|
28
39
|
}
|
|
29
40
|
>;
|
|
@@ -47,6 +58,8 @@ export const ConsentFlowContract = ModelFactory<FlatDbContractType, ConsentFlowR
|
|
|
47
58
|
createdAt: { type: 'string', required: true },
|
|
48
59
|
updatedAt: { type: 'string', required: true },
|
|
49
60
|
expiresAt: { type: 'string', required: false },
|
|
61
|
+
audienceVersion: { type: 'number', required: false },
|
|
62
|
+
hasConsented: { type: 'boolean', required: false },
|
|
50
63
|
} as any,
|
|
51
64
|
relationships: {
|
|
52
65
|
createdBy: { model: Profile, direction: 'out', name: 'CREATED_BY' },
|
|
@@ -70,17 +83,35 @@ export const ConsentFlowContract = ModelFactory<FlatDbContractType, ConsentFlowR
|
|
|
70
83
|
},
|
|
71
84
|
},
|
|
72
85
|
canWrite: { model: Profile, direction: 'out', name: 'CAN_WRITE' },
|
|
86
|
+
sharesDataWith: { model: Profile, direction: 'out', name: 'SHARES_DATA_WITH' },
|
|
73
87
|
relatedTo: { model: Boost, direction: 'out', name: 'RELATED_TO' },
|
|
74
88
|
requestedFor: {
|
|
75
89
|
model: Profile,
|
|
76
90
|
direction: 'out',
|
|
77
91
|
name: 'REQUESTED_FOR',
|
|
78
92
|
properties: {
|
|
93
|
+
requestId: {
|
|
94
|
+
property: 'requestId',
|
|
95
|
+
schema: { type: 'string', required: false },
|
|
96
|
+
},
|
|
97
|
+
requestedBy: {
|
|
98
|
+
property: 'requestedBy',
|
|
99
|
+
schema: { type: 'string', required: false },
|
|
100
|
+
},
|
|
101
|
+
externalReferenceId: {
|
|
102
|
+
property: 'externalReferenceId',
|
|
103
|
+
schema: { type: 'string', required: false },
|
|
104
|
+
},
|
|
105
|
+
message: { property: 'message', schema: { type: 'string', required: false } },
|
|
106
|
+
requestedAt: {
|
|
107
|
+
property: 'requestedAt',
|
|
108
|
+
schema: { type: 'string', required: false },
|
|
109
|
+
},
|
|
79
110
|
status: {
|
|
80
111
|
property: 'status',
|
|
81
112
|
schema: {
|
|
82
113
|
type: 'string',
|
|
83
|
-
enum: ['pending', 'accepted', 'denied'],
|
|
114
|
+
enum: ['pending', 'accepted', 'denied', 'cancelled'],
|
|
84
115
|
required: false,
|
|
85
116
|
},
|
|
86
117
|
},
|
|
@@ -19,10 +19,20 @@ export const ConsentFlowTerms = ModelFactory<FlatDbTermsType, ConsentFlowTermsRe
|
|
|
19
19
|
{
|
|
20
20
|
label: 'ConsentFlowTerms',
|
|
21
21
|
schema: {
|
|
22
|
+
smartResumeFingerprint: { type: 'string', required: false },
|
|
23
|
+
smartResumePublicationStatus: { type: 'string', required: false },
|
|
24
|
+
smartResumeLeaseId: { type: 'string', required: false },
|
|
25
|
+
smartResumeLeaseUntil: { type: 'number', required: false },
|
|
26
|
+
smartResumeMutationVersion: { type: 'number', required: false },
|
|
27
|
+
smartResumeRedirectUrl: { type: 'string', required: false },
|
|
22
28
|
id: { type: 'string', required: true },
|
|
29
|
+
'referral.requestId': { type: 'string', required: false },
|
|
30
|
+
'referral.requestedBy': { type: 'string', required: false },
|
|
31
|
+
'referral.externalReferenceId': { type: 'string', required: false },
|
|
23
32
|
status: { type: 'string', required: true },
|
|
24
33
|
createdAt: { type: 'string', required: false },
|
|
25
34
|
updatedAt: { type: 'string', required: false },
|
|
35
|
+
mutationVersion: { type: 'number', required: false },
|
|
26
36
|
expiresAt: { type: 'string', required: false },
|
|
27
37
|
oneTime: { type: 'boolean', required: false },
|
|
28
38
|
deniedWriters: { type: 'string[]', required: false },
|
|
@@ -21,6 +21,9 @@ export const ConsentFlowTransaction = ModelFactory<
|
|
|
21
21
|
label: 'ConsentFlowTransaction',
|
|
22
22
|
schema: {
|
|
23
23
|
id: { type: 'string', required: true },
|
|
24
|
+
'referral.requestId': { type: 'string', required: false },
|
|
25
|
+
'referral.requestedBy': { type: 'string', required: false },
|
|
26
|
+
'referral.externalReferenceId': { type: 'string', required: false },
|
|
24
27
|
status: { type: 'string', required: true },
|
|
25
28
|
expiresAt: { type: 'string', required: false },
|
|
26
29
|
oneTime: { type: 'boolean', required: false },
|
|
@@ -3,11 +3,13 @@ import { ModelFactory, ModelRelatedNodesI, NeogmaInstance } from 'neogma';
|
|
|
3
3
|
import { neogma } from '@instance';
|
|
4
4
|
|
|
5
5
|
import { Profile, ProfileInstance } from './Profile';
|
|
6
|
+
import type { AppManifestVersion, AppManifestVersionInstance } from './AppManifestVersion';
|
|
6
7
|
import { FlatIntegrationType } from 'types/integration';
|
|
7
8
|
|
|
8
9
|
export type IntegrationRelationships = {
|
|
9
10
|
createdBy: ModelRelatedNodesI<typeof Profile, ProfileInstance>;
|
|
10
11
|
publishesListing: ModelRelatedNodesI<any, any>;
|
|
12
|
+
hasManifestVersion: ModelRelatedNodesI<typeof AppManifestVersion, AppManifestVersionInstance>;
|
|
11
13
|
};
|
|
12
14
|
|
|
13
15
|
export type IntegrationInstance = NeogmaInstance<FlatIntegrationType, IntegrationRelationships>;
|
package/src/models/ShareLink.ts
CHANGED
|
@@ -33,6 +33,8 @@ export type ShareLinkRecord = {
|
|
|
33
33
|
ownerProfileId: string;
|
|
34
34
|
version: number;
|
|
35
35
|
contentVersion: number;
|
|
36
|
+
attachmentId?: string | null;
|
|
37
|
+
attachmentChunkCount?: number | null;
|
|
36
38
|
/**
|
|
37
39
|
* Monotonic fence. Bumped on every reservation and on revoke; a worker may
|
|
38
40
|
* only finalize the reservation whose generation still equals this value.
|
|
@@ -90,6 +92,8 @@ export const ShareLink = ModelFactory<ShareLinkProperties, Record<string, never>
|
|
|
90
92
|
ownerProfileId: { type: 'string', required: true },
|
|
91
93
|
version: { type: 'number', required: true },
|
|
92
94
|
contentVersion: { type: 'number', required: true },
|
|
95
|
+
attachmentId: { type: 'string', required: false },
|
|
96
|
+
attachmentChunkCount: { type: 'number', required: false },
|
|
93
97
|
generation: { type: 'number', required: true },
|
|
94
98
|
status: { type: 'string', required: true, enum: ['pending', 'active', 'stopped'] },
|
|
95
99
|
contentState: {
|
package/src/models/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { environment } from '@environment';
|
|
2
2
|
import { neogma } from '@instance';
|
|
3
|
+
import { contractEventMaintenanceSchema } from '@helpers/contract-event-maintenance.helpers';
|
|
3
4
|
|
|
4
5
|
import { Boost } from './Boost';
|
|
5
6
|
import { Profile } from './Profile';
|
|
@@ -11,6 +12,7 @@ import { Skill } from './Skill';
|
|
|
11
12
|
import { Tag } from './Tag';
|
|
12
13
|
import { AppStoreListing } from './AppStoreListing';
|
|
13
14
|
import { Integration } from './Integration';
|
|
15
|
+
import { AppManifestVersion } from './AppManifestVersion';
|
|
14
16
|
import { CredentialActivity } from './CredentialActivity';
|
|
15
17
|
import { CredentialRefresh } from './CredentialRefresh';
|
|
16
18
|
import { StatusList } from './StatusList';
|
|
@@ -92,6 +94,19 @@ Integration.addRelationships({
|
|
|
92
94
|
direction: 'out',
|
|
93
95
|
name: 'PUBLISHES_LISTING',
|
|
94
96
|
},
|
|
97
|
+
hasManifestVersion: {
|
|
98
|
+
model: AppManifestVersion,
|
|
99
|
+
direction: 'out',
|
|
100
|
+
name: 'HAS_MANIFEST_VERSION',
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
AppStoreListing.addRelationships({
|
|
105
|
+
usesManifestVersion: {
|
|
106
|
+
model: AppManifestVersion,
|
|
107
|
+
direction: 'out',
|
|
108
|
+
name: 'USES_MANIFEST_VERSION',
|
|
109
|
+
},
|
|
95
110
|
});
|
|
96
111
|
|
|
97
112
|
Profile.addRelationships({
|
|
@@ -128,6 +143,9 @@ const shouldCreateIndices =
|
|
|
128
143
|
environment.NODE_ENV === 'production' || !environment.NEO4J_SKIP_INDICES;
|
|
129
144
|
|
|
130
145
|
const indexQueries = [
|
|
146
|
+
'CREATE CONSTRAINT consent_event_id IF NOT EXISTS FOR (e:ConsentFlowEvent) REQUIRE e.id IS UNIQUE',
|
|
147
|
+
'CREATE CONSTRAINT consent_delivery_id IF NOT EXISTS FOR (d:ConsentFlowEventDelivery) REQUIRE d.id IS UNIQUE',
|
|
148
|
+
...contractEventMaintenanceSchema,
|
|
131
149
|
'CREATE INDEX profileId_idx IF NOT EXISTS FOR (p:Profile) ON (p.profileId)',
|
|
132
150
|
'CREATE INDEX profile_did_idx IF NOT EXISTS FOR (p:Profile) ON (p.did)',
|
|
133
151
|
'CREATE TEXT INDEX profileId_text_idx IF NOT EXISTS FOR (n:Profile) ON (n.profileId)',
|
|
@@ -152,6 +170,10 @@ const indexQueries = [
|
|
|
152
170
|
'CREATE INDEX claim_hook_updated_idx IF NOT EXISTS FOR (c:ClaimHook) ON (c.updatedAt)',
|
|
153
171
|
'CREATE INDEX integration_id_idx IF NOT EXISTS FOR (i:Integration) ON (i.id)',
|
|
154
172
|
'CREATE INDEX integration_publishablekey_idx IF NOT EXISTS FOR (i:Integration) ON (i.publishableKey)',
|
|
173
|
+
'CREATE INDEX app_manifest_version_id_idx IF NOT EXISTS FOR (m:AppManifestVersion) ON (m.id)',
|
|
174
|
+
'CREATE INDEX app_manifest_version_version_idx IF NOT EXISTS FOR (m:AppManifestVersion) ON (m.version)',
|
|
175
|
+
'CREATE INDEX app_manifest_version_hash_idx IF NOT EXISTS FOR (m:AppManifestVersion) ON (m.manifestHash)',
|
|
176
|
+
'CREATE INDEX app_manifest_version_status_idx IF NOT EXISTS FOR (m:AppManifestVersion) ON (m.status)',
|
|
155
177
|
'CREATE INDEX skill_framework_id_idx IF NOT EXISTS FOR (f:SkillFramework) ON (f.id)',
|
|
156
178
|
'CREATE TEXT INDEX skill_framework_name_text_idx IF NOT EXISTS FOR (f:SkillFramework) ON (f.name)',
|
|
157
179
|
'CREATE INDEX skill_id_idx IF NOT EXISTS FOR (s:Skill) ON (s.id)',
|
|
@@ -254,6 +276,7 @@ export * from './SkillFramework';
|
|
|
254
276
|
export * from './Skill';
|
|
255
277
|
export * from './Tag';
|
|
256
278
|
export * from './Integration';
|
|
279
|
+
export * from './AppManifestVersion';
|
|
257
280
|
export * from './AppStoreListing';
|
|
258
281
|
export * from './CredentialActivity';
|
|
259
282
|
export * from './CredentialRefresh';
|
|
@@ -9,6 +9,9 @@ import { neogma } from '@instance';
|
|
|
9
9
|
* makes the resulting race fail closed instead of forking state.
|
|
10
10
|
*/
|
|
11
11
|
const SHARE_LINK_CONSTRAINT_QUERIES = [
|
|
12
|
+
'CREATE CONSTRAINT share_link_attachment_stage_key_unique IF NOT EXISTS FOR (a:ShareLinkAttachmentStage) REQUIRE (a.key) IS UNIQUE',
|
|
13
|
+
'CREATE CONSTRAINT share_link_attachment_id_unique IF NOT EXISTS FOR (a:ShareLinkAttachmentStage) REQUIRE (a.attachmentId) IS UNIQUE',
|
|
14
|
+
'CREATE CONSTRAINT share_attachment_owner_quota_key_unique IF NOT EXISTS FOR (q:ShareAttachmentOwnerQuota) REQUIRE (q.key) IS UNIQUE',
|
|
12
15
|
// A share id is globally unique across namespaces.
|
|
13
16
|
'CREATE CONSTRAINT share_link_id_unique IF NOT EXISTS FOR (s:ShareLink) REQUIRE (s.id) IS UNIQUE',
|
|
14
17
|
// One idempotency record per (namespace, owner, operation kind, client request).
|
|
@@ -26,6 +29,8 @@ const SHARE_LINK_CONSTRAINT_QUERIES = [
|
|
|
26
29
|
* idempotent and shares the same readiness gate as the constraints.
|
|
27
30
|
*/
|
|
28
31
|
const SHARE_LINK_INDEX_QUERIES = [
|
|
32
|
+
'CREATE INDEX share_attachment_stage_owner_idx IF NOT EXISTS FOR (a:ShareLinkAttachmentStage) ON (a.namespace, a.ownerProfileId, a.status)',
|
|
33
|
+
'CREATE INDEX share_attachment_stage_expiry_idx IF NOT EXISTS FOR (a:ShareLinkAttachmentStage) ON (a.namespace, a.status, a.expiresAt)',
|
|
29
34
|
'CREATE INDEX share_link_ns_owner_idx IF NOT EXISTS FOR (s:ShareLink) ON (s.namespace, s.ownerProfileId)',
|
|
30
35
|
// Bounded owner-list keyset pagination: filters on the leading
|
|
31
36
|
// (namespace, ownerProfileId) prefix and orders by the immutable
|