@learncard/credential-library 2.0.3 → 2.0.4

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.
@@ -13,8 +13,14 @@ import type { CredentialFixture } from '../../types';
13
13
  * the fixture carries an inline context fragment — DIDKit's data-loss detection
14
14
  * otherwise refuses to sign.
15
15
  */
16
- /** Inline JSON-LD context fragment defining the refresh-service terms inline. */
16
+ /**
17
+ * Inline JSON-LD context fragment for terms the published contexts leave undefined.
18
+ * `partial` is in the CLR v2 spec (https://www.imsglobal.org/spec/clr/v2p0/#clrcredential)
19
+ * but the live purl.imsglobal.org CLR context only maps five type names, so without this
20
+ * the signer's data-loss check drops it.
21
+ */
17
22
  export declare const REFRESH_SERVICE_INLINE_CONTEXT: {
23
+ readonly partial: "https://purl.imsglobal.org/spec/clr/v2p0#partial";
18
24
  readonly LearnCardCredentialRefresh2026: "https://learncard.com/refresh#LearnCardCredentialRefresh2026";
19
25
  readonly authorization: {
20
26
  readonly '@id': "https://purl.imsglobal.org/spec/ob/v3p0#authorization";
@@ -1 +1 @@
1
- {"version":3,"file":"provisional-transcript.d.ts","sourceRoot":"","sources":["../../../src/fixtures/clr/provisional-transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;;;;;GAYG;AAEH,iFAAiF;AACjF,eAAO,MAAM,8BAA8B;;;;;;;;CASjC,CAAC;AAaX,eAAO,MAAM,wBAAwB,EAAE,iBAoGtC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GACpC,aAAa,UAAU,EACvB,UAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,KACrC,UAsCF,CAAC"}
1
+ {"version":3,"file":"provisional-transcript.d.ts","sourceRoot":"","sources":["../../../src/fixtures/clr/provisional-transcript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,8BAA8B;;;;;;;;;CAUjC,CAAC;AAaX,eAAO,MAAM,wBAAwB,EAAE,iBAuGtC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GACpC,aAAa,UAAU,EACvB,UAAS;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,KACrC,UA0CF,CAAC"}
@@ -17,6 +17,7 @@ import { obv3CourseCompletion } from './obv3/course-completion';
17
17
  import { obv3StandaloneFullCourse } from './obv3/standalone-full-course';
18
18
  import { obv3K12Diploma } from './obv3/k12-diploma';
19
19
  import { obv3EndorsementCredential } from './obv3/endorsement';
20
+ import { obv3RubricAlignedBadge } from './obv3/rubric-aligned-badge';
20
21
  import { clrMinimal } from './clr/minimal';
21
22
  import { clrMultiAchievement } from './clr/multi-achievement';
22
23
  import { clrUniversityTranscript } from './clr/university-transcript';
@@ -42,5 +43,5 @@ import { clrProvisionalTranscript, buildFinalTranscriptVariant, REFRESH_SERVICE_
42
43
  import { clrDemoIsdDiplomaAssessments } from './clr/demo-isd-diploma-assessments';
43
44
  import { sdJwtVcCourseCompletion } from './sd-jwt-vc/course-completion';
44
45
  export declare const ALL_FIXTURES: LibraryFixture[];
45
- export { vcV1Basic, vcV1WithStatus, vcV2Basic, vcV2WithEvidence, vcV2MultipleSubjects, vcV2RenderMethodExample, obv3MinimalBadge, obv3FullBadge, obv3WithAlignment, obv3WithEndorsement, obv3PlugfestJff2, clrMinimal, clrMultiAchievement, boostBasic, boostId, boostWithSkills, invalidMissingContext, invalidEmptyType, invalidMissingIssuer, clrNdStudentTranscript, obv3OneedtechFull, obv3ProfessionalCert, obv3MicroCredential, obv3CourseCompletion, obv3StandaloneFullCourse, obv3K12Diploma, obv3EndorsementCredential, clrUniversityTranscript, boostCommunityAward, boostDelegate, vcV1AlumniCredential, vcV2EmploymentCredential, vcV2EducationDegree, vcV2DigitalId, vcV2MembershipCredential, vcV2LicenseCredential, clrGreatPlainsFull, clrWestbridgeFull, clrCompetencyAligned, clrProvisionalTranscript, buildFinalTranscriptVariant, REFRESH_SERVICE_INLINE_CONTEXT, clrDemoIsdDiplomaAssessments, sdJwtVcCourseCompletion, };
46
+ export { vcV1Basic, vcV1WithStatus, vcV2Basic, vcV2WithEvidence, vcV2MultipleSubjects, vcV2RenderMethodExample, obv3MinimalBadge, obv3FullBadge, obv3WithAlignment, obv3WithEndorsement, obv3PlugfestJff2, clrMinimal, clrMultiAchievement, boostBasic, boostId, boostWithSkills, invalidMissingContext, invalidEmptyType, invalidMissingIssuer, clrNdStudentTranscript, obv3OneedtechFull, obv3ProfessionalCert, obv3MicroCredential, obv3CourseCompletion, obv3StandaloneFullCourse, obv3K12Diploma, obv3EndorsementCredential, obv3RubricAlignedBadge, clrUniversityTranscript, boostCommunityAward, boostDelegate, vcV1AlumniCredential, vcV2EmploymentCredential, vcV2EducationDegree, vcV2DigitalId, vcV2MembershipCredential, vcV2LicenseCredential, clrGreatPlainsFull, clrWestbridgeFull, clrCompetencyAligned, clrProvisionalTranscript, buildFinalTranscriptVariant, REFRESH_SERVICE_INLINE_CONTEXT, clrDemoIsdDiplomaAssessments, sdJwtVcCourseCompletion, };
46
47
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixtures/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAGrD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAGhF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAGtE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAGjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EACH,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EACjC,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,4BAA4B,EAAE,MAAM,oCAAoC,CAAC;AAGlF,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAMxE,eAAO,MAAM,YAAY,EAAE,cAAc,EA6DxC,CAAC;AAGF,OAAO,EACH,SAAS,EACT,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,oBAAoB,EACpB,uBAAuB,EACvB,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,UAAU,EACV,mBAAmB,EACnB,UAAU,EACV,OAAO,EACP,eAAe,EACf,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,cAAc,EACd,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,EACpB,wBAAwB,EACxB,mBAAmB,EACnB,aAAa,EACb,wBAAwB,EACxB,qBAAqB,EACrB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,EAC3B,8BAA8B,EAC9B,4BAA4B,EAC5B,uBAAuB,GAC1B,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CredentialFixture } from '../../types';
2
+ export declare const obv3RubricAlignedBadge: CredentialFixture;
3
+ //# sourceMappingURL=rubric-aligned-badge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rubric-aligned-badge.d.ts","sourceRoot":"","sources":["../../../src/fixtures/obv3/rubric-aligned-badge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKrD,eAAO,MAAM,sBAAsB,EAAE,iBAiGpC,CAAC"}
package/dist/prepare.d.ts CHANGED
@@ -12,24 +12,6 @@ export interface PrepareOptions {
12
12
  /** Generate fresh UUIDs for id fields (defaults to true) */
13
13
  freshIds?: boolean;
14
14
  }
15
- /**
16
- * Takes a fixture's credential and returns a fresh unsigned VC with real DIDs,
17
- * current timestamps, and fresh UUIDs — ready to pass to
18
- * `wallet.invoke.issueCredential()`.
19
- *
20
- * @example
21
- * ```typescript
22
- * import { getFixture, prepareFixture } from '@learncard/credential-library';
23
- *
24
- * const fixture = getFixture('obv3/full-badge');
25
- * const unsigned = prepareFixture(fixture, {
26
- * issuerDid: wallet.id.did(),
27
- * subjectDid: recipientDid,
28
- * });
29
- * const signed = await wallet.invoke.issueCredential(unsigned);
30
- * await wallet.store.LearnCloud.uploadEncrypted(signed);
31
- * ```
32
- */
33
15
  export declare const prepareFixture: (fixture: LibraryFixture, options: PrepareOptions) => UnsignedVC;
34
16
  /**
35
17
  * Shorthand that combines getFixture + prepareFixture.
@@ -1 +1 @@
1
- {"version":3,"file":"prepare.d.ts","sourceRoot":"","sources":["../src/prepare.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAOhE,MAAM,WAAW,cAAc;IAC3B,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAElB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAkGD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,cAAc,EAAE,SAAS,cAAc,KAAG,UAyDjF,CAAC;AAMF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,EAAE,SAAS,cAAc,KAAG,UAC9B,CAAC"}
1
+ {"version":3,"file":"prepare.d.ts","sourceRoot":"","sources":["../src/prepare.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAOhE,MAAM,WAAW,cAAc;IAC3B,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAElB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAsHD,eAAO,MAAM,cAAc,GAAI,SAAS,cAAc,EAAE,SAAS,cAAc,KAAG,UAsEjF,CAAC;AAMF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAI,WAAW,MAAM,EAAE,SAAS,cAAc,KAAG,UAC9B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@learncard/credential-library",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "Comprehensive library of Verifiable Credential fixtures for testing, development, and regression prevention across the VC ecosystem",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/credential-library.esm.js",
@@ -26,8 +26,8 @@
26
26
  "url": "https://github.com/learningeconomy/LearnCard/issues"
27
27
  },
28
28
  "devDependencies": {
29
- "@learncard/didkit-plugin": "1.10.0",
30
- "@learncard/init": "2.4.16",
29
+ "@learncard/didkit-plugin": "1.10.1",
30
+ "@learncard/init": "2.5.0",
31
31
  "@types/node": "^17.0.38",
32
32
  "esbuild": "^0.27.1",
33
33
  "jose": "^5.9.6",
@@ -36,8 +36,8 @@
36
36
  "vitest": "4.1.11"
37
37
  },
38
38
  "dependencies": {
39
- "@learncard/sd-jwt-vc-plugin": "0.2.13",
40
- "@learncard/types": "5.20.0",
39
+ "@learncard/sd-jwt-vc-plugin": "0.2.14",
40
+ "@learncard/types": "5.21.0",
41
41
  "@sd-jwt/sd-jwt-vc": "^0.19.0",
42
42
  "zod": "4.1.13"
43
43
  },
@@ -508,6 +508,49 @@ describe('Spec coverage', () => {
508
508
  // ---------------------------------------------------------------------------
509
509
 
510
510
  describe('prepareFixture', () => {
511
+ it.each(['validUntil', 'expirationDate'])(
512
+ 'refreshes stale %s even with a historical validFrom',
513
+ field => {
514
+ const fixture = getFixture('vc-v2/basic');
515
+ const original = {
516
+ ...fixture,
517
+ credential: { ...fixture.credential, [field]: '2001-01-01T00:00:00Z' },
518
+ };
519
+ const before = Date.now();
520
+ const prepared = prepareFixture(original, {
521
+ issuerDid: 'did:example:issuer',
522
+ validFrom: '2000-01-01T00:00:00Z',
523
+ });
524
+ const expiry = new Date(prepared[field] as string).getTime();
525
+ expect(expiry).toBeGreaterThanOrEqual(before + 180 * 24 * 60 * 60 * 1000);
526
+ expect(original.credential[field]).toBe('2001-01-01T00:00:00Z');
527
+ }
528
+ );
529
+
530
+ it.each(['validUntil', 'expirationDate'])(
531
+ 'keeps regenerated %s after a future validFrom',
532
+ field => {
533
+ const fixture = getFixture('vc-v2/basic');
534
+ const from = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString();
535
+ const prepared = prepareFixture(
536
+ { ...fixture, credential: { ...fixture.credential, [field]: from } },
537
+ { issuerDid: 'did:example:issuer', validFrom: from }
538
+ );
539
+ expect(new Date(prepared[field] as string).getTime()).toBe(
540
+ new Date(from).getTime() + 180 * 24 * 60 * 60 * 1000
541
+ );
542
+ }
543
+ );
544
+
545
+ it.each(['validUntil', 'expirationDate'])('preserves an explicit past %s override', field => {
546
+ const fixture = getFixture('vc-v2/basic');
547
+ const expiry = '2001-01-01T00:00:00Z';
548
+ const prepared = prepareFixture(
549
+ { ...fixture, credential: { ...fixture.credential, [field]: expiry } },
550
+ { issuerDid: 'did:example:issuer', validUntil: expiry }
551
+ );
552
+ expect(prepared[field]).toBe(expiry);
553
+ });
511
554
  const issuerDid = 'did:key:z6MkTestIssuer123';
512
555
  const subjectDid = 'did:key:z6MkTestSubject456';
513
556
 
@@ -16,8 +16,14 @@ import type { CredentialFixture } from '../../types';
16
16
  * otherwise refuses to sign.
17
17
  */
18
18
 
19
- /** Inline JSON-LD context fragment defining the refresh-service terms inline. */
19
+ /**
20
+ * Inline JSON-LD context fragment for terms the published contexts leave undefined.
21
+ * `partial` is in the CLR v2 spec (https://www.imsglobal.org/spec/clr/v2p0/#clrcredential)
22
+ * but the live purl.imsglobal.org CLR context only maps five type names, so without this
23
+ * the signer's data-loss check drops it.
24
+ */
20
25
  export const REFRESH_SERVICE_INLINE_CONTEXT = {
26
+ partial: 'https://purl.imsglobal.org/spec/clr/v2p0#partial',
21
27
  'LearnCardCredentialRefresh2026':
22
28
  'https://learncard.com/refresh#LearnCardCredentialRefresh2026',
23
29
  authorization: {
@@ -71,6 +77,8 @@ export const clrProvisionalTranscript: CredentialFixture = {
71
77
  name: 'Ridgeview Community College — Office of the Registrar',
72
78
  },
73
79
  validFrom: '2026-01-15T00:00:00Z',
80
+ validUntil: '2026-05-31T00:00:00Z',
81
+ partial: true,
74
82
  refreshService: PLACEHOLDER_REFRESH_SERVICE,
75
83
  credentialSubject: {
76
84
  id: 'did:example:student-ridgeview-042',
@@ -92,7 +100,8 @@ export const clrProvisionalTranscript: CredentialFixture = {
92
100
  id: 'urn:uuid:7d2e9f41-3c58-4e21-9b6a-1f0c5d8e2a49',
93
101
  type: ['ResultDescription'],
94
102
  name: 'Course Status',
95
- resultType: 'RawScore',
103
+ resultType: 'Status',
104
+ allowedValue: ['InProgress', 'Provisional', 'Completed'],
96
105
  },
97
106
  ],
98
107
  },
@@ -163,6 +172,8 @@ export const buildFinalTranscriptVariant = (
163
172
  'Final official transcript certified by the registrar. Supersedes the provisional record.';
164
173
 
165
174
  if (options.validFrom) final.validFrom = options.validFrom;
175
+ delete final.validUntil;
176
+ delete final.partial;
166
177
 
167
178
  const subject = final.credentialSubject;
168
179
 
@@ -180,7 +191,9 @@ export const buildFinalTranscriptVariant = (
180
191
  next.credentialSubject = {
181
192
  ...next.credentialSubject,
182
193
  result: next.credentialSubject.result.map((result: unknown) =>
183
- isRecord(result) ? { ...result, status: 'Completed', value: 'A' } : result
194
+ isRecord(result)
195
+ ? { ...result, status: 'Completed', value: 'Completed' }
196
+ : result
184
197
  ),
185
198
  };
186
199
  }
@@ -23,6 +23,7 @@ import { obv3CourseCompletion } from './obv3/course-completion';
23
23
  import { obv3StandaloneFullCourse } from './obv3/standalone-full-course';
24
24
  import { obv3K12Diploma } from './obv3/k12-diploma';
25
25
  import { obv3EndorsementCredential } from './obv3/endorsement';
26
+ import { obv3RubricAlignedBadge } from './obv3/rubric-aligned-badge';
26
27
 
27
28
  // CLR v2
28
29
  import { clrMinimal } from './clr/minimal';
@@ -94,6 +95,7 @@ export const ALL_FIXTURES: LibraryFixture[] = [
94
95
  obv3StandaloneFullCourse,
95
96
  obv3K12Diploma,
96
97
  obv3EndorsementCredential,
98
+ obv3RubricAlignedBadge,
97
99
 
98
100
  // CLR v2
99
101
  clrMinimal,
@@ -161,6 +163,7 @@ export {
161
163
  obv3StandaloneFullCourse,
162
164
  obv3K12Diploma,
163
165
  obv3EndorsementCredential,
166
+ obv3RubricAlignedBadge,
164
167
  clrUniversityTranscript,
165
168
  boostCommunityAward,
166
169
  boostDelegate,
@@ -0,0 +1,105 @@
1
+ import { UnsignedAchievementCredentialValidator } from '@learncard/types';
2
+
3
+ import type { CredentialFixture } from '../../types';
4
+
5
+ const RESULT_DESCRIPTION_ID = 'urn:uuid:7cc1519e-87f4-4cae-b7a5-786ec15db769';
6
+ const PROFICIENT_LEVEL_ID = 'urn:uuid:eb753d86-9277-478d-b9c4-3d589c82aff8';
7
+
8
+ export const obv3RubricAlignedBadge: CredentialFixture = {
9
+ id: 'obv3/rubric-aligned-badge',
10
+ name: 'Rubric-Aligned OBv3 Badge',
11
+ description:
12
+ 'Open Badges v3 credential with rubric levels, an achieved level, and a CTDL result alignment',
13
+ spec: 'obv3',
14
+ profile: 'badge',
15
+ features: ['alignment', 'results'],
16
+ source: 'synthetic',
17
+ signed: false,
18
+ validity: 'valid',
19
+ validator: UnsignedAchievementCredentialValidator,
20
+ tags: ['rubric', 'open-skill-alignment'],
21
+
22
+ credential: {
23
+ '@context': [
24
+ 'https://www.w3.org/ns/credentials/v2',
25
+ 'https://purl.imsglobal.org/spec/ob/v3p0/context-3.0.3.json',
26
+ ],
27
+ id: 'urn:uuid:b3e5babd-f68e-4095-979d-3e910a444e73',
28
+ type: ['VerifiableCredential', 'OpenBadgeCredential'],
29
+ name: 'Applied Data Analysis',
30
+ description: 'Recognizes applied data analysis at the proficient rubric level.',
31
+ issuer: {
32
+ id: 'did:example:issuer123',
33
+ type: ['Profile'],
34
+ name: 'Example Skills Institute',
35
+ url: 'https://example.org',
36
+ },
37
+ validFrom: '2026-01-15T00:00:00Z',
38
+ credentialSubject: {
39
+ id: 'did:example:learner456',
40
+ type: ['AchievementSubject'],
41
+ achievement: {
42
+ id: 'urn:uuid:e736a10c-aa36-466f-99af-e52440f32d8e',
43
+ type: ['Achievement'],
44
+ achievementType: 'Badge',
45
+ name: 'Applied Data Analysis',
46
+ description: 'Analyze a real-world dataset and communicate supported conclusions.',
47
+ criteria: {
48
+ narrative:
49
+ 'Submit an analysis that meets at least the proficient rubric level.',
50
+ },
51
+ resultDescription: [
52
+ {
53
+ id: RESULT_DESCRIPTION_ID,
54
+ type: ['ResultDescription'],
55
+ name: 'Data Analysis Rubric',
56
+ resultType: 'RubricCriterionLevel',
57
+ valueMin: '1',
58
+ valueMax: '4',
59
+ rubricCriterionLevel: [
60
+ {
61
+ id: 'urn:uuid:a4993932-d453-4417-b5aa-52b1bc1ea80e',
62
+ type: ['RubricCriterionLevel'],
63
+ name: 'Developing',
64
+ level: '2',
65
+ points: '2',
66
+ },
67
+ {
68
+ id: PROFICIENT_LEVEL_ID,
69
+ type: ['RubricCriterionLevel'],
70
+ name: 'Proficient',
71
+ level: '3',
72
+ points: '3',
73
+ },
74
+ {
75
+ id: 'urn:uuid:217fc04f-383b-48a0-a2e5-1cf1b016f7d4',
76
+ type: ['RubricCriterionLevel'],
77
+ name: 'Advanced',
78
+ level: '4',
79
+ points: '4',
80
+ },
81
+ ],
82
+ alignment: [
83
+ {
84
+ type: ['Alignment'],
85
+ targetName: 'Analyze data using appropriate methods',
86
+ targetUrl:
87
+ 'https://credentialengineregistry.org/resources/ce-2f5dce8d-29ad-40cb-a9e1-5a5517ff79a7',
88
+ targetType: 'CTDL',
89
+ targetFramework: 'Credential Engine Registry',
90
+ },
91
+ ],
92
+ },
93
+ ],
94
+ },
95
+ result: [
96
+ {
97
+ type: ['Result'],
98
+ resultDescription: RESULT_DESCRIPTION_ID,
99
+ value: '3',
100
+ achievedLevel: PROFICIENT_LEVEL_ID,
101
+ },
102
+ ],
103
+ },
104
+ },
105
+ };
package/src/prepare.ts CHANGED
@@ -138,6 +138,8 @@ const patchSubject = (subject: unknown, subjectDid: string): unknown => {
138
138
  * await wallet.store.LearnCloud.uploadEncrypted(signed);
139
139
  * ```
140
140
  */
141
+ const FIXTURE_VALIDITY_MS = 180 * 24 * 60 * 60 * 1000;
142
+
141
143
  export const prepareFixture = (fixture: LibraryFixture, options: PrepareOptions): UnsignedVC => {
142
144
  if (isSdJwtVcFixture(fixture)) {
143
145
  throw new Error(
@@ -192,6 +194,19 @@ export const prepareFixture = (fixture: LibraryFixture, options: PrepareOptions)
192
194
  } else {
193
195
  credential.validUntil = validUntil;
194
196
  }
197
+ } else {
198
+ // A fixture's hard-coded expiry goes stale; keep provisional records valid
199
+ // relative to when they are prepared so verification does not fail on age.
200
+ const from = new Date(
201
+ (credential.validFrom ?? credential.issuanceDate) as string
202
+ ).getTime();
203
+ const baseline = Math.max(from, Date.now());
204
+ for (const field of ['validUntil', 'expirationDate']) {
205
+ const expiry = credential[field];
206
+ if (typeof expiry === 'string' && new Date(expiry).getTime() <= baseline) {
207
+ credential[field] = new Date(baseline + FIXTURE_VALIDITY_MS).toISOString();
208
+ }
209
+ }
195
210
  }
196
211
 
197
212
  return credential as UnsignedVC;