@learncard/network-plugin 2.13.17 → 2.14.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.
@@ -15894,7 +15894,10 @@ var SendOptionsValidator = external_exports.object({
15894
15894
  webhookUrl: external_exports.string().url().optional().describe("Webhook URL to receive claim notifications"),
15895
15895
  suppressDelivery: external_exports.boolean().optional().describe("If true, returns claimUrl without sending email/SMS"),
15896
15896
  branding: SendBrandingOptionsValidator.optional().describe("Branding for email/SMS delivery"),
15897
- guardianEmail: external_exports.string().email().optional().describe("Guardian email that must approve before student can claim")
15897
+ guardianEmail: external_exports.string().email().optional().describe("Guardian email that must approve before student can claim"),
15898
+ expiresInDays: external_exports.number().int().min(1).max(720).optional().describe(
15899
+ "How many days the credential stays claimable in the Universal Inbox (default 30). Does not change the credential validity period."
15900
+ )
15898
15901
  });
15899
15902
  var SendBoostInputValidator = external_exports.object({
15900
15903
  type: external_exports.literal("boost"),
@@ -16189,7 +16192,8 @@ var LCNNotificationTypeEnumValidator = external_exports.enum([
16189
16192
  "APP_NOTIFICATION",
16190
16193
  "CREDENTIAL_REVOKED",
16191
16194
  "CREDENTIAL_SUSPENDED",
16192
- "CREDENTIAL_UNSUSPENDED"
16195
+ "CREDENTIAL_UNSUSPENDED",
16196
+ "CREDENTIAL_REFRESHED"
16193
16197
  ]);
16194
16198
  var LCNNotificationMessageValidator = external_exports.object({
16195
16199
  title: external_exports.string().optional(),
@@ -16321,12 +16325,16 @@ var CreateContactMethodSessionResponseValidator = external_exports.object({
16321
16325
  });
16322
16326
  var InboxCredentialValidator = external_exports.object({
16323
16327
  id: external_exports.string(),
16324
- credential: external_exports.string(),
16328
+ credential: external_exports.string().optional(),
16325
16329
  isSigned: external_exports.boolean(),
16326
16330
  currentStatus: LCNInboxStatusEnumValidator,
16327
16331
  isAccepted: external_exports.boolean().optional(),
16328
16332
  expiresAt: external_exports.string(),
16329
16333
  createdAt: external_exports.string(),
16334
+ finalizedAt: external_exports.string().optional(),
16335
+ expiredAt: external_exports.string().optional(),
16336
+ credentialName: external_exports.string().optional(),
16337
+ achievementType: external_exports.string().optional(),
16330
16338
  issuerDid: external_exports.string(),
16331
16339
  webhookUrl: external_exports.string().optional(),
16332
16340
  boostUri: external_exports.string().optional(),
@@ -16380,7 +16388,9 @@ var IssueInboxCredentialValidator = external_exports.object({
16380
16388
  "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."
16381
16389
  ),
16382
16390
  webhookUrl: external_exports.string().url().optional().describe("The webhook URL to receive credential issuance events."),
16383
- expiresInDays: external_exports.number().min(1).max(365).optional().describe("The number of days the credential will be valid for."),
16391
+ expiresInDays: external_exports.number().int().min(1).max(720).optional().describe(
16392
+ "How many days the encrypted inbox payload remains claimable. This does not change the credential validity period."
16393
+ ),
16384
16394
  templateData: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe(
16385
16395
  "Template data to render into the boost credential template using Mustache syntax. Only used when boostUri is provided."
16386
16396
  ),
@@ -16443,6 +16453,9 @@ var ClaimInboxCredentialValidator = external_exports.object({
16443
16453
  credential: VCValidator.or(VPValidator).or(UnsignedVCValidator).or(CredentialNameRefValidator).describe("The credential to issue, or a { name } reference to resolve a boost template."),
16444
16454
  configuration: external_exports.object({
16445
16455
  publishableKey: external_exports.string(),
16456
+ expiresInDays: external_exports.number().int().min(1).max(720).optional().describe(
16457
+ "Inbox claim window in days. Defaults to 720; use a shorter window for sensitive records."
16458
+ ),
16446
16459
  signingAuthorityName: external_exports.string().optional(),
16447
16460
  listingId: external_exports.string().optional(),
16448
16461
  listingSlug: external_exports.string().optional()
@@ -17069,6 +17082,191 @@ var inAppMessagesFlagValidator = external_exports.object({
17069
17082
  version: external_exports.number().default(1),
17070
17083
  messages: external_exports.array(inAppMessageValidator).default([])
17071
17084
  }).passthrough();
17085
+ var LearnCardRefreshAuthorizationValidator = external_exports.object({ type: external_exports.literal("LearnCardDIDAuth") }).catchall(external_exports.any());
17086
+ var ManagedCredentialRefreshServiceValidator = external_exports.object({
17087
+ id: external_exports.string().min(1),
17088
+ type: external_exports.literal("LearnCardCredentialRefresh2026"),
17089
+ authorization: LearnCardRefreshAuthorizationValidator.optional()
17090
+ }).catchall(external_exports.any());
17091
+ var StandardCredentialRefreshServiceValidator = external_exports.object({
17092
+ id: external_exports.string().min(1),
17093
+ type: external_exports.literal("1EdTechCredentialRefresh")
17094
+ }).catchall(external_exports.any());
17095
+ var SupportedCredentialRefreshServiceValidator = external_exports.union([
17096
+ ManagedCredentialRefreshServiceValidator,
17097
+ StandardCredentialRefreshServiceValidator
17098
+ ]);
17099
+ var AllocateCredentialRefreshInputValidator = external_exports.object({
17100
+ holder: external_exports.object({
17101
+ profileId: external_exports.string().optional(),
17102
+ did: external_exports.string().min(1)
17103
+ }),
17104
+ credentialId: external_exports.string().min(1)
17105
+ });
17106
+ var AllocateCredentialRefreshResultValidator = external_exports.object({
17107
+ refreshId: external_exports.string().min(1),
17108
+ refreshService: ManagedCredentialRefreshServiceValidator.extend({
17109
+ authorization: LearnCardRefreshAuthorizationValidator
17110
+ })
17111
+ });
17112
+ var CredentialRefreshSigningModeValidator = external_exports.enum(["issuer-signed", "signing-authority"]);
17113
+ var PublishCredentialRefreshBaseFields = {
17114
+ refreshId: external_exports.string().min(1),
17115
+ notifyHolder: external_exports.boolean().optional(),
17116
+ updateSummary: external_exports.string().optional(),
17117
+ idempotencyKey: external_exports.string().optional()
17118
+ };
17119
+ var PublishIssuerSignedRefreshValidator = external_exports.object({
17120
+ ...PublishCredentialRefreshBaseFields,
17121
+ mode: external_exports.literal("issuer-signed"),
17122
+ signedCredential: VCValidator
17123
+ });
17124
+ var PublishSigningAuthorityRefreshValidator = external_exports.object({
17125
+ ...PublishCredentialRefreshBaseFields,
17126
+ mode: external_exports.literal("signing-authority"),
17127
+ credential: UnsignedVCValidator,
17128
+ signingAuthority: external_exports.object({
17129
+ type: external_exports.string().min(1)
17130
+ }).catchall(external_exports.any())
17131
+ });
17132
+ var PublishCredentialRefreshInputValidator = external_exports.object({
17133
+ ...PublishCredentialRefreshBaseFields,
17134
+ mode: CredentialRefreshSigningModeValidator,
17135
+ signedCredential: VCValidator.optional(),
17136
+ credential: UnsignedVCValidator.optional(),
17137
+ signingAuthority: external_exports.object({
17138
+ type: external_exports.string().min(1)
17139
+ }).catchall(external_exports.any()).optional()
17140
+ }).superRefine((input, ctx) => {
17141
+ if (input.mode === "issuer-signed" && !input.signedCredential) {
17142
+ ctx.addIssue({
17143
+ code: "custom",
17144
+ path: ["signedCredential"],
17145
+ message: "signedCredential is required for issuer-signed publication"
17146
+ });
17147
+ }
17148
+ if (input.mode === "issuer-signed" && (input.credential !== void 0 || input.signingAuthority !== void 0)) {
17149
+ ctx.addIssue({
17150
+ code: "custom",
17151
+ path: ["mode"],
17152
+ message: "issuer-signed publication cannot include signing-authority fields"
17153
+ });
17154
+ }
17155
+ if (input.mode === "signing-authority") {
17156
+ if (input.signedCredential !== void 0) {
17157
+ ctx.addIssue({
17158
+ code: "custom",
17159
+ path: ["signedCredential"],
17160
+ message: "signing-authority publication cannot include signedCredential"
17161
+ });
17162
+ }
17163
+ if (!input.credential) {
17164
+ ctx.addIssue({
17165
+ code: "custom",
17166
+ path: ["credential"],
17167
+ message: "credential is required for signing-authority publication"
17168
+ });
17169
+ }
17170
+ if (!input.signingAuthority) {
17171
+ ctx.addIssue({
17172
+ code: "custom",
17173
+ path: ["signingAuthority"],
17174
+ message: "signingAuthority is required for signing-authority publication"
17175
+ });
17176
+ }
17177
+ }
17178
+ });
17179
+ var PublishCredentialRefreshNotificationValidator = external_exports.enum([
17180
+ "queued",
17181
+ "suppressed",
17182
+ "not-applicable",
17183
+ /** Publication succeeded, but the post-commit notification enqueue must be retried. */
17184
+ "delivery-failed"
17185
+ ]);
17186
+ var PublishCredentialRefreshResultValidator = external_exports.object({
17187
+ refreshId: external_exports.string().min(1),
17188
+ version: external_exports.number().int().positive(),
17189
+ publishedAt: external_exports.string().min(1),
17190
+ notification: PublishCredentialRefreshNotificationValidator
17191
+ });
17192
+ var CredentialRefreshVersionMetadataValidator = external_exports.object({
17193
+ version: external_exports.number().int().positive(),
17194
+ publishedAt: external_exports.string().min(1),
17195
+ effectiveAt: external_exports.string().optional(),
17196
+ etag: external_exports.string().optional(),
17197
+ signingMode: CredentialRefreshSigningModeValidator.optional(),
17198
+ updateSummary: external_exports.string().optional()
17199
+ });
17200
+ var GetCredentialRefreshHistoryInputValidator = external_exports.object({
17201
+ refreshId: external_exports.string().min(1),
17202
+ cursor: external_exports.string().optional(),
17203
+ limit: external_exports.number().int().positive().optional()
17204
+ });
17205
+ var GetCredentialRefreshHistoryResultValidator = external_exports.object({
17206
+ records: CredentialRefreshVersionMetadataValidator.array(),
17207
+ hasMore: external_exports.boolean(),
17208
+ cursor: external_exports.string().optional()
17209
+ });
17210
+ var CredentialRefreshChallengeValidator = external_exports.object({
17211
+ challenge: external_exports.string().min(1),
17212
+ expiresAt: external_exports.string().min(1),
17213
+ domain: external_exports.string().optional(),
17214
+ scheme: external_exports.literal("LearnCardDIDAuth").optional()
17215
+ });
17216
+ var PublicCredentialRefreshEnvelopeValidator = external_exports.object({
17217
+ format: external_exports.literal("vc"),
17218
+ credential: VCValidator,
17219
+ etag: external_exports.string().optional()
17220
+ });
17221
+ var JweCredentialRefreshEnvelopeValidator = external_exports.object({
17222
+ format: external_exports.literal("jwe"),
17223
+ jwe: JWEValidator,
17224
+ etag: external_exports.string().optional(),
17225
+ /** Present on LearnCard-managed endpoints; optional for interoperable JWE services. */
17226
+ version: external_exports.number().int().positive().optional()
17227
+ });
17228
+ var CredentialRefreshResponseEnvelopeValidator = external_exports.discriminatedUnion("format", [
17229
+ PublicCredentialRefreshEnvelopeValidator,
17230
+ JweCredentialRefreshEnvelopeValidator
17231
+ ]);
17232
+ var CredentialRefreshFailureCodeValidator = external_exports.enum([
17233
+ "UNAVAILABLE",
17234
+ "TIMEOUT",
17235
+ "UNSUPPORTED_SERVICE",
17236
+ "UNAUTHORIZED",
17237
+ "MALFORMED_RESPONSE",
17238
+ "INVALID_PROOF",
17239
+ "ISSUER_MISMATCH",
17240
+ "ID_MISMATCH",
17241
+ "ROLLBACK",
17242
+ "REVOKED",
17243
+ "UNSAFE_ENDPOINT"
17244
+ ]);
17245
+ var CredentialRefreshUpdatedResultValidator = external_exports.object({
17246
+ status: external_exports.literal("updated"),
17247
+ credential: VCValidator,
17248
+ etag: external_exports.string().optional(),
17249
+ managedVersion: external_exports.number().int().positive().optional()
17250
+ });
17251
+ var CredentialRefreshUnchangedResultValidator = external_exports.object({
17252
+ status: external_exports.literal("unchanged"),
17253
+ checkedAt: external_exports.string().min(1),
17254
+ etag: external_exports.string().optional()
17255
+ });
17256
+ var CredentialRefreshUnsupportedResultValidator = external_exports.object({
17257
+ status: external_exports.literal("unsupported")
17258
+ });
17259
+ var CredentialRefreshFailedResultValidator = external_exports.object({
17260
+ status: external_exports.literal("failed"),
17261
+ code: CredentialRefreshFailureCodeValidator,
17262
+ retryable: external_exports.boolean()
17263
+ });
17264
+ var CredentialRefreshResultValidator = external_exports.discriminatedUnion("status", [
17265
+ CredentialRefreshUpdatedResultValidator,
17266
+ CredentialRefreshUnchangedResultValidator,
17267
+ CredentialRefreshUnsupportedResultValidator,
17268
+ CredentialRefreshFailedResultValidator
17269
+ ]);
17072
17270
 
17073
17271
  // src/plugin.ts
17074
17272
  var import_helpers = require("@learncard/helpers");
@@ -17686,6 +17884,27 @@ var issueCredentialWithNetworkStatus = /* @__PURE__ */ __name(async (learnCard,
17686
17884
  await appendNetworkCredentialStatus(client, credential, statusPurposes)
17687
17885
  );
17688
17886
  }, "issueCredentialWithNetworkStatus");
17887
+ var MANAGED_REFRESH_SERVICE_CONTEXT = {
17888
+ "LearnCardCredentialRefresh2026": "https://learncard.com/refresh#LearnCardCredentialRefresh2026",
17889
+ authorization: {
17890
+ "@id": "https://purl.imsglobal.org/spec/ob/v3p0#authorization",
17891
+ "@context": {
17892
+ LearnCardDIDAuth: "https://docs.learncard.com/definitions#LearnCardDIDAuth"
17893
+ }
17894
+ }
17895
+ };
17896
+ var injectManagedRefreshService = /* @__PURE__ */ __name((credential, refreshService) => {
17897
+ const existingContext = credential["@context"];
17898
+ const contextList = Array.isArray(existingContext) ? existingContext : [existingContext];
17899
+ const hasMapping = contextList.some(
17900
+ (entry) => !!entry && typeof entry === "object" && "LearnCardCredentialRefresh2026" in entry
17901
+ );
17902
+ return {
17903
+ ...credential,
17904
+ "@context": hasMapping ? contextList : [...contextList, MANAGED_REFRESH_SERVICE_CONTEXT],
17905
+ refreshService
17906
+ };
17907
+ }, "injectManagedRefreshService");
17689
17908
  async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, options) {
17690
17909
  const apiToken = typeof apiTokenOrOptions === "string" ? apiTokenOrOptions : void 0;
17691
17910
  const resolvedOptions = (typeof apiTokenOrOptions === "object" ? apiTokenOrOptions : options) ?? {};
@@ -18447,6 +18666,27 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18447
18666
  await ensureUser();
18448
18667
  return client.boost.allocateCredentialStatus.mutate(options2);
18449
18668
  }, "allocateCredentialStatus"),
18669
+ allocateCredentialRefresh: /* @__PURE__ */ __name(async (_learnCard, input) => {
18670
+ await ensureUser();
18671
+ return client.credentialRefresh.allocateCredentialRefresh.mutate(input);
18672
+ }, "allocateCredentialRefresh"),
18673
+ sendRefreshableCredential: /* @__PURE__ */ __name(async (_learnCard, refreshId, credential, boostUri, skipNotification) => {
18674
+ await ensureUser();
18675
+ return client.credentialRefresh.sendRefreshableCredential.mutate({
18676
+ refreshId,
18677
+ credential,
18678
+ boostUri,
18679
+ ...skipNotification ? { skipNotification: true } : {}
18680
+ });
18681
+ }, "sendRefreshableCredential"),
18682
+ publishCredentialRefresh: /* @__PURE__ */ __name(async (_learnCard, input) => {
18683
+ await ensureUser();
18684
+ return client.credentialRefresh.publishCredentialRefresh.mutate(input);
18685
+ }, "publishCredentialRefresh"),
18686
+ getCredentialRefreshHistory: /* @__PURE__ */ __name(async (_learnCard, input) => {
18687
+ await ensureUser();
18688
+ return client.credentialRefresh.getCredentialRefreshHistory.query(input);
18689
+ }, "getCredentialRefreshHistory"),
18450
18690
  revokeBoostRecipient: /* @__PURE__ */ __name(async (_learnCard, boostUri, recipientProfileId, credentialUri) => {
18451
18691
  await ensureUser();
18452
18692
  const input = { boostUri, recipientProfileId };
@@ -18513,6 +18753,17 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18513
18753
  if (typeof options2 === "object" && options2.overideFn) {
18514
18754
  boost = options2.overideFn(boost);
18515
18755
  }
18756
+ const enableRefresh = typeof options2 === "object" && options2.enableRefresh === true;
18757
+ let managedRefreshId;
18758
+ if (enableRefresh) {
18759
+ if (!boost.id) boost.id = `urn:uuid:${crypto.randomUUID()}`;
18760
+ const allocation = await client.credentialRefresh.allocateCredentialRefresh.mutate({
18761
+ holder: { profileId, did: targetProfile.did },
18762
+ credentialId: boost.id
18763
+ });
18764
+ managedRefreshId = allocation.refreshId;
18765
+ boost = injectManagedRefreshService(boost, allocation.refreshService);
18766
+ }
18516
18767
  const statusPurposes = typeof options2 === "object" ? options2.statusPurposes : void 0;
18517
18768
  const vc = await issueCredentialWithNetworkStatus(
18518
18769
  _learnCard,
@@ -18520,6 +18771,14 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
18520
18771
  boost,
18521
18772
  statusPurposes
18522
18773
  );
18774
+ if (managedRefreshId) {
18775
+ return client.credentialRefresh.sendRefreshableCredential.mutate({
18776
+ refreshId: managedRefreshId,
18777
+ credential: vc,
18778
+ boostUri,
18779
+ ...typeof options2 === "object" && options2.skipNotification ? { skipNotification: true } : {}
18780
+ });
18781
+ }
18523
18782
  if (typeof options2 === "object" && !options2.encrypt || !options2) {
18524
18783
  return client.boost.sendBoost.mutate({
18525
18784
  profileId,
@@ -19002,6 +19261,23 @@ async function getLearnCardNetworkPlugin(learnCard, url2, apiTokenOrOptions, opt
19002
19261
  await ensureUser();
19003
19262
  return client.inbox.finalize.mutate();
19004
19263
  }, "finalizeInboxCredentials"),
19264
+ recoverInboxCredentials: /* @__PURE__ */ __name(async (learnCard2, options2 = {}) => {
19265
+ const result = await client.inbox.getMyInboxDeliveries.query(options2);
19266
+ const results = await Promise.allSettled(
19267
+ result.records.map(async (record2) => ({
19268
+ ...record2,
19269
+ credential: VCValidator.parse(
19270
+ await learnCard2.invoke.decryptDagJwe(record2.credential, [
19271
+ learnCard2.id.keypair()
19272
+ ])
19273
+ )
19274
+ }))
19275
+ );
19276
+ const records = results.flatMap(
19277
+ (record2) => record2.status === "fulfilled" ? [record2.value] : []
19278
+ );
19279
+ return { ...result, records, failed: results.length - records.length };
19280
+ }, "recoverInboxCredentials"),
19005
19281
  sendGuardianApprovalEmail: /* @__PURE__ */ __name(async (_learnCard, options2) => {
19006
19282
  await ensureUser();
19007
19283
  return client.inbox.sendGuardianApprovalEmail.mutate(options2);