@learncard/network-plugin 2.14.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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(),
@@ -17002,6 +17409,12 @@ var AuthSessionError = (_a3 = class extends Error {
17002
17409
  this.name = "AuthSessionError";
17003
17410
  }
17004
17411
  }, __name(_a3, "AuthSessionError"), __name2(_a3, "AuthSessionError"), _a3);
17412
+ var EscrowPinStatusValidator = external_exports.object({
17413
+ state: external_exports.enum(["none", "enabled", "locked", "stale"]),
17414
+ enabled: external_exports.boolean(),
17415
+ attemptsRemaining: external_exports.number().int().nonnegative(),
17416
+ salt: external_exports.string().optional()
17417
+ });
17005
17418
  var BITSTRING_STATUS_PURPOSES = ["revocation", "suspension"];
17006
17419
  var BitstringStatusPurposeValidator = external_exports.enum(BITSTRING_STATUS_PURPOSES);
17007
17420
  var BitstringStatusListEntryValidator = external_exports.object({
@@ -17110,191 +17523,456 @@ var inAppMessagesFlagValidator = external_exports.object({
17110
17523
  version: external_exports.number().default(1),
17111
17524
  messages: external_exports.array(inAppMessageValidator).default([])
17112
17525
  }).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
- });
17526
+ var SHARE_LINK_ID_BYTES = 16;
17527
+ var SHARE_CONTENT_KEY_BYTES = 32;
17528
+ var SHARE_IV_BYTES = 12;
17529
+ var SHARE_TAG_BYTES = 16;
17530
+ var MAX_SHARE_CIPHERTEXT_BYTES = 512 * 1024;
17531
+ var MAX_SHARE_RECOVERY_JWE_BYTES = 64 * 1024;
17532
+ var MAX_SELECTED_CREDENTIALS = 50;
17533
+ var MAX_ENDORSEMENTS = 200;
17534
+ var MAX_VP_MEMBERS = MAX_SELECTED_CREDENTIALS + MAX_ENDORSEMENTS;
17535
+ var MAX_SHARE_SOURCE_URI_CHARS = 2048;
17536
+ var MAX_SHARE_LINK_REQUEST_BYTES = 1024 * 1024;
17537
+ var SHARE_LINK_PROTOCOL = "lc-share/v1";
17538
+ var SHARE_RECOVERY_PROTOCOL = "lc-share-recovery/v1";
17539
+ var BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
17540
+ var BASE64URL_LOOKUP = (() => {
17541
+ const table = new Int16Array(128).fill(-1);
17542
+ for (let index = 0; index < BASE64URL_ALPHABET.length; index += 1) {
17543
+ table[BASE64URL_ALPHABET.charCodeAt(index)] = index;
17544
+ }
17545
+ return table;
17546
+ })();
17547
+ var encodeBase64Url = /* @__PURE__ */ __name2((bytes) => {
17548
+ let output = "";
17549
+ for (let index = 0; index < bytes.length; index += 3) {
17550
+ const first = bytes[index];
17551
+ const second = bytes[index + 1];
17552
+ const third = bytes[index + 2];
17553
+ output += BASE64URL_ALPHABET[first >> 2];
17554
+ output += BASE64URL_ALPHABET[(first & 3) << 4 | (second ?? 0) >> 4];
17555
+ if (second === void 0) break;
17556
+ output += BASE64URL_ALPHABET[(second & 15) << 2 | (third ?? 0) >> 6];
17557
+ if (third === void 0) break;
17558
+ output += BASE64URL_ALPHABET[third & 63];
17559
+ }
17560
+ return output;
17561
+ }, "encodeBase64Url");
17562
+ var decodeBase64Url = /* @__PURE__ */ __name2((value) => {
17563
+ if (typeof value !== "string") return null;
17564
+ const output = new Uint8Array(Math.floor(value.length * 6 / 8));
17565
+ let bits = 0;
17566
+ let bitCount = 0;
17567
+ let outputIndex = 0;
17568
+ for (let index = 0; index < value.length; index += 1) {
17569
+ const code = value.charCodeAt(index);
17570
+ const digit = code < 128 ? BASE64URL_LOOKUP[code] : -1;
17571
+ if (digit < 0) return null;
17572
+ bits = bits << 6 | digit;
17573
+ bitCount += 6;
17574
+ if (bitCount >= 8) {
17575
+ bitCount -= 8;
17576
+ output[outputIndex] = bits >> bitCount & 255;
17577
+ outputIndex += 1;
17578
+ }
17579
+ }
17580
+ return output;
17581
+ }, "decodeBase64Url");
17582
+ var isCanonicalBase64Url = /* @__PURE__ */ __name2((value, expectedBytes) => {
17583
+ if (typeof value !== "string") return false;
17584
+ if (expectedBytes !== void 0 && value.length !== Math.ceil(expectedBytes * 4 / 3))
17585
+ return false;
17586
+ const decoded = decodeBase64Url(value);
17587
+ if (decoded === null) return false;
17588
+ if (expectedBytes !== void 0 && decoded.length !== expectedBytes) return false;
17589
+ return encodeBase64Url(decoded) === value;
17590
+ }, "isCanonicalBase64Url");
17591
+ var utf8ByteLength = /* @__PURE__ */ __name2((value) => new TextEncoder().encode(value).length, "utf8ByteLength");
17592
+ var canonicalBase64Url = /* @__PURE__ */ __name2((bytes) => external_exports.string().refine((value) => isCanonicalBase64Url(value, bytes), {
17593
+ message: `must be canonical base64url for exactly ${bytes} bytes`
17594
+ }), "canonicalBase64Url");
17595
+ var ShareLinkIdValidator = canonicalBase64Url(SHARE_LINK_ID_BYTES);
17596
+ var ShareContentKeyValidator = canonicalBase64Url(SHARE_CONTENT_KEY_BYTES);
17597
+ var ShareIvValidator = canonicalBase64Url(SHARE_IV_BYTES);
17598
+ var ShareCiphertextValidator = external_exports.string().refine(
17599
+ (value) => {
17600
+ if (value.length > Math.ceil(MAX_SHARE_CIPHERTEXT_BYTES * 4 / 3)) return false;
17601
+ const decoded = decodeBase64Url(value);
17602
+ if (decoded === null) return false;
17603
+ if (encodeBase64Url(decoded) !== value) return false;
17604
+ return decoded.length >= SHARE_TAG_BYTES && decoded.length <= MAX_SHARE_CIPHERTEXT_BYTES;
17605
+ },
17606
+ {
17607
+ message: `must be canonical base64url decoding to ${SHARE_TAG_BYTES}..${MAX_SHARE_CIPHERTEXT_BYTES} bytes`
17175
17608
  }
17176
- if (input.mode === "issuer-signed" && (input.credential !== void 0 || input.signingAuthority !== void 0)) {
17609
+ );
17610
+ var ShareEnvelopeValidator = external_exports.object({
17611
+ v: external_exports.literal(1),
17612
+ alg: external_exports.literal("A256GCM"),
17613
+ iv: ShareIvValidator,
17614
+ ct: ShareCiphertextValidator
17615
+ }).strict();
17616
+ var safeVersion = external_exports.number().int().min(1).max(2 ** 31 - 1);
17617
+ var safeCredentialIndex = external_exports.number().int().min(0).max(MAX_VP_MEMBERS - 1);
17618
+ var ShareSelectionEntryValidator = external_exports.object({ credentialIndex: safeCredentialIndex }).strict();
17619
+ var ShareEndorsementEntryValidator = external_exports.object({ credentialIndex: safeCredentialIndex, targetCredentialIndex: safeCredentialIndex }).strict();
17620
+ var ShareSharerValidator = external_exports.object({
17621
+ profileId: external_exports.string().min(1).max(128),
17622
+ displayName: external_exports.string().min(1).max(120),
17623
+ avatar: external_exports.string().max(2048).optional()
17624
+ }).strict();
17625
+ var presentationShape = VPValidator.extend({
17626
+ verifiableCredential: VCValidator.array().min(1).max(MAX_VP_MEMBERS)
17627
+ });
17628
+ var hasBoundedPresentation = /* @__PURE__ */ __name2((value) => {
17629
+ let credentialCount = 0;
17630
+ const ancestors = /* @__PURE__ */ new Set();
17631
+ const visit = /* @__PURE__ */ __name2((node, depth) => {
17632
+ if (node === null || typeof node !== "object") return true;
17633
+ if (depth > 32 || ancestors.has(node)) return false;
17634
+ ancestors.add(node);
17635
+ try {
17636
+ for (const [key, child] of Object.entries(node)) {
17637
+ if (key === "verifiableCredential") {
17638
+ credentialCount += Array.isArray(child) ? child.length : 1;
17639
+ if (credentialCount > MAX_VP_MEMBERS) return false;
17640
+ }
17641
+ if (!visit(child, depth + 1)) return false;
17642
+ }
17643
+ return true;
17644
+ } finally {
17645
+ ancestors.delete(node);
17646
+ }
17647
+ }, "visit");
17648
+ return visit(value, 0);
17649
+ }, "hasBoundedPresentation");
17650
+ var ShareManifestPresentationValidator = external_exports.custom(
17651
+ (value) => hasBoundedPresentation(value) && presentationShape.safeParse(value).success,
17652
+ { message: "invalid share presentation" }
17653
+ );
17654
+ var SharePayloadValidatorShape = external_exports.object({
17655
+ protocol: external_exports.literal(SHARE_LINK_PROTOCOL),
17656
+ shareId: ShareLinkIdValidator,
17657
+ contentVersion: safeVersion,
17658
+ createdAt: external_exports.iso.datetime(),
17659
+ sharer: ShareSharerValidator,
17660
+ presentation: ShareManifestPresentationValidator,
17661
+ selection: ShareSelectionEntryValidator.array().min(1).max(MAX_SELECTED_CREDENTIALS),
17662
+ endorsements: ShareEndorsementEntryValidator.array().max(MAX_ENDORSEMENTS).default([])
17663
+ }).strict();
17664
+ var classificationFailure = /* @__PURE__ */ __name2((code, message, path = []) => ({ ok: false, code, message, path }), "classificationFailure");
17665
+ var readSignedClaimId = /* @__PURE__ */ __name2((member) => {
17666
+ if (member === null || typeof member !== "object") return void 0;
17667
+ const record2 = member;
17668
+ const claim = record2.credentialSubject ?? record2.endorsement;
17669
+ if (claim === null || typeof claim !== "object") return void 0;
17670
+ const claimRecord = claim;
17671
+ const nested = claimRecord.endorsement;
17672
+ const nestedId = nested !== null && typeof nested === "object" ? nested.id : void 0;
17673
+ return claimRecord.id ?? nestedId;
17674
+ }, "readSignedClaimId");
17675
+ var classifyShareManifest = /* @__PURE__ */ __name2((payload) => {
17676
+ const members = payload.presentation?.verifiableCredential;
17677
+ if (!Array.isArray(members) || members.length === 0) {
17678
+ return classificationFailure("NO_PRESENTATION_MEMBERS", "presentation has no credentials");
17679
+ }
17680
+ if (members.length > MAX_VP_MEMBERS) {
17681
+ return classificationFailure(
17682
+ "TOO_MANY_VP_MEMBERS",
17683
+ `presentation has ${members.length} members, over the ${MAX_VP_MEMBERS} bound`
17684
+ );
17685
+ }
17686
+ const selection = payload.selection;
17687
+ const endorsements = payload.endorsements ?? [];
17688
+ if (!Array.isArray(selection) || selection.length < 1 || selection.length > MAX_SELECTED_CREDENTIALS) {
17689
+ return classificationFailure("BAD_SELECTION", "selection must contain 1..50 entries");
17690
+ }
17691
+ if (!Array.isArray(endorsements) || endorsements.length > MAX_ENDORSEMENTS) {
17692
+ return classificationFailure(
17693
+ "BAD_ENDORSEMENTS",
17694
+ "endorsements must contain at most 200 entries"
17695
+ );
17696
+ }
17697
+ const selectedIndices = [];
17698
+ const selected = /* @__PURE__ */ new Set();
17699
+ for (let index = 0; index < selection.length; index += 1) {
17700
+ const entry = selection[index];
17701
+ const credentialIndex = entry?.credentialIndex;
17702
+ if (!Number.isSafeInteger(credentialIndex) || credentialIndex < 0 || credentialIndex >= members.length) {
17703
+ return classificationFailure(
17704
+ "SELECTION_INDEX_OUT_OF_BOUNDS",
17705
+ `selection[${index}].credentialIndex is out of bounds`,
17706
+ ["selection", index, "credentialIndex"]
17707
+ );
17708
+ }
17709
+ if (selected.has(credentialIndex)) {
17710
+ return classificationFailure(
17711
+ "SELECTION_INDEX_DUPLICATE",
17712
+ `selection[${index}].credentialIndex is duplicated`,
17713
+ ["selection", index, "credentialIndex"]
17714
+ );
17715
+ }
17716
+ selected.add(credentialIndex);
17717
+ selectedIndices.push(credentialIndex);
17718
+ }
17719
+ const classified = new Set(selected);
17720
+ const endorsementIndices = [];
17721
+ for (let index = 0; index < endorsements.length; index += 1) {
17722
+ const entry = endorsements[index];
17723
+ const credentialIndex = entry?.credentialIndex;
17724
+ const targetIndex = entry?.targetCredentialIndex;
17725
+ if (!Number.isSafeInteger(credentialIndex) || credentialIndex < 0 || credentialIndex >= members.length) {
17726
+ return classificationFailure(
17727
+ "ENDORSEMENT_INDEX_OUT_OF_BOUNDS",
17728
+ `endorsements[${index}].credentialIndex is out of bounds`,
17729
+ ["endorsements", index, "credentialIndex"]
17730
+ );
17731
+ }
17732
+ if (classified.has(credentialIndex)) {
17733
+ return classificationFailure(
17734
+ "VP_MEMBER_CLASSIFIED_TWICE",
17735
+ `endorsements[${index}].credentialIndex was already classified`,
17736
+ ["endorsements", index, "credentialIndex"]
17737
+ );
17738
+ }
17739
+ if (!selected.has(targetIndex)) {
17740
+ return classificationFailure(
17741
+ "ENDORSEMENT_TARGET_NOT_SELECTED",
17742
+ `endorsements[${index}].targetCredentialIndex must reference a selected credential`,
17743
+ ["endorsements", index, "targetCredentialIndex"]
17744
+ );
17745
+ }
17746
+ const referenced = readSignedClaimId(members[credentialIndex]);
17747
+ const target = members[targetIndex];
17748
+ const targetId = target !== null && typeof target === "object" ? target.id : void 0;
17749
+ if (typeof referenced !== "string" || typeof targetId !== "string" || referenced !== targetId) {
17750
+ return classificationFailure(
17751
+ "ENDORSEMENT_TARGET_UNBOUND",
17752
+ `endorsements[${index}] claim does not reference the target credential id`,
17753
+ ["endorsements", index]
17754
+ );
17755
+ }
17756
+ classified.add(credentialIndex);
17757
+ endorsementIndices.push(credentialIndex);
17758
+ }
17759
+ if (classified.size !== members.length) {
17760
+ return classificationFailure(
17761
+ "UNCLASSIFIED_VP_MEMBER",
17762
+ "every presentation member must be classified exactly once",
17763
+ ["presentation", "verifiableCredential"]
17764
+ );
17765
+ }
17766
+ return {
17767
+ ok: true,
17768
+ classification: { selectedIndices, endorsementIndices, memberCount: members.length }
17769
+ };
17770
+ }, "classifyShareManifest");
17771
+ var SharePayloadValidator = SharePayloadValidatorShape.superRefine((payload, ctx) => {
17772
+ const result = classifyShareManifest(payload);
17773
+ if (!result.ok) {
17177
17774
  ctx.addIssue({
17178
17775
  code: "custom",
17179
- path: ["mode"],
17180
- message: "issuer-signed publication cannot include signing-authority fields"
17776
+ message: result.message,
17777
+ path: result.path,
17778
+ params: { shareLinkCode: result.code }
17181
17779
  });
17182
17780
  }
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) {
17781
+ });
17782
+ var ShareRecoverySelectionValidator = external_exports.object({
17783
+ ref: external_exports.string().min(1).max(MAX_SHARE_SOURCE_URI_CHARS),
17784
+ order: external_exports.number().int().min(0).max(MAX_SELECTED_CREDENTIALS - 1)
17785
+ }).strict();
17786
+ var ShareRecoveryEndorsementValidator = external_exports.object({ targetRef: external_exports.string().min(1).max(MAX_SHARE_SOURCE_URI_CHARS) }).strict();
17787
+ var ShareRecoveryPlaintextValidator = external_exports.object({
17788
+ protocol: external_exports.literal(SHARE_RECOVERY_PROTOCOL),
17789
+ shareId: ShareLinkIdValidator,
17790
+ ownerProfileId: external_exports.string().min(1).max(128),
17791
+ createdAt: external_exports.iso.datetime(),
17792
+ latest: external_exports.object({ contentVersion: safeVersion, key: ShareContentKeyValidator }).strict(),
17793
+ selection: ShareRecoverySelectionValidator.array().min(1).max(MAX_SELECTED_CREDENTIALS),
17794
+ endorsements: ShareRecoveryEndorsementValidator.array().max(MAX_ENDORSEMENTS).default([])
17795
+ }).strict().superRefine((recovery, ctx) => {
17796
+ const orders = /* @__PURE__ */ new Set();
17797
+ recovery.selection.forEach((entry, index) => {
17798
+ if (entry.order >= recovery.selection.length) {
17192
17799
  ctx.addIssue({
17193
17800
  code: "custom",
17194
- path: ["credential"],
17195
- message: "credential is required for signing-authority publication"
17801
+ message: "order must be within the selection bounds",
17802
+ path: ["selection", index, "order"]
17196
17803
  });
17197
17804
  }
17198
- if (!input.signingAuthority) {
17805
+ if (orders.has(entry.order)) {
17199
17806
  ctx.addIssue({
17200
17807
  code: "custom",
17201
- path: ["signingAuthority"],
17202
- message: "signingAuthority is required for signing-authority publication"
17808
+ message: "order must be unique within the selection",
17809
+ path: ["selection", index, "order"]
17203
17810
  });
17204
17811
  }
17812
+ orders.add(entry.order);
17813
+ });
17814
+ });
17815
+ var ShareOwnerRecoveryValidator = JWEValidator.refine(
17816
+ (value) => utf8ByteLength(JSON.stringify(value)) <= MAX_SHARE_RECOVERY_JWE_BYTES,
17817
+ { message: `serialized recovery JWE must be at most ${MAX_SHARE_RECOVERY_JWE_BYTES} bytes` }
17818
+ );
17819
+ var ShareLinkStatusValidator = external_exports.enum(["pending", "active", "stopped"]);
17820
+ var ShareContentStateValidator = external_exports.enum(["staging", "finalized", "content_missing"]);
17821
+ var ShareLinkValidator = external_exports.object({
17822
+ id: ShareLinkIdValidator,
17823
+ title: external_exports.string().min(1).max(120),
17824
+ note: external_exports.string().max(500).optional(),
17825
+ selectedCount: external_exports.number().int().min(1).max(MAX_SELECTED_CREDENTIALS),
17826
+ version: safeVersion,
17827
+ contentVersion: safeVersion,
17828
+ status: ShareLinkStatusValidator,
17829
+ contentState: ShareContentStateValidator,
17830
+ createdAt: external_exports.iso.datetime(),
17831
+ updatedAt: external_exports.iso.datetime(),
17832
+ expiresAt: external_exports.iso.datetime().nullable(),
17833
+ stoppedAt: external_exports.iso.datetime().nullable(),
17834
+ lastViewedAt: external_exports.iso.datetime().nullable(),
17835
+ viewCount: external_exports.number().int().min(0).optional(),
17836
+ passcodeProtected: external_exports.boolean(),
17837
+ notifyOnView: external_exports.boolean(),
17838
+ minorPolicy: external_exports.object({
17839
+ isMinor: external_exports.boolean().nullable(),
17840
+ policyResolved: external_exports.boolean(),
17841
+ defaultExpiryDays: external_exports.union([external_exports.literal(30), external_exports.literal(365)]),
17842
+ viewCountingEnabled: external_exports.boolean()
17843
+ }),
17844
+ /**
17845
+ * Guarded application/API URL for the content. Optional because owner APIs in
17846
+ * D1 have no public resolve/content endpoint yet; it must never be a
17847
+ * LearnCloud object URL or carry a fabricated decryption key.
17848
+ */
17849
+ contentUrl: external_exports.string().optional()
17850
+ });
17851
+ var clientRequestId = external_exports.string().uuid();
17852
+ var CreateShareLinkInputValidator = external_exports.object({
17853
+ id: ShareLinkIdValidator,
17854
+ clientRequestId,
17855
+ title: external_exports.string().min(1).max(120),
17856
+ note: external_exports.string().max(500).optional(),
17857
+ expiresAt: external_exports.iso.datetime().nullable().optional(),
17858
+ passcode: external_exports.string().min(8).max(64).optional(),
17859
+ notifyOnView: external_exports.boolean().default(false),
17860
+ selectedCount: external_exports.number().int().min(1).max(MAX_SELECTED_CREDENTIALS),
17861
+ contentVersion: external_exports.literal(1),
17862
+ envelope: ShareEnvelopeValidator,
17863
+ ownerEncryptedRecovery: ShareOwnerRecoveryValidator
17864
+ }).strict();
17865
+ var UpdateShareLinkInputValidator = external_exports.object({
17866
+ id: ShareLinkIdValidator,
17867
+ expectedVersion: safeVersion,
17868
+ clientRequestId,
17869
+ title: external_exports.string().min(1).max(120).optional(),
17870
+ note: external_exports.string().max(500).nullable().optional(),
17871
+ expiresAt: external_exports.iso.datetime().nullable().optional(),
17872
+ /** Omitted preserves the current passcode, null removes it, and a string replaces it. */
17873
+ passcode: external_exports.string().min(8).max(64).nullable().optional(),
17874
+ notifyOnView: external_exports.boolean().optional(),
17875
+ contentVersion: safeVersion.optional(),
17876
+ selectedCount: external_exports.number().int().min(1).max(MAX_SELECTED_CREDENTIALS).optional(),
17877
+ envelope: ShareEnvelopeValidator.optional(),
17878
+ ownerEncryptedRecovery: ShareOwnerRecoveryValidator.optional()
17879
+ }).strict().superRefine((value, ctx) => {
17880
+ const provided = [
17881
+ value.contentVersion,
17882
+ value.selectedCount,
17883
+ value.envelope,
17884
+ value.ownerEncryptedRecovery
17885
+ ].filter((field) => field !== void 0).length;
17886
+ if (provided !== 0 && provided !== 4) {
17887
+ ctx.addIssue({
17888
+ code: "custom",
17889
+ message: "content replacement requires contentVersion, selectedCount, envelope and ownerEncryptedRecovery together"
17890
+ });
17205
17891
  }
17206
17892
  });
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"
17893
+ var ShareLinkIdInputValidator = external_exports.object({ id: ShareLinkIdValidator }).strict();
17894
+ var ShareLinkOperationKeyInputValidator = external_exports.object({ id: ShareLinkIdValidator, operationId: external_exports.string().uuid() }).strict();
17895
+ var ShareLinkOwnerCommitOutputValidator = external_exports.discriminatedUnion("status", [
17896
+ external_exports.object({ status: external_exports.literal("completed"), share: ShareLinkValidator }).strict(),
17897
+ external_exports.object({
17898
+ status: external_exports.literal("pending"),
17899
+ id: ShareLinkIdValidator,
17900
+ operationId: external_exports.string().uuid()
17901
+ }).strict()
17213
17902
  ]);
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
17903
+ var ShareLinkOwnerStatusOutputValidator = external_exports.discriminatedUnion("status", [
17904
+ external_exports.object({ status: external_exports.literal("found"), share: ShareLinkValidator }).strict(),
17905
+ external_exports.object({
17906
+ status: external_exports.literal("pending"),
17907
+ id: ShareLinkIdValidator,
17908
+ operationId: external_exports.string().uuid()
17909
+ }).strict(),
17910
+ external_exports.object({ status: external_exports.literal("not_found"), id: ShareLinkIdValidator }).strict()
17259
17911
  ]);
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"
17912
+ var ShareLinkOwnerRecoveryOutputValidator = external_exports.object({ recovery: ShareOwnerRecoveryValidator }).strict();
17913
+ var ShareLinkOwnerContentOutputValidator = external_exports.object({
17914
+ id: ShareLinkIdValidator,
17915
+ contentVersion: safeVersion,
17916
+ envelope: ShareEnvelopeValidator
17917
+ }).strict();
17918
+ var ResolveShareLinkInputValidator = external_exports.object({
17919
+ id: ShareLinkIdValidator,
17920
+ /** Sent only in a POST body; it must never be placed in a share URL. */
17921
+ passcode: external_exports.string().min(4).max(64).optional()
17922
+ }).strict();
17923
+ var ShareLinkPublicStateValidator = external_exports.discriminatedUnion("state", [
17924
+ external_exports.object({
17925
+ state: external_exports.literal("passcode_required"),
17926
+ id: ShareLinkIdValidator
17927
+ }).strict(),
17928
+ external_exports.object({ state: external_exports.literal("try_later"), id: ShareLinkIdValidator }).strict(),
17929
+ external_exports.object({
17930
+ state: external_exports.literal("active"),
17931
+ id: ShareLinkIdValidator,
17932
+ title: external_exports.string().max(120),
17933
+ note: external_exports.string().max(500).optional(),
17934
+ selectedCount: external_exports.number().int().min(1).max(MAX_SELECTED_CREDENTIALS),
17935
+ contentVersion: safeVersion,
17936
+ contentUrl: external_exports.string(),
17937
+ sharer: external_exports.object({
17938
+ displayName: external_exports.string().max(120),
17939
+ avatar: external_exports.string().max(2048).optional()
17940
+ }),
17941
+ createdAt: external_exports.iso.datetime(),
17942
+ updatedAt: external_exports.iso.datetime(),
17943
+ expiresAt: external_exports.iso.datetime().nullable()
17944
+ }).strict(),
17945
+ external_exports.object({
17946
+ state: external_exports.literal("expired"),
17947
+ id: ShareLinkIdValidator,
17948
+ expiresAt: external_exports.iso.datetime()
17949
+ }).strict(),
17950
+ external_exports.object({
17951
+ state: external_exports.literal("stopped"),
17952
+ id: ShareLinkIdValidator,
17953
+ stoppedAt: external_exports.iso.datetime()
17954
+ }).strict(),
17955
+ external_exports.object({ state: external_exports.literal("not_found"), id: ShareLinkIdValidator }).strict()
17272
17956
  ]);
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()
17957
+ var ListShareLinksInputValidator = external_exports.object({
17958
+ limit: external_exports.number().int().min(1).max(50).default(25),
17959
+ cursor: external_exports.string().max(512).optional()
17960
+ }).strict();
17961
+ var PaginatedShareLinksValidator = PaginationResponseValidator.extend({
17962
+ records: ShareLinkValidator.array()
17291
17963
  });
17292
- var CredentialRefreshResultValidator = external_exports.discriminatedUnion("status", [
17293
- CredentialRefreshUpdatedResultValidator,
17294
- CredentialRefreshUnchangedResultValidator,
17295
- CredentialRefreshUnsupportedResultValidator,
17296
- CredentialRefreshFailedResultValidator
17297
- ]);
17964
+ var AcknowledgeViewInputValidator = external_exports.object({
17965
+ receipt: external_exports.string().min(22).max(128).regex(/^[A-Za-z0-9_-]+$/)
17966
+ }).strict();
17967
+ var AcknowledgeViewOutputValidator = external_exports.object({ ok: external_exports.literal(true) }).strict();
17968
+ var SHARE_VIEW_RECEIPT_TTL_SECONDS = 10 * 60;
17969
+ var ShareLinkPublicContentViewValidator = external_exports.object({
17970
+ id: ShareLinkIdValidator,
17971
+ contentVersion: safeVersion,
17972
+ envelope: ShareEnvelopeValidator,
17973
+ contentUrl: external_exports.string(),
17974
+ receipt: external_exports.string().min(22).max(128).regex(/^[A-Za-z0-9_-]+$/)
17975
+ }).strict();
17298
17976
 
17299
17977
  // src/plugin.ts
17300
17978
  var import_helpers = require("@learncard/helpers");
@@ -17912,27 +18590,40 @@ var issueCredentialWithNetworkStatus = /* @__PURE__ */ __name(async (learnCard,
17912
18590
  await appendNetworkCredentialStatus(client, credential, statusPurposes)
17913
18591
  );
17914
18592
  }, "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
- );
18593
+ var injectManagedRefreshService = /* @__PURE__ */ __name((credential, refreshService) => (0, import_helpers.injectManagedRefreshService)(credential, refreshService), "injectManagedRefreshService");
18594
+ var getCredentialSubjectIds = /* @__PURE__ */ __name((vc) => {
18595
+ const subject = vc.credentialSubject;
18596
+ const subjects = Array.isArray(subject) ? subject : subject ? [subject] : [];
18597
+ return subjects.flatMap((entry) => {
18598
+ const id = entry?.id;
18599
+ return typeof id === "string" && id.length > 0 ? [id] : [];
18600
+ });
18601
+ }, "getCredentialSubjectIds");
18602
+ var buildManagedRefreshReceipt = /* @__PURE__ */ __name((vc, allocation, credentialId, fallbackHolderDid, fallbackIssuerDid) => {
18603
+ const issuerDid = (0, import_helpers.getCredentialIssuerId)(vc) ?? fallbackIssuerDid;
18604
+ const holderDid = getCredentialSubjectIds(vc)[0] ?? fallbackHolderDid;
18605
+ const rawStatus = vc.credentialStatus;
18606
+ const hasStatus = rawStatus !== void 0 && rawStatus !== null && !(Array.isArray(rawStatus) && rawStatus.length === 0);
17930
18607
  return {
17931
- ...credential,
17932
- "@context": hasMapping ? contextList : [...contextList, MANAGED_REFRESH_SERVICE_CONTEXT],
17933
- refreshService
17934
- };
17935
- }, "injectManagedRefreshService");
18608
+ refreshId: allocation.refreshId,
18609
+ refreshService: allocation.refreshService,
18610
+ credentialId: typeof vc.id === "string" && vc.id.length > 0 ? vc.id : credentialId,
18611
+ issuerDid,
18612
+ holderDid,
18613
+ ...hasStatus ? {
18614
+ credentialStatus: rawStatus
18615
+ } : {}
18616
+ };
18617
+ }, "buildManagedRefreshReceipt");
18618
+ var ACT_AS_TARGET_NOT_FOUND_MESSAGE = "Act-as target profile not found";
18619
+ var isActAsDenial = /* @__PURE__ */ __name((error51) => {
18620
+ const code = error51?.data?.code;
18621
+ if (code === "FORBIDDEN" || code === "BAD_REQUEST") return true;
18622
+ if (code === "NOT_FOUND") {
18623
+ return error51?.message === ACT_AS_TARGET_NOT_FOUND_MESSAGE;
18624
+ }
18625
+ return false;
18626
+ }, "isActAsDenial");
17936
18627
  async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, options) {
17937
18628
  const apiToken = typeof apiTokenOrOptions === "string" ? apiTokenOrOptions : void 0;
17938
18629
  const resolvedOptions = (typeof apiTokenOrOptions === "object" ? apiTokenOrOptions : options) ?? {};
@@ -17940,8 +18631,10 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17940
18631
  guardianApprovalGetter,
17941
18632
  extraHeaders,
17942
18633
  trustedFederationHosts,
17943
- allowLocalhostFederation
18634
+ allowLocalhostFederation,
18635
+ actAs
17944
18636
  } = resolvedOptions;
