@learncard/types 5.17.4 → 5.17.5

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.
Files changed (49) hide show
  1. package/README.md +5 -5
  2. package/dist/bitstring-status-list.d.ts +1 -1
  3. package/dist/bitstring-status-list.d.ts.map +1 -1
  4. package/dist/clr.d.ts +1 -1
  5. package/dist/clr.d.ts.map +1 -1
  6. package/dist/credential-format.d.ts +1 -1
  7. package/dist/credential-format.d.ts.map +1 -1
  8. package/dist/crypto.d.ts +1 -1
  9. package/dist/crypto.d.ts.map +1 -1
  10. package/dist/did.d.ts +1 -1
  11. package/dist/did.d.ts.map +1 -1
  12. package/dist/lcn.d.ts +5 -2
  13. package/dist/lcn.d.ts.map +1 -1
  14. package/dist/learncard.d.ts +1 -1
  15. package/dist/learncard.d.ts.map +1 -1
  16. package/dist/learncloud.d.ts +1 -1
  17. package/dist/learncloud.d.ts.map +1 -1
  18. package/dist/mongo.d.ts +1 -1
  19. package/dist/mongo.d.ts.map +1 -1
  20. package/dist/obv3.d.ts +1 -1
  21. package/dist/obv3.d.ts.map +1 -1
  22. package/dist/queries.d.ts +1 -1
  23. package/dist/queries.d.ts.map +1 -1
  24. package/dist/types.cjs.development.cjs +82 -81
  25. package/dist/types.cjs.development.cjs.map +3 -3
  26. package/dist/types.cjs.production.min.cjs +1 -1
  27. package/dist/types.cjs.production.min.cjs.map +3 -3
  28. package/dist/types.esm.js +14 -13
  29. package/dist/types.esm.js.map +2 -2
  30. package/dist/vc.d.ts +1 -1
  31. package/dist/vc.d.ts.map +1 -1
  32. package/package.json +64 -62
  33. package/src/auth.ts +460 -0
  34. package/src/bitstring-status-list.ts +44 -0
  35. package/src/clr.ts +68 -0
  36. package/src/credential-format.ts +154 -0
  37. package/src/crypto.ts +41 -0
  38. package/src/did.ts +47 -0
  39. package/src/helpers.ts +10 -0
  40. package/src/index.ts +17 -0
  41. package/src/lcn.ts +2181 -0
  42. package/src/learncard.ts +123 -0
  43. package/src/learncloud.ts +26 -0
  44. package/src/mongo.ts +14 -0
  45. package/src/obv3.ts +252 -0
  46. package/src/queries.ts +56 -0
  47. package/src/registries.ts +9 -0
  48. package/src/vc.ts +221 -0
  49. package/src/wasm.ts +1 -0
