@learncard/network-plugin 2.14.1 → 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.
@@ -21,11 +21,59 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  // src/index.ts
22
22
  var index_exports = {};
23
23
  __export(index_exports, {
24
+ ACT_AS_HEADER: () => ACT_AS_HEADER,
24
25
  getLearnCardNetworkPlugin: () => getLearnCardNetworkPlugin,
25
26
  getVerifyBoostPlugin: () => getVerifyBoostPlugin
26
27
  });
27
28
  module.exports = __toCommonJS(index_exports);
28
29
 
30
+ // src/inbox-batch.ts
31
+ var waitForInboxCredentialBatch = /* @__PURE__ */ __name(async (read, options = {}) => {
32
+ const { timeoutMs = 6e5, intervalMs = 2e3, signal, onProgress } = options;
33
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > 2147483647 || !Number.isFinite(intervalMs) || intervalMs <= 0 || intervalMs > 2147483647) {
34
+ throw new RangeError("timeoutMs and intervalMs must be positive finite timer durations.");
35
+ }
36
+ const controller = new AbortController();
37
+ const abort = /* @__PURE__ */ __name(() => controller.abort(signal?.reason), "abort");
38
+ signal?.addEventListener("abort", abort, { once: true });
39
+ if (signal?.aborted) abort();
40
+ const timeout = setTimeout(() => {
41
+ const error51 = new Error(
42
+ "Timed out waiting for inbox batch. Keep the batch ID to check again."
43
+ );
44
+ error51.name = "TimeoutError";
45
+ controller.abort(error51);
46
+ }, timeoutMs);
47
+ const cancellable = /* @__PURE__ */ __name((operation) => new Promise((resolve, reject) => {
48
+ const interrupted = /* @__PURE__ */ __name(() => reject(controller.signal.reason), "interrupted");
49
+ if (controller.signal.aborted) return interrupted();
50
+ controller.signal.addEventListener("abort", interrupted, { once: true });
51
+ Promise.resolve().then(() => {
52
+ if (controller.signal.aborted) throw controller.signal.reason;
53
+ return operation();
54
+ }).then(resolve, reject).finally(() => controller.signal.removeEventListener("abort", interrupted));
55
+ }), "cancellable");
56
+ let delay = intervalMs;
57
+ let sleepTimer;
58
+ try {
59
+ while (true) {
60
+ const batch = await cancellable(() => read(controller.signal));
61
+ onProgress?.(batch);
62
+ if (batch.done) return batch;
63
+ await cancellable(
64
+ () => new Promise((resolve) => {
65
+ sleepTimer = setTimeout(resolve, delay);
66
+ })
67
+ );
68
+ delay = Math.min(delay * 1.5, Math.max(intervalMs, 1e4));
69
+ }
70
+ } finally {
71
+ clearTimeout(timeout);
72
+ clearTimeout(sleepTimer);
73
+ signal?.removeEventListener("abort", abort);
74
+ }
75
+ }, "waitForInboxCredentialBatch");
76
+
29
77
  // src/plugin.ts
30
78
  var import_network_brain_client = require("@learncard/network-brain-client");
31
79
 
@@ -15583,6 +15631,204 @@ var StringQuery = external_exports.union([
15583
15631
  $or: BaseStringQuery.array()
15584
15632
  })
15585
15633
  ]);