18637
+ const mergedExtraHeaders = actAs ? { ...extraHeaders, [ACT_AS_HEADER]: actAs } : extraHeaders;
17945
18638
  const serviceUrl = new URL(url2);
17946
18639
  const serviceIsLocalhost = isLocalhostHost(serviceUrl.hostname);
17947
18640
  const federationConfig = {
@@ -17959,7 +18652,7 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17959
18652
  learnCard?.debug?.("LCN: no local DID available at init; will fetch from profile");
17960
18653
  }
17961
18654
  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)(
18655
+ const client = apiToken ? await (0, import_network_brain_client.getApiTokenClient)(url2, apiToken, guardianApprovalGetter, mergedExtraHeaders) : await (0, import_network_brain_client.getClient)(
17963
18656
  url2,
17964
18657
  async (challenge) => {
17965
18658
  const jwt2 = await learnCard.invoke.getDidAuthVp({
@@ -17970,7 +18663,7 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
17970
18663
  return jwt2;
17971
18664
  },
17972
18665
  guardianApprovalGetter,
17973
- extraHeaders
18666
+ mergedExtraHeaders
17974
18667
  );
17975
18668
  let userData;
17976
18669
  learnCard?.debug?.("LCN: initial getProfile query starting", { apiToken: !!apiToken });
@@ -18173,6 +18866,23 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18173
18866
  getManagedProfiles: /* @__PURE__ */ __name(async (_learnCard, options2 = {}) => {
18174
18867
  return client.profileManager.getManagedProfiles.query(options2);
18175
18868
  }, "getManagedProfiles"),
18869
+ actAs: /* @__PURE__ */ __name(async (_learnCard, profileId) => {
18870
+ const actingOptions = {
18871
+ ...resolvedOptions,
18872
+ actAs: profileId
18873
+ };
18874
+ const actingPlugin = apiToken ? await getLearnCardNetworkPlugin(_learnCard, url2, apiToken, actingOptions) : await getLearnCardNetworkPlugin(_learnCard, url2, actingOptions);
18875
+ try {
18876
+ await actingPlugin.methods.getLCNClient(_learnCard).profile.getProfile.query();
18877
+ } catch (error51) {
18878
+ if (isActAsDenial(error51)) {
18879
+ const message = error51 instanceof Error ? error51.message : "Act-as request was denied.";
18880
+ throw new Error(message, { cause: error51 });
18881
+ }
18882
+ _learnCard.debug?.("LCN actAs: getProfile failed (non-fatal)", error51);
18883
+ }
18884
+ return _learnCard.addPlugin(actingPlugin);
18885
+ }, "actAs"),
18176
18886
  claimPendingGuardianLinks: /* @__PURE__ */ __name(async () => {
18177
18887
  await ensureUser();
18178
18888
  return client.inbox.claimPendingGuardianLinks.mutate({});
@@ -18326,6 +19036,49 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18326
19036
  await ensureUser();
18327
19037
  return client.profile.invalidateInvite.mutate({ challenge });
18328
19038
  }, "invalidateInvite"),
19039
+ createShareLink: /* @__PURE__ */ __name(async (_learnCard, input) => {
19040
+ await ensureUser();
19041
+ return client.shareLinks.create.mutate(input);
19042
+ }, "createShareLink"),
19043
+ updateShareLink: /* @__PURE__ */ __name(async (_learnCard, input) => {
19044
+ await ensureUser();
19045
+ return client.shareLinks.update.mutate(input);
19046
+ }, "updateShareLink"),
19047
+ revokeShareLink: /* @__PURE__ */ __name(async (_learnCard, input) => {
19048
+ await ensureUser();
19049
+ return client.shareLinks.revoke.mutate(input);
19050
+ }, "revokeShareLink"),
19051
+ getShareLink: /* @__PURE__ */ __name(async (_learnCard, id) => {
19052
+ await ensureUser();
19053
+ return client.shareLinks.get.query({ id });
19054
+ }, "getShareLink"),
19055
+ getShareLinkOperationStatus: /* @__PURE__ */ __name(async (_learnCard, input) => {
19056
+ await ensureUser();
19057
+ return client.shareLinks.getOperationStatus.query(input);
19058
+ }, "getShareLinkOperationStatus"),
19059
+ retryShareLinkOperation: /* @__PURE__ */ __name(async (_learnCard, input) => {
19060
+ await ensureUser();
19061
+ return client.shareLinks.retry.mutate(input);
19062
+ }, "retryShareLinkOperation"),
19063
+ getShareLinkRecovery: /* @__PURE__ */ __name(async (_learnCard, id) => {
19064
+ await ensureUser();
19065
+ return client.shareLinks.getRecovery.query({ id });
19066
+ }, "getShareLinkRecovery"),
19067
+ getShareLinkOwnerContent: /* @__PURE__ */ __name(async (_learnCard, id) => {
19068
+ await ensureUser();
19069
+ return client.shareLinks.getContent.query({ id });
19070
+ }, "getShareLinkOwnerContent"),
19071
+ listShareLinks: /* @__PURE__ */ __name(async (_learnCard, input) => {
19072
+ await ensureUser();
19073
+ return client.shareLinks.list.query(input);
19074
+ }, "listShareLinks"),
19075
+ // Anonymous public methods: deliberately NO `ensureUser()`. A viewer
19076
+ // has no account and must not need one.
19077
+ // POST keeps an optional passcode in the request body and out of URLs,
19078
+ // access logs, browser history and referrers.
19079
+ resolveShareLink: /* @__PURE__ */ __name(async (_learnCard, id, passcode) => client.publicShareLinks.resolve.mutate({ id, passcode }), "resolveShareLink"),
19080
+ getShareLinkContent: /* @__PURE__ */ __name(async (_learnCard, id, passcode) => client.publicShareLinks.content.mutate({ id, passcode }), "getShareLinkContent"),
19081
+ acknowledgeShareLinkView: /* @__PURE__ */ __name(async (_learnCard, receipt) => client.publicShareLinks.acknowledgeView.mutate({ receipt }), "acknowledgeShareLinkView"),
18329
19082
  blockProfile: /* @__PURE__ */ __name(async (_learnCard, profileId) => {
18330
19083
  await ensureUser();
18331
19084
  return client.profile.blockProfile.mutate({ profileId });
@@ -18440,12 +19193,15 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18440
19193
  await ensureUser();
18441
19194
  return client.credential.deleteCredential.mutate({ uri });
18442
19195
  }, "deleteCredential"),
18443
- sendPresentation: /* @__PURE__ */ __name(async (_learnCard, profileId, vp, encrypt = true) => {
19196
+ sendPresentation: /* @__PURE__ */ __name(async (_learnCard, profileId, vp, metadataOrEncrypt, encrypt) => {
18444
19197
  await ensureUser();
18445
- if (!encrypt) {
19198
+ const metadata = typeof metadataOrEncrypt === "object" ? metadataOrEncrypt : void 0;
19199
+ const shouldEncrypt = typeof metadataOrEncrypt === "boolean" ? metadataOrEncrypt : encrypt ?? true;
19200
+ if (!shouldEncrypt) {
18446
19201
  return client.presentation.sendPresentation.mutate({
18447
19202
  profileId,
18448
- presentation: vp
19203
+ presentation: vp,
19204
+ metadata
18449
19205
  });
18450
19206
  }
18451
19207
  const target = await _learnCard.invoke.getProfile(profileId);
@@ -18455,7 +19211,11 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18455
19211
  _learnCard.id.did(),
18456
19212
  target.did
18457
19213
  ]);
18458
- return client.presentation.sendPresentation.mutate({ profileId, presentation });
19214
+ return client.presentation.sendPresentation.mutate({
19215
+ profileId,
19216
+ presentation,
19217
+ metadata
19218
+ });
18459
19219
  }, "sendPresentation"),
18460
19220
  acceptPresentation: /* @__PURE__ */ __name(async (_learnCard, uri) => {
18461
19221
  await ensureUser();
@@ -18782,15 +19542,14 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18782
19542
  boost = options2.overideFn(boost);
18783
19543
  }
18784
19544
  const enableRefresh = typeof options2 === "object" && options2.enableRefresh === true;
18785
- let managedRefreshId;
19545
+ let refreshAllocation;
18786
19546
  if (enableRefresh) {
18787
19547
  if (!boost.id) boost.id = `urn:uuid:${crypto.randomUUID()}`;
18788
- const allocation = await client.credentialRefresh.allocateCredentialRefresh.mutate({
19548
+ refreshAllocation = await client.credentialRefresh.allocateCredentialRefresh.mutate({
18789
19549
  holder: { profileId, did: targetProfile.did },
18790
19550
  credentialId: boost.id
18791
19551
  });
18792
- managedRefreshId = allocation.refreshId;
18793
- boost = injectManagedRefreshService(boost, allocation.refreshService);
19552
+ boost = injectManagedRefreshService(boost, refreshAllocation.refreshService);
18794
19553
  }
18795
19554
  const statusPurposes = typeof options2 === "object" ? options2.statusPurposes : void 0;
18796
19555
  const vc = await issueCredentialWithNetworkStatus(
@@ -18799,13 +19558,23 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18799
19558
  boost,
18800
19559
  statusPurposes
18801
19560
  );
18802
- if (managedRefreshId) {
18803
- return client.credentialRefresh.sendRefreshableCredential.mutate({
18804
- refreshId: managedRefreshId,
19561
+ if (refreshAllocation) {
19562
+ const credentialUri = await client.credentialRefresh.sendRefreshableCredential.mutate({
19563
+ refreshId: refreshAllocation.refreshId,
18805
19564
  credential: vc,
18806
19565
  boostUri,
18807
19566
  ...typeof options2 === "object" && options2.skipNotification ? { skipNotification: true } : {}
18808
19567
  });
19568
+ return {
19569
+ credentialUri,
19570
+ refresh: buildManagedRefreshReceipt(
19571
+ vc,
19572
+ refreshAllocation,
19573
+ boost.id ?? "",
19574
+ targetProfile.did,
19575
+ _learnCard.id.did()
19576
+ )
19577
+ };
18809
19578
  }
18810
19579
  if (typeof options2 === "object" && !options2.encrypt || !options2) {
18811
19580
  return client.boost.sendBoost.mutate({
@@ -18871,6 +19640,94 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18871
19640
  }, "claimBoostWithLink"),
18872
19641
  send: /* @__PURE__ */ __name(async (_learnCard, input) => {
18873
19642
  await ensureUser();
19643
+ if (input.type === "boost" && input.refresh === true) {
19644
+ const isEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input.recipient);
19645
+ const isPhone = /^\+?[\d\s-]{10,}$/.test(input.recipient.replace(/[\s-]/g, ""));
19646
+ if (isEmail || isPhone) return client.boost.send.mutate(input);
19647
+ const canIssueLocally = "issueCredential" in _learnCard.invoke;
19648
+ if (canIssueLocally && !input.signedCredential && (input.templateUri || input.template)) {
19649
+ let boost;
19650
+ if (input.templateUri) {
19651
+ const result = await getBoostTemplateForIssuance(
19652
+ _learnCard,
19653
+ input.templateUri
19654
+ );
19655
+ const data = await UnsignedVCValidator.spa(result);
19656
+ if (!data.success)
19657
+ throw new Error("Did not get a valid boost from URI");
19658
+ boost = data.data;
19659
+ } else {
19660
+ boost = JSON.parse(
19661
+ JSON.stringify(input.template.credential)
19662
+ );
19663
+ }
19664
+ const prepared = await client.boost.prepareRefreshableSend.mutate({
19665
+ recipient: input.recipient,
19666
+ ...input.templateUri ? { templateUri: input.templateUri } : { template: input.template },
19667
+ ...input.contractUri ? { contractUri: input.contractUri } : {},
19668
+ ...input.templateData ? { templateData: input.templateData } : {},
19669
+ ...input.integrationId ? { integrationId: input.integrationId } : {},
19670
+ ...boost.id ? { credentialId: boost.id } : {},
19671
+ ...input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}
19672
+ });
19673
+ if (prepared.completed) return prepared.completed;
19674
+ const boostString = JSON.stringify(boost);
19675
+ const allowAutoAppendEvidence = !hasDynamicEvidenceTemplate(boostString);
19676
+ if (input.templateData && Object.keys(input.templateData).length > 0) {
19677
+ try {
19678
+ const rendered = renderTemplateJson(
19679
+ boostString,
19680
+ input.templateData
19681
+ );
19682
+ boost = JSON.parse(rendered);
19683
+ boost = appendTemplateEvidence(
19684
+ boost,
19685
+ input.templateData,
19686
+ allowAutoAppendEvidence
19687
+ );
19688
+ } catch (error51) {
19689
+ throw new Error(
19690
+ `Failed to apply template data: ${error51 instanceof Error ? error51.message : "Unknown error"}`,
19691
+ { cause: error51 }
19692
+ );
19693
+ }
19694
+ }
19695
+ if ((0, import_helpers.isVC2Format)(boost)) {
19696
+ boost.validFrom = (/* @__PURE__ */ new Date()).toISOString();
19697
+ } else {
19698
+ boost.issuanceDate = (/* @__PURE__ */ new Date()).toISOString();
19699
+ }
19700
+ boost.issuer = _learnCard.id.did();
19701
+ if (Array.isArray(boost.credentialSubject)) {
19702
+ boost.credentialSubject = boost.credentialSubject.map((subject) => ({
19703
+ ...subject,
19704
+ id: prepared.holderDid
19705
+ }));
19706
+ } else {
19707
+ boost.credentialSubject = {
19708
+ ...boost.credentialSubject,
19709
+ id: prepared.holderDid
19710
+ };
19711
+ }
19712
+ boost.id = prepared.credentialId;
19713
+ if (boost.type?.includes("BoostCredential"))
19714
+ boost.boostId = prepared.boostUri;
19715
+ boost = injectManagedRefreshService(boost, prepared.refreshService);
19716
+ const signedCredential = await issueCredentialWithNetworkStatus(
19717
+ _learnCard,
19718
+ client,
19719
+ boost
19720
+ );
19721
+ return client.boost.send.mutate({
19722
+ ...input,
19723
+ template: void 0,
19724
+ templateUri: prepared.boostUri,
19725
+ signedCredential,
19726
+ refresh: true
19727
+ });
19728
+ }
19729
+ return client.boost.send.mutate(input);
19730
+ }
18874
19731
  if (input.type === "boost") {
18875
19732
  const recipient = input.recipient;
18876
19733
  const isDid = recipient.startsWith("did:");
@@ -19277,6 +20134,37 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
19277
20134
  await ensureUser();
19278
20135
  return client.inbox.issue.mutate(issueInboxCredential);
19279
20136
  }, "sendCredentialViaInbox"),
20137
+ sendCredentialsViaInbox: /* @__PURE__ */ __name(async (_learnCard, batch) => {
20138
+ await ensureUser();
20139
+ return client.inbox.issueBatch.mutate(batch);
20140
+ }, "sendCredentialsViaInbox"),
20141
+ sendCredentialBatchViaInbox: /* @__PURE__ */ __name(async (_learnCard, batch) => {
20142
+ await ensureUser();
20143
+ return client.inbox.issueBatch.mutate(batch);
20144
+ }, "sendCredentialBatchViaInbox"),
20145
+ waitForInboxCredentialBatch: /* @__PURE__ */ __name(async (_learnCard, batchId, options2) => {
20146
+ await ensureUser();
20147
+ return waitForInboxCredentialBatch(
20148
+ (signal) => client.inbox.getBatch.query({ batchId }, { signal }),
20149
+ options2
20150
+ );
20151
+ }, "waitForInboxCredentialBatch"),
20152
+ sendCredentialsViaInboxAndWait: /* @__PURE__ */ __name(async (_learnCard, batch, options2) => {
20153
+ await ensureUser();
20154
+ if (options2?.signal?.aborted) throw options2.signal.reason;
20155
+ const receipt = await client.inbox.issueBatch.mutate(batch, {
20156
+ signal: options2?.signal
20157
+ });
20158
+ await options2?.onSubmitted?.(receipt);
20159
+ return waitForInboxCredentialBatch(
20160
+ (signal) => client.inbox.getBatch.query({ batchId: receipt.batchId }, { signal }),
20161
+ options2
20162
+ );
20163
+ }, "sendCredentialsViaInboxAndWait"),
20164
+ getInboxCredentialBatch: /* @__PURE__ */ __name(async (_learnCard, batchId) => {
20165
+ await ensureUser();
20166
+ return client.inbox.getBatch.query({ batchId });
20167
+ }, "getInboxCredentialBatch"),
19280
20168
  getMySentInboxCredentials: /* @__PURE__ */ __name(async (_learnCard, options2) => {
19281
20169
  await ensureUser();
19282
20170
  return client.inbox.getMyIssuedCredentials.query(options2);