package/src/clr.ts ADDED
@@ -0,0 +1,68 @@
1
+ import { z } from 'zod/v4';
2
+
3
+ import { UnsignedVCValidator, ProofValidator, ProfileValidator, ImageValidator } from './vc';
4
+
5
+ import { AchievementValidator, EndorsementCredentialValidator } from './obv3';
6
+
7
+ // ---------------------------------------------------------------------------
8
+ // CLR v2 — Comprehensive Learner Record
9
+ // Based on 1EdTech CLR Standard v2.0
10
+ // https://www.imsglobal.org/spec/clr/v2p0
11
+ // ---------------------------------------------------------------------------
12
+
13
+ export const AssociationTypeValidator = z
14
+ .enum([
15
+ 'exactMatchOf',
16
+ 'extends',
17
+ 'isChildOf',
18
+ 'isParentOf',
19
+ 'isPartOf',
20
+ 'isPeerOf',
21
+ 'isRelatedTo',
22
+ 'precedes',
23
+ 'replacedBy',
24
+ ])
25
+ .or(z.string());
26
+ export type AssociationType = z.infer<typeof AssociationTypeValidator>;
27
+
28
+ export const AssociationValidator = z
29
+ .object({
30
+ type: z.string().array().nonempty(),
31
+ associationType: AssociationTypeValidator,
32
+ sourceId: z.string().optional(),
33
+ targetId: z.string(),
34
+ })
35
+ .catchall(z.any());
36
+ export type Association = z.infer<typeof AssociationValidator>;
37
+
38
+ export const ClrSubjectValidator = z
39
+ .object({
40
+ id: z.string().optional(),
41
+ type: z.string().array().nonempty(),
42
+ identifier: z.any().array().optional(),
43
+ achievement: AchievementValidator.array().optional(),
44
+ association: AssociationValidator.array().optional(),
45
+ verifiableCredential: z.any().array().optional(),
46
+ })
47
+ .catchall(z.any());
48
+ export type ClrSubject = z.infer<typeof ClrSubjectValidator>;
49
+
50
+ export const UnsignedClrCredentialValidator = UnsignedVCValidator.extend({
51
+ name: z.string().optional(),
52
+ description: z.string().optional(),
53
+ image: ImageValidator.optional(),
54
+
55
+ credentialSubject: ClrSubjectValidator.or(ClrSubjectValidator.array()) as z.ZodUnion<
56
+ [typeof ClrSubjectValidator, z.ZodArray<typeof ClrSubjectValidator>]
57
+ >,
58
+
59
+ endorsement: EndorsementCredentialValidator.array().optional(),
60
+
61
+ partial: z.boolean().optional(),
62
+ });
63
+ export type UnsignedClrCredential = z.infer<typeof UnsignedClrCredentialValidator>;
64
+
65
+ export const ClrCredentialValidator = UnsignedClrCredentialValidator.extend({
66
+ proof: ProofValidator.or(ProofValidator.array()),
67
+ });
68
+ export type ClrCredential = z.infer<typeof ClrCredentialValidator>;
@@ -0,0 +1,154 @@
1
+ import { z } from 'zod/v4';
2
+ import type { VC } from './vc';
3
+
4
+ /**
5
+ * Wire-format identifier for a credential at rest in the wallet.
6
+ *
7
+ * Optional metadata on `CredentialRecord`. Existing W3C records work
8
+ * without it. Format-aware code paths use this value to dispatch on
9
+ * the correct wire-form representation. See ADR-0001 for rationale.
10
+ *
11
+ * Values follow OID4VCI / OID4VP draft-16 conventions:
12
+ * - `w3c-vc-2.0` — JSON-LD VC, VCDM 2.0 `@context`
13
+ * - `w3c-vc-1.1` — JSON-LD VC, VCDM 1.1 `@context` (legacy)
14
+ * - `jwt-vc-json` — compact JWS string, VCDM §6.3.1 payload shape
15
+ * - `dc+sd-jwt` — SD-JWT-VC compact form (draft-16 canonical name)
16
+ * - `vc+sd-jwt` — SD-JWT-VC compact form (legacy alias accepted on read)
17
+ * - `mso_mdoc` — ISO 18013-5 mDoc, CBOR-encoded (stored base64)
18
+ */
19
+ export const CredentialFormatValidator = z.enum([
20
+ 'w3c-vc-2.0',
21
+ 'w3c-vc-1.1',
22
+ 'jwt-vc-json',
23
+ 'dc+sd-jwt',
24
+ 'vc+sd-jwt',
25
+ 'mso_mdoc',
26
+ ]);
27
+ export type CredentialFormat = z.infer<typeof CredentialFormatValidator>;
28
+
29
+ /**
30
+ * Storage-plane envelope for native (non-W3C) credential formats.
31
+ *
32
+ * The storage plane previously accepted only `VC | VP`, which forced
33
+ * SD-JWT-VC to synthesize a JSON-LD wrapper around the compact form
34
+ * just to satisfy the type — even though the underlying transport
35
+ * (LearnCloud tRPC) accepts any JSON-serializable value.
36
+ *
37
+ * The envelope is the on-wire shape for any credential that is NOT a
38
+ * W3C VC/VP. Consumers identify the envelope by the presence of both
39
+ * `format` and `data` fields (use `isStoredCredentialEnvelope`).
40
+ *
41
+ * Per-format `data` conventions:
42
+ * - `dc+sd-jwt` / `vc+sd-jwt`: the compact `<JWT>~<disclosures>~`
43
+ * string (no KB-JWT — that is per-presentation).
44
+ * - `jwt-vc-json`: the compact JWS string.
45
+ * - `mso_mdoc`: base64url-encoded CBOR bytes. The TypeScript type
46
+ * allows `Uint8Array` for in-memory ergonomics; storage plugins
47
+ * MUST convert to a base64url string at the transport boundary.
48
+ * The Zod validator (used at the wire layer) is string-only.
49
+ *
50
+ * W3C VCs continue to flow through `upload(vc: VC)` directly — they
51
+ * do not use the envelope. This keeps the legacy partner surface
52
+ * untouched.
53
+ */
54
+ // Wire validator: data is `string` only because JSON transport (tRPC, OpenAPI)
55
+ // cannot carry Uint8Array natively. Storage plugins encode binary `Uint8Array`
56
+ // data to base64url BEFORE the validator runs at the transport boundary.
57
+ // The TypeScript type below is intentionally wider (`string | Uint8Array`) to
58
+ // preserve in-memory ergonomics for plugins doing the conversion.
59
+ export const StoredCredentialEnvelopeValidator = z
60
+ .object({
61
+ format: CredentialFormatValidator,
62
+ data: z.string(),
63
+ })
64
+ .passthrough();
65
+ export type StoredCredentialEnvelope = {
66
+ format: CredentialFormat;
67
+ data: string | Uint8Array;
68
+ [key: string]: unknown;
69
+ };
70
+
71
+ /**
72
+ * Runtime typeguard for the storage envelope shape. Storage plugins
73
+ * use this to branch in `upload`/`read.get` between the legacy W3C
74
+ * path and the envelope path. Performs a shallow structural check —
75
+ * does not validate `data` semantics for the chosen format.
76
+ */
77
+ export const isStoredCredentialEnvelope = (value: unknown): value is StoredCredentialEnvelope => {
78
+ if (!value || typeof value !== 'object') return false;
79
+ const candidate = value as Record<string, unknown>;
80
+ if (typeof candidate.format !== 'string') return false;
81
+ if (!CredentialFormatValidator.safeParse(candidate.format).success) return false;
82
+ return typeof candidate.data === 'string' || candidate.data instanceof Uint8Array;
83
+ };
84
+
85
+ /**
86
+ * Format-discriminated read view over a stored credential. Returned
87
+ * by `toStoredCredential(record)` in `@learncard/helpers`.
88
+ *
89
+ * The `data` field carries the correct wire-form representation for
90
+ * the credential's format:
91
+ * - W3C VCs: the JSON-LD VC object (also what `record.vc` holds)
92
+ * - JWT-VC: the compact JWS string (extracted from `record.vc.proof.jwt`
93
+ * if the record uses the legacy LDP-around-JWT envelope, otherwise
94
+ * the raw string from `record.rawWireForm`)
95
+ * - SD-JWT-VC: the compact `<JWT>~<disclosures>~` string
96
+ * - mDoc: base64url-encoded CBOR bytes (stored as a string for
97
+ * LearnCloud's JSON-only encrypted store; consumers base64-decode
98
+ * when they need raw bytes)
99
+ *
100
+ * Format-aware consumers pattern-match on `format` and use `data`.
101
+ * Legacy consumers continue to read `record.vc` directly — the
102
+ * projector is opt-in, never required.
103
+ */
104
+ export type StoredCredential =
105
+ | { format: 'w3c-vc-2.0'; data: VC }
106
+ | { format: 'w3c-vc-1.1'; data: VC }
107
+ | { format: 'jwt-vc-json'; data: string }
108
+ | { format: 'dc+sd-jwt'; data: string }
109
+ | { format: 'vc+sd-jwt'; data: string }
110
+ | { format: 'mso_mdoc'; data: string };
111
+
112
+ /**
113
+ * Unified display projection for any credential format. Returned by
114
+ * the `toDisplayViewModel(stored, learnCard)` adapter that lands in
115
+ * UI components consume this shape regardless of underlying format,
116
+ * so the same BoostEarnedCard / category view / search index works
117
+ * across all credential types. The format-specific decoding logic
118
+ * lives in the per-format display adapter, not the UI.
119
+ */
120
+ export interface CredentialDisplayViewModel {
121
+ /** Source format of the underlying credential. */
122
+ format: CredentialFormat;
123
+ /** Best-effort issuer display name (resolved DID document or HTTPS metadata). */
124
+ issuerName?: string;
125
+ /** Raw DID or URL identifier of the issuer. */
126
+ issuerDid?: string;
127
+ /** Human-readable title (from credential `name`, derived from vct, or humanized type). */
128
+ title?: string;
129
+ /** Wallet category (e.g., `'Achievement'`, `'ID'`) used by the wallet's category tabs. */
130
+ category?: string;
131
+ /** Issuance time, if present in the credential. */
132
+ issuedAt?: Date;
133
+ /** Expiration time, if present. */
134
+ expiresAt?: Date;
135
+ /**
136
+ * Reconstructed claims. For W3C VCs this mirrors `credentialSubject`;
137
+ * for SD-JWT this is the payload + reconstructed disclosable claims;
138
+ * for mDoc it's the decoded namespace tree projected as a flat record.
139
+ */
140
+ claims: Record<string, unknown>;
141
+ /**
142
+ * Whether the credential supports selective disclosure at presentation
143
+ * time. SD-JWT-VC and mDoc → true; W3C VCs → false. UI components use
144
+ * this to decide whether to show per-claim consent checkboxes.
145
+ */
146
+ isSelectivelyDisclosable: boolean;
147
+ /**
148
+ * The on-the-wire form for re-serialization at egress time. Apps
149
+ * preparing outbound presentations should NEVER reconstruct from
150
+ * `claims` — always re-serialize from this field via
151
+ * `serializeForWire(stored)` (Phase 3).
152
+ */
153
+ rawWireForm: string | VC;
154
+ }
package/src/crypto.ts ADDED
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod/v4';
2
+
3
+ export const JWKValidator = z.object({
4
+ kty: z.string(),
5
+ crv: z.string(),
6
+ x: z.string(),
7
+ y: z.string().optional(),
8
+ n: z.string().optional(),
9
+ d: z.string().optional(),
10
+ });
11
+ export type JWK = z.infer<typeof JWKValidator>;
12
+
13
+ export const JWKWithPrivateKeyValidator = JWKValidator.omit({ d: true }).extend({ d: z.string() });
14
+ export type JWKWithPrivateKey = z.infer<typeof JWKWithPrivateKeyValidator>;
15
+
16
+ export const JWERecipientHeaderValidator = z.object({
17
+ alg: z.string(),
18
+ iv: z.string(),
19
+ tag: z.string(),
20
+ epk: JWKValidator.partial().optional(),
21
+ kid: z.string().optional(),
22
+ apv: z.string().optional(),
23
+ apu: z.string().optional(),
24
+ });
25
+ export type JWERecipientHeader = z.infer<typeof JWERecipientHeaderValidator>;
26
+
27
+ export const JWERecipientValidator = z.object({
28
+ header: JWERecipientHeaderValidator,
29
+ encrypted_key: z.string(),
30
+ });
31
+ export type JWERecipient = z.infer<typeof JWERecipientValidator>;
32
+
33
+ export const JWEValidator = z.object({
34
+ protected: z.string(),
35
+ iv: z.string(),
36
+ ciphertext: z.string(),
37
+ tag: z.string(),
38
+ aad: z.string().optional(),
39
+ recipients: JWERecipientValidator.array().optional(),
40
+ });
41
+ export type JWE = z.infer<typeof JWEValidator>;
package/src/did.ts ADDED
@@ -0,0 +1,47 @@
1
+ import { z } from 'zod/v4';
2
+ import { ContextValidator, ProofValidator } from './vc';
3
+ import { JWKValidator } from './crypto';
4
+
5
+ export const VerificationMethodValidator = z.string().or(
6
+ z
7
+ .object({
8
+ '@context': ContextValidator.optional(),
9
+ id: z.string(),
10
+ type: z.string(),
11
+ controller: z.string(),
12
+ publicKeyJwk: JWKValidator.optional(),
13
+ publicKeyBase58: z.string().optional(),
14
+ publicKeyMultibase: z.string().optional(),
15
+ blockChainAccountId: z.string().optional(),
16
+ })
17
+ .catchall(z.any())
18
+ );
19
+ export type VerificationMethod = z.infer<typeof VerificationMethodValidator>;
20
+
21
+ export const ServiceValidator = z
22
+ .object({
23
+ id: z.string(),
24
+ type: z.string().or(z.string().array().nonempty()),
25
+ serviceEndpoint: z.any().or(z.any().array().nonempty()),
26
+ })
27
+ .catchall(z.any());
28
+ export type Service = z.infer<typeof ServiceValidator>;
29
+
30
+ export const DidDocumentValidator = z
31
+ .object({
32
+ '@context': ContextValidator,
33
+ id: z.string(),
34
+ alsoKnownAs: z.string().optional(),
35
+ controller: z.string().or(z.string().array().nonempty()).optional(),
36
+ verificationMethod: VerificationMethodValidator.array().optional(),
37
+ authentication: VerificationMethodValidator.array().optional(),
38
+ assertionMethod: VerificationMethodValidator.array().optional(),
39
+ keyAgreement: VerificationMethodValidator.array().optional(),
40
+ capabilityInvocation: VerificationMethodValidator.array().optional(),
41
+ capabilityDelegation: VerificationMethodValidator.array().optional(),
42
+ publicKey: VerificationMethodValidator.array().optional(),
43
+ service: ServiceValidator.array().optional(),
44
+ proof: ProofValidator.or(ProofValidator.array()).optional(),
45
+ })
46
+ .catchall(z.any());
47
+ export type DidDocument = z.infer<typeof DidDocumentValidator>;
package/src/helpers.ts ADDED
@@ -0,0 +1,10 @@
1
+ export type DeepPartial<T> = T extends object
2
+ ? {
3
+ [P in keyof T]?: DeepPartial<T[P]>;
4
+ }
5
+ : T;
6
+
7
+ export interface Nothing { }
8
+ export type Other<T> = T & Nothing;
9
+
10
+ export type SuggestString<Literals extends string> = Literals | Other<string>;
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ import type {} from 'zod-openapi';
2
+
3
+ export * from './vc';
4
+ export * from './did';
5
+ export * from './obv3';
6
+ export * from './clr';
7
+ export * from './credential-format';
8
+ export * from './learncard';
9
+ export * from './learncloud';
10
+ export * from './lcn';
11
+ export * from './crypto';
12
+ export * from './mongo';
13
+ export * from './wasm';
14
+ export * from './helpers';
15
+ export * from './queries';
16
+ export * from './auth';
17
+ export * from './bitstring-status-list';