15634
+ var LearnCardRefreshAuthorizationValidator = external_exports.object({ type: external_exports.literal("LearnCardDIDAuth") }).catchall(external_exports.any());
15635
+ var ManagedCredentialRefreshServiceValidator = external_exports.object({
15636
+ id: external_exports.string().min(1),
15637
+ type: external_exports.literal("LearnCardCredentialRefresh2026"),
15638
+ authorization: LearnCardRefreshAuthorizationValidator.optional()
15639
+ }).catchall(external_exports.any());
15640
+ var StandardCredentialRefreshServiceValidator = external_exports.object({
15641
+ id: external_exports.string().min(1),
15642
+ type: external_exports.literal("1EdTechCredentialRefresh")
15643
+ }).catchall(external_exports.any());
15644
+ var SupportedCredentialRefreshServiceValidator = external_exports.union([
15645
+ ManagedCredentialRefreshServiceValidator,
15646
+ StandardCredentialRefreshServiceValidator
15647
+ ]);
15648
+ var AllocateCredentialRefreshInputValidator = external_exports.object({
15649
+ holder: external_exports.object({
15650
+ profileId: external_exports.string().optional(),
15651
+ did: external_exports.string().min(1)
15652
+ }),
15653
+ credentialId: external_exports.string().min(1)
15654
+ });
15655
+ var AllocateCredentialRefreshResultValidator = external_exports.object({
15656
+ refreshId: external_exports.string().min(1),
15657
+ refreshService: ManagedCredentialRefreshServiceValidator.extend({
15658
+ authorization: LearnCardRefreshAuthorizationValidator
15659
+ })
15660
+ });
15661
+ var ManagedCredentialRefreshReceiptValidator = external_exports.object({
15662
+ refreshId: external_exports.string().min(1),
15663
+ refreshService: ManagedCredentialRefreshServiceValidator,
15664
+ credentialId: external_exports.string().min(1),
15665
+ issuerDid: external_exports.string().min(1),
15666
+ holderDid: external_exports.string().min(1),
15667
+ credentialStatus: CredentialStatusValidator.or(
15668
+ CredentialStatusValidator.array()
15669
+ ).optional()
15670
+ }).strip();
15671
+ var InboxCredentialRefreshReceiptValidator = ManagedCredentialRefreshReceiptValidator.omit(
15672
+ { holderDid: true }
15673
+ ).extend({ holderDid: external_exports.string().min(1).optional() });
15674
+ var CredentialRefreshSigningModeValidator = external_exports.enum(["issuer-signed", "signing-authority"]);
15675
+ var PublishCredentialRefreshBaseFields = {
15676
+ refreshId: external_exports.string().min(1),
15677
+ notifyHolder: external_exports.boolean().optional(),
15678
+ updateSummary: external_exports.string().optional(),
15679
+ idempotencyKey: external_exports.string().optional()
15680
+ };
15681
+ var PublishIssuerSignedRefreshValidator = external_exports.object({
15682
+ ...PublishCredentialRefreshBaseFields,
15683
+ mode: external_exports.literal("issuer-signed"),
15684
+ signedCredential: VCValidator
15685
+ });
15686
+ var PublishSigningAuthorityRefreshValidator = external_exports.object({
15687
+ ...PublishCredentialRefreshBaseFields,
15688
+ mode: external_exports.literal("signing-authority"),
15689
+ credential: UnsignedVCValidator,
15690
+ signingAuthority: external_exports.object({
15691
+ type: external_exports.string().min(1)
15692
+ }).catchall(external_exports.any())
15693
+ });
15694
+ var PublishCredentialRefreshInputValidator = external_exports.object({
15695
+ ...PublishCredentialRefreshBaseFields,
15696
+ mode: CredentialRefreshSigningModeValidator,
15697
+ signedCredential: VCValidator.optional(),
15698
+ credential: UnsignedVCValidator.optional(),
15699
+ signingAuthority: external_exports.object({
15700
+ type: external_exports.string().min(1)
15701
+ }).catchall(external_exports.any()).optional()
15702
+ }).superRefine((input, ctx) => {
15703
+ if (input.mode === "issuer-signed" && !input.signedCredential) {
15704
+ ctx.addIssue({
15705
+ code: "custom",
15706
+ path: ["signedCredential"],
15707
+ message: "signedCredential is required for issuer-signed publication"
15708
+ });
15709
+ }
15710
+ if (input.mode === "issuer-signed" && (input.credential !== void 0 || input.signingAuthority !== void 0)) {
15711
+ ctx.addIssue({
15712
+ code: "custom",
15713
+ path: ["mode"],
15714
+ message: "issuer-signed publication cannot include signing-authority fields"
15715
+ });
15716
+ }
15717
+ if (input.mode === "signing-authority") {
15718
+ if (input.signedCredential !== void 0) {
15719
+ ctx.addIssue({
15720
+ code: "custom",
15721
+ path: ["signedCredential"],
15722
+ message: "signing-authority publication cannot include signedCredential"
15723
+ });
15724
+ }
15725
+ if (!input.credential) {
15726
+ ctx.addIssue({
15727
+ code: "custom",
15728
+ path: ["credential"],
15729
+ message: "credential is required for signing-authority publication"
15730
+ });
15731
+ }
15732
+ if (!input.signingAuthority) {
15733
+ ctx.addIssue({
15734
+ code: "custom",
15735
+ path: ["signingAuthority"],
15736
+ message: "signingAuthority is required for signing-authority publication"
15737
+ });
15738
+ }
15739
+ }
15740
+ });
15741
+ var PublishCredentialRefreshNotificationValidator = external_exports.enum([
15742
+ "queued",
15743
+ "suppressed",
15744
+ "not-applicable",
15745
+ /** Publication succeeded, but the post-commit notification enqueue must be retried. */
15746
+ "delivery-failed"
15747
+ ]);
15748
+ var PublishCredentialRefreshResultValidator = external_exports.object({
15749
+ refreshId: external_exports.string().min(1),
15750
+ version: external_exports.number().int().positive(),
15751
+ publishedAt: external_exports.string().min(1),
15752
+ notification: PublishCredentialRefreshNotificationValidator
15753
+ });
15754
+ var CredentialRefreshVersionMetadataValidator = external_exports.object({
15755
+ version: external_exports.number().int().positive(),
15756
+ publishedAt: external_exports.string().min(1),
15757
+ effectiveAt: external_exports.string().optional(),
15758
+ etag: external_exports.string().optional(),
15759
+ signingMode: CredentialRefreshSigningModeValidator.optional(),
15760
+ updateSummary: external_exports.string().optional()
15761
+ });
15762
+ var GetCredentialRefreshHistoryInputValidator = external_exports.object({
15763
+ refreshId: external_exports.string().min(1),
15764
+ cursor: external_exports.string().optional(),
15765
+ limit: external_exports.number().int().positive().optional()
15766
+ });
15767
+ var GetCredentialRefreshHistoryResultValidator = external_exports.object({
15768
+ records: CredentialRefreshVersionMetadataValidator.array(),
15769
+ hasMore: external_exports.boolean(),
15770
+ cursor: external_exports.string().optional()
15771
+ });
15772
+ var CredentialRefreshChallengeValidator = external_exports.object({
15773
+ challenge: external_exports.string().min(1),
15774
+ expiresAt: external_exports.string().min(1),
15775
+ domain: external_exports.string().optional(),
15776
+ scheme: external_exports.literal("LearnCardDIDAuth").optional()
15777
+ });
15778
+ var PublicCredentialRefreshEnvelopeValidator = external_exports.object({
15779
+ format: external_exports.literal("vc"),
15780
+ credential: VCValidator,
15781
+ etag: external_exports.string().optional()
15782
+ });
15783
+ var JweCredentialRefreshEnvelopeValidator = external_exports.object({
15784
+ format: external_exports.literal("jwe"),
15785
+ jwe: JWEValidator,
15786
+ etag: external_exports.string().optional(),
15787
+ /** Present on LearnCard-managed endpoints; optional for interoperable JWE services. */
15788
+ version: external_exports.number().int().positive().optional()
15789
+ });
15790
+ var CredentialRefreshResponseEnvelopeValidator = external_exports.discriminatedUnion("format", [
15791
+ PublicCredentialRefreshEnvelopeValidator,
15792
+ JweCredentialRefreshEnvelopeValidator
15793
+ ]);
15794
+ var CredentialRefreshFailureCodeValidator = external_exports.enum([
15795
+ "UNAVAILABLE",
15796
+ "TIMEOUT",
15797
+ "UNSUPPORTED_SERVICE",
15798
+ "UNAUTHORIZED",
15799
+ "MALFORMED_RESPONSE",
15800
+ "INVALID_PROOF",
15801
+ "ISSUER_MISMATCH",
15802
+ "ID_MISMATCH",
15803
+ "ROLLBACK",
15804
+ "REVOKED",
15805
+ "UNSAFE_ENDPOINT"
15806
+ ]);
15807
+ var CredentialRefreshUpdatedResultValidator = external_exports.object({
15808
+ status: external_exports.literal("updated"),
15809
+ credential: VCValidator,
15810
+ etag: external_exports.string().optional(),
15811
+ managedVersion: external_exports.number().int().positive().optional()
15812
+ });
15813
+ var CredentialRefreshUnchangedResultValidator = external_exports.object({
15814
+ status: external_exports.literal("unchanged"),
15815
+ checkedAt: external_exports.string().min(1),
15816
+ etag: external_exports.string().optional()
15817
+ });
15818
+ var CredentialRefreshUnsupportedResultValidator = external_exports.object({
15819
+ status: external_exports.literal("unsupported")
15820
+ });
15821
+ var CredentialRefreshFailedResultValidator = external_exports.object({
15822
+ status: external_exports.literal("failed"),
15823
+ code: CredentialRefreshFailureCodeValidator,
15824
+ retryable: external_exports.boolean()
15825
+ });
15826
+ var CredentialRefreshResultValidator = external_exports.discriminatedUnion("status", [
15827
+ CredentialRefreshUpdatedResultValidator,
15828
+ CredentialRefreshUnchangedResultValidator,
15829
+ CredentialRefreshUnsupportedResultValidator,
15830
+ CredentialRefreshFailedResultValidator
15831
+ ]);
15586
15832
  var LCNProfileDisplayValidator = external_exports.object({
15587
15833
  backgroundColor: external_exports.string().optional(),
15588
15834
  backgroundImage: external_exports.string().optional(),
@@ -15918,7 +16164,13 @@ var SendBoostInputValidator = external_exports.object({
15918
16164
  "Options for email/phone recipients (Universal Inbox)"
15919
16165
  ),
15920
16166
  templateData: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
15921
- integrationId: external_exports.string().optional().describe("Integration ID for activity tracking")
16167
+ integrationId: external_exports.string().optional().describe("Integration ID for activity tracking"),
16168
+ refresh: external_exports.boolean().optional().describe(
16169
+ "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."
16170
+ ),
16171
+ idempotencyKey: external_exports.string().min(1).max(200).optional().describe(
16172
+ "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."
16173
+ )
15922
16174
  }).refine((data) => data.templateUri || data.template || data.signedCredential, {
15923
16175
  message: "Either templateUri, template, or signedCredential must be provided.",
15924
16176
  path: ["templateUri"]
@@ -15933,8 +16185,12 @@ var SendBoostInputValidator = external_exports.object({
15933
16185
  message: "guardianEmail must differ from recipient (self-approval not allowed)",
15934
16186
  path: ["options", "guardianEmail"]
15935
16187
  }
15936
- );
16188
+ ).refine((data) => !data.idempotencyKey || data.refresh === true, {
16189
+ message: "idempotencyKey is only supported with refresh: true.",
16190
+ path: ["idempotencyKey"]
16191
+ });
15937
16192
  var SendInboxResponseValidator = external_exports.object({
16193
+ refresh: InboxCredentialRefreshReceiptValidator.optional(),
15938
16194
  issuanceId: external_exports.string(),
15939
16195
  status: external_exports.enum(["PENDING", "ISSUED", "EXPIRED", "DELIVERED", "CLAIMED"]),
15940
16196
  claimUrl: external_exports.string().url().optional().describe("Present when suppressDelivery=true"),
@@ -15949,8 +16205,34 @@ var SendBoostResponseValidator = external_exports.object({
15949
16205
  activityId: external_exports.string().describe("Links to the activity lifecycle for this issuance"),
15950
16206
  inbox: SendInboxResponseValidator.optional().describe(
15951
16207
  "Present when sent via email/phone (Universal Inbox)"
16208
+ ),
16209
+ refresh: ManagedCredentialRefreshReceiptValidator.optional().describe(
16210
+ "Present when managed refresh was requested: issuance metadata the issuer keeps to publish future updates"
15952
16211
  )
15953
16212
  });
16213
+ var PrepareRefreshableSendInputValidator = external_exports.object({
16214
+ recipient: external_exports.string(),
16215
+ templateUri: external_exports.string().optional(),
16216
+ template: SendBoostTemplateValidator.optional(),
16217
+ contractUri: external_exports.string().optional(),
16218
+ templateData: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
16219
+ integrationId: external_exports.string().optional(),
16220
+ /** Credential ID to allocate for; generated server-side when omitted. */
16221
+ credentialId: external_exports.string().min(1).optional(),
16222
+ idempotencyKey: external_exports.string().min(1).max(200).optional()
16223
+ }).refine((data) => Boolean(data.templateUri) !== Boolean(data.template), {
16224
+ message: "Provide exactly one of templateUri or template."
16225
+ });
16226
+ var PrepareRefreshableSendResultValidator = external_exports.object({
16227
+ boostUri: external_exports.string(),
16228
+ credentialId: external_exports.string(),
16229
+ refreshId: external_exports.string(),
16230
+ refreshService: ManagedCredentialRefreshServiceValidator,
16231
+ /** The DID to use as credentialSubject.id (recipient DID, or the profile's did:web). */
16232
+ holderDid: external_exports.string(),
16233
+ /** Present when this idempotencyKey already completed: return it without signing. */
16234
+ completed: SendBoostResponseValidator.optional()
16235
+ });
15954
16236
  var SendInputValidator = external_exports.discriminatedUnion("type", [SendBoostInputValidator]);
15955
16237
  var SendResponseValidator = external_exports.discriminatedUnion("type", [SendBoostResponseValidator]);
15956
16238
  var ConsentFlowTermsStatusValidator = external_exports.enum(["live", "stale", "withdrawn"]);
@@ -16269,6 +16551,7 @@ var LCNNotificationValidator = external_exports.object({
16269
16551
  webhookUrl: external_exports.string().optional()
16270
16552
  });
16271
16553
  var AUTH_GRANT_AUDIENCE_DOMAIN_PREFIX = "auth-grant:";
16554
+ var ACT_AS_HEADER = "X-LearnCard-Act-As";
16272
16555
  var AuthGrantValidator = external_exports.object({
16273
16556
  id: external_exports.string(),
16274
16557
  name: external_exports.string(),
@@ -16281,6 +16564,7 @@ var AuthGrantValidator = external_exports.object({
16281
16564
  }, "error")
16282
16565
  }),
16283
16566
  scope: external_exports.string(),
16567
+ actAs: external_exports.string().optional(),
16284
16568
  createdAt: external_exports.iso.datetime({ error: "createdAt must be a valid ISO 8601 datetime string" }),
16285
16569
  expiresAt: external_exports.iso.datetime({ error: "expiresAt must be a valid ISO 8601 datetime string" }).nullish().optional()
16286
16570
  });
@@ -16352,6 +16636,8 @@ var CreateContactMethodSessionResponseValidator = external_exports.object({
16352
16636
  sessionJwt: external_exports.string()
16353
16637
  });
16354
16638
  var InboxCredentialValidator = external_exports.object({
16639
+ refresh: InboxCredentialRefreshReceiptValidator.optional(),
16640
+ refreshId: external_exports.string().optional(),
16355
16641
  id: external_exports.string(),
16356
16642
  credential: external_exports.string().optional(),
16357
16643
  isSigned: external_exports.boolean(),
@@ -16406,12 +16692,19 @@ var IssueInboxCredentialValidator = external_exports.object({
16406
16692
  templateUri: external_exports.string().optional().describe(
16407
16693
  "URI of a boost template to use for issuance. The boost credential will be resolved and used. Mutually exclusive with credential field."
16408
16694
  ),
16695
+ refresh: external_exports.boolean().optional().describe(
16696
+ "Allocate managed refresh before signing. Requires unsigned content and a registered signing authority; binds the holder on claim."
16697
+ ),
16698
+ idempotencyKey: external_exports.string().min(1).max(200).optional(),
16409
16699
  // === OPTIONAL FEATURES ===
16410
16700
  // Add major, distinct features at the top level.
16411
16701
  //consentRequest: ConsentRequestValidator.optional(),
16412
16702
  // === PROCESS CONFIGURATION (Optional) ===
16413
16703
  // HOW should this issuance be handled?
16414
16704
  configuration: external_exports.object({
16705
+ guardianEmail: external_exports.string().email().optional().describe(
16706
+ "Require approval from this guardian before the recipient can claim. Must differ from the recipient email."
16707
+ ),
16415
16708
  signingAuthority: IssueInboxSigningAuthorityValidator.optional().describe(
16416
16709
  "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."
16417
16710
  ),
@@ -16465,17 +16758,130 @@ var IssueInboxCredentialValidator = external_exports.object({
16465
16758
  }).optional().describe(
16466
16759
  "Configuration for the credential issuance. If not provided, the default configuration will be used."
16467
16760
  )
16761
+ }).refine((data) => !data.idempotencyKey || data.refresh === true, {
16762
+ message: "idempotencyKey requires refresh: true."
16468
16763
  }).refine((data) => data.credential || data.templateUri, {
16469
16764
  message: "Either credential or templateUri must be provided.",
16470
16765
  path: ["credential"]
16471
- });
16766
+ }).refine(
16767
+ (data) => !data.configuration?.guardianEmail || data.recipient.type !== "email" || data.configuration.guardianEmail.toLowerCase() !== data.recipient.value.toLowerCase(),
16768
+ {
16769
+ message: "guardianEmail must differ from recipient (self-approval not allowed)",
16770
+ path: ["configuration", "guardianEmail"]
16771
+ }
16772
+ );
16472
16773
  var IssueInboxCredentialResponseValidator = external_exports.object({
16774
+ refresh: InboxCredentialRefreshReceiptValidator.optional(),
16473
16775
  issuanceId: external_exports.string(),
16474
16776
  status: LCNInboxStatusEnumValidator,
16475
16777
  recipient: ContactMethodQueryValidator,
16476
16778
  claimUrl: external_exports.string().url().optional(),
16477
16779
  recipientDid: external_exports.string().optional()
16478
16780
  });
16781
+ var InboxBatchConfigurationValidator = IssueInboxCredentialValidator.shape.configuration.unwrap().extend({
16782
+ refresh: IssueInboxCredentialValidator.shape.refresh.describe(
16783
+ "Enable managed refresh by default. An item configuration.refresh overrides this value, including false."
16784
+ ),
16785
+ delivery: IssueInboxCredentialValidator.shape.configuration.unwrap().shape.delivery.unwrap().extend({ suppress: external_exports.boolean().optional() }).optional()
16786
+ });
16787
+ var InboxBatchItemConfigurationValidator = InboxBatchConfigurationValidator.extend({
16788
+ guardianEmail: InboxBatchConfigurationValidator.shape.guardianEmail.nullable().describe(
16789
+ "Require guardian approval, or set null to clear a batch-level guardianEmail for this item."
16790
+ )
16791
+ });
16792
+ var IssueInboxCredentialBatchItemValidator = external_exports.object({
16793
+ ...IssueInboxCredentialValidator.shape,
16794
+ configuration: InboxBatchItemConfigurationValidator.optional(),
16795
+ idempotencyKey: external_exports.string().max(256).optional()
16796
+ }).refine((data) => data.credential || data.templateUri, {
16797
+ message: "Either credential or templateUri must be provided.",
16798
+ path: ["credential"]
16799
+ }).describe(
16800
+ "One issuance: provide credential or templateUri. Invalid input is rejected at submission with its item index."
16801
+ );
16802
+ var IssueInboxCredentialBatchValidator = external_exports.object({
16803
+ requestId: external_exports.string().min(1).max(256).optional(),
16804
+ items: external_exports.array(IssueInboxCredentialBatchItemValidator).min(1).max(100),
16805
+ configuration: InboxBatchConfigurationValidator.optional()
16806
+ }).superRefine((batch, ctx) => {
16807
+ batch.items.forEach((item, index) => {
16808
+ const itemGuardian = item.configuration?.guardianEmail;
16809
+ const guardian = itemGuardian === null ? void 0 : itemGuardian ?? batch.configuration?.guardianEmail;
16810
+ if (guardian && item.recipient.type === "email" && guardian.toLowerCase() === item.recipient.value.toLowerCase()) {
16811
+ ctx.addIssue({
16812
+ code: "custom",
16813
+ path: ["items", index, "configuration", "guardianEmail"],
16814
+ message: "guardianEmail must differ from recipient (self-approval not allowed)"
16815
+ });
16816
+ }
16817
+ });
16818
+ });
16819
+ var InboxBatchErrorReasonValidator = external_exports.enum([
16820
+ "DUPLICATE_KEY",
16821
+ "IDEMPOTENCY_MISMATCH",
16822
+ "IN_PROGRESS",
16823
+ "UNCONFIRMED"
16824
+ ]);
16825
+ var IssueInboxCredentialBatchItemResultValidator = external_exports.discriminatedUnion("success", [
16826
+ IssueInboxCredentialResponseValidator.extend({
16827
+ success: external_exports.literal(true),
16828
+ index: external_exports.number().int().nonnegative(),
16829
+ deduplicated: external_exports.boolean().optional(),
16830
+ guardianStatus: GuardianStatusValidator.optional(),
16831
+ idempotencyKey: external_exports.string().optional()
16832
+ }),
16833
+ external_exports.object({
16834
+ success: external_exports.literal(false),
16835
+ index: external_exports.number().int().nonnegative(),
16836
+ idempotencyKey: external_exports.string().optional(),
16837
+ recipient: ContactMethodQueryValidator.optional(),
16838
+ error: external_exports.object({
16839
+ code: external_exports.string(),
16840
+ message: external_exports.string(),
16841
+ reason: InboxBatchErrorReasonValidator.optional()
16842
+ }),
16843
+ issuanceId: external_exports.string().optional().describe(
16844
+ "Present when issuance completed but replay storage could not be confirmed. Reconcile this issuance; do not issue again with a new key."
16845
+ ),
16846
+ claimUrl: external_exports.string().url().optional().describe(
16847
+ "Claim URL of the completed issuance, if available, when replay storage could not be confirmed."
16848
+ )
16849
+ })
16850
+ ]);
16851
+ var IssueInboxCredentialBatchResponseValidator = external_exports.object({
16852
+ results: external_exports.array(IssueInboxCredentialBatchItemResultValidator),
16853
+ summary: external_exports.object({
16854
+ total: external_exports.number(),
16855
+ succeeded: external_exports.number(),
16856
+ failed: external_exports.number(),
16857
+ deduplicated: external_exports.number()
16858
+ })
16859
+ });
16860
+ var InboxBatchReceiptValidator = external_exports.object({
16861
+ batchId: external_exports.string(),
16862
+ status: external_exports.enum(["QUEUED", "PROCESSING", "COMPLETED", "NEEDS_RECONCILIATION"]),
16863
+ createdAt: external_exports.string()
16864
+ });
16865
+ var InboxBatchStatusValidator = external_exports.object({
16866
+ batchId: external_exports.string(),
16867
+ createdAt: external_exports.string(),
16868
+ done: external_exports.boolean().describe(
16869
+ "True when no queued or processing items remain, including unconfirmed outcomes."
16870
+ ),
16871
+ status: external_exports.enum(["QUEUED", "PROCESSING", "COMPLETED", "NEEDS_RECONCILIATION"]),
16872
+ items: external_exports.array(
16873
+ external_exports.object({
16874
+ index: external_exports.number().int().nonnegative(),
16875
+ state: external_exports.enum(["QUEUED", "PROCESSING", "COMPLETED", "NEEDS_RECONCILIATION"]),
16876
+ result: IssueInboxCredentialBatchItemResultValidator.optional()
16877
+ })
16878
+ ),
16879
+ summary: IssueInboxCredentialBatchResponseValidator.shape.summary.extend({
16880
+ completed: external_exports.number(),
16881
+ pending: external_exports.number(),
16882
+ unconfirmed: external_exports.number()
16883
+ })
16884
+ });
16479
16885
  var CredentialNameRefValidator = external_exports.object({ name: external_exports.string() }).passthrough();
16480
16886
  var ClaimInboxCredentialValidator = external_exports.object({
16481
16887
  credential: VCValidator.or(VPValidator).or(UnsignedVCValidator).or(CredentialNameRefValidator).describe("The credential to issue, or a { name } reference to resolve a boost template."),
@@ -16961,6 +17367,7 @@ var CredentialActivityValidator = external_exports.object({
16961
17367
  eventType: CredentialActivityEventTypeValidator,
16962
17368
  timestamp: external_exports.string(),
16963
17369
  actorProfileId: external_exports.string().optional(),
17370
+ onBehalfOf: external_exports.string().optional(),
16964
17371
  recipientType: CredentialActivityRecipientTypeValidator,
16965
17372
  recipientIdentifier: external_exports.string(),
16966
17373
  boostUri: external_exports.string().optional(),
@@ -17110,191 +17517,6 @@ var inAppMessagesFlagValidator = external_exports.object({
17110
17517
  version: external_exports.number().default(1),
17111
17518
  messages: external_exports.array(inAppMessageValidator).default([])
17112
17519
  }).passthrough();
17113
- var LearnCardRefreshAuthorizationValidator = external_exports.object({ type: external_exports.literal("LearnCardDIDAuth") }).catchall(external_exports.any());
17114
- var ManagedCredentialRefreshServiceValidator = external_exports.object({
17115
- id: external_exports.string().min(1),
17116
- type: external_exports.literal("LearnCardCredentialRefresh2026"),
17117
- authorization: LearnCardRefreshAuthorizationValidator.optional()
17118
- }).catchall(external_exports.any());
17119
- var StandardCredentialRefreshServiceValidator = external_exports.object({
17120
- id: external_exports.string().min(1),
17121
- type: external_exports.literal("1EdTechCredentialRefresh")
17122
- }).catchall(external_exports.any());
17123
- var SupportedCredentialRefreshServiceValidator = external_exports.union([
17124
- ManagedCredentialRefreshServiceValidator,
17125
- StandardCredentialRefreshServiceValidator
17126
- ]);
17127
- var AllocateCredentialRefreshInputValidator = external_exports.object({
17128
- holder: external_exports.object({
17129
- profileId: external_exports.string().optional(),
17130
- did: external_exports.string().min(1)
17131
- }),
17132
- credentialId: external_exports.string().min(1)
17133
- });
17134
- var AllocateCredentialRefreshResultValidator = external_exports.object({
17135
- refreshId: external_exports.string().min(1),
17136
- refreshService: ManagedCredentialRefreshServiceValidator.extend({
17137
- authorization: LearnCardRefreshAuthorizationValidator
17138
- })
17139
- });
17140
- var CredentialRefreshSigningModeValidator = external_exports.enum(["issuer-signed", "signing-authority"]);
17141
- var PublishCredentialRefreshBaseFields = {
17142
- refreshId: external_exports.string().min(1),
17143
- notifyHolder: external_exports.boolean().optional(),
17144
- updateSummary: external_exports.string().optional(),
17145
- idempotencyKey: external_exports.string().optional()
17146
- };
17147
- var PublishIssuerSignedRefreshValidator = external_exports.object({
17148
- ...PublishCredentialRefreshBaseFields,
17149
- mode: external_exports.literal("issuer-signed"),
17150
- signedCredential: VCValidator
17151
- });
17152
- var PublishSigningAuthorityRefreshValidator = external_exports.object({
17153
- ...PublishCredentialRefreshBaseFields,
17154
- mode: external_exports.literal("signing-authority"),
17155
- credential: UnsignedVCValidator,
17156
- signingAuthority: external_exports.object({
17157
- type: external_exports.string().min(1)
17158
- }).catchall(external_exports.any())
17159
- });
17160
- var PublishCredentialRefreshInputValidator = external_exports.object({
17161
- ...PublishCredentialRefreshBaseFields,
17162
- mode: CredentialRefreshSigningModeValidator,
17163
- signedCredential: VCValidator.optional(),
17164
- credential: UnsignedVCValidator.optional(),
17165
- signingAuthority: external_exports.object({
17166
- type: external_exports.string().min(1)
17167
- }).catchall(external_exports.any()).optional()
17168
- }).superRefine((input, ctx) => {
17169
- if (input.mode === "issuer-signed" && !input.signedCredential) {
17170
- ctx.addIssue({
17171
- code: "custom",
17172
- path: ["signedCredential"],
17173
- message: "signedCredential is required for issuer-signed publication"
17174
- });
17175
- }
17176
- if (input.mode === "issuer-signed" && (input.credential !== void 0 || input.signingAuthority !== void 0)) {
17177
- ctx.addIssue({
17178
- code: "custom",
17179
- path: ["mode"],
17180
- message: "issuer-signed publication cannot include signing-authority fields"
17181
- });
17182
- }
17183
- if (input.mode === "signing-authority") {
17184
- if (input.signedCredential !== void 0) {
17185
- ctx.addIssue({
17186
- code: "custom",
17187
- path: ["signedCredential"],
17188
- message: "signing-authority publication cannot include signedCredential"
17189
- });
17190
- }
17191
- if (!input.credential) {
17192
- ctx.addIssue({
17193
- code: "custom",
17194
- path: ["credential"],
17195
- message: "credential is required for signing-authority publication"
17196
- });
17197
- }
17198
- if (!input.signingAuthority) {
17199
- ctx.addIssue({
17200
- code: "custom",
17201
- path: ["signingAuthority"],
17202
- message: "signingAuthority is required for signing-authority publication"
17203
- });
17204
- }
17205
- }
17206
- });
17207
- var PublishCredentialRefreshNotificationValidator = external_exports.enum([
17208
- "queued",
17209
- "suppressed",
17210
- "not-applicable",
17211
- /** Publication succeeded, but the post-commit notification enqueue must be retried. */
17212
- "delivery-failed"
17213
- ]);
17214
- var PublishCredentialRefreshResultValidator = external_exports.object({
17215
- refreshId: external_exports.string().min(1),
17216
- version: external_exports.number().int().positive(),
17217
- publishedAt: external_exports.string().min(1),
17218
- notification: PublishCredentialRefreshNotificationValidator
17219
- });
17220
- var CredentialRefreshVersionMetadataValidator = external_exports.object({
17221
- version: external_exports.number().int().positive(),
17222
- publishedAt: external_exports.string().min(1),
17223
- effectiveAt: external_exports.string().optional(),
17224
- etag: external_exports.string().optional(),
17225
- signingMode: CredentialRefreshSigningModeValidator.optional(),
17226
- updateSummary: external_exports.string().optional()
17227
- });
17228
- var GetCredentialRefreshHistoryInputValidator = external_exports.object({
17229
- refreshId: external_exports.string().min(1),
17230
- cursor: external_exports.string().optional(),
17231
- limit: external_exports.number().int().positive().optional()
17232
- });
17233
- var GetCredentialRefreshHistoryResultValidator = external_exports.object({
17234
- records: CredentialRefreshVersionMetadataValidator.array(),
17235
- hasMore: external_exports.boolean(),
17236
- cursor: external_exports.string().optional()
17237
- });
17238
- var CredentialRefreshChallengeValidator = external_exports.object({
17239
- challenge: external_exports.string().min(1),
17240
- expiresAt: external_exports.string().min(1),
17241
- domain: external_exports.string().optional(),
17242
- scheme: external_exports.literal("LearnCardDIDAuth").optional()
17243
- });
17244
- var PublicCredentialRefreshEnvelopeValidator = external_exports.object({
17245
- format: external_exports.literal("vc"),
17246
- credential: VCValidator,
17247
- etag: external_exports.string().optional()
17248
- });
17249
- var JweCredentialRefreshEnvelopeValidator = external_exports.object({
17250
- format: external_exports.literal("jwe"),
17251
- jwe: JWEValidator,
17252
- etag: external_exports.string().optional(),
17253
- /** Present on LearnCard-managed endpoints; optional for interoperable JWE services. */
17254
- version: external_exports.number().int().positive().optional()
17255
- });
17256
- var CredentialRefreshResponseEnvelopeValidator = external_exports.discriminatedUnion("format", [
17257
- PublicCredentialRefreshEnvelopeValidator,
17258
- JweCredentialRefreshEnvelopeValidator
17259
- ]);
17260
- var CredentialRefreshFailureCodeValidator = external_exports.enum([
17261
- "UNAVAILABLE",
17262
- "TIMEOUT",
17263
- "UNSUPPORTED_SERVICE",
17264
- "UNAUTHORIZED",
17265
- "MALFORMED_RESPONSE",
17266
- "INVALID_PROOF",
17267
- "ISSUER_MISMATCH",
17268
- "ID_MISMATCH",
17269
- "ROLLBACK",
17270
- "REVOKED",
17271
- "UNSAFE_ENDPOINT"
17272
- ]);
17273
- var CredentialRefreshUpdatedResultValidator = external_exports.object({
17274
- status: external_exports.literal("updated"),
17275
- credential: VCValidator,
17276
- etag: external_exports.string().optional(),
17277
- managedVersion: external_exports.number().int().positive().optional()
17278
- });
17279
- var CredentialRefreshUnchangedResultValidator = external_exports.object({
17280
- status: external_exports.literal("unchanged"),
17281
- checkedAt: external_exports.string().min(1),
17282
- etag: external_exports.string().optional()
17283
- });
17284
- var CredentialRefreshUnsupportedResultValidator = external_exports.object({
17285
- status: external_exports.literal("unsupported")
17286
- });
17287
- var CredentialRefreshFailedResultValidator = external_exports.object({
17288
- status: external_exports.literal("failed"),
17289
- code: CredentialRefreshFailureCodeValidator,
17290
- retryable: external_exports.boolean()
17291
- });
17292
- var CredentialRefreshResultValidator = external_exports.discriminatedUnion("status", [
17293
- CredentialRefreshUpdatedResultValidator,
17294
- CredentialRefreshUnchangedResultValidator,
17295
- CredentialRefreshUnsupportedResultValidator,
17296
- CredentialRefreshFailedResultValidator
17297
- ]);
17298
17520
 
17299
17521
  // src/plugin.ts
17300
17522
  var import_helpers = require("@learncard/helpers");
@@ -17912,27 +18134,40 @@ var issueCredentialWithNetworkStatus = /* @__PURE__ */ __name(async (learnCard,
17912
18134
  await appendNetworkCredentialStatus(client, credential, statusPurposes)
17913
18135
  );
17914
18136
  }, "issueCredentialWithNetworkStatus");
17915
- var MANAGED_REFRESH_SERVICE_CONTEXT = {
17916
- "LearnCardCredentialRefresh2026": "https://learncard.com/refresh#LearnCardCredentialRefresh2026",
17917
- authorization: {
17918
- "@id": "https://purl.imsglobal.org/spec/ob/v3p0#authorization",
17919
- "@context": {
17920
- LearnCardDIDAuth: "https://docs.learncard.com/definitions#LearnCardDIDAuth"
17921
- }
17922
- }
17923
- };
17924
- var injectManagedRefreshService = /* @__PURE__ */ __name((credential, refreshService) => {
17925
- const existingContext = credential["@context"];
17926
- const contextList = Array.isArray(existingContext) ? existingContext : [existingContext];
17927
- const hasMapping = contextList.some(
17928
- (entry) => !!entry && typeof entry === "object" && "LearnCardCredentialRefresh2026" in entry
17929
- );
18137
+ var injectManagedRefreshService = /* @__PURE__ */ __name((credential, refreshService) => (0, import_helpers.injectManagedRefreshService)(credential, refreshService), "injectManagedRefreshService");
18138
+ var getCredentialSubjectIds = /* @__PURE__ */ __name((vc) => {
18139
+ const subject = vc.credentialSubject;
18140
+ const subjects = Array.isArray(subject) ? subject : subject ? [subject] : [];
18141
+ return subjects.flatMap((entry) => {
18142
+ const id = entry?.id;
18143
+ return typeof id === "string" && id.length > 0 ? [id] : [];
18144
+ });
18145
+ }, "getCredentialSubjectIds");
18146
+ var buildManagedRefreshReceipt = /* @__PURE__ */ __name((vc, allocation, credentialId, fallbackHolderDid, fallbackIssuerDid) => {
18147
+ const issuerDid = (0, import_helpers.getCredentialIssuerId)(vc) ?? fallbackIssuerDid;
18148
+ const holderDid = getCredentialSubjectIds(vc)[0] ?? fallbackHolderDid;
18149
+ const rawStatus = vc.credentialStatus;
18150
+ const hasStatus = rawStatus !== void 0 && rawStatus !== null && !(Array.isArray(rawStatus) && rawStatus.length === 0);
17930
18151
  return {
17931
- ...credential,
17932
- "@context": hasMapping ? contextList : [...contextList, MANAGED_REFRESH_SERVICE_CONTEXT],
17933
- refreshService
17934
- };
17935
- }, "injectManagedRefreshService");
18152
+ refreshId: allocation.refreshId,
18153
+ refreshService: allocation.refreshService,
18154
+ credentialId: typeof vc.id === "string" && vc.id.length > 0 ? vc.id : credentialId,
18155
+ issuerDid,
18156
+ holderDid,
18157
+ ...hasStatus ? {
18158
+ credentialStatus: rawStatus
18159
+ } : {}
18160
+ };
18161
+ }, "buildManagedRefreshReceipt");
18162
+ var ACT_AS_TARGET_NOT_FOUND_MESSAGE = "Act-as target profile not found";
18163
+ var isActAsDenial = /* @__PURE__ */ __name((error51) => {
18164
+ const code = error51?.data?.code;
18165
+ if (code === "FORBIDDEN" || code === "BAD_REQUEST") return true;
18166
+ if (code === "NOT_FOUND") {
18167
+ return error51?.message === ACT_AS_TARGET_NOT_FOUND_MESSAGE;
18168
+ }
18169
+ return false;
18170
+ }, "isActAsDenial");
17936
18171
  async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, options) {
17937
18172
  const apiToken = typeof apiTokenOrOptions === "string" ? apiTokenOrOptions : void 0;
17938
18173
  const resolvedOptions = (typeof apiTokenOrOptions === "object" ? apiTokenOrOptions : options) ?? {};
@@ -17940,8 +18175,10 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17940
18175
  guardianApprovalGetter,
17941
18176
  extraHeaders,
17942
18177
  trustedFederationHosts,
17943
- allowLocalhostFederation
18178
+ allowLocalhostFederation,
18179
+ actAs
17944
18180
  } = resolvedOptions;
18181
+ const mergedExtraHeaders = actAs ? { ...extraHeaders, [ACT_AS_HEADER]: actAs } : extraHeaders;
17945
18182
  const serviceUrl = new URL(url2);
17946
18183
  const serviceIsLocalhost = isLocalhostHost(serviceUrl.hostname);
17947
18184
  const federationConfig = {
@@ -17959,7 +18196,7 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17959
18196
  learnCard?.debug?.("LCN: no local DID available at init; will fetch from profile");
17960
18197
  }
17961
18198
  learnCard?.debug?.("Adding LearnCardNetwork Plugin");
17962
- const client = apiToken ? await (0, import_network_brain_client.getApiTokenClient)(url2, apiToken, guardianApprovalGetter, extraHeaders) : await (0, import_network_brain_client.getClient)(
18199
+ const client = apiToken ? await (0, import_network_brain_client.getApiTokenClient)(url2, apiToken, guardianApprovalGetter, mergedExtraHeaders) : await (0, import_network_brain_client.getClient)(
17963
18200
  url2,
17964
18201
  async (challenge) => {
17965
18202
  const jwt2 = await learnCard.invoke.getDidAuthVp({
@@ -17970,7 +18207,7 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17970
18207
  return jwt2;
17971
18208
  },
17972
18209
  guardianApprovalGetter,
17973
- extraHeaders
18210
+ mergedExtraHeaders
17974
18211
  );
17975
18212
  let userData;
17976
18213
  learnCard?.debug?.("LCN: initial getProfile query starting", { apiToken: !!apiToken });
@@ -18173,6 +18410,23 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18173
18410
  getManagedProfiles: /* @__PURE__ */ __name(async (_learnCard, options2 = {}) => {
18174
18411
  return client.profileManager.getManagedProfiles.query(options2);
18175
18412
  }, "getManagedProfiles"),
18413
+ actAs: /* @__PURE__ */ __name(async (_learnCard, profileId) => {
18414
+ const actingOptions = {
18415
+ ...resolvedOptions,
18416
+ actAs: profileId
18417
+ };
18418
+ const actingPlugin = apiToken ? await getLearnCardNetworkPlugin(_learnCard, url2, apiToken, actingOptions) : await getLearnCardNetworkPlugin(_learnCard, url2, actingOptions);
18419
+ try {
18420
+ await actingPlugin.methods.getLCNClient(_learnCard).profile.getProfile.query();
18421
+ } catch (error51) {
18422
+ if (isActAsDenial(error51)) {
18423
+ const message = error51 instanceof Error ? error51.message : "Act-as request was denied.";
18424
+ throw new Error(message, { cause: error51 });
18425
+ }
18426
+ _learnCard.debug?.("LCN actAs: getProfile failed (non-fatal)", error51);
18427
+ }
18428
+ return _learnCard.addPlugin(actingPlugin);
18429
+ }, "actAs"),
18176
18430
  claimPendingGuardianLinks: /* @__PURE__ */ __name(async () => {
18177
18431
  await ensureUser();
18178
18432
  return client.inbox.claimPendingGuardianLinks.mutate({});
@@ -18782,15 +19036,14 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18782
19036
  boost = options2.overideFn(boost);
18783
19037
  }
18784
19038
  const enableRefresh = typeof options2 === "object" && options2.enableRefresh === true;
18785
- let managedRefreshId;
19039
+ let refreshAllocation;
18786
19040
  if (enableRefresh) {
18787
19041
  if (!boost.id) boost.id = `urn:uuid:${crypto.randomUUID()}`;
18788
- const allocation = await client.credentialRefresh.allocateCredentialRefresh.mutate({
19042
+ refreshAllocation = await client.credentialRefresh.allocateCredentialRefresh.mutate({
18789
19043
  holder: { profileId, did: targetProfile.did },
18790
19044
  credentialId: boost.id
18791
19045
  });
18792
- managedRefreshId = allocation.refreshId;
18793
- boost = injectManagedRefreshService(boost, allocation.refreshService);
19046
+ boost = injectManagedRefreshService(boost, refreshAllocation.refreshService);
18794
19047
  }
18795
19048
  const statusPurposes = typeof options2 === "object" ? options2.statusPurposes : void 0;
18796
19049
  const vc = await issueCredentialWithNetworkStatus(
@@ -18799,13 +19052,23 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18799
19052
  boost,
18800
19053
  statusPurposes
18801
19054
  );
18802
- if (managedRefreshId) {
18803
- return client.credentialRefresh.sendRefreshableCredential.mutate({
18804
- refreshId: managedRefreshId,
19055
+ if (refreshAllocation) {
19056
+ const credentialUri = await client.credentialRefresh.sendRefreshableCredential.mutate({
19057
+ refreshId: refreshAllocation.refreshId,
18805
19058
  credential: vc,
18806
19059
  boostUri,
18807
19060
  ...typeof options2 === "object" && options2.skipNotification ? { skipNotification: true } : {}
18808
19061
  });
19062
+ return {
19063
+ credentialUri,
19064
+ refresh: buildManagedRefreshReceipt(
19065
+ vc,
19066
+ refreshAllocation,
19067
+ boost.id ?? "",
19068
+ targetProfile.did,
19069
+ _learnCard.id.did()
19070
+ )
19071
+ };
18809
19072
  }
18810
19073
  if (typeof options2 === "object" && !options2.encrypt || !options2) {
18811
19074
  return client.boost.sendBoost.mutate({
@@ -18871,6 +19134,94 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18871
19134
  }, "claimBoostWithLink"),
18872
19135
  send: /* @__PURE__ */ __name(async (_learnCard, input) => {
18873
19136
  await ensureUser();
19137
+ if (input.type === "boost" && input.refresh === true) {
19138
+ const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.recipient);
19139
+ const isPhone = /^\+?[\d\s-]{10,}$/.test(input.recipient.replace(/[\s-]/g, ""));
19140
+ if (isEmail || isPhone) return client.boost.send.mutate(input);
19141
+ const canIssueLocally = "issueCredential" in _learnCard.invoke;
19142
+ if (canIssueLocally && !input.signedCredential && (input.templateUri || input.template)) {
19143
+ let boost;
19144
+ if (input.templateUri) {
19145
+ const result = await getBoostTemplateForIssuance(
19146
+ _learnCard,
19147
+ input.templateUri
19148
+ );
19149
+ const data = await UnsignedVCValidator.spa(result);
19150
+ if (!data.success)
19151
+ throw new Error("Did not get a valid boost from URI");
19152
+ boost = data.data;
19153
+ } else {
19154
+ boost = JSON.parse(
19155
+ JSON.stringify(input.template.credential)
19156
+ );
19157
+ }
19158
+ const prepared = await client.boost.prepareRefreshableSend.mutate({
19159
+ recipient: input.recipient,
19160
+ ...input.templateUri ? { templateUri: input.templateUri } : { template: input.template },
19161
+ ...input.contractUri ? { contractUri: input.contractUri } : {},
19162
+ ...input.templateData ? { templateData: input.templateData } : {},
19163
+ ...input.integrationId ? { integrationId: input.integrationId } : {},
19164
+ ...boost.id ? { credentialId: boost.id } : {},
19165
+ ...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
19166
+ });
19167
+ if (prepared.completed) return prepared.completed;
19168
+ const boostString = JSON.stringify(boost);
19169
+ const allowAutoAppendEvidence = !hasDynamicEvidenceTemplate(boostString);
19170
+ if (input.templateData && Object.keys(input.templateData).length > 0) {
19171
+ try {
19172
+ const rendered = renderTemplateJson(
19173
+ boostString,
19174
+ input.templateData
19175
+ );
19176
+ boost = JSON.parse(rendered);
19177
+ boost = appendTemplateEvidence(
19178
+ boost,
19179
+ input.templateData,
19180
+ allowAutoAppendEvidence
19181
+ );
19182
+ } catch (error51) {
19183
+ throw new Error(
19184
+ `Failed to apply template data: ${error51 instanceof Error ? error51.message : "Unknown error"}`,
19185
+ { cause: error51 }
19186
+ );
19187
+ }
19188
+ }
19189
+ if ((0, import_helpers.isVC2Format)(boost)) {
19190
+ boost.validFrom = (/* @__PURE__ */ new Date()).toISOString();
19191
+ } else {
19192
+ boost.issuanceDate = (/* @__PURE__ */ new Date()).toISOString();
19193
+ }
19194
+ boost.issuer = _learnCard.id.did();
19195
+ if (Array.isArray(boost.credentialSubject)) {
19196
+ boost.credentialSubject = boost.credentialSubject.map((subject) => ({
19197
+ ...subject,
19198
+ id: prepared.holderDid
19199
+ }));
19200
+ } else {
19201
+ boost.credentialSubject = {
19202
+ ...boost.credentialSubject,
19203
+ id: prepared.holderDid
19204
+ };
19205
+ }
19206
+ boost.id = prepared.credentialId;
19207
+ if (boost.type?.includes("BoostCredential"))
19208
+ boost.boostId = prepared.boostUri;
19209
+ boost = injectManagedRefreshService(boost, prepared.refreshService);
19210
+ const signedCredential = await issueCredentialWithNetworkStatus(
19211
+ _learnCard,
19212
+ client,
19213
+ boost
19214
+ );
19215
+ return client.boost.send.mutate({
19216
+ ...input,
19217
+ template: void 0,
19218
+ templateUri: prepared.boostUri,
19219
+ signedCredential,
19220
+ refresh: true
19221
+ });
19222
+ }
19223
+ return client.boost.send.mutate(input);
19224
+ }
18874
19225
  if (input.type === "boost") {
18875
19226
  const recipient = input.recipient;
18876
19227
  const isDid = recipient.startsWith("did:");
@@ -19277,6 +19628,37 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
19277
19628
  await ensureUser();
19278
19629
  return client.inbox.issue.mutate(issueInboxCredential);
19279
19630
  }, "sendCredentialViaInbox"),
19631
+ sendCredentialsViaInbox: /* @__PURE__ */ __name(async (_learnCard, batch) => {
19632
+ await ensureUser();
19633
+ return client.inbox.issueBatch.mutate(batch);
19634
+ }, "sendCredentialsViaInbox"),
19635
+ sendCredentialBatchViaInbox: /* @__PURE__ */ __name(async (_learnCard, batch) => {
19636
+ await ensureUser();
19637
+ return client.inbox.issueBatch.mutate(batch);
19638
+ }, "sendCredentialBatchViaInbox"),
19639
+ waitForInboxCredentialBatch: /* @__PURE__ */ __name(async (_learnCard, batchId, options2) => {
19640
+ await ensureUser();
19641
+ return waitForInboxCredentialBatch(
19642
+ (signal) => client.inbox.getBatch.query({ batchId }, { signal }),
19643
+ options2
19644
+ );
19645
+ }, "waitForInboxCredentialBatch"),
19646
+ sendCredentialsViaInboxAndWait: /* @__PURE__ */ __name(async (_learnCard, batch, options2) => {
19647
+ await ensureUser();
19648
+ if (options2?.signal?.aborted) throw options2.signal.reason;
19649
+ const receipt = await client.inbox.issueBatch.mutate(batch, {
19650
+ signal: options2?.signal
19651
+ });
19652
+ await options2?.onSubmitted?.(receipt);
19653
+ return waitForInboxCredentialBatch(
19654
+ (signal) => client.inbox.getBatch.query({ batchId: receipt.batchId }, { signal }),
19655
+ options2
19656
+ );
19657
+ }, "sendCredentialsViaInboxAndWait"),
19658
+ getInboxCredentialBatch: /* @__PURE__ */ __name(async (_learnCard, batchId) => {
19659
+ await ensureUser();
19660
+ return client.inbox.getBatch.query({ batchId });
19661
+ }, "getInboxCredentialBatch"),
19280
19662
  getMySentInboxCredentials: /* @__PURE__ */ __name(async (_learnCard, options2) => {
19281
19663
  await ensureUser();
19282
19664
  return client.inbox.getMyIssuedCredentials.query(options2);