@learncard/network-brain-service 3.17.0 → 3.19.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 +4 -0
- package/AGENTS.md +177 -159
- package/CHANGELOG.md +148 -0
- package/README.md +26 -8
- package/compose.inbox.yml +7 -0
- package/dist/accesslayer/app-store-listing/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/auth-grant/read.d.ts +1 -0
- package/dist/accesslayer/auth-grant/read.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/create.d.ts +3 -2
- package/dist/accesslayer/consentflowcontract/relationships/create.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/read.d.ts +1 -0
- package/dist/accesslayer/consentflowcontract/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/consentflowcontract/relationships/update.d.ts +5 -3
- 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/create.test.d.ts +2 -0
- package/dist/accesslayer/credential/create.test.d.ts.map +1 -0
- package/dist/accesslayer/credential/relationships/read.d.ts +1 -0
- package/dist/accesslayer/credential/relationships/read.d.ts.map +1 -1
- package/dist/accesslayer/credential-activity/create.d.ts.map +1 -1
- package/dist/accesslayer/credential-refresh/email-delivery.d.ts +18 -0
- package/dist/accesslayer/credential-refresh/email-delivery.d.ts.map +1 -0
- package/dist/accesslayer/credential-refresh/index.d.ts +1 -0
- package/dist/accesslayer/credential-refresh/index.d.ts.map +1 -1
- 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-batch/store.d.ts +33 -0
- package/dist/accesslayer/inbox-batch/store.d.ts.map +1 -0
- package/dist/accesslayer/inbox-credential/create.d.ts +5 -0
- package/dist/accesslayer/inbox-credential/create.d.ts.map +1 -1
- package/dist/accesslayer/inbox-credential/refresh.d.ts +71 -0
- package/dist/accesslayer/inbox-credential/refresh.d.ts.map +1 -0
- package/dist/accesslayer/inbox-credential/update.d.ts +1 -1
- package/dist/accesslayer/inbox-credential/update.d.ts.map +1 -1
- package/dist/cache/atomic-counter.test-helpers.d.ts +3 -0
- package/dist/cache/atomic-counter.test-helpers.d.ts.map +1 -0
- package/dist/cache/atomic-counter.test.d.ts +2 -0
- package/dist/cache/atomic-counter.test.d.ts.map +1 -0
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/config/environment.d.ts +46 -0
- package/dist/config/environment.d.ts.map +1 -1
- package/dist/credential-refresh.d.ts.map +1 -1
- package/dist/didkit_wasm_bg.wasm +0 -0
- package/dist/helpers/activity.helpers.d.ts +4 -0
- package/dist/helpers/activity.helpers.d.ts.map +1 -1
- package/dist/helpers/boost-storage.helpers.test.d.ts +2 -0
- package/dist/helpers/boost-storage.helpers.test.d.ts.map +1 -0
- package/dist/helpers/boost.helpers.d.ts +3 -7
- package/dist/helpers/boost.helpers.d.ts.map +1 -1
- package/dist/helpers/contact-method.helpers.d.ts.map +1 -1
- package/dist/helpers/contact-method.helpers.test.d.ts +2 -0
- package/dist/helpers/contact-method.helpers.test.d.ts.map +1 -0
- package/dist/helpers/credential-refresh-email-content.helpers.d.ts +44 -0
- package/dist/helpers/credential-refresh-email-content.helpers.d.ts.map +1 -0
- package/dist/helpers/credential-refresh-email-content.helpers.test.d.ts +2 -0
- package/dist/helpers/credential-refresh-email-content.helpers.test.d.ts.map +1 -0
- package/dist/helpers/credential-refresh-email.helpers.d.ts +17 -0
- package/dist/helpers/credential-refresh-email.helpers.d.ts.map +1 -0
- package/dist/helpers/credential-refresh-proof.helpers.d.ts +4 -0
- package/dist/helpers/credential-refresh-proof.helpers.d.ts.map +1 -0
- package/dist/helpers/credential-refresh-proof.helpers.test.d.ts +2 -0
- package/dist/helpers/credential-refresh-proof.helpers.test.d.ts.map +1 -0
- package/dist/helpers/credential-refresh.helpers.d.ts +45 -2
- package/dist/helpers/credential-refresh.helpers.d.ts.map +1 -1
- package/dist/helpers/credential.helpers.d.ts +4 -2
- package/dist/helpers/credential.helpers.d.ts.map +1 -1
- package/dist/helpers/finalize-inbox.helpers.d.ts.map +1 -1
- package/dist/helpers/inbox-batch-http.helpers.d.ts +15 -0
- package/dist/helpers/inbox-batch-http.helpers.d.ts.map +1 -0
- package/dist/helpers/inbox-batch-http.helpers.test.d.ts +2 -0
- package/dist/helpers/inbox-batch-http.helpers.test.d.ts.map +1 -0
- package/dist/helpers/inbox-batch-status.helpers.d.ts +3 -0
- package/dist/helpers/inbox-batch-status.helpers.d.ts.map +1 -0
- package/dist/helpers/inbox-batch.helpers.d.ts +10 -0
- package/dist/helpers/inbox-batch.helpers.d.ts.map +1 -0
- package/dist/helpers/inbox-batch.helpers.test.d.ts +2 -0
- package/dist/helpers/inbox-batch.helpers.test.d.ts.map +1 -0
- package/dist/helpers/inbox-issuance-error.helpers.d.ts +13 -0
- package/dist/helpers/inbox-issuance-error.helpers.d.ts.map +1 -0
- package/dist/helpers/inbox-queue.helpers.d.ts +11 -0
- package/dist/helpers/inbox-queue.helpers.d.ts.map +1 -0
- package/dist/helpers/inbox-queue.helpers.test.d.ts +2 -0
- package/dist/helpers/inbox-queue.helpers.test.d.ts.map +1 -0
- package/dist/helpers/inbox-refresh.helpers.d.ts +186 -0
- package/dist/helpers/inbox-refresh.helpers.d.ts.map +1 -0
- package/dist/helpers/inbox.helpers.d.ts +9 -1
- package/dist/helpers/inbox.helpers.d.ts.map +1 -1
- package/dist/helpers/issuedCredentialStatus.helpers.d.ts +5 -0
- package/dist/helpers/issuedCredentialStatus.helpers.d.ts.map +1 -0
- package/dist/helpers/notifications.helpers.d.ts.map +1 -1
- package/dist/helpers/rateLimit.helpers.d.ts.map +1 -1
- package/dist/helpers/refresh-send-intent.helpers.d.ts +51 -0
- package/dist/helpers/refresh-send-intent.helpers.d.ts.map +1 -0
- package/dist/helpers/shim.d.ts +1 -1
- package/dist/helpers/shim.d.ts.map +1 -1
- package/dist/helpers/signingAuthority.helpers.d.ts +3 -2
- package/dist/helpers/signingAuthority.helpers.d.ts.map +1 -1
- package/dist/helpers/signingAuthority.helpers.test.d.ts +2 -0
- package/dist/helpers/signingAuthority.helpers.test.d.ts.map +1 -0
- package/dist/helpers/status-list.helpers.d.ts.map +1 -1
- package/dist/helpers/status-list.helpers.test.d.ts +2 -0
- package/dist/helpers/status-list.helpers.test.d.ts.map +1 -0
- package/dist/inbox-queue-local.d.ts +2 -0
- package/dist/inbox-queue-local.d.ts.map +1 -0
- package/dist/index.js +2 -2
- package/dist/models/AuthGrant.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/Credential.d.ts +1 -0
- package/dist/models/Credential.d.ts.map +1 -1
- package/dist/models/CredentialActivity.d.ts +1 -0
- package/dist/models/CredentialActivity.d.ts.map +1 -1
- package/dist/models/CredentialRefresh.d.ts +5 -2
- package/dist/models/CredentialRefresh.d.ts.map +1 -1
- package/dist/models/InboxCredential.d.ts +1 -0
- package/dist/models/InboxCredential.d.ts.map +1 -1
- package/dist/models/credential-refresh-constraints.d.ts.map +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/routes/act-as.test.d.ts +2 -0
- package/dist/routes/act-as.test.d.ts.map +1 -0
- package/dist/routes/activity.d.ts +3 -0
- package/dist/routes/activity.d.ts.map +1 -1
- package/dist/routes/app-store.d.ts.map +1 -1
- package/dist/routes/auth-grants.d.ts +10 -0
- package/dist/routes/auth-grants.d.ts.map +1 -1
- package/dist/routes/boosts.d.ts +506 -12
- package/dist/routes/boosts.d.ts.map +1 -1
- package/dist/routes/contracts.d.ts +48 -2
- package/dist/routes/contracts.d.ts.map +1 -1
- package/dist/routes/credential-refreshes.d.ts +4 -4
- package/dist/routes/credential-refreshes.d.ts.map +1 -1
- package/dist/routes/credentials.d.ts +8 -2
- package/dist/routes/credentials.d.ts.map +1 -1
- package/dist/routes/did-metadata.d.ts +8 -8
- package/dist/routes/federation.d.ts +2 -2
- package/dist/routes/inbox.d.ts +973 -31
- package/dist/routes/inbox.d.ts.map +1 -1
- package/dist/routes/index.d.ts +47 -127
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/presentations.d.ts +6 -6
- package/dist/routes/storage.d.ts +63 -63
- package/dist/routes/test.d.ts +6 -0
- package/dist/routes/test.d.ts.map +1 -1
- package/dist/routes/workflows.d.ts +14 -14
- package/dist/routes/workflows.d.ts.map +1 -1
- package/dist/services/delivery/adapters/postmark.adapter.d.ts.map +1 -1
- package/dist/services/delivery/adapters/postmark.adapter.test.d.ts +2 -0
- package/dist/services/delivery/adapters/postmark.adapter.test.d.ts.map +1 -0
- package/dist/services/registry/registry.factory.d.ts.map +1 -1
- package/dist/types/activity.d.ts +4 -0
- package/dist/types/activity.d.ts.map +1 -1
- package/dist/types/consentflowcontract.d.ts +22 -8
- package/dist/types/consentflowcontract.d.ts.map +1 -1
- package/dist/types/credential-refresh.d.ts +10 -1
- package/dist/types/credential-refresh.d.ts.map +1 -1
- package/dist/types/credential.d.ts +7 -0
- package/dist/types/credential.d.ts.map +1 -1
- package/dist/types/did-metadata.d.ts +2 -2
- package/dist/types/inbox-batch.d.ts +38 -0
- package/dist/types/inbox-batch.d.ts.map +1 -0
- package/inbox-e2e-setup.ts +53 -1
- package/inbox-elasticmq.conf +10 -0
- package/lambda.ts +61 -16
- package/package.json +18 -16
- package/scripts/setup-inbox-queues.ts +60 -0
- package/serverless-local.yml +2 -0
- package/serverless.yml +75 -0
- package/src/accesslayer/app-store-listing/relationships/read.ts +4 -3
- package/src/accesslayer/auth-grant/read.ts +2 -1
- package/src/accesslayer/consentflowcontract/relationships/create.ts +15 -5
- package/src/accesslayer/consentflowcontract/relationships/read.ts +161 -63
- package/src/accesslayer/consentflowcontract/relationships/update.ts +43 -10
- package/src/accesslayer/credential/create.test.ts +141 -0
- package/src/accesslayer/credential/create.ts +27 -3
- package/src/accesslayer/credential-activity/create.ts +1 -0
- package/src/accesslayer/credential-refresh/email-delivery.ts +116 -0
- package/src/accesslayer/credential-refresh/index.ts +1 -0
- package/src/accesslayer/credential-refresh/read.ts +8 -2
- package/src/accesslayer/credential-refresh/update.ts +4 -0
- package/src/accesslayer/inbox-batch/store.ts +469 -0
- package/src/accesslayer/inbox-credential/create.ts +51 -19
- package/src/accesslayer/inbox-credential/refresh.ts +221 -0
- package/src/accesslayer/inbox-credential/update.ts +1 -1
- package/src/cache/atomic-counter.test-helpers.ts +27 -0
- package/src/cache/atomic-counter.test.ts +6 -0
- package/src/cache/index.ts +25 -13
- package/src/config/environment.ts +26 -0
- package/src/credential-refresh.ts +5 -1
- package/src/docker-entry.ts +8 -0
- package/src/helpers/activity.helpers.ts +4 -0
- package/src/helpers/app-counter.helpers.ts +1 -1
- package/src/helpers/boost-storage.helpers.test.ts +242 -0
- package/src/helpers/boost.helpers.ts +58 -437
- package/src/helpers/contact-method.helpers.test.ts +43 -0
- package/src/helpers/contact-method.helpers.ts +3 -4
- package/src/helpers/credential-refresh-email-content.helpers.test.ts +222 -0
- package/src/helpers/credential-refresh-email-content.helpers.ts +155 -0
- package/src/helpers/credential-refresh-email.helpers.ts +201 -0
- package/src/helpers/credential-refresh-proof.helpers.test.ts +103 -0
- package/src/helpers/credential-refresh-proof.helpers.ts +43 -0
- package/src/helpers/credential-refresh.helpers.ts +385 -107
- package/src/helpers/credential.helpers.ts +6 -2
- package/src/helpers/finalize-inbox.helpers.ts +39 -22
- package/src/helpers/inbox-batch-http.helpers.test.ts +188 -0
- package/src/helpers/inbox-batch-http.helpers.ts +150 -0
- package/src/helpers/inbox-batch-status.helpers.ts +11 -0
- package/src/helpers/inbox-batch.helpers.test.ts +668 -0
- package/src/helpers/inbox-batch.helpers.ts +374 -0
- package/src/helpers/inbox-issuance-error.helpers.ts +25 -0
- package/src/helpers/inbox-queue.helpers.test.ts +253 -0
- package/src/helpers/inbox-queue.helpers.ts +372 -0
- package/src/helpers/inbox-refresh.helpers.ts +432 -0
- package/src/helpers/inbox.helpers.ts +301 -50
- package/src/helpers/issuedCredentialStatus.helpers.ts +11 -0
- package/src/helpers/notifications.helpers.ts +4 -2
- package/src/helpers/rateLimit.helpers.ts +2 -5
- package/src/helpers/refresh-send-intent.helpers.ts +273 -0
- package/src/helpers/shim.ts +32 -31
- package/src/helpers/signingAuthority.helpers.test.ts +198 -0
- package/src/helpers/signingAuthority.helpers.ts +41 -18
- package/src/helpers/status-list.helpers.test.ts +77 -0
- package/src/helpers/status-list.helpers.ts +31 -8
- package/src/inbox-queue-local.ts +28 -0
- package/src/models/AuthGrant.ts +1 -0
- package/src/models/ConsentFlowTerms.ts +4 -0
- package/src/models/ConsentFlowTransaction.ts +4 -0
- package/src/models/Credential.ts +1 -0
- package/src/models/CredentialActivity.ts +3 -5
- package/src/models/CredentialRefresh.ts +4 -2
- package/src/models/InboxCredential.ts +2 -0
- package/src/models/credential-refresh-constraints.test.ts +8 -3
- package/src/models/credential-refresh-constraints.ts +5 -0
- package/src/openapi.ts +8 -0
- package/src/routes/act-as.test.ts +239 -0
- package/src/routes/app-store.ts +69 -52
- package/src/routes/auth-grants.ts +13 -11
- package/src/routes/boosts.ts +943 -120
- package/src/routes/contracts.ts +55 -7
- package/src/routes/credential-refreshes.test.ts +8 -2
- package/src/routes/credential-refreshes.ts +4 -1
- package/src/routes/credentials.ts +2 -1
- package/src/routes/inbox.ts +95 -49
- package/src/routes/index.ts +164 -88
- package/src/routes/skills.ts +1 -1
- package/src/routes/workflows.ts +80 -31
- package/src/services/delivery/adapters/postmark.adapter.test.ts +54 -0
- package/src/services/delivery/adapters/postmark.adapter.ts +12 -0
- package/src/services/registry/registry.factory.ts +2 -1
- package/src/types/activity.ts +2 -0
- package/src/types/consentflowcontract.ts +21 -3
- package/src/types/credential-refresh.ts +21 -2
- package/src/types/credential.ts +13 -1
- package/src/types/inbox-batch.ts +46 -0
- package/test/app-store-listing.spec.ts +66 -30
- package/test/atomic-counter.e2e.ts +12 -0
- package/test/auth-grant.spec.ts +21 -21
- package/test/bitstring-status-list.spec.ts +12 -9
- package/test/consentflow.spec.ts +453 -26
- package/test/credential-refresh-email.spec.ts +663 -0
- package/test/credential-refresh-publication.spec.ts +13 -5
- package/test/guardian-gated-routes.spec.ts +337 -180
- package/test/helpers/inbox-e2e-environment.ts +6 -0
- package/test/inbox-batch.spec.ts +1338 -0
- package/test/inbox-refresh.spec.ts +534 -0
- package/test/inbox-security.e2e.ts +48 -3
- package/test/openapi.spec.ts +41 -1
- package/test/refresh-send.spec.ts +1799 -0
- package/test/registry.spec.ts +56 -11
- package/test/revoke-suspend-per-instance.spec.ts +9 -1
- package/vitest.config.ts +13 -0
- package/vitest.inbox-e2e.config.ts +5 -1
- package/vitest.integration.config.ts +2 -0
package/src/routes/contracts.ts
CHANGED
|
@@ -24,8 +24,6 @@ import {
|
|
|
24
24
|
VCValidator,
|
|
25
25
|
JWEValidator,
|
|
26
26
|
UnsignedVC,
|
|
27
|
-
VC,
|
|
28
|
-
JWE,
|
|
29
27
|
AutoBoostConfigValidator,
|
|
30
28
|
LCNNotificationTypeEnumValidator,
|
|
31
29
|
LCNProfileValidator,
|
|
@@ -45,6 +43,7 @@ import {
|
|
|
45
43
|
getContractTermsForProfile,
|
|
46
44
|
getTransactionsForTerms,
|
|
47
45
|
hasProfileConsentedToContract,
|
|
46
|
+
hasGuardianApprovalHistory,
|
|
48
47
|
isProfileConsentFlowContractAdmin,
|
|
49
48
|
getWritersForContract,
|
|
50
49
|
} from '@accesslayer/consentflowcontract/relationships/read';
|
|
@@ -89,6 +88,7 @@ import { getCredentialUri } from '@helpers/credential.helpers';
|
|
|
89
88
|
import { getSigningAuthorityForUserByName } from '@accesslayer/signing-authority/relationships/read';
|
|
90
89
|
import { getDidWeb } from '@helpers/did.helpers';
|
|
91
90
|
import { issueCredentialWithSigningAuthority } from '@helpers/signingAuthority.helpers';
|
|
91
|
+
import type { IssuedCredential } from '../types/credential';
|
|
92
92
|
import { getProfilesByProfileIds } from '@accesslayer/profile/read';
|
|
93
93
|
import { getProfilesThatManageAProfile } from '@accesslayer/profile/relationships/read';
|
|
94
94
|
import { resolveAndValidateDeniedWriters } from '@helpers/consentflow.helpers';
|
|
@@ -854,7 +854,7 @@ export const contractsRouter = t.router({
|
|
|
854
854
|
}
|
|
855
855
|
|
|
856
856
|
// Issue VC with signing authority
|
|
857
|
-
let credential:
|
|
857
|
+
let credential: IssuedCredential;
|
|
858
858
|
try {
|
|
859
859
|
credential = await issueCredentialWithSigningAuthority(
|
|
860
860
|
{ type: 'profile', profile },
|
|
@@ -907,7 +907,7 @@ export const contractsRouter = t.router({
|
|
|
907
907
|
.output(z.object({ termsUri: z.string(), redirectUrl: z.string().optional() }))
|
|
908
908
|
.mutation(async ({ input, ctx }) => {
|
|
909
909
|
const { profile } = ctx.user;
|
|
910
|
-
const { isChildAccount, hasGuardianApproval } = ctx;
|
|
910
|
+
const { isChildAccount, hasGuardianApproval, guardianIdentity } = ctx;
|
|
911
911
|
|
|
912
912
|
if (isChildAccount && !hasGuardianApproval) {
|
|
913
913
|
throw new TRPCError({
|
|
@@ -938,6 +938,19 @@ export const contractsRouter = t.router({
|
|
|
938
938
|
});
|
|
939
939
|
}
|
|
940
940
|
|
|
941
|
+
if (!guardianIdentity) {
|
|
942
|
+
const previousTerms = await getContractTermsForProfile(
|
|
943
|
+
profile,
|
|
944
|
+
contractDetails.contract
|
|
945
|
+
);
|
|
946
|
+
if (previousTerms && (await hasGuardianApprovalHistory(previousTerms))) {
|
|
947
|
+
throw new TRPCError({
|
|
948
|
+
code: 'FORBIDDEN',
|
|
949
|
+
message: 'This consent requires approval from a current guardian',
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
941
954
|
if (!areTermsValid(terms, contractDetails.contract.contract)) {
|
|
942
955
|
throw new TRPCError({ code: 'BAD_REQUEST', message: 'Invalid Terms for Contract' });
|
|
943
956
|
}
|
|
@@ -1077,7 +1090,19 @@ export const contractsRouter = t.router({
|
|
|
1077
1090
|
await consentToContract(
|
|
1078
1091
|
profile,
|
|
1079
1092
|
contractDetails,
|
|
1080
|
-
{
|
|
1093
|
+
{
|
|
1094
|
+
terms,
|
|
1095
|
+
expiresAt,
|
|
1096
|
+
oneTime,
|
|
1097
|
+
guardianApproval: guardianIdentity
|
|
1098
|
+
? {
|
|
1099
|
+
guardianProfileId: guardianIdentity.profileId,
|
|
1100
|
+
guardianDid: guardianIdentity.did,
|
|
1101
|
+
approvedAt: new Date().toISOString(),
|
|
1102
|
+
contractUpdatedAt: contractDetails.contract.updatedAt,
|
|
1103
|
+
}
|
|
1104
|
+
: undefined,
|
|
1105
|
+
},
|
|
1081
1106
|
ctx.domain
|
|
1082
1107
|
);
|
|
1083
1108
|
|
|
@@ -1196,7 +1221,7 @@ export const contractsRouter = t.router({
|
|
|
1196
1221
|
.output(z.boolean())
|
|
1197
1222
|
.mutation(async ({ ctx, input }) => {
|
|
1198
1223
|
const { profile } = ctx.user;
|
|
1199
|
-
const { isChildAccount, hasGuardianApproval } = ctx;
|
|
1224
|
+
const { isChildAccount, hasGuardianApproval, guardianIdentity } = ctx;
|
|
1200
1225
|
|
|
1201
1226
|
if (isChildAccount && !hasGuardianApproval) {
|
|
1202
1227
|
throw new TRPCError({
|
|
@@ -1225,6 +1250,13 @@ export const contractsRouter = t.router({
|
|
|
1225
1250
|
});
|
|
1226
1251
|
}
|
|
1227
1252
|
|
|
1253
|
+
if (!guardianIdentity && (await hasGuardianApprovalHistory(relationship.terms))) {
|
|
1254
|
+
throw new TRPCError({
|
|
1255
|
+
code: 'FORBIDDEN',
|
|
1256
|
+
message: 'This consent requires approval from a current guardian',
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1228
1260
|
if (!areTermsValid(terms, relationship.contract.contract)) {
|
|
1229
1261
|
throw new TRPCError({
|
|
1230
1262
|
code: 'BAD_REQUEST',
|
|
@@ -1242,7 +1274,23 @@ export const contractsRouter = t.router({
|
|
|
1242
1274
|
}
|
|
1243
1275
|
|
|
1244
1276
|
await Promise.all([
|
|
1245
|
-
updateTerms(
|
|
1277
|
+
updateTerms(
|
|
1278
|
+
relationship,
|
|
1279
|
+
{
|
|
1280
|
+
terms,
|
|
1281
|
+
expiresAt,
|
|
1282
|
+
oneTime,
|
|
1283
|
+
guardianApproval: guardianIdentity
|
|
1284
|
+
? {
|
|
1285
|
+
guardianProfileId: guardianIdentity.profileId,
|
|
1286
|
+
guardianDid: guardianIdentity.did,
|
|
1287
|
+
approvedAt: new Date().toISOString(),
|
|
1288
|
+
contractUpdatedAt: relationship.contract.updatedAt,
|
|
1289
|
+
}
|
|
1290
|
+
: undefined,
|
|
1291
|
+
},
|
|
1292
|
+
ctx.domain
|
|
1293
|
+
),
|
|
1246
1294
|
deleteStorageForUri(uri),
|
|
1247
1295
|
]);
|
|
1248
1296
|
|
|
@@ -116,7 +116,10 @@ describe('credential refresh issuer route gating', () => {
|
|
|
116
116
|
markConstraintsReady = resolve;
|
|
117
117
|
})
|
|
118
118
|
);
|
|
119
|
-
mocks.sendRefreshableCredential.mockResolvedValue(
|
|
119
|
+
mocks.sendRefreshableCredential.mockResolvedValue({
|
|
120
|
+
uri: 'lc:network:credential:root',
|
|
121
|
+
receipt: { refreshId: 'opaque-refresh-id' },
|
|
122
|
+
});
|
|
120
123
|
|
|
121
124
|
const caller = credentialRefreshesRouter.createCaller({
|
|
122
125
|
domain: 'network.example.com',
|
|
@@ -174,7 +177,10 @@ describe('credential refresh issuer route gating', () => {
|
|
|
174
177
|
|
|
175
178
|
it('forwards initial notification suppression to managed delivery', async () => {
|
|
176
179
|
process.env.CREDENTIAL_REFRESH_ENABLED = 'true';
|
|
177
|
-
mocks.sendRefreshableCredential.mockResolvedValue(
|
|
180
|
+
mocks.sendRefreshableCredential.mockResolvedValue({
|
|
181
|
+
uri: 'lc:network:credential:root',
|
|
182
|
+
receipt: { refreshId: 'opaque-refresh-id' },
|
|
183
|
+
});
|
|
178
184
|
|
|
179
185
|
const caller = credentialRefreshesRouter.createCaller({
|
|
180
186
|
domain: 'network.example.com',
|
|
@@ -124,7 +124,7 @@ export const credentialRefreshesRouter = t.router({
|
|
|
124
124
|
.mutation(async ({ ctx, input }) => {
|
|
125
125
|
const { profile } = ctx.user;
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
const { uri } = await sendRefreshableCredential({
|
|
128
128
|
issuerProfile: profile,
|
|
129
129
|
refreshId: input.refreshId,
|
|
130
130
|
credential: input.credential,
|
|
@@ -132,6 +132,8 @@ export const credentialRefreshesRouter = t.router({
|
|
|
132
132
|
skipNotification: input.skipNotification,
|
|
133
133
|
domain: ctx.domain,
|
|
134
134
|
});
|
|
135
|
+
|
|
136
|
+
return uri;
|
|
135
137
|
}),
|
|
136
138
|
|
|
137
139
|
publishCredentialRefresh: credentialRefreshRoute
|
|
@@ -156,6 +158,7 @@ export const credentialRefreshesRouter = t.router({
|
|
|
156
158
|
issuerProfile: profile,
|
|
157
159
|
input: input as PublishCredentialRefreshInput,
|
|
158
160
|
domain: ctx.domain,
|
|
161
|
+
branding: ctx.tenant?.emailBranding,
|
|
159
162
|
});
|
|
160
163
|
}),
|
|
161
164
|
|
|
@@ -71,6 +71,7 @@ export const credentialsRouter = t.router({
|
|
|
71
71
|
// Log credential activity FIRST to get activityId
|
|
72
72
|
const activityId = await logCredentialSent({
|
|
73
73
|
actorProfileId: profile.profileId,
|
|
74
|
+
onBehalfOf: ctx.user.onBehalfOf,
|
|
74
75
|
recipientType: 'profile',
|
|
75
76
|
recipientIdentifier: targetProfile.profileId,
|
|
76
77
|
recipientProfileId: targetProfile.profileId,
|
|
@@ -118,7 +119,7 @@ export const credentialsRouter = t.router({
|
|
|
118
119
|
const { profile } = ctx.user;
|
|
119
120
|
const { uri } = input;
|
|
120
121
|
|
|
121
|
-
return acceptCredential(profile, uri, input?.options ?? {});
|
|
122
|
+
return acceptCredential(profile, uri, input?.options ?? {}, ctx.tenant?.emailBranding);
|
|
122
123
|
}),
|
|
123
124
|
|
|
124
125
|
receivedCredentials: profileRoute
|
package/src/routes/inbox.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import { trace } from '@tracing';
|
|
2
|
+
import { submitInboxBatch, getInboxBatch } from '@helpers/inbox-queue.helpers';
|
|
3
|
+
import {
|
|
4
|
+
assertInboxRefreshEnabled,
|
|
5
|
+
inboxRefreshRequestDigest,
|
|
6
|
+
getInboxRefreshReplay,
|
|
7
|
+
getInboxRefreshReceipt,
|
|
8
|
+
resumeInboxRefreshDelivery,
|
|
9
|
+
} from '@helpers/inbox-refresh.helpers';
|
|
1
10
|
import { getDidWeb } from '@helpers/did.helpers';
|
|
2
11
|
import { TRPCError } from '@trpc/server';
|
|
3
12
|
import { z } from 'zod';
|
|
@@ -6,6 +15,9 @@ import { t, profileRoute, openRoute, verifiedContactRoute, scopedRoute } from '@
|
|
|
6
15
|
import {
|
|
7
16
|
PaginationOptionsValidator,
|
|
8
17
|
IssueInboxCredentialValidator,
|
|
18
|
+
IssueInboxCredentialBatchValidator,
|
|
19
|
+
InboxBatchReceiptValidator,
|
|
20
|
+
InboxBatchStatusValidator,
|
|
9
21
|
IssueInboxCredentialResponseValidator,
|
|
10
22
|
InboxCredentialValidator,
|
|
11
23
|
PaginatedInboxCredentialsValidator,
|
|
@@ -18,15 +30,14 @@ import {
|
|
|
18
30
|
JWEValidator,
|
|
19
31
|
} from '@learncard/types';
|
|
20
32
|
import { getInboxCredentialMeta } from '@helpers/credential-meta.helpers';
|
|
21
|
-
import { claimIntoInbox, issueToInbox } from '@helpers/inbox.helpers';
|
|
22
|
-
import { prepareCredentialFromBoost, getBoostUri } from '@helpers/boost.helpers';
|
|
33
|
+
import { claimIntoInbox, issueToInbox, resolveInboxCredentialInput } from '@helpers/inbox.helpers';
|
|
23
34
|
import {
|
|
24
35
|
hasMustacheVariables,
|
|
25
36
|
renderBoostTemplate,
|
|
26
37
|
parseRenderedTemplate,
|
|
27
38
|
} from '@helpers/template.helpers';
|
|
28
39
|
import { getProfileByVerifiedContactMethod } from '@accesslayer/contact-method/relationships/read';
|
|
29
|
-
import {
|
|
40
|
+
import { getBoostsForProfile } from '@accesslayer/boost/read';
|
|
30
41
|
import {
|
|
31
42
|
generateGuardianApprovalToken,
|
|
32
43
|
generateGuardianApprovalUrl,
|
|
@@ -447,55 +458,36 @@ export const inboxRouter = t.router({
|
|
|
447
458
|
.output(IssueInboxCredentialResponseValidator)
|
|
448
459
|
.mutation(async ({ ctx, input }) => {
|
|
449
460
|
const { profile } = ctx.user;
|
|
450
|
-
const { recipient,
|
|
451
|
-
|
|
452
|
-
// Resolve credential from templateUri if provided
|
|
453
|
-
let credential = inputCredential;
|
|
454
|
-
let resolvedBoostUri: string | undefined;
|
|
455
|
-
|
|
456
|
-
if (templateUri && !credential) {
|
|
457
|
-
const boostInstance = await getBoostByUri(templateUri);
|
|
458
|
-
|
|
459
|
-
if (!boostInstance) {
|
|
460
|
-
throw new TRPCError({
|
|
461
|
-
code: 'NOT_FOUND',
|
|
462
|
-
message: `Boost not found: ${templateUri}`,
|
|
463
|
-
});
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
if (!boostInstance.dataValues.boost) {
|
|
467
|
-
throw new TRPCError({
|
|
468
|
-
code: 'BAD_REQUEST',
|
|
469
|
-
message: `Boost does not contain a credential template: ${templateUri}`,
|
|
470
|
-
});
|
|
471
|
-
}
|
|
461
|
+
const { recipient, configuration } = input;
|
|
472
462
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
463
|
+
const refreshDigest = input.refresh ? inboxRefreshRequestDigest(input) : undefined;
|
|
464
|
+
if (input.refresh) {
|
|
465
|
+
await assertInboxRefreshEnabled(ctx.user.scope);
|
|
466
|
+
const replay = await getInboxRefreshReplay(
|
|
467
|
+
profile.profileId,
|
|
468
|
+
input.idempotencyKey,
|
|
469
|
+
refreshDigest!
|
|
470
|
+
);
|
|
471
|
+
if (replay && (replay.claimUrl || replay.inbox.currentStatus !== 'PENDING')) {
|
|
472
|
+
await resumeInboxRefreshDelivery(replay.inbox.refreshId!, ctx.domain);
|
|
473
|
+
const receipt = await getInboxRefreshReceipt(
|
|
474
|
+
replay.inbox.refreshId!,
|
|
475
|
+
ctx.domain
|
|
483
476
|
);
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
477
|
+
return {
|
|
478
|
+
issuanceId: replay.inbox.id,
|
|
479
|
+
status: replay.inbox.currentStatus,
|
|
480
|
+
recipient,
|
|
481
|
+
claimUrl: replay.claimUrl,
|
|
482
|
+
refresh: receipt,
|
|
483
|
+
...(replay.inbox.currentStatus === 'ISSUED'
|
|
484
|
+
? { recipientDid: receipt.holderDid }
|
|
485
|
+
: {}),
|
|
486
|
+
};
|
|
490
487
|
}
|
|
491
488
|
}
|
|
492
489
|
|
|
493
|
-
|
|
494
|
-
throw new TRPCError({
|
|
495
|
-
code: 'BAD_REQUEST',
|
|
496
|
-
message: 'Either credential or templateUri must be provided',
|
|
497
|
-
});
|
|
498
|
-
}
|
|
490
|
+
const { credential, resolvedBoostUri } = await resolveInboxCredentialInput(input, ctx);
|
|
499
491
|
|
|
500
492
|
// Normalize signing authority name if provided
|
|
501
493
|
const normalizedConfiguration = configuration?.signingAuthority
|
|
@@ -513,11 +505,18 @@ export const inboxRouter = t.router({
|
|
|
513
505
|
profile,
|
|
514
506
|
recipient,
|
|
515
507
|
credential,
|
|
516
|
-
|
|
508
|
+
{
|
|
509
|
+
...normalizedConfiguration,
|
|
510
|
+
boostUri: resolvedBoostUri,
|
|
511
|
+
refresh: input.refresh,
|
|
512
|
+
idempotencyKey: input.idempotencyKey,
|
|
513
|
+
refreshRequestDigest: refreshDigest,
|
|
514
|
+
},
|
|
517
515
|
ctx
|
|
518
516
|
);
|
|
519
517
|
|
|
520
518
|
return {
|
|
519
|
+
refresh: result.refresh,
|
|
521
520
|
issuanceId: result.inboxCredential.id,
|
|
522
521
|
status: result.status,
|
|
523
522
|
recipient,
|
|
@@ -536,6 +535,42 @@ export const inboxRouter = t.router({
|
|
|
536
535
|
}
|
|
537
536
|
}),
|
|
538
537
|
|
|
538
|
+
issueBatch: profileRoute
|
|
539
|
+
.meta({
|
|
540
|
+
openapi: {
|
|
541
|
+
protect: true,
|
|
542
|
+
method: 'POST',
|
|
543
|
+
path: '/inbox/issue-batch',
|
|
544
|
+
tags: ['Universal Inbox'],
|
|
545
|
+
summary: 'Issue Credentials to Universal Inbox (Batch)',
|
|
546
|
+
description:
|
|
547
|
+
'Queue 1–100 credentials for background issuance. Returns a durable batch ID; poll GET /inbox/batches/{batchId} for ordered results. Request and item idempotency keys are issuer-scoped for 24 hours. Maximum JSON payload: 4 MiB.',
|
|
548
|
+
},
|
|
549
|
+
requiredScope: 'inbox:write',
|
|
550
|
+
})
|
|
551
|
+
.input(IssueInboxCredentialBatchValidator)
|
|
552
|
+
.output(InboxBatchReceiptValidator)
|
|
553
|
+
.mutation(({ ctx, input }) =>
|
|
554
|
+
trace('route', 'issueBatch', () => submitInboxBatch(ctx.user.profile, input, ctx), {
|
|
555
|
+
itemCount: input.items.length,
|
|
556
|
+
})
|
|
557
|
+
),
|
|
558
|
+
|
|
559
|
+
getBatch: profileRoute
|
|
560
|
+
.meta({
|
|
561
|
+
openapi: {
|
|
562
|
+
protect: true,
|
|
563
|
+
method: 'GET',
|
|
564
|
+
path: '/inbox/batches/{batchId}',
|
|
565
|
+
tags: ['Universal Inbox'],
|
|
566
|
+
summary: 'Get Inbox Batch Progress',
|
|
567
|
+
},
|
|
568
|
+
requiredScope: 'inbox:read',
|
|
569
|
+
})
|
|
570
|
+
.input(z.object({ batchId: z.string() }))
|
|
571
|
+
.output(InboxBatchStatusValidator)
|
|
572
|
+
.query(({ ctx, input }) => getInboxBatch(ctx.user.profile.profileId, input.batchId)),
|
|
573
|
+
|
|
539
574
|
claim: verifiedContactRoute
|
|
540
575
|
.meta({
|
|
541
576
|
openapi: {
|
|
@@ -682,6 +717,7 @@ export const inboxRouter = t.router({
|
|
|
682
717
|
// Log initial activity so embed claims appear in the dashboard
|
|
683
718
|
const activityId = await logCredentialSent({
|
|
684
719
|
actorProfileId: issuerProfile.profileId,
|
|
720
|
+
onBehalfOf: ctx.user?.onBehalfOf,
|
|
685
721
|
recipientType: contactMethod.type as 'email' | 'phone',
|
|
686
722
|
recipientIdentifier: contactMethod.value,
|
|
687
723
|
integrationId: integration.id,
|
|
@@ -825,7 +861,17 @@ export const inboxRouter = t.router({
|
|
|
825
861
|
});
|
|
826
862
|
}
|
|
827
863
|
|
|
828
|
-
return
|
|
864
|
+
return {
|
|
865
|
+
...inboxCredential,
|
|
866
|
+
...(inboxCredential.refreshId
|
|
867
|
+
? {
|
|
868
|
+
refresh: await getInboxRefreshReceipt(
|
|
869
|
+
inboxCredential.refreshId,
|
|
870
|
+
ctx.domain
|
|
871
|
+
),
|
|
872
|
+
}
|
|
873
|
+
: {}),
|
|
874
|
+
};
|
|
829
875
|
}),
|
|
830
876
|
|
|
831
877
|
// ─── Guardian Credential Approval Routes ─────────────────────────────────────
|