@learncard/network-plugin 2.14.0 → 3.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.
@@ -5,6 +5,53 @@ var __export = (target, all) => {
5
5
  __defProp(target, name, { get: all[name], enumerable: true });
6
6
  };
7
7
 
8
+ // src/inbox-batch.ts
9
+ var waitForInboxCredentialBatch = /* @__PURE__ */ __name(async (read, options = {}) => {
10
+ const { timeoutMs = 6e5, intervalMs = 2e3, signal, onProgress } = options;
11
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647 || !Number.isFinite(intervalMs) || intervalMs <= 0 || intervalMs > 2147483647) {
12
+ throw new RangeError("timeoutMs and intervalMs must be positive finite timer durations.");
13
+ }
14
+ const controller = new AbortController();
15
+ const abort = /* @__PURE__ */ __name(() => controller.abort(signal?.reason), "abort");
16
+ signal?.addEventListener("abort", abort, { once: true });
17
+ if (signal?.aborted) abort();
18
+ const timeout = setTimeout(() => {
19
+ const error51 = new Error(
20
+ "Timed out waiting for inbox batch. Keep the batch ID to check again."
21
+ );
22
+ error51.name = "TimeoutError";
23
+ controller.abort(error51);
24
+ }, timeoutMs);
25
+ const cancellable = /* @__PURE__ */ __name((operation) => new Promise((resolve, reject) => {
26
+ const interrupted = /* @__PURE__ */ __name(() => reject(controller.signal.reason), "interrupted");
27
+ if (controller.signal.aborted) return interrupted();
28
+ controller.signal.addEventListener("abort", interrupted, { once: true });
29
+ Promise.resolve().then(() => {
30
+ if (controller.signal.aborted) throw controller.signal.reason;
31
+ return operation();
32
+ }).then(resolve, reject).finally(() => controller.signal.removeEventListener("abort", interrupted));
33
+ }), "cancellable");
34
+ let delay = intervalMs;
35
+ let sleepTimer;
36
+ try {
37
+ while (true) {
38
+ const batch = await cancellable(() => read(controller.signal));
39
+ onProgress?.(batch);
40
+ if (batch.done) return batch;
41
+ await cancellable(
42
+ () => new Promise((resolve) => {
43
+ sleepTimer = setTimeout(resolve, delay);
44
+ })
45
+ );
46
+ delay = Math.min(delay * 1.5, Math.max(intervalMs, 1e4));
47
+ }
48
+ } finally {
49
+ clearTimeout(timeout);
50
+ clearTimeout(sleepTimer);
51
+ signal?.removeEventListener("abort", abort);
52
+ }
53
+ }, "waitForInboxCredentialBatch");
54
+
8
55
  // src/plugin.ts
9
56
  import { getClient, getApiTokenClient } from "@learncard/network-brain-client";
10
57
 
@@ -15105,14 +15152,22 @@ var UnsignedVCValidator = external_exports.object({
15105
15152
  }).catchall(external_exports.any());
15106
15153
  var ProofValidator = external_exports.object({
15107
15154
  type: external_exports.string(),
15108
- created: external_exports.string(),
15155
+ created: external_exports.string().optional(),
15109
15156
  challenge: external_exports.string().optional(),
15110
15157
  domain: external_exports.string().optional(),
15111
15158
  nonce: external_exports.string().optional(),
15112
15159
  proofPurpose: external_exports.string(),
15113
15160
  verificationMethod: external_exports.string(),
15114
15161
  jws: external_exports.string().optional()
15115
- }).catchall(external_exports.any());
15162
+ }).catchall(external_exports.any()).superRefine((proof, ctx) => {
15163
+ if (proof.created === void 0 && (proof.type !== "DataIntegrityProof" || proof.cryptosuite !== "ecdsa-rdfc-2019")) {
15164
+ ctx.addIssue({
15165
+ code: "custom",
15166
+ path: ["created"],
15167
+ message: "created is required for this proof suite"
15168
+ });
15169
+ }
15170
+ });
15116
15171
  var VCValidator = UnsignedVCValidator.extend({
15117
15172
  proof: ProofValidator.or(ProofValidator.array())
15118
15173
  });
@@ -15554,6 +15609,204 @@ var StringQuery = external_exports.union([
15554
15609
  $or: BaseStringQuery.array()
15555
15610
  })
15556
15611
  ]);
