@learncard/types 5.17.3 → 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.
- package/README.md +5 -5
- package/dist/bitstring-status-list.d.ts +1 -1
- package/dist/bitstring-status-list.d.ts.map +1 -1
- package/dist/clr.d.ts +1 -1
- package/dist/clr.d.ts.map +1 -1
- package/dist/credential-format.d.ts +1 -1
- package/dist/credential-format.d.ts.map +1 -1
- package/dist/crypto.d.ts +1 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/did.d.ts +1 -1
- package/dist/did.d.ts.map +1 -1
- package/dist/lcn.d.ts +137 -134
- package/dist/lcn.d.ts.map +1 -1
- package/dist/learncard.d.ts +1 -1
- package/dist/learncard.d.ts.map +1 -1
- package/dist/learncloud.d.ts +1 -1
- package/dist/learncloud.d.ts.map +1 -1
- package/dist/mongo.d.ts +1 -1
- package/dist/mongo.d.ts.map +1 -1
- package/dist/obv3.d.ts +1 -1
- package/dist/obv3.d.ts.map +1 -1
- package/dist/queries.d.ts +4 -4
- package/dist/queries.d.ts.map +1 -1
- package/dist/types.cjs.development.cjs +4307 -2430
- package/dist/types.cjs.development.cjs.map +4 -4
- package/dist/types.cjs.production.min.cjs +56 -14
- package/dist/types.cjs.production.min.cjs.map +4 -4
- package/dist/types.esm.js +19 -22
- package/dist/types.esm.js.map +2 -2
- package/dist/vc.d.ts +1 -1
- package/dist/vc.d.ts.map +1 -1
- package/package.json +64 -59
- package/src/auth.ts +460 -0
- package/src/bitstring-status-list.ts +44 -0
- package/src/clr.ts +68 -0
- package/src/credential-format.ts +154 -0
- package/src/crypto.ts +41 -0
- package/src/did.ts +47 -0
- package/src/helpers.ts +10 -0
- package/src/index.ts +17 -0
- package/src/lcn.ts +2181 -0
- package/src/learncard.ts +123 -0
- package/src/learncloud.ts +26 -0
- package/src/mongo.ts +14 -0
- package/src/obv3.ts +252 -0
- package/src/queries.ts +56 -0
- package/src/registries.ts +9 -0
- package/src/vc.ts +221 -0
- 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
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';
|