15612
+ var LearnCardRefreshAuthorizationValidator = external_exports.object({ type: external_exports.literal("LearnCardDIDAuth") }).catchall(external_exports.any());
15613
+ var ManagedCredentialRefreshServiceValidator = external_exports.object({
15614
+ id: external_exports.string().min(1),
15615
+ type: external_exports.literal("LearnCardCredentialRefresh2026"),
15616
+ authorization: LearnCardRefreshAuthorizationValidator.optional()
15617
+ }).catchall(external_exports.any());
15618
+ var StandardCredentialRefreshServiceValidator = external_exports.object({
15619
+ id: external_exports.string().min(1),
15620
+ type: external_exports.literal("1EdTechCredentialRefresh")
15621
+ }).catchall(external_exports.any());
15622
+ var SupportedCredentialRefreshServiceValidator = external_exports.union([
15623
+ ManagedCredentialRefreshServiceValidator,
15624
+ StandardCredentialRefreshServiceValidator
15625
+ ]);
15626
+ var AllocateCredentialRefreshInputValidator = external_exports.object({
15627
+ holder: external_exports.object({
15628
+ profileId: external_exports.string().optional(),
15629
+ did: external_exports.string().min(1)
15630
+ }),
15631
+ credentialId: external_exports.string().min(1)
15632
+ });
15633
+ var AllocateCredentialRefreshResultValidator = external_exports.object({
15634
+ refreshId: external_exports.string().min(1),
15635
+ refreshService: ManagedCredentialRefreshServiceValidator.extend({
15636
+ authorization: LearnCardRefreshAuthorizationValidator
15637
+ })
15638
+ });
15639
+ var ManagedCredentialRefreshReceiptValidator = external_exports.object({
15640
+ refreshId: external_exports.string().min(1),
15641
+ refreshService: ManagedCredentialRefreshServiceValidator,
15642
+ credentialId: external_exports.string().min(1),
15643
+ issuerDid: external_exports.string().min(1),
15644
+ holderDid: external_exports.string().min(1),
15645
+ credentialStatus: CredentialStatusValidator.or(
15646
+ CredentialStatusValidator.array()
15647
+ ).optional()
15648
+ }).strip();
15649
+ var InboxCredentialRefreshReceiptValidator = ManagedCredentialRefreshReceiptValidator.omit(
15650
+ { holderDid: true }
15651
+ ).extend({ holderDid: external_exports.string().min(1).optional() });
15652
+ var CredentialRefreshSigningModeValidator = external_exports.enum(["issuer-signed", "signing-authority"]);
15653
+ var PublishCredentialRefreshBaseFields = {
15654
+ refreshId: external_exports.string().min(1),
15655
+ notifyHolder: external_exports.boolean().optional(),
15656
+ updateSummary: external_exports.string().optional(),
15657
+ idempotencyKey: external_exports.string().optional()
15658
+ };
15659
+ var PublishIssuerSignedRefreshValidator = external_exports.object({
15660
+ ...PublishCredentialRefreshBaseFields,
15661
+ mode: external_exports.literal("issuer-signed"),
15662
+ signedCredential: VCValidator
15663
+ });
15664
+ var PublishSigningAuthorityRefreshValidator = external_exports.object({
15665
+ ...PublishCredentialRefreshBaseFields,
15666
+ mode: external_exports.literal("signing-authority"),
15667
+ credential: UnsignedVCValidator,
15668
+ signingAuthority: external_exports.object({
15669
+ type: external_exports.string().min(1)
15670
+ }).catchall(external_exports.any())
15671
+ });
15672
+ var PublishCredentialRefreshInputValidator = external_exports.object({
15673
+ ...PublishCredentialRefreshBaseFields,
15674
+ mode: CredentialRefreshSigningModeValidator,
15675
+ signedCredential: VCValidator.optional(),
15676
+ credential: UnsignedVCValidator.optional(),
15677
+ signingAuthority: external_exports.object({
15678
+ type: external_exports.string().min(1)
15679
+ }).catchall(external_exports.any()).optional()
15680
+ }).superRefine((input, ctx) => {
15681
+ if (input.mode === "issuer-signed" && !input.signedCredential) {
15682
+ ctx.addIssue({
15683
+ code: "custom",
15684
+ path: ["signedCredential"],
15685
+ message: "signedCredential is required for issuer-signed publication"
15686
+ });
15687
+ }
15688
+ if (input.mode === "issuer-signed" && (input.credential !== void 0 || input.signingAuthority !== void 0)) {
15689
+ ctx.addIssue({
15690
+ code: "custom",
15691
+ path: ["mode"],
15692
+ message: "issuer-signed publication cannot include signing-authority fields"
15693
+ });
15694
+ }
15695
+ if (input.mode === "signing-authority") {
15696
+ if (input.signedCredential !== void 0) {
15697
+ ctx.addIssue({
15698
+ code: "custom",
15699
+ path: ["signedCredential"],
15700
+ message: "signing-authority publication cannot include signedCredential"
15701
+ });
15702
+ }
15703
+ if (!input.credential) {
15704
+ ctx.addIssue({
15705
+ code: "custom",
15706
+ path: ["credential"],
15707
+ message: "credential is required for signing-authority publication"
15708
+ });
15709
+ }
15710
+ if (!input.signingAuthority) {
15711
+ ctx.addIssue({
15712
+ code: "custom",
15713
+ path: ["signingAuthority"],
15714
+ message: "signingAuthority is required for signing-authority publication"
15715
+ });
15716
+ }
15717
+ }
15718
+ });
15719
+ var PublishCredentialRefreshNotificationValidator = external_exports.enum([
15720
+ "queued",
15721
+ "suppressed",
15722
+ "not-applicable",
15723
+ /** Publication succeeded, but the post-commit notification enqueue must be retried. */
15724
+ "delivery-failed"
15725
+ ]);
15726
+ var PublishCredentialRefreshResultValidator = external_exports.object({
15727
+ refreshId: external_exports.string().min(1),
15728
+ version: external_exports.number().int().positive(),
15729
+ publishedAt: external_exports.string().min(1),
15730
+ notification: PublishCredentialRefreshNotificationValidator
15731
+ });
15732
+ var CredentialRefreshVersionMetadataValidator = external_exports.object({
15733
+ version: external_exports.number().int().positive(),
15734
+ publishedAt: external_exports.string().min(1),
15735
+ effectiveAt: external_exports.string().optional(),
15736
+ etag: external_exports.string().optional(),
15737
+ signingMode: CredentialRefreshSigningModeValidator.optional(),
15738
+ updateSummary: external_exports.string().optional()
15739
+ });
15740
+ var GetCredentialRefreshHistoryInputValidator = external_exports.object({
15741
+ refreshId: external_exports.string().min(1),
15742
+ cursor: external_exports.string().optional(),
15743
+ limit: external_exports.number().int().positive().optional()
15744
+ });
15745
+ var GetCredentialRefreshHistoryResultValidator = external_exports.object({
15746
+ records: CredentialRefreshVersionMetadataValidator.array(),
15747
+ hasMore: external_exports.boolean(),
15748
+ cursor: external_exports.string().optional()
15749
+ });
15750
+ var CredentialRefreshChallengeValidator = external_exports.object({
15751
+ challenge: external_exports.string().min(1),
15752
+ expiresAt: external_exports.string().min(1),
15753
+ domain: external_exports.string().optional(),
15754
+ scheme: external_exports.literal("LearnCardDIDAuth").optional()
15755
+ });
15756
+ var PublicCredentialRefreshEnvelopeValidator = external_exports.object({
15757
+ format: external_exports.literal("vc"),
15758
+ credential: VCValidator,
15759
+ etag: external_exports.string().optional()
15760
+ });
15761
+ var JweCredentialRefreshEnvelopeValidator = external_exports.object({
15762
+ format: external_exports.literal("jwe"),
15763
+ jwe: JWEValidator,
15764
+ etag: external_exports.string().optional(),
15765
+ /** Present on LearnCard-managed endpoints; optional for interoperable JWE services. */
15766
+ version: external_exports.number().int().positive().optional()
15767
+ });
15768
+ var CredentialRefreshResponseEnvelopeValidator = external_exports.discriminatedUnion("format", [
15769
+ PublicCredentialRefreshEnvelopeValidator,
15770
+ JweCredentialRefreshEnvelopeValidator
15771
+ ]);
15772
+ var CredentialRefreshFailureCodeValidator = external_exports.enum([
15773
+ "UNAVAILABLE",
15774
+ "TIMEOUT",
15775
+ "UNSUPPORTED_SERVICE",
15776
+ "UNAUTHORIZED",
15777
+ "MALFORMED_RESPONSE",
15778
+ "INVALID_PROOF",
15779
+ "ISSUER_MISMATCH",
15780
+ "ID_MISMATCH",
15781
+ "ROLLBACK",
15782
+ "REVOKED",
15783
+ "UNSAFE_ENDPOINT"
15784
+ ]);
15785
+ var CredentialRefreshUpdatedResultValidator = external_exports.object({
15786
+ status: external_exports.literal("updated"),
15787
+ credential: VCValidator,
15788
+ etag: external_exports.string().optional(),
15789
+ managedVersion: external_exports.number().int().positive().optional()
15790
+ });
15791
+ var CredentialRefreshUnchangedResultValidator = external_exports.object({
15792
+ status: external_exports.literal("unchanged"),
15793
+ checkedAt: external_exports.string().min(1),
15794
+ etag: external_exports.string().optional()
15795
+ });
15796
+ var CredentialRefreshUnsupportedResultValidator = external_exports.object({
15797
+ status: external_exports.literal("unsupported")
15798
+ });
15799
+ var CredentialRefreshFailedResultValidator = external_exports.object({
15800
+ status: external_exports.literal("failed"),
15801
+ code: CredentialRefreshFailureCodeValidator,
15802
+ retryable: external_exports.boolean()
15803
+ });
15804
+ var CredentialRefreshResultValidator = external_exports.discriminatedUnion("status", [
15805
+ CredentialRefreshUpdatedResultValidator,
15806
+ CredentialRefreshUnchangedResultValidator,
15807
+ CredentialRefreshUnsupportedResultValidator,
15808
+ CredentialRefreshFailedResultValidator
15809
+ ]);
15557
15810
  var LCNProfileDisplayValidator = external_exports.object({
15558
15811
  backgroundColor: external_exports.string().optional(),
15559
15812
  backgroundImage: external_exports.string().optional(),
@@ -15889,7 +16142,13 @@ var SendBoostInputValidator = external_exports.object({
15889
16142
  "Options for email/phone recipients (Universal Inbox)"
15890
16143
  ),
15891
16144
  templateData: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
15892
- integrationId: external_exports.string().optional().describe("Integration ID for activity tracking")
16145
+ integrationId: external_exports.string().optional().describe("Integration ID for activity tracking"),
16146
+ refresh: external_exports.boolean().optional().describe(
16147
+ "Request managed credential refresh for this send. Profile/DID recipients use immediate issuance; email/phone recipients use deferred Universal Inbox signing and bind the holder at claim."
16148
+ ),
16149
+ idempotencyKey: external_exports.string().min(1).max(200).optional().describe(
16150
+ "Caller-chosen key that makes a managed refresh send (refresh: true) safe to retry as a whole: retries with the same key reuse the same boost, refresh allocation and result. Reusing a key for a different request is rejected. With signedCredential, requires prior tRPC prepareRefreshableSend; direct REST callers omit the key and retry the exact signed credential and templateUri."
16151
+ )
15893
16152
  }).refine((data) => data.templateUri || data.template || data.signedCredential, {
15894
16153
  message: "Either templateUri, template, or signedCredential must be provided.",
15895
16154
  path: ["templateUri"]
@@ -15904,8 +16163,12 @@ var SendBoostInputValidator = external_exports.object({
15904
16163
  message: "guardianEmail must differ from recipient (self-approval not allowed)",
15905
16164
  path: ["options", "guardianEmail"]
15906
16165
  }
15907
- );
16166
+ ).refine((data) => !data.idempotencyKey || data.refresh === true, {
16167
+ message: "idempotencyKey is only supported with refresh: true.",
16168
+ path: ["idempotencyKey"]
16169
+ });
15908
16170
  var SendInboxResponseValidator = external_exports.object({
16171
+ refresh: InboxCredentialRefreshReceiptValidator.optional(),
15909
16172
  issuanceId: external_exports.string(),
15910
16173
  status: external_exports.enum(["PENDING", "ISSUED", "EXPIRED", "DELIVERED", "CLAIMED"]),
15911
16174
  claimUrl: external_exports.string().url().optional().describe("Present when suppressDelivery=true"),
@@ -15920,8 +16183,34 @@ var SendBoostResponseValidator = external_exports.object({
15920
16183
  activityId: external_exports.string().describe("Links to the activity lifecycle for this issuance"),
15921
16184
  inbox: SendInboxResponseValidator.optional().describe(
15922
16185
  "Present when sent via email/phone (Universal Inbox)"
16186
+ ),
16187
+ refresh: ManagedCredentialRefreshReceiptValidator.optional().describe(
16188
+ "Present when managed refresh was requested: issuance metadata the issuer keeps to publish future updates"
15923
16189
  )
15924
16190
  });
16191
+ var PrepareRefreshableSendInputValidator = external_exports.object({
16192
+ recipient: external_exports.string(),
16193
+ templateUri: external_exports.string().optional(),
16194
+ template: SendBoostTemplateValidator.optional(),
16195
+ contractUri: external_exports.string().optional(),
16196
+ templateData: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
16197
+ integrationId: external_exports.string().optional(),
16198
+ /** Credential ID to allocate for; generated server-side when omitted. */
16199
+ credentialId: external_exports.string().min(1).optional(),
16200
+ idempotencyKey: external_exports.string().min(1).max(200).optional()
16201
+ }).refine((data) => Boolean(data.templateUri) !== Boolean(data.template), {
16202
+ message: "Provide exactly one of templateUri or template."
16203
+ });
16204
+ var PrepareRefreshableSendResultValidator = external_exports.object({
16205
+ boostUri: external_exports.string(),
16206
+ credentialId: external_exports.string(),
16207
+ refreshId: external_exports.string(),
16208
+ refreshService: ManagedCredentialRefreshServiceValidator,
16209
+ /** The DID to use as credentialSubject.id (recipient DID, or the profile's did:web). */
16210
+ holderDid: external_exports.string(),
16211
+ /** Present when this idempotencyKey already completed: return it without signing. */
16212
+ completed: SendBoostResponseValidator.optional()
16213
+ });
15925
16214
  var SendInputValidator = external_exports.discriminatedUnion("type", [SendBoostInputValidator]);
15926
16215
  var SendResponseValidator = external_exports.discriminatedUnion("type", [SendBoostResponseValidator]);
15927
16216
  var ConsentFlowTermsStatusValidator = external_exports.enum(["live", "stale", "withdrawn"]);
@@ -15997,15 +16286,6 @@ var ConsentFlowContractDataValidator = external_exports.object({
15997
16286
  var PaginatedConsentFlowDataValidator = PaginationResponseValidator.extend({
15998
16287
  records: ConsentFlowContractDataValidator.array()
15999
16288
  });
16000
- var ConsentFlowContractDataForDidValidator = external_exports.object({
16001
- credentials: external_exports.object({ category: external_exports.string(), uri: external_exports.string() }).array(),
16002
- personal: external_exports.record(external_exports.string(), external_exports.string()).default({}),
16003
- date: external_exports.string(),
16004
- contractUri: external_exports.string()
16005
- });
16006
- var PaginatedConsentFlowDataForDidValidator = PaginationResponseValidator.extend({
16007
- records: ConsentFlowContractDataForDidValidator.array()
16008
- });
16009
16289
  var ConsentFlowTermValidator = external_exports.object({
16010
16290
  sharing: external_exports.boolean().optional(),
16011
16291
  shared: external_exports.string().array().optional(),
@@ -16039,6 +16319,34 @@ var PaginatedConsentFlowTermsValidator = PaginationResponseValidator.extend({
16039
16319
  status: ConsentFlowTermsStatusValidator
16040
16320
  }).array()
16041
16321
  });
16322
+ var ConsentFlowGuardianApprovalValidator = external_exports.object({
16323
+ guardianProfileId: external_exports.string(),
16324
+ guardianDid: external_exports.string(),
16325
+ approvedAt: external_exports.string().datetime(),
16326
+ contractUpdatedAt: external_exports.string()
16327
+ });
16328
+ var ConsentFlowContractDataForDidValidator = external_exports.object({
16329
+ credentials: external_exports.object({ category: external_exports.string(), uri: external_exports.string() }).array(),
16330
+ personal: external_exports.record(external_exports.string(), external_exports.string()).default({}),
16331
+ date: external_exports.string(),
16332
+ createdAt: external_exports.string().optional(),
16333
+ contractUpdatedAt: external_exports.string(),
16334
+ contractExpiresAt: external_exports.string().optional(),
16335
+ reasonForAccessing: external_exports.string().optional(),
16336
+ guardian: external_exports.object({
16337
+ required: external_exports.boolean(),
16338
+ approved: external_exports.boolean(),
16339
+ approval: ConsentFlowGuardianApprovalValidator.optional()
16340
+ }),
16341
+ contractUri: external_exports.string(),
16342
+ termsUri: external_exports.string(),
16343
+ status: ConsentFlowTermsStatusValidator,
16344
+ expiresAt: external_exports.string().optional(),
16345
+ terms: ConsentFlowTermsValidator
16346
+ });
16347
+ var PaginatedConsentFlowDataForDidValidator = PaginationResponseValidator.extend({
16348
+ records: ConsentFlowContractDataForDidValidator.array()
16349
+ });
16042
16350
  var ConsentFlowContractQueryValidator = external_exports.object({
16043
16351
  read: external_exports.object({
16044
16352
  anonymize: external_exports.boolean().optional(),
@@ -16099,6 +16407,7 @@ var ConsentFlowTransactionValidator = external_exports.object({
16099
16407
  expiresAt: external_exports.string().optional(),
16100
16408
  oneTime: external_exports.boolean().optional(),
16101
16409
  terms: ConsentFlowTermsValidator.optional(),
16410
+ guardianApproval: ConsentFlowGuardianApprovalValidator.optional(),
16102
16411
  id: external_exports.string(),
16103
16412
  action: ConsentFlowTransactionActionValidator,
16104
16413
  date: external_exports.string(),
@@ -16220,6 +16529,7 @@ var LCNNotificationValidator = external_exports.object({
16220
16529
  webhookUrl: external_exports.string().optional()
16221
16530
  });
16222
16531
  var AUTH_GRANT_AUDIENCE_DOMAIN_PREFIX = "auth-grant:";
16532
+ var ACT_AS_HEADER = "X-LearnCard-Act-As";
16223
16533
  var AuthGrantValidator = external_exports.object({
16224
16534
  id: external_exports.string(),
16225
16535
  name: external_exports.string(),
@@ -16232,6 +16542,7 @@ var AuthGrantValidator = external_exports.object({
16232
16542
  }, "error")
16233
16543
  }),
16234
16544
  scope: external_exports.string(),
16545
+ actAs: external_exports.string().optional(),
16235
16546
  createdAt: external_exports.iso.datetime({ error: "createdAt must be a valid ISO 8601 datetime string" }),
16236
16547
  expiresAt: external_exports.iso.datetime({ error: "expiresAt must be a valid ISO 8601 datetime string" }).nullish().optional()
16237
16548
  });
@@ -16303,6 +16614,8 @@ var CreateContactMethodSessionResponseValidator = external_exports.object({
16303
16614
  sessionJwt: external_exports.string()
16304
16615
  });
16305
16616
  var InboxCredentialValidator = external_exports.object({
16617
+ refresh: InboxCredentialRefreshReceiptValidator.optional(),
16618
+ refreshId: external_exports.string().optional(),
16306
16619
  id: external_exports.string(),
16307
16620
  credential: external_exports.string().optional(),
16308
16621
  isSigned: external_exports.boolean(),
@@ -16357,12 +16670,19 @@ var IssueInboxCredentialValidator = external_exports.object({
16357
16670
  templateUri: external_exports.string().optional().describe(
16358
16671
  "URI of a boost template to use for issuance. The boost credential will be resolved and used. Mutually exclusive with credential field."
16359
16672
  ),
16673
+ refresh: external_exports.boolean().optional().describe(
16674
+ "Allocate managed refresh before signing. Requires unsigned content and a registered signing authority; binds the holder on claim."
16675
+ ),
16676
+ idempotencyKey: external_exports.string().min(1).max(200).optional(),
16360
16677
  // === OPTIONAL FEATURES ===
16361
16678
  // Add major, distinct features at the top level.
16362
16679
  //consentRequest: ConsentRequestValidator.optional(),
16363
16680
  // === PROCESS CONFIGURATION (Optional) ===
16364
16681
  // HOW should this issuance be handled?
16365
16682
  configuration: external_exports.object({
16683
+ guardianEmail: external_exports.string().email().optional().describe(
16684
+ "Require approval from this guardian before the recipient can claim. Must differ from the recipient email."
16685
+ ),
16366
16686
  signingAuthority: IssueInboxSigningAuthorityValidator.optional().describe(
16367
16687
  "The signing authority to use for the credential. If not provided, the users default signing authority will be used if the credential is not signed."
16368
16688
  ),
@@ -16416,25 +16736,138 @@ var IssueInboxCredentialValidator = external_exports.object({
16416
16736
  }).optional().describe(
16417
16737
  "Configuration for the credential issuance. If not provided, the default configuration will be used."
16418
16738
  )
16739
+ }).refine((data) => !data.idempotencyKey || data.refresh === true, {
16740
+ message: "idempotencyKey requires refresh: true."
16419
16741
  }).refine((data) => data.credential || data.templateUri, {
16420
16742
  message: "Either credential or templateUri must be provided.",
16421
16743
  path: ["credential"]
16422
- });
16744
+ }).refine(
16745
+ (data) => !data.configuration?.guardianEmail || data.recipient.type !== "email" || data.configuration.guardianEmail.toLowerCase() !== data.recipient.value.toLowerCase(),
16746
+ {
16747
+ message: "guardianEmail must differ from recipient (self-approval not allowed)",
16748
+ path: ["configuration", "guardianEmail"]
16749
+ }
16750
+ );
16423
16751
  var IssueInboxCredentialResponseValidator = external_exports.object({
16752
+ refresh: InboxCredentialRefreshReceiptValidator.optional(),
16424
16753
  issuanceId: external_exports.string(),
16425
16754
  status: LCNInboxStatusEnumValidator,
16426
16755
  recipient: ContactMethodQueryValidator,
16427
16756
  claimUrl: external_exports.string().url().optional(),
16428
16757
  recipientDid: external_exports.string().optional()
16429
16758
  });
16430
- var CredentialNameRefValidator = external_exports.object({ name: external_exports.string() }).passthrough();
16431
- var ClaimInboxCredentialValidator = external_exports.object({
16432
- credential: VCValidator.or(VPValidator).or(UnsignedVCValidator).or(CredentialNameRefValidator).describe("The credential to issue, or a { name } reference to resolve a boost template."),
16433
- configuration: external_exports.object({
16434
- publishableKey: external_exports.string(),
16435
- expiresInDays: external_exports.number().int().min(1).max(720).optional().describe(
16436
- "Inbox claim window in days. Defaults to 720; use a shorter window for sensitive records."
16437
- ),
16759
+ var InboxBatchConfigurationValidator = IssueInboxCredentialValidator.shape.configuration.unwrap().extend({
16760
+ refresh: IssueInboxCredentialValidator.shape.refresh.describe(
16761
+ "Enable managed refresh by default. An item configuration.refresh overrides this value, including false."
16762
+ ),
16763
+ delivery: IssueInboxCredentialValidator.shape.configuration.unwrap().shape.delivery.unwrap().extend({ suppress: external_exports.boolean().optional() }).optional()
16764
+ });
16765
+ var InboxBatchItemConfigurationValidator = InboxBatchConfigurationValidator.extend({
16766
+ guardianEmail: InboxBatchConfigurationValidator.shape.guardianEmail.nullable().describe(
16767
+ "Require guardian approval, or set null to clear a batch-level guardianEmail for this item."
16768
+ )
16769
+ });
16770
+ var IssueInboxCredentialBatchItemValidator = external_exports.object({
16771
+ ...IssueInboxCredentialValidator.shape,
16772
+ configuration: InboxBatchItemConfigurationValidator.optional(),
16773
+ idempotencyKey: external_exports.string().max(256).optional()
16774
+ }).refine((data) => data.credential || data.templateUri, {
16775
+ message: "Either credential or templateUri must be provided.",
16776
+ path: ["credential"]
16777
+ }).describe(
16778
+ "One issuance: provide credential or templateUri. Invalid input is rejected at submission with its item index."
16779
+ );
16780
+ var IssueInboxCredentialBatchValidator = external_exports.object({
16781
+ requestId: external_exports.string().min(1).max(256).optional(),
16782
+ items: external_exports.array(IssueInboxCredentialBatchItemValidator).min(1).max(100),
16783
+ configuration: InboxBatchConfigurationValidator.optional()
16784
+ }).superRefine((batch, ctx) => {
16785
+ batch.items.forEach((item, index) => {
16786
+ const itemGuardian = item.configuration?.guardianEmail;
16787
+ const guardian = itemGuardian === null ? void 0 : itemGuardian ?? batch.configuration?.guardianEmail;
16788
+ if (guardian && item.recipient.type === "email" && guardian.toLowerCase() === item.recipient.value.toLowerCase()) {
16789
+ ctx.addIssue({
16790
+ code: "custom",
16791
+ path: ["items", index, "configuration", "guardianEmail"],
16792
+ message: "guardianEmail must differ from recipient (self-approval not allowed)"
16793
+ });
16794
+ }
16795
+ });
16796
+ });
16797
+ var InboxBatchErrorReasonValidator = external_exports.enum([
16798
+ "DUPLICATE_KEY",
16799
+ "IDEMPOTENCY_MISMATCH",
16800
+ "IN_PROGRESS",
16801
+ "UNCONFIRMED"
16802
+ ]);
16803
+ var IssueInboxCredentialBatchItemResultValidator = external_exports.discriminatedUnion("success", [
16804
+ IssueInboxCredentialResponseValidator.extend({
16805
+ success: external_exports.literal(true),
16806
+ index: external_exports.number().int().nonnegative(),
16807
+ deduplicated: external_exports.boolean().optional(),
16808
+ guardianStatus: GuardianStatusValidator.optional(),
16809
+ idempotencyKey: external_exports.string().optional()
16810
+ }),
16811
+ external_exports.object({
16812
+ success: external_exports.literal(false),
16813
+ index: external_exports.number().int().nonnegative(),
16814
+ idempotencyKey: external_exports.string().optional(),
16815
+ recipient: ContactMethodQueryValidator.optional(),
16816
+ error: external_exports.object({
16817
+ code: external_exports.string(),
16818
+ message: external_exports.string(),
16819
+ reason: InboxBatchErrorReasonValidator.optional()
16820
+ }),
16821
+ issuanceId: external_exports.string().optional().describe(
16822
+ "Present when issuance completed but replay storage could not be confirmed. Reconcile this issuance; do not issue again with a new key."
16823
+ ),
16824
+ claimUrl: external_exports.string().url().optional().describe(
16825
+ "Claim URL of the completed issuance, if available, when replay storage could not be confirmed."
16826
+ )
16827
+ })
16828
+ ]);
16829
+ var IssueInboxCredentialBatchResponseValidator = external_exports.object({
16830
+ results: external_exports.array(IssueInboxCredentialBatchItemResultValidator),
16831
+ summary: external_exports.object({
16832
+ total: external_exports.number(),
16833
+ succeeded: external_exports.number(),
16834
+ failed: external_exports.number(),
16835
+ deduplicated: external_exports.number()
16836
+ })
16837
+ });
16838
+ var InboxBatchReceiptValidator = external_exports.object({
16839
+ batchId: external_exports.string(),
16840
+ status: external_exports.enum(["QUEUED", "PROCESSING", "COMPLETED", "NEEDS_RECONCILIATION"]),
16841
+ createdAt: external_exports.string()
16842
+ });
16843
+ var InboxBatchStatusValidator = external_exports.object({
16844
+ batchId: external_exports.string(),
16845
+ createdAt: external_exports.string(),
16846
+ done: external_exports.boolean().describe(
16847
+ "True when no queued or processing items remain, including unconfirmed outcomes."
16848
+ ),
16849
+ status: external_exports.enum(["QUEUED", "PROCESSING", "COMPLETED", "NEEDS_RECONCILIATION"]),
16850
+ items: external_exports.array(
16851
+ external_exports.object({
16852
+ index: external_exports.number().int().nonnegative(),
16853
+ state: external_exports.enum(["QUEUED", "PROCESSING", "COMPLETED", "NEEDS_RECONCILIATION"]),
16854
+ result: IssueInboxCredentialBatchItemResultValidator.optional()
16855
+ })
16856
+ ),
16857
+ summary: IssueInboxCredentialBatchResponseValidator.shape.summary.extend({
16858
+ completed: external_exports.number(),
16859
+ pending: external_exports.number(),
16860
+ unconfirmed: external_exports.number()
16861
+ })
16862
+ });
16863
+ var CredentialNameRefValidator = external_exports.object({ name: external_exports.string() }).passthrough();
16864
+ var ClaimInboxCredentialValidator = external_exports.object({
16865
+ credential: VCValidator.or(VPValidator).or(UnsignedVCValidator).or(CredentialNameRefValidator).describe("The credential to issue, or a { name } reference to resolve a boost template."),
16866
+ configuration: external_exports.object({
16867
+ publishableKey: external_exports.string(),
16868
+ expiresInDays: external_exports.number().int().min(1).max(720).optional().describe(
16869
+ "Inbox claim window in days. Defaults to 720; use a shorter window for sensitive records."
16870
+ ),
16438
16871
  signingAuthorityName: external_exports.string().optional(),
16439
16872
  listingId: external_exports.string().optional(),
16440
16873
  listingSlug: external_exports.string().optional()
@@ -16912,6 +17345,7 @@ var CredentialActivityValidator = external_exports.object({
16912
17345
  eventType: CredentialActivityEventTypeValidator,
16913
17346
  timestamp: external_exports.string(),
16914
17347
  actorProfileId: external_exports.string().optional(),
17348
+ onBehalfOf: external_exports.string().optional(),
16915
17349
  recipientType: CredentialActivityRecipientTypeValidator,
16916
17350
  recipientIdentifier: external_exports.string(),
16917
17351
  boostUri: external_exports.string().optional(),
@@ -17061,195 +17495,12 @@ var inAppMessagesFlagValidator = external_exports.object({
17061
17495
  version: external_exports.number().default(1),
17062
17496
  messages: external_exports.array(inAppMessageValidator).default([])
17063
17497
  }).passthrough();
17064
- var LearnCardRefreshAuthorizationValidator = external_exports.object({ type: external_exports.literal("LearnCardDIDAuth") }).catchall(external_exports.any());
17065
- var ManagedCredentialRefreshServiceValidator = external_exports.object({
17066
- id: external_exports.string().min(1),
17067
- type: external_exports.literal("LearnCardCredentialRefresh2026"),
17068
- authorization: LearnCardRefreshAuthorizationValidator.optional()
17069
- }).catchall(external_exports.any());
17070
- var StandardCredentialRefreshServiceValidator = external_exports.object({
17071
- id: external_exports.string().min(1),
17072
- type: external_exports.literal("1EdTechCredentialRefresh")
17073
- }).catchall(external_exports.any());
17074
- var SupportedCredentialRefreshServiceValidator = external_exports.union([
17075
- ManagedCredentialRefreshServiceValidator,
17076
- StandardCredentialRefreshServiceValidator
17077
- ]);
17078
- var AllocateCredentialRefreshInputValidator = external_exports.object({
17079
- holder: external_exports.object({
17080
- profileId: external_exports.string().optional(),
17081
- did: external_exports.string().min(1)
17082
- }),
17083
- credentialId: external_exports.string().min(1)
17084
- });
17085
- var AllocateCredentialRefreshResultValidator = external_exports.object({
17086
- refreshId: external_exports.string().min(1),
17087
- refreshService: ManagedCredentialRefreshServiceValidator.extend({
17088
- authorization: LearnCardRefreshAuthorizationValidator
17089
- })
17090
- });
17091
- var CredentialRefreshSigningModeValidator = external_exports.enum(["issuer-signed", "signing-authority"]);
17092
- var PublishCredentialRefreshBaseFields = {
17093
- refreshId: external_exports.string().min(1),
17094
- notifyHolder: external_exports.boolean().optional(),
17095
- updateSummary: external_exports.string().optional(),
17096
- idempotencyKey: external_exports.string().optional()
17097
- };
17098
- var PublishIssuerSignedRefreshValidator = external_exports.object({
17099
- ...PublishCredentialRefreshBaseFields,
17100
- mode: external_exports.literal("issuer-signed"),
17101
- signedCredential: VCValidator
17102
- });
17103
- var PublishSigningAuthorityRefreshValidator = external_exports.object({
17104
- ...PublishCredentialRefreshBaseFields,
17105
- mode: external_exports.literal("signing-authority"),
17106
- credential: UnsignedVCValidator,
17107
- signingAuthority: external_exports.object({
17108
- type: external_exports.string().min(1)
17109
- }).catchall(external_exports.any())
17110
- });
17111
- var PublishCredentialRefreshInputValidator = external_exports.object({
17112
- ...PublishCredentialRefreshBaseFields,
17113
- mode: CredentialRefreshSigningModeValidator,
17114
- signedCredential: VCValidator.optional(),
17115
- credential: UnsignedVCValidator.optional(),
17116
- signingAuthority: external_exports.object({
17117
- type: external_exports.string().min(1)
17118
- }).catchall(external_exports.any()).optional()
17119
- }).superRefine((input, ctx) => {
17120
- if (input.mode === "issuer-signed" && !input.signedCredential) {
17121
- ctx.addIssue({
17122
- code: "custom",
17123
- path: ["signedCredential"],
17124
- message: "signedCredential is required for issuer-signed publication"
17125
- });
17126
- }
17127
- if (input.mode === "issuer-signed" && (input.credential !== void 0 || input.signingAuthority !== void 0)) {
17128
- ctx.addIssue({
17129
- code: "custom",
17130
- path: ["mode"],
17131
- message: "issuer-signed publication cannot include signing-authority fields"
17132
- });
17133
- }
17134
- if (input.mode === "signing-authority") {
17135
- if (input.signedCredential !== void 0) {
17136
- ctx.addIssue({
17137
- code: "custom",
17138
- path: ["signedCredential"],
17139
- message: "signing-authority publication cannot include signedCredential"
17140
- });
17141
- }
17142
- if (!input.credential) {
17143
- ctx.addIssue({
17144
- code: "custom",
17145
- path: ["credential"],
17146
- message: "credential is required for signing-authority publication"
17147
- });
17148
- }
17149
- if (!input.signingAuthority) {
17150
- ctx.addIssue({
17151
- code: "custom",
17152
- path: ["signingAuthority"],
17153
- message: "signingAuthority is required for signing-authority publication"
17154
- });
17155
- }
17156
- }
17157
- });
17158
- var PublishCredentialRefreshNotificationValidator = external_exports.enum([
17159
- "queued",
17160
- "suppressed",
17161
- "not-applicable",
17162
- /** Publication succeeded, but the post-commit notification enqueue must be retried. */
17163
- "delivery-failed"
17164
- ]);
17165
- var PublishCredentialRefreshResultValidator = external_exports.object({
17166
- refreshId: external_exports.string().min(1),
17167
- version: external_exports.number().int().positive(),
17168
- publishedAt: external_exports.string().min(1),
17169
- notification: PublishCredentialRefreshNotificationValidator
17170
- });
17171
- var CredentialRefreshVersionMetadataValidator = external_exports.object({
17172
- version: external_exports.number().int().positive(),
17173
- publishedAt: external_exports.string().min(1),
17174
- effectiveAt: external_exports.string().optional(),
17175
- etag: external_exports.string().optional(),
17176
- signingMode: CredentialRefreshSigningModeValidator.optional(),
17177
- updateSummary: external_exports.string().optional()
17178
- });
17179
- var GetCredentialRefreshHistoryInputValidator = external_exports.object({
17180
- refreshId: external_exports.string().min(1),
17181
- cursor: external_exports.string().optional(),
17182
- limit: external_exports.number().int().positive().optional()
17183
- });
17184
- var GetCredentialRefreshHistoryResultValidator = external_exports.object({
17185
- records: CredentialRefreshVersionMetadataValidator.array(),
17186
- hasMore: external_exports.boolean(),
17187
- cursor: external_exports.string().optional()
17188
- });
17189
- var CredentialRefreshChallengeValidator = external_exports.object({
17190
- challenge: external_exports.string().min(1),
17191
- expiresAt: external_exports.string().min(1),
17192
- domain: external_exports.string().optional(),
17193
- scheme: external_exports.literal("LearnCardDIDAuth").optional()
17194
- });
17195
- var PublicCredentialRefreshEnvelopeValidator = external_exports.object({
17196
- format: external_exports.literal("vc"),
17197
- credential: VCValidator,
17198
- etag: external_exports.string().optional()
17199
- });
17200
- var JweCredentialRefreshEnvelopeValidator = external_exports.object({
17201
- format: external_exports.literal("jwe"),
17202
- jwe: JWEValidator,
17203
- etag: external_exports.string().optional(),
17204
- /** Present on LearnCard-managed endpoints; optional for interoperable JWE services. */
17205
- version: external_exports.number().int().positive().optional()
17206
- });
17207
- var CredentialRefreshResponseEnvelopeValidator = external_exports.discriminatedUnion("format", [
17208
- PublicCredentialRefreshEnvelopeValidator,
17209
- JweCredentialRefreshEnvelopeValidator
17210
- ]);
17211
- var CredentialRefreshFailureCodeValidator = external_exports.enum([
17212
- "UNAVAILABLE",
17213
- "TIMEOUT",
17214
- "UNSUPPORTED_SERVICE",
17215
- "UNAUTHORIZED",
17216
- "MALFORMED_RESPONSE",
17217
- "INVALID_PROOF",
17218
- "ISSUER_MISMATCH",
17219
- "ID_MISMATCH",
17220
- "ROLLBACK",
17221
- "REVOKED",
17222
- "UNSAFE_ENDPOINT"
17223
- ]);
17224
- var CredentialRefreshUpdatedResultValidator = external_exports.object({
17225
- status: external_exports.literal("updated"),
17226
- credential: VCValidator,
17227
- etag: external_exports.string().optional(),
17228
- managedVersion: external_exports.number().int().positive().optional()
17229
- });
17230
- var CredentialRefreshUnchangedResultValidator = external_exports.object({
17231
- status: external_exports.literal("unchanged"),
17232
- checkedAt: external_exports.string().min(1),
17233
- etag: external_exports.string().optional()
17234
- });
17235
- var CredentialRefreshUnsupportedResultValidator = external_exports.object({
17236
- status: external_exports.literal("unsupported")
17237
- });
17238
- var CredentialRefreshFailedResultValidator = external_exports.object({
17239
- status: external_exports.literal("failed"),
17240
- code: CredentialRefreshFailureCodeValidator,
17241
- retryable: external_exports.boolean()
17242
- });
17243
- var CredentialRefreshResultValidator = external_exports.discriminatedUnion("status", [
17244
- CredentialRefreshUpdatedResultValidator,
17245
- CredentialRefreshUnchangedResultValidator,
17246
- CredentialRefreshUnsupportedResultValidator,
17247
- CredentialRefreshFailedResultValidator
17248
- ]);
17249
17498
 
17250
17499
  // src/plugin.ts
17251
17500
  import {
17501
+ getCredentialIssuerId,
17252
17502
  getCredentialStatusArray,
17503
+ injectManagedRefreshService as injectSharedManagedRefreshService,
17253
17504
  isVC2Format,
17254
17505
  resolveStorageReadResult
17255
17506
  } from "@learncard/helpers";
@@ -17867,27 +18118,40 @@ var issueCredentialWithNetworkStatus = /* @__PURE__ */ __name(async (learnCard,
17867
18118
  await appendNetworkCredentialStatus(client, credential, statusPurposes)
17868
18119
  );
17869
18120
  }, "issueCredentialWithNetworkStatus");
17870
- var MANAGED_REFRESH_SERVICE_CONTEXT = {
17871
- "LearnCardCredentialRefresh2026": "https://learncard.com/refresh#LearnCardCredentialRefresh2026",
17872
- authorization: {
17873
- "@id": "https://purl.imsglobal.org/spec/ob/v3p0#authorization",
17874
- "@context": {
17875
- LearnCardDIDAuth: "https://docs.learncard.com/definitions#LearnCardDIDAuth"
17876
- }
17877
- }
17878
- };
17879
- var injectManagedRefreshService = /* @__PURE__ */ __name((credential, refreshService) => {
17880
- const existingContext = credential["@context"];
17881
- const contextList = Array.isArray(existingContext) ? existingContext : [existingContext];
17882
- const hasMapping = contextList.some(
17883
- (entry) => !!entry && typeof entry === "object" && "LearnCardCredentialRefresh2026" in entry
17884
- );
18121
+ var injectManagedRefreshService = /* @__PURE__ */ __name((credential, refreshService) => injectSharedManagedRefreshService(credential, refreshService), "injectManagedRefreshService");
18122
+ var getCredentialSubjectIds = /* @__PURE__ */ __name((vc) => {
18123
+ const subject = vc.credentialSubject;
18124
+ const subjects = Array.isArray(subject) ? subject : subject ? [subject] : [];
18125
+ return subjects.flatMap((entry) => {
18126
+ const id = entry?.id;
18127
+ return typeof id === "string" && id.length > 0 ? [id] : [];
18128
+ });
18129
+ }, "getCredentialSubjectIds");
18130
+ var buildManagedRefreshReceipt = /* @__PURE__ */ __name((vc, allocation, credentialId, fallbackHolderDid, fallbackIssuerDid) => {
18131
+ const issuerDid = getCredentialIssuerId(vc) ?? fallbackIssuerDid;
18132
+ const holderDid = getCredentialSubjectIds(vc)[0] ?? fallbackHolderDid;
18133
+ const rawStatus = vc.credentialStatus;
18134
+ const hasStatus = rawStatus !== void 0 && rawStatus !== null && !(Array.isArray(rawStatus) && rawStatus.length === 0);
17885
18135
  return {
17886
- ...credential,
17887
- "@context": hasMapping ? contextList : [...contextList, MANAGED_REFRESH_SERVICE_CONTEXT],
17888
- refreshService
17889
- };
17890
- }, "injectManagedRefreshService");
18136
+ refreshId: allocation.refreshId,
18137
+ refreshService: allocation.refreshService,
18138
+ credentialId: typeof vc.id === "string" && vc.id.length > 0 ? vc.id : credentialId,
18139
+ issuerDid,
18140
+ holderDid,
18141
+ ...hasStatus ? {
18142
+ credentialStatus: rawStatus
18143
+ } : {}
18144
+ };
18145
+ }, "buildManagedRefreshReceipt");
18146
+ var ACT_AS_TARGET_NOT_FOUND_MESSAGE = "Act-as target profile not found";
18147
+ var isActAsDenial = /* @__PURE__ */ __name((error51) => {
18148
+ const code = error51?.data?.code;
18149
+ if (code === "FORBIDDEN" || code === "BAD_REQUEST") return true;
18150
+ if (code === "NOT_FOUND") {
18151
+ return error51?.message === ACT_AS_TARGET_NOT_FOUND_MESSAGE;
18152
+ }
18153
+ return false;
18154
+ }, "isActAsDenial");
17891
18155
  async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, options) {
17892
18156
  const apiToken = typeof apiTokenOrOptions === "string" ? apiTokenOrOptions : void 0;
17893
18157
  const resolvedOptions = (typeof apiTokenOrOptions === "object" ? apiTokenOrOptions : options) ?? {};
@@ -17895,8 +18159,10 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17895
18159
  guardianApprovalGetter,
17896
18160
  extraHeaders,
17897
18161
  trustedFederationHosts,
17898
- allowLocalhostFederation
18162
+ allowLocalhostFederation,
18163
+ actAs
17899
18164
  } = resolvedOptions;
18165
+ const mergedExtraHeaders = actAs ? { ...extraHeaders, [ACT_AS_HEADER]: actAs } : extraHeaders;
17900
18166
  const serviceUrl = new URL(url2);
17901
18167
  const serviceIsLocalhost = isLocalhostHost(serviceUrl.hostname);
17902
18168
  const federationConfig = {
@@ -17914,7 +18180,7 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17914
18180
  learnCard?.debug?.("LCN: no local DID available at init; will fetch from profile");
17915
18181
  }
17916
18182
  learnCard?.debug?.("Adding LearnCardNetwork Plugin");
17917
- const client = apiToken ? await getApiTokenClient(url2, apiToken, guardianApprovalGetter, extraHeaders) : await getClient(
18183
+ const client = apiToken ? await getApiTokenClient(url2, apiToken, guardianApprovalGetter, mergedExtraHeaders) : await getClient(
17918
18184
  url2,
17919
18185
  async (challenge) => {
17920
18186
  const jwt2 = await learnCard.invoke.getDidAuthVp({
@@ -17925,7 +18191,7 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17925
18191
  return jwt2;
17926
18192
  },
17927
18193
  guardianApprovalGetter,
17928
- extraHeaders
18194
+ mergedExtraHeaders
17929
18195
  );
17930
18196
  let userData;
17931
18197
  learnCard?.debug?.("LCN: initial getProfile query starting", { apiToken: !!apiToken });
@@ -18128,6 +18394,23 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18128
18394
  getManagedProfiles: /* @__PURE__ */ __name(async (_learnCard, options2 = {}) => {
18129
18395
  return client.profileManager.getManagedProfiles.query(options2);
18130
18396
  }, "getManagedProfiles"),
18397
+ actAs: /* @__PURE__ */ __name(async (_learnCard, profileId) => {
18398
+ const actingOptions = {
18399
+ ...resolvedOptions,
18400
+ actAs: profileId
18401
+ };
18402
+ const actingPlugin = apiToken ? await getLearnCardNetworkPlugin(_learnCard, url2, apiToken, actingOptions) : await getLearnCardNetworkPlugin(_learnCard, url2, actingOptions);
18403
+ try {
18404
+ await actingPlugin.methods.getLCNClient(_learnCard).profile.getProfile.query();
18405
+ } catch (error51) {
18406
+ if (isActAsDenial(error51)) {
18407
+ const message = error51 instanceof Error ? error51.message : "Act-as request was denied.";
18408
+ throw new Error(message, { cause: error51 });
18409
+ }
18410
+ _learnCard.debug?.("LCN actAs: getProfile failed (non-fatal)", error51);
18411
+ }
18412
+ return _learnCard.addPlugin(actingPlugin);
18413
+ }, "actAs"),
18131
18414
  claimPendingGuardianLinks: /* @__PURE__ */ __name(async () => {
18132
18415
  await ensureUser();
18133
18416
  return client.inbox.claimPendingGuardianLinks.mutate({});
@@ -18737,15 +19020,14 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18737
19020
  boost = options2.overideFn(boost);
18738
19021
  }
18739
19022
  const enableRefresh = typeof options2 === "object" && options2.enableRefresh === true;
18740
- let managedRefreshId;
19023
+ let refreshAllocation;
18741
19024
  if (enableRefresh) {
18742
19025
  if (!boost.id) boost.id = `urn:uuid:${crypto.randomUUID()}`;
18743
- const allocation = await client.credentialRefresh.allocateCredentialRefresh.mutate({
19026
+ refreshAllocation = await client.credentialRefresh.allocateCredentialRefresh.mutate({
18744
19027
  holder: { profileId, did: targetProfile.did },
18745
19028
  credentialId: boost.id
18746
19029
  });
18747
- managedRefreshId = allocation.refreshId;
18748
- boost = injectManagedRefreshService(boost, allocation.refreshService);
19030
+ boost = injectManagedRefreshService(boost, refreshAllocation.refreshService);
18749
19031
  }
18750
19032
  const statusPurposes = typeof options2 === "object" ? options2.statusPurposes : void 0;
18751
19033
  const vc = await issueCredentialWithNetworkStatus(
@@ -18754,13 +19036,23 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18754
19036
  boost,
18755
19037
  statusPurposes
18756
19038
  );
18757
- if (managedRefreshId) {
18758
- return client.credentialRefresh.sendRefreshableCredential.mutate({
18759
- refreshId: managedRefreshId,
19039
+ if (refreshAllocation) {
19040
+ const credentialUri = await client.credentialRefresh.sendRefreshableCredential.mutate({
19041
+ refreshId: refreshAllocation.refreshId,
18760
19042
  credential: vc,
18761
19043
  boostUri,
18762
19044
  ...typeof options2 === "object" && options2.skipNotification ? { skipNotification: true } : {}
18763
19045
  });
19046
+ return {
19047
+ credentialUri,
19048
+ refresh: buildManagedRefreshReceipt(
19049
+ vc,
19050
+ refreshAllocation,
19051
+ boost.id ?? "",
19052
+ targetProfile.did,
19053
+ _learnCard.id.did()
19054
+ )
19055
+ };
18764
19056
  }
18765
19057
  if (typeof options2 === "object" && !options2.encrypt || !options2) {
18766
19058
  return client.boost.sendBoost.mutate({
@@ -18826,6 +19118,94 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18826
19118
  }, "claimBoostWithLink"),
18827
19119
  send: /* @__PURE__ */ __name(async (_learnCard, input) => {
18828
19120
  await ensureUser();
19121
+ if (input.type === "boost" && input.refresh === true) {
19122
+ const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.recipient);
19123
+ const isPhone = /^\+?[\d\s-]{10,}$/.test(input.recipient.replace(/[\s-]/g, ""));
19124
+ if (isEmail || isPhone) return client.boost.send.mutate(input);
19125
+ const canIssueLocally = "issueCredential" in _learnCard.invoke;
19126
+ if (canIssueLocally && !input.signedCredential && (input.templateUri || input.template)) {
19127
+ let boost;
19128
+ if (input.templateUri) {
19129
+ const result = await getBoostTemplateForIssuance(
19130
+ _learnCard,
19131
+ input.templateUri
19132
+ );
19133
+ const data = await UnsignedVCValidator.spa(result);
19134
+ if (!data.success)
19135
+ throw new Error("Did not get a valid boost from URI");
19136
+ boost = data.data;
19137
+ } else {
19138
+ boost = JSON.parse(
19139
+ JSON.stringify(input.template.credential)
19140
+ );
19141
+ }
19142
+ const prepared = await client.boost.prepareRefreshableSend.mutate({
19143
+ recipient: input.recipient,
19144
+ ...input.templateUri ? { templateUri: input.templateUri } : { template: input.template },
19145
+ ...input.contractUri ? { contractUri: input.contractUri } : {},
19146
+ ...input.templateData ? { templateData: input.templateData } : {},
19147
+ ...input.integrationId ? { integrationId: input.integrationId } : {},
19148
+ ...boost.id ? { credentialId: boost.id } : {},
19149
+ ...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
19150
+ });
19151
+ if (prepared.completed) return prepared.completed;
19152
+ const boostString = JSON.stringify(boost);
19153
+ const allowAutoAppendEvidence = !hasDynamicEvidenceTemplate(boostString);
19154
+ if (input.templateData && Object.keys(input.templateData).length > 0) {
19155
+ try {
19156
+ const rendered = renderTemplateJson(
19157
+ boostString,
19158
+ input.templateData
19159
+ );
19160
+ boost = JSON.parse(rendered);
19161
+ boost = appendTemplateEvidence(
19162
+ boost,
19163
+ input.templateData,
19164
+ allowAutoAppendEvidence
19165
+ );
19166
+ } catch (error51) {
19167
+ throw new Error(
19168
+ `Failed to apply template data: ${error51 instanceof Error ? error51.message : "Unknown error"}`,
19169
+ { cause: error51 }
19170
+ );
19171
+ }
19172
+ }
19173
+ if (isVC2Format(boost)) {
19174
+ boost.validFrom = (/* @__PURE__ */ new Date()).toISOString();
19175
+ } else {
19176
+ boost.issuanceDate = (/* @__PURE__ */ new Date()).toISOString();
19177
+ }
19178
+ boost.issuer = _learnCard.id.did();
19179
+ if (Array.isArray(boost.credentialSubject)) {
19180
+ boost.credentialSubject = boost.credentialSubject.map((subject) => ({
19181
+ ...subject,
19182
+ id: prepared.holderDid
19183
+ }));
19184
+ } else {
19185
+ boost.credentialSubject = {
19186
+ ...boost.credentialSubject,
19187
+ id: prepared.holderDid
19188
+ };
19189
+ }
19190
+ boost.id = prepared.credentialId;
19191
+ if (boost.type?.includes("BoostCredential"))
19192
+ boost.boostId = prepared.boostUri;
19193
+ boost = injectManagedRefreshService(boost, prepared.refreshService);
19194
+ const signedCredential = await issueCredentialWithNetworkStatus(
19195
+ _learnCard,
19196
+ client,
19197
+ boost
19198
+ );
19199
+ return client.boost.send.mutate({
19200
+ ...input,
19201
+ template: void 0,
19202
+ templateUri: prepared.boostUri,
19203
+ signedCredential,
19204
+ refresh: true
19205
+ });
19206
+ }
19207
+ return client.boost.send.mutate(input);
19208
+ }
18829
19209
  if (input.type === "boost") {
18830
19210
  const recipient = input.recipient;
18831
19211
  const isDid = recipient.startsWith("did:");
@@ -19232,6 +19612,37 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
19232
19612
  await ensureUser();
19233
19613
  return client.inbox.issue.mutate(issueInboxCredential);
19234
19614
  }, "sendCredentialViaInbox"),
19615
+ sendCredentialsViaInbox: /* @__PURE__ */ __name(async (_learnCard, batch) => {
19616
+ await ensureUser();
19617
+ return client.inbox.issueBatch.mutate(batch);
19618
+ }, "sendCredentialsViaInbox"),
19619
+ sendCredentialBatchViaInbox: /* @__PURE__ */ __name(async (_learnCard, batch) => {
19620
+ await ensureUser();
19621
+ return client.inbox.issueBatch.mutate(batch);
19622
+ }, "sendCredentialBatchViaInbox"),
19623
+ waitForInboxCredentialBatch: /* @__PURE__ */ __name(async (_learnCard, batchId, options2) => {
19624
+ await ensureUser();
19625
+ return waitForInboxCredentialBatch(
19626
+ (signal) => client.inbox.getBatch.query({ batchId }, { signal }),
19627
+ options2
19628
+ );
19629
+ }, "waitForInboxCredentialBatch"),
19630
+ sendCredentialsViaInboxAndWait: /* @__PURE__ */ __name(async (_learnCard, batch, options2) => {
19631
+ await ensureUser();
19632
+ if (options2?.signal?.aborted) throw options2.signal.reason;
19633
+ const receipt = await client.inbox.issueBatch.mutate(batch, {
19634
+ signal: options2?.signal
19635
+ });
19636
+ await options2?.onSubmitted?.(receipt);
19637
+ return waitForInboxCredentialBatch(
19638
+ (signal) => client.inbox.getBatch.query({ batchId: receipt.batchId }, { signal }),
19639
+ options2
19640
+ );
19641
+ }, "sendCredentialsViaInboxAndWait"),
19642
+ getInboxCredentialBatch: /* @__PURE__ */ __name(async (_learnCard, batchId) => {
19643
+ await ensureUser();
19644
+ return client.inbox.getBatch.query({ batchId });
19645
+ }, "getInboxCredentialBatch"),
19235
19646
  getMySentInboxCredentials: /* @__PURE__ */ __name(async (_learnCard, options2) => {
19236
19647
  await ensureUser();
19237
19648
  return client.inbox.getMyIssuedCredentials.query(options2);
@@ -19694,6 +20105,13 @@ var getVerifyBoostPlugin = /* @__PURE__ */ __name(async (learnCard, trustedBoost
19694
20105
  if (!issuerDID) return;
19695
20106
  return boostRegistry.find((o) => o.did === issuerDID);
19696
20107
  }, "getTrustedBoostVerifier");
20108
+ const getTrustedBoostNetwork = /* @__PURE__ */ __name((boostId) => {
20109
+ if (typeof boostId !== "string") return;
20110
+ const match = /^lc:network:([^?#\s]+)\/(?:trpc:)?boost:([^/?#\s]+)$/.exec(boostId);
20111
+ if (!match) return;
20112
+ const networkDid = `did:web:${match[1].replace(/\//g, ":")}`;
20113
+ return boostRegistry.find((entry) => entry.did === networkDid);
20114
+ }, "getTrustedBoostNetwork");
19697
20115
  return {
19698
20116
  name: "VerifyBoost",
19699
20117
  displayName: "Verify Boost Extension",
@@ -19704,18 +20122,20 @@ var getVerifyBoostPlugin = /* @__PURE__ */ __name(async (learnCard, trustedBoost
19704
20122
  credential,
19705
20123
  options
19706
20124
  );
20125
+ const hasOuterVerificationErrors = Boolean(verificationCheck.errors?.length);
19707
20126
  const boostCredential = credential?.boostCredential;
19708
20127
  try {
19709
- if (boostCredential) {
19710
- const verifyBoostCredential = await learnCard.invoke.verifyCredential(boostCredential);
19711
- const boostCredentialErrors = verifyBoostCredential.errors ?? [];
19712
- if (verifyBoostCredential.status?.length) {
20128
+ const boostId = boostCredential?.boostId ?? credential?.boostId;
20129
+ if (boostCredential || credential?.boostId || credential?.type?.includes("BoostCredential")) {
20130
+ const verifyBoostCredential = boostCredential ? await learnCard.invoke.verifyCredential(boostCredential) : verificationCheck;
20131
+ const boostCredentialErrors = boostCredential ? verifyBoostCredential.errors ?? [] : [];
20132
+ if (boostCredential && verifyBoostCredential.status?.length) {
19713
20133
  verificationCheck.status = [
19714
20134
  ...verificationCheck.status ?? [],
19715
20135
  ...verifyBoostCredential.status
19716
20136
  ];
19717
20137
  }
19718
- if (!boostCredential?.boostId && !credential?.boostId) {
20138
+ if (!boostId) {
19719
20139
  verificationCheck.warnings.push(
19720
20140
  "Boost Authenticity could not be verified: Boost ID metadata is missing."
19721
20141
  );
@@ -19733,21 +20153,26 @@ var getVerifyBoostPlugin = /* @__PURE__ */ __name(async (learnCard, trustedBoost
19733
20153
  ...verificationCheck.errors || [],
19734
20154
  "Boost Credential could not be verified."
19735
20155
  ];
19736
- } else if (boostCredential?.boostId !== credential?.boostId) {
20156
+ } else if (hasOuterVerificationErrors) {
20157
+ verificationCheck.warnings.push(
20158
+ "Boost Authenticity could not be verified: Credential verification failed."
20159
+ );
20160
+ } else if (!boostId) {
20161
+ } else if (boostCredential && boostCredential.boostId !== credential.boostId) {
19737
20162
  verificationCheck.errors.push(
19738
20163
  "Boost Authenticity could not be verified: Boost ID metadata is mismatched."
19739
20164
  );
19740
20165
  } else {
19741
- const trustedBoostIssuer = getTrustedBoostVerifier(credential?.issuer);
20166
+ const trustedBoostIssuer = boostCredential ? getTrustedBoostVerifier(credential?.issuer) : getTrustedBoostNetwork(boostId);
19742
20167
  if (trustedBoostIssuer) {
19743
20168
  verificationCheck.checks.push(
19744
20169
  `Boost is Authentic. Verified by ${trustedBoostIssuer.id}.`
19745
20170
  );
19746
20171
  } else {
19747
20172
  verificationCheck.warnings.push(
19748
- `Boost Authenticity could not be verified. Issuer is outside of trust network: ${getIssuerDID(
20173
+ boostCredential ? `Boost Authenticity could not be verified. Issuer is outside of trust network: ${getIssuerDID(
19749
20174
  credential?.issuer
19750
- )}`
20175
+ )}` : `Boost Authenticity could not be verified. Boost ID does not identify a trusted network: ${boostId}`
19751
20176
  );
19752
20177
  }
19753
20178
  }
@@ -19761,6 +20186,7 @@ var getVerifyBoostPlugin = /* @__PURE__ */ __name(async (learnCard, trustedBoost
19761
20186
  };
19762
20187
  }, "getVerifyBoostPlugin");
19763
20188
  export {
20189
+ ACT_AS_HEADER,
19764
20190
  getLearnCardNetworkPlugin,
19765
20191
  getVerifyBoostPlugin
19766
20192
  };