@learncard/openid4vc-plugin 0.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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +592 -0
  3. package/dist/dcql/adapt.d.ts +80 -0
  4. package/dist/dcql/adapt.d.ts.map +1 -0
  5. package/dist/dcql/build.d.ts +122 -0
  6. package/dist/dcql/build.d.ts.map +1 -0
  7. package/dist/dcql/compose.d.ts +78 -0
  8. package/dist/dcql/compose.d.ts.map +1 -0
  9. package/dist/dcql/index.d.ts +18 -0
  10. package/dist/dcql/index.d.ts.map +1 -0
  11. package/dist/dcql/parse.d.ts +16 -0
  12. package/dist/dcql/parse.d.ts.map +1 -0
  13. package/dist/dcql/respond.d.ts +115 -0
  14. package/dist/dcql/respond.d.ts.map +1 -0
  15. package/dist/dcql/select.d.ts +63 -0
  16. package/dist/dcql/select.d.ts.map +1 -0
  17. package/dist/dcql/types.d.ts +93 -0
  18. package/dist/dcql/types.d.ts.map +1 -0
  19. package/dist/index.d.ts +8 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +7 -0
  22. package/dist/offer/index.d.ts +4 -0
  23. package/dist/offer/index.d.ts.map +1 -0
  24. package/dist/offer/normalize.d.ts +15 -0
  25. package/dist/offer/normalize.d.ts.map +1 -0
  26. package/dist/offer/parse.d.ts +24 -0
  27. package/dist/offer/parse.d.ts.map +1 -0
  28. package/dist/offer/types.d.ts +92 -0
  29. package/dist/offer/types.d.ts.map +1 -0
  30. package/dist/openid4vc-plugin.cjs.development.js +27402 -0
  31. package/dist/openid4vc-plugin.cjs.development.js.map +7 -0
  32. package/dist/openid4vc-plugin.cjs.production.min.js +146 -0
  33. package/dist/openid4vc-plugin.cjs.production.min.js.map +7 -0
  34. package/dist/openid4vc-plugin.esm.js +27396 -0
  35. package/dist/openid4vc-plugin.esm.js.map +7 -0
  36. package/dist/plugin.d.ts +12 -0
  37. package/dist/plugin.d.ts.map +1 -0
  38. package/dist/siop/index.d.ts +11 -0
  39. package/dist/siop/index.d.ts.map +1 -0
  40. package/dist/siop/sign.d.ts +92 -0
  41. package/dist/siop/sign.d.ts.map +1 -0
  42. package/dist/types.d.ts +359 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/vci/accept.d.ts +24 -0
  45. package/dist/vci/accept.d.ts.map +1 -0
  46. package/dist/vci/auth-code.d.ts +148 -0
  47. package/dist/vci/auth-code.d.ts.map +1 -0
  48. package/dist/vci/decode.d.ts +65 -0
  49. package/dist/vci/decode.d.ts.map +1 -0
  50. package/dist/vci/errors.d.ts +22 -0
  51. package/dist/vci/errors.d.ts.map +1 -0
  52. package/dist/vci/index.d.ts +12 -0
  53. package/dist/vci/index.d.ts.map +1 -0
  54. package/dist/vci/metadata.d.ts +25 -0
  55. package/dist/vci/metadata.d.ts.map +1 -0
  56. package/dist/vci/pkce.d.ts +85 -0
  57. package/dist/vci/pkce.d.ts.map +1 -0
  58. package/dist/vci/proof.d.ts +43 -0
  59. package/dist/vci/proof.d.ts.map +1 -0
  60. package/dist/vci/request.d.ts +48 -0
  61. package/dist/vci/request.d.ts.map +1 -0
  62. package/dist/vci/store.d.ts +89 -0
  63. package/dist/vci/store.d.ts.map +1 -0
  64. package/dist/vci/token.d.ts +16 -0
  65. package/dist/vci/token.d.ts.map +1 -0
  66. package/dist/vci/types.d.ts +156 -0
  67. package/dist/vci/types.d.ts.map +1 -0
  68. package/dist/vp/client-id-prefix.d.ts +115 -0
  69. package/dist/vp/client-id-prefix.d.ts.map +1 -0
  70. package/dist/vp/encrypt.d.ts +221 -0
  71. package/dist/vp/encrypt.d.ts.map +1 -0
  72. package/dist/vp/index.d.ts +27 -0
  73. package/dist/vp/index.d.ts.map +1 -0
  74. package/dist/vp/parse.d.ts +60 -0
  75. package/dist/vp/parse.d.ts.map +1 -0
  76. package/dist/vp/pex.d.ts +83 -0
  77. package/dist/vp/pex.d.ts.map +1 -0
  78. package/dist/vp/present.d.ts +126 -0
  79. package/dist/vp/present.d.ts.map +1 -0
  80. package/dist/vp/request-object.d.ts +99 -0
  81. package/dist/vp/request-object.d.ts.map +1 -0
  82. package/dist/vp/select.d.ts +137 -0
  83. package/dist/vp/select.d.ts.map +1 -0
  84. package/dist/vp/sign.d.ts +125 -0
  85. package/dist/vp/sign.d.ts.map +1 -0
  86. package/dist/vp/submit.d.ts +175 -0
  87. package/dist/vp/submit.d.ts.map +1 -0
  88. package/dist/vp/types.d.ts +255 -0
  89. package/dist/vp/types.d.ts.map +1 -0
  90. package/package.json +52 -0
@@ -0,0 +1,12 @@
1
+ import { OpenID4VCDependentLearnCard, OpenID4VCPlugin, OpenID4VCPluginConfig } from './types';
2
+ /**
3
+ * Create the OpenID4VC holder plugin.
4
+ *
5
+ * Current scope (Slice 1): Credential Offer URI parsing + by-reference
6
+ * resolution. Subsequent slices will add token exchange, credential request,
7
+ * OID4VP Authorization Request handling, and SIOPv2 ID tokens.
8
+ *
9
+ * @group Plugins
10
+ */
11
+ export declare const getOpenID4VCPlugin: (_learnCard: OpenID4VCDependentLearnCard, config?: OpenID4VCPluginConfig) => OpenID4VCPlugin;
12
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,2BAA2B,EAC3B,eAAe,EACf,qBAAqB,EACxB,MAAM,SAAS,CAAC;AAkDjB;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,eACf,2BAA2B,WAC/B,qBAAqB,KAC9B,eAkYF,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SIOPv2 (Self-Issued OpenID Provider v2) surface.
3
+ *
4
+ * Currently scoped to **holder-side ID token issuance** used by OID4VP
5
+ * combined flows (`response_type=vp_token id_token`). SIOPv2-only
6
+ * flows (no VP at all, just an id_token) reuse the same module — the
7
+ * wallet just wouldn't call `buildPresentation` beforehand.
8
+ */
9
+ export { signIdToken, SiopSignError, responseTypeSet, requiresIdToken, } from './sign';
10
+ export type { SignIdTokenOptions, SignIdTokenHelpers, SignIdTokenResult, SiopSignErrorCode, } from './sign';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/siop/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACH,WAAW,EACX,aAAa,EACb,eAAe,EACf,eAAe,GAClB,MAAM,QAAQ,CAAC;AAEhB,YAAY,EACR,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,GACpB,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Slice 8 — **SIOPv2 ID token signing**.
3
+ *
4
+ * OpenID for Verifiable Presentations combined flows
5
+ * (`response_type=vp_token id_token`) require the wallet to return a
6
+ * Self-Issued OpenID Provider v2 (SIOPv2) ID token alongside the VP
7
+ * token. The ID token proves the holder controls the DID the VP was
8
+ * bound to.
9
+ *
10
+ * This module builds + signs the ID token per §9 of the SIOPv2 spec:
11
+ * - `iss` = the holder DID (or `https://self-issued.me/v2` when the
12
+ * spec-reserved form is requested; we default to the DID because
13
+ * that's what every real verifier expects).
14
+ * - `sub` = the holder DID.
15
+ * - `aud` = verifier's `client_id` (from the Authorization Request).
16
+ * - `nonce` = verifier's nonce.
17
+ * - `iat` / `exp` = now / now+5min.
18
+ *
19
+ * Purely dependency-injected: the signer is the same
20
+ * {@link ProofJwtSigner} shape used by VCI proof-of-possession and VP
21
+ * signing. Plugin wires in the Ed25519 signer built from the host
22
+ * LearnCard's keypair.
23
+ */
24
+ import { ProofJwtSigner } from '../vci/types';
25
+ export interface SignIdTokenOptions {
26
+ /** Holder DID — becomes both `iss` and `sub`. */
27
+ holder: string;
28
+ /** Verifier's `client_id` — becomes `aud`. */
29
+ audience: string;
30
+ /** Verifier's `nonce` — must match between vp_token and id_token. */
31
+ nonce: string;
32
+ /**
33
+ * Optional. When the verifier's Authorization Request requested a
34
+ * `_vp_token` hash binding, the caller can pre-compute it and
35
+ * pass it here. We just stamp the claim unchanged — calculation
36
+ * of the JWT-VP hash belongs in the caller.
37
+ */
38
+ vpTokenHash?: string;
39
+ /** Override `iat` for deterministic tests. Defaults to `Math.floor(Date.now() / 1000)`. */
40
+ iat?: number;
41
+ /**
42
+ * Override token lifetime in seconds. Defaults to 300 (5 min) —
43
+ * enough for the verifier to receive and validate before expiry
44
+ * even over slow networks, short enough that a leaked token
45
+ * won't linger.
46
+ */
47
+ lifetimeSeconds?: number;
48
+ /**
49
+ * SIOPv2 §9 allows `iss` to be either the holder DID or the
50
+ * reserved value `https://self-issued.me/v2`. Default: holder DID
51
+ * (matches what EUDI + Sphereon + walt.id all expect). Flip to
52
+ * `'self-issued.me'` for spec-purity test cases.
53
+ */
54
+ issuerMode?: 'did' | 'self-issued.me';
55
+ }
56
+ export interface SignIdTokenHelpers {
57
+ signer: ProofJwtSigner;
58
+ }
59
+ export interface SignIdTokenResult {
60
+ /** Compact JWS suitable for submission as the `id_token` form field. */
61
+ idToken: string;
62
+ }
63
+ export type SiopSignErrorCode = 'invalid_input' | 'missing_signer' | 'id_token_sign_failed';
64
+ export declare class SiopSignError extends Error {
65
+ readonly code: SiopSignErrorCode;
66
+ constructor(code: SiopSignErrorCode, message: string, options?: {
67
+ cause?: unknown;
68
+ });
69
+ }
70
+ /**
71
+ * Build + sign a SIOPv2 ID token. See module doc for claim shape.
72
+ *
73
+ * Typed `SiopSignError`s on every failure so UIs can surface
74
+ * "couldn't prove holder identity" distinctly from "verifier
75
+ * rejected the VP".
76
+ */
77
+ export declare const signIdToken: (options: SignIdTokenOptions, helpers: SignIdTokenHelpers) => Promise<SignIdTokenResult>;
78
+ /**
79
+ * Parse a space-separated `response_type` value into a set. Handy for
80
+ * plugin consumers that need to decide whether to emit an id_token:
81
+ *
82
+ * responseTypeSet(req.response_type).has('id_token')
83
+ */
84
+ export declare const responseTypeSet: (value: string | undefined) => Set<string>;
85
+ /**
86
+ * Convenience predicate mirroring OID4VP spec intent:
87
+ * - `vp_token` alone → VP only.
88
+ * - `id_token` alone → SIOPv2 identity only, no VP.
89
+ * - `vp_token id_token` → combined flow, both.
90
+ */
91
+ export declare const requiresIdToken: (responseType: string | undefined) => boolean;
92
+ //# sourceMappingURL=sign.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../../src/siop/sign.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAM9C,MAAM,WAAW,kBAAkB;IAC/B,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IAEf,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IAEjB,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,2FAA2F;IAC3F,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,KAAK,GAAG,gBAAgB,CAAC;CACzC;AAED,MAAM,WAAW,kBAAkB;IAC/B,MAAM,EAAE,cAAc,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAC9B,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC;CACnB;AAMD,MAAM,MAAM,iBAAiB,GACvB,eAAe,GACf,gBAAgB,GAChB,sBAAsB,CAAC;AAE7B,qBAAa,aAAc,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;gBAG7B,IAAI,EAAE,iBAAiB,EACvB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CASpC;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,YACX,kBAAkB,WAClB,kBAAkB,KAC5B,OAAO,CAAC,iBAAiB,CAuC3B,CAAC;AA2CF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,UAAW,MAAM,GAAG,SAAS,KAAG,GAAG,CAAC,MAAM,CAGrE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,iBAAkB,MAAM,GAAG,SAAS,KAAG,OAClB,CAAC"}
@@ -0,0 +1,359 @@
1
+ import { Plugin, LearnCard } from '@learncard/core';
2
+ import { UnsignedVC, VC, UnsignedVP, VP } from '@learncard/types';
3
+ import { ProofOptions } from '@learncard/didkit-plugin';
4
+ import { CredentialOffer, ParsedCredentialOfferUri } from './offer/types';
5
+ import { AcceptCredentialOfferOptions, AcceptedCredentialResult } from './vci/types';
6
+ import { AuthCodeFlowHandle, BeginAuthCodeFlowResult } from './vci/auth-code';
7
+ import { StoreAcceptedCredentialsOptions, StoreAcceptedCredentialsResult } from './vci/store';
8
+ import { AuthorizationRequest, ParsedAuthorizationRequest } from './vp/types';
9
+ import { CandidateCredential, PresentationSubmission, SelectionResult } from './vp/select';
10
+ import { ChosenCredential, PreparedPresentation, VpFormat } from './vp/present';
11
+ import { SignPresentationResult } from './vp/sign';
12
+ import { SubmitPresentationResult } from './vp/submit';
13
+ import { DidResolver } from './vp/request-object';
14
+ import { SignIdTokenResult } from './siop/sign';
15
+ import { ProofJwtSigner } from './vci/types';
16
+ import type { DcqlChosenCredential, BuiltDcqlPresentation } from './dcql/build';
17
+ import type { DcqlSelectionResult } from './dcql/select';
18
+ import type { DcqlSignedPresentation } from './dcql/respond';
19
+ /**
20
+ * A holder pick for either the PEX or DCQL pipeline.
21
+ *
22
+ * The plugin auto-routes based on which query language the verifier's
23
+ * Authorization Request carried:
24
+ *
25
+ * - PEX (`request.presentation_definition` set) → entries MUST use
26
+ * {@link ChosenCredential} (with `descriptorId`).
27
+ * - DCQL (`request.dcql_query` set) → entries MUST use
28
+ * {@link DcqlChosenCredential} (with `credentialQueryId`).
29
+ *
30
+ * Mixing shapes within a single call is rejected with a typed error
31
+ * — every entry must match the request's query language.
32
+ */
33
+ export type ChosenForPresentation = ChosenCredential | DcqlChosenCredential;
34
+ /**
35
+ * Methods the host LearnCard must provide for the OpenID4VC plugin to work.
36
+ *
37
+ * We lean on the existing VC plugin for credential signing (needed for
38
+ * proof-of-possession JWTs and, eventually, VP token construction) and on
39
+ * the `id` plane for keypair/DID access.
40
+ */
41
+ export type OpenID4VCPluginDependentMethods = {
42
+ issueCredential: (credential: UnsignedVC, signingOptions?: Partial<ProofOptions>) => Promise<VC>;
43
+ issuePresentation: (presentation: UnsignedVP, signingOptions?: Partial<ProofOptions>) => Promise<VP>;
44
+ didToVerificationMethod: (did: string) => Promise<string>;
45
+ };
46
+ /** Public surface of the OpenID4VC plugin. */
47
+ export type OpenID4VCPluginMethods = {
48
+ /**
49
+ * Parse an OpenID4VCI Credential Offer URI. Does not hit the network.
50
+ *
51
+ * Returns a discriminated union so callers can decide whether to resolve
52
+ * a by-reference offer themselves or delegate to {@link resolveCredentialOffer}.
53
+ */
54
+ parseCredentialOffer: (input: string) => ParsedCredentialOfferUri;
55
+ /**
56
+ * Parse a Credential Offer URI and, if it's by-reference, fetch and
57
+ * normalize the underlying offer. Returns the normalized Draft 13 offer.
58
+ */
59
+ resolveCredentialOffer: (input: string) => Promise<CredentialOffer>;
60
+ /**
61
+ * Drive the pre-authorized_code flow end-to-end for a credential offer
62
+ * and return the raw issued credentials. Accepts either a Credential
63
+ * Offer URI (which will be parsed + resolved) or an already-parsed offer.
64
+ *
65
+ * The plugin auto-builds an Ed25519 proof-of-possession signer from the
66
+ * host LearnCard's keypair. Callers using other key types (HSM, secp256k1)
67
+ * should supply their own `options.signer`.
68
+ *
69
+ * Storage of the returned credentials is the caller's responsibility.
70
+ * Use {@link acceptAndStoreCredentialOffer} for the turnkey "accept and
71
+ * persist to the wallet" flow.
72
+ */
73
+ acceptCredentialOffer: (input: string | CredentialOffer, options?: AcceptCredentialOfferOptions) => Promise<AcceptedCredentialResult>;
74
+ /**
75
+ * Accept a Credential Offer **and** persist the resulting credentials
76
+ * to the wallet's store + index planes, so they appear in the UI.
77
+ *
78
+ * Internally: runs {@link acceptCredentialOffer}, then normalizes each
79
+ * issued credential into a W3C VC (JWT → VC per VCDM §6.3.1), uploads
80
+ * to `learnCard.store.LearnCloud.uploadEncrypted` by default, and adds
81
+ * an index record so the wallet's credential list picks it up.
82
+ *
83
+ * Per-credential failures are surfaced in the `failures` array rather
84
+ * than aborting the batch — one bad credential in an offer shouldn't
85
+ * discard the rest.
86
+ */
87
+ acceptAndStoreCredentialOffer: (input: string | CredentialOffer, options?: AcceptCredentialOfferOptions & StoreAcceptedCredentialsOptions) => Promise<AcceptedCredentialResult & StoreAcceptedCredentialsResult>;
88
+ /**
89
+ * Slice 4 — phase 1 of the OID4VCI **authorization_code** flow.
90
+ *
91
+ * Resolves issuer + AS metadata, generates PKCE, and builds the
92
+ * `authorization_endpoint` URL the wallet should open in a
93
+ * user-agent. Returns an opaque `flowHandle` the wallet persists
94
+ * until the redirect callback fires.
95
+ *
96
+ * This method is purely preparation — no codes are exchanged, no
97
+ * credentials requested. The actual credential issuance happens
98
+ * in {@link completeCredentialOfferAuthCode} once the redirect
99
+ * delivers a `code`.
100
+ */
101
+ beginCredentialOfferAuthCode: (input: string | CredentialOffer, options: {
102
+ /** Wallet's OAuth 2.0 redirect_uri for the callback. Required. */
103
+ redirectUri: string;
104
+ /** Wallet's OAuth client_id. Required by most authorization servers. */
105
+ clientId: string;
106
+ /** Optional subset of credential_configuration_ids. Default: all. */
107
+ configurationIds?: string[];
108
+ /** Optional OAuth scope. */
109
+ scope?: string;
110
+ }) => Promise<BeginAuthCodeFlowResult>;
111
+ /**
112
+ * Slice 4 — phase 2 of the OID4VCI **authorization_code** flow.
113
+ *
114
+ * Takes the `code` (and `state`) delivered on the redirect
115
+ * callback, the `flowHandle` persisted from
116
+ * {@link beginCredentialOfferAuthCode}, and:
117
+ * - Exchanges the code for an access token (PKCE verifier sent).
118
+ * - Builds a proof-of-possession JWT via the host signer.
119
+ * - POSTs the credential request + returns the issued VC(s).
120
+ */
121
+ completeCredentialOfferAuthCode: (options: {
122
+ flowHandle: AuthCodeFlowHandle;
123
+ code: string;
124
+ state?: string;
125
+ signer?: AcceptCredentialOfferOptions['signer'];
126
+ }) => Promise<AcceptedCredentialResult>;
127
+ /**
128
+ * Parse an OpenID4VP Authorization Request URI. Does not hit the
129
+ * network. Returns a discriminated union so callers can detect
130
+ * signed Request Objects (`request` / `request_uri`) — those require
131
+ * JWS verification via Slice 7.
132
+ *
133
+ * @see resolveAuthorizationRequest for the one-shot version that
134
+ * also fetches `presentation_definition_uri` when present.
135
+ */
136
+ parseAuthorizationRequest: (input: string) => ParsedAuthorizationRequest;
137
+ /**
138
+ * End-to-end: parse the Authorization Request URI and, if it's a
139
+ * by-value request with an out-of-band `presentation_definition_uri`,
140
+ * fetch and inline the PD. Returns a fully resolved
141
+ * {@link AuthorizationRequest} ready for PEX matching.
142
+ *
143
+ * Throws `VpError` with code `request_object_not_supported` when
144
+ * the URI points at a signed Request Object (Slice 7 surface).
145
+ */
146
+ resolveAuthorizationRequest: (input: string) => Promise<AuthorizationRequest>;
147
+ /**
148
+ * The main OID4VP entry point for wallet UIs: resolve the verifier's
149
+ * Authorization Request, match every `input_descriptor` in its
150
+ * Presentation Definition against the holder's candidate credentials,
151
+ * and return a preview object carrying:
152
+ *
153
+ * - The resolved {@link AuthorizationRequest} (for UI to show
154
+ * verifier identity, purpose, etc.).
155
+ * - A {@link SelectionResult} with per-descriptor candidate lists
156
+ * so the UI can render selection rows and disable "Share" up
157
+ * front when `canSatisfy === false`.
158
+ *
159
+ * This method is read-only — it never signs, never POSTs, and never
160
+ * touches the holder's private keys. Actual vp_token construction
161
+ * + `direct_post` submission happens in Slice 7.
162
+ *
163
+ * Match the holder's candidate pool against either the
164
+ * verifier's PEX `presentation_definition` or DCQL `dcql_query`,
165
+ * whichever the request carries.
166
+ *
167
+ * The returned object exposes BOTH `selection` (PEX) and
168
+ * `dcqlSelection` (DCQL) fields; exactly one is populated, mirroring
169
+ * which query language the request used. Callers can either:
170
+ * - branch on `request.dcql_query` first (preferred), or
171
+ * - branch on which selection field is defined.
172
+ *
173
+ * @param input Authorization Request URI, or an already-parsed request.
174
+ * @param credentials Wallet's candidate pool (same shape used by both routes).
175
+ */
176
+ prepareVerifiablePresentation: (input: string | AuthorizationRequest, credentials: CandidateCredential[]) => Promise<{
177
+ request: AuthorizationRequest;
178
+ /** Populated when the verifier sent PEX. Undefined for DCQL requests. */
179
+ selection?: SelectionResult;
180
+ /** Populated when the verifier sent DCQL. Undefined for PEX requests. */
181
+ dcqlSelection?: DcqlSelectionResult;
182
+ }>;
183
+ /**
184
+ * Slice 7a — build an unsigned Verifiable Presentation + DIF PEX
185
+ * Presentation Submission from the user's per-descriptor picks.
186
+ *
187
+ * Pure / synchronous w.r.t. cryptography: this method never touches
188
+ * the holder's private keys, so UIs can call it to show a preview
189
+ * of exactly what will be submitted before the user consents to
190
+ * sign.
191
+ *
192
+ * @param input The verifier's Authorization Request (or URI that
193
+ * will be re-resolved for convenience).
194
+ * @param chosen One {@link ChosenCredential} per input_descriptor
195
+ * the user picked. Order determines `verifiableCredential[i]`
196
+ * slots in the VP and the corresponding `descriptor_map` entries.
197
+ * @param options `holder` defaults to `learnCard.id.did()`;
198
+ * `envelopeFormat` is inferred from `pd.format` + the inner
199
+ * credential formats when omitted.
200
+ */
201
+ buildPresentation: (input: string | AuthorizationRequest, chosen: ChosenCredential[], options?: {
202
+ holder?: string;
203
+ envelopeFormat?: VpFormat;
204
+ }) => Promise<{
205
+ request: AuthorizationRequest;
206
+ prepared: PreparedPresentation;
207
+ }>;
208
+ /**
209
+ * Slice 7b — sign a prepared VP into a submittable `vp_token`.
210
+ *
211
+ * For `jwt_vp_json` envelopes: builds a VCDM §6.3.1 JWT-VP with
212
+ * `iss`/`sub` = holder, `aud` = verifier `client_id`, `nonce` =
213
+ * verifier nonce, and signs with an Ed25519 signer derived from
214
+ * the host's primary keypair (unless overridden via `options.signer`).
215
+ *
216
+ * For `ldp_vp` envelopes: delegates to
217
+ * `learnCard.invoke.issuePresentation`, passing `domain = client_id`
218
+ * and `challenge = nonce` so the resulting Linked-Data proof binds
219
+ * to the verifier's replay-resistant context.
220
+ */
221
+ signPresentation: (input: string | AuthorizationRequest, prepared: PreparedPresentation, options?: {
222
+ /** Override the JWT signer (for HSM/secp256k1/etc. backends). */
223
+ signer?: ProofJwtSigner;
224
+ /** Override holder DID. Defaults to `prepared.unsignedVp.holder` or `learnCard.id.did()`. */
225
+ holder?: string;
226
+ }) => Promise<SignPresentationResult>;
227
+ /**
228
+ * Slice 7c — POST the signed `vp_token` + `presentation_submission`
229
+ * to the verifier's `response_uri` per OID4VP §8 (direct_post).
230
+ * Pass `idToken` to include a SIOPv2 id_token alongside the VP
231
+ * (required when `response_type=vp_token id_token`). `state` is
232
+ * echoed back when the verifier included one.
233
+ */
234
+ submitPresentation: (input: string | AuthorizationRequest, signed: SignPresentationResult, submission: PresentationSubmission, options?: {
235
+ idToken?: string;
236
+ }) => Promise<SubmitPresentationResult>;
237
+ /**
238
+ * Slice 8 — sign a SIOPv2 ID token proving holder control of
239
+ * their DID. Used on its own for SIOPv2-only flows
240
+ * (`response_type=id_token`), or bundled into `presentCredentials`
241
+ * for combined `vp_token id_token` flows.
242
+ */
243
+ signIdToken: (input: string | AuthorizationRequest, options?: {
244
+ holder?: string;
245
+ signer?: ProofJwtSigner;
246
+ lifetimeSeconds?: number;
247
+ issuerMode?: 'did' | 'self-issued.me';
248
+ vpTokenHash?: string;
249
+ }) => Promise<SignIdTokenResult>;
250
+ /**
251
+ * End-to-end convenience: resolve the verifier's request, build +
252
+ * sign the VP around the user's picks, and POST it. Returns every
253
+ * intermediate stage so UIs can surface per-step progress or errors.
254
+ *
255
+ * When the verifier's `response_type` includes `id_token`, a
256
+ * SIOPv2 id_token is also signed and included in the direct_post
257
+ * submission. The returned `signedIdToken` is populated on those
258
+ * flows; on pure `vp_token` flows it's undefined.
259
+ *
260
+ * Typed error codes bubble up from each stage (`BuildPresentationError`,
261
+ * `VpSignError`, `SiopSignError`, `VpSubmitError`) — wrap this in
262
+ * a `try/catch` to distinguish "we couldn't build the VP" from
263
+ * "the verifier rejected it" in the UI.
264
+ */
265
+ presentCredentials: (input: string | AuthorizationRequest, chosen: ChosenForPresentation[], options?: {
266
+ holder?: string;
267
+ envelopeFormat?: VpFormat;
268
+ signer?: ProofJwtSigner;
269
+ }) => Promise<{
270
+ request: AuthorizationRequest;
271
+ /**
272
+ * PEX flow output: the unsigned VP + DIF PEX presentation_submission
273
+ * built before signing. Populated only when the request carried
274
+ * `presentation_definition`.
275
+ */
276
+ prepared?: PreparedPresentation;
277
+ /**
278
+ * PEX flow output: the signed PEX `vp_token`. Populated only when
279
+ * the request carried `presentation_definition`.
280
+ */
281
+ signed?: SignPresentationResult;
282
+ /** SIOPv2 id_token (both PEX and DCQL flows route through this). */
283
+ signedIdToken?: SignIdTokenResult;
284
+ /**
285
+ * DCQL flow output: per-credential-query unsigned VPs.
286
+ * Populated only when the request carried `dcql_query`.
287
+ */
288
+ dcqlBuilt?: BuiltDcqlPresentation[];
289
+ /**
290
+ * DCQL flow output: per-credential-query signed presentations.
291
+ * Populated only when the request carried `dcql_query`.
292
+ */
293
+ dcqlSigned?: DcqlSignedPresentation[];
294
+ /**
295
+ * DCQL flow output: the assembled `vp_token` object (keys =
296
+ * credential_query_id, values = signed presentations).
297
+ * Populated only when the request carried `dcql_query`.
298
+ */
299
+ dcqlVpToken?: Record<string, unknown>;
300
+ /** HTTP-level result of the direct_post submission. Always populated. */
301
+ submitted: SubmitPresentationResult;
302
+ }>;
303
+ };
304
+ /** Configuration passed to {@link getOpenID4VCPlugin}. */
305
+ export interface OpenID4VCPluginConfig {
306
+ /**
307
+ * Fetch implementation used for HTTP calls (offer resolution,
308
+ * issuer metadata, token exchange, credential request).
309
+ *
310
+ * Defaults to `globalThis.fetch` when available.
311
+ */
312
+ fetch?: typeof fetch;
313
+ /**
314
+ * DID resolver used to verify signed Authorization Request Objects
315
+ * whose `client_id_scheme=did` (Slice 7.5). When omitted, a
316
+ * built-in resolver handles `did:jwk` (offline) and `did:web` (over
317
+ * `fetch`). Host apps shipping `did:key` / `did:ion` / `did:pkh`
318
+ * etc. wire their own resolver here.
319
+ */
320
+ didResolver?: DidResolver;
321
+ /**
322
+ * PEM-encoded trust anchors for signed Request Objects whose
323
+ * `client_id_scheme=x509_san_dns` (Slice 7.5). When empty, the
324
+ * plugin refuses x509-signed requests unless
325
+ * {@link unsafeAllowSelfSignedRequestObject} is explicitly true.
326
+ */
327
+ trustedX509Roots?: readonly string[];
328
+ /**
329
+ * **Dev-only.** When true, accept `x509_san_dns` chains that don't
330
+ * root into {@link trustedX509Roots}. Exists so smoke tests can
331
+ * hit self-signed staging verifiers; production wallets must leave
332
+ * this off.
333
+ */
334
+ unsafeAllowSelfSignedRequestObject?: boolean;
335
+ /**
336
+ * **Maximally dangerous, dev-only.** Skip JWS signature
337
+ * verification on signed Request Objects entirely (claims are
338
+ * still parsed). Use ONLY when interoperating with a verifier
339
+ * whose signing keys are pre-shared out-of-band and not
340
+ * published on any in-band channel (e.g. EUDI's reference
341
+ * verifier in `pre-registered` mode, which embeds
342
+ * `kid: "access_certificate"` referencing a keystore inside
343
+ * the verifier container with no JWKS endpoint).
344
+ *
345
+ * Production wallets MUST leave this off — when set, tampered
346
+ * Request Objects bypass detection. The other binding checks
347
+ * (URL `client_id` ↔ signed `client_id`, mutual exclusion of
348
+ * PEX vs. DCQL, etc.) still run because they're integrity
349
+ * checks against the host-supplied URL, not the signature.
350
+ */
351
+ unsafeSkipRequestObjectSignatureVerification?: boolean;
352
+ }
353
+ /** LearnCard shape the plugin factory consumes. */
354
+ export type OpenID4VCDependentLearnCard = LearnCard<any, 'id', OpenID4VCPluginDependentMethods>;
355
+ /** LearnCard shape after the plugin has been added. */
356
+ export type OpenID4VCImplicitLearnCard = LearnCard<any, 'id', OpenID4VCPluginMethods & OpenID4VCPluginDependentMethods>;
357
+ /** @group OpenID4VC Plugin */
358
+ export type OpenID4VCPlugin = Plugin<'OpenID4VC', any, OpenID4VCPluginMethods, 'id', OpenID4VCPluginDependentMethods>;
359
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { CredentialOffer } from '../offer/types';
2
+ import { AcceptCredentialOfferOptions, AcceptedCredentialResult, ProofJwtSigner } from './types';
3
+ /**
4
+ * Drive the pre-authorized_code flow end-to-end for a single credential
5
+ * offer, returning the raw issued credentials.
6
+ *
7
+ * Flow:
8
+ * 1. Validate the offer has the pre-authorized_code grant.
9
+ * 2. Fetch issuer metadata + resolve the authorization server.
10
+ * 3. Fetch AS metadata to discover the token endpoint.
11
+ * 4. Exchange the pre-auth code (+ optional tx_code) for an access token.
12
+ * 5. Build a proof-of-possession JWT bound to the issuer + c_nonce.
13
+ * 6. POST a credential request per configuration id.
14
+ * 7. Aggregate the returned credentials.
15
+ *
16
+ * Storage (wallet index, LearnCloud) happens in Slice 3.
17
+ */
18
+ export declare const acceptCredentialOffer: (args: {
19
+ offer: CredentialOffer;
20
+ signer: ProofJwtSigner;
21
+ options?: AcceptCredentialOfferOptions;
22
+ fetchImpl?: typeof fetch;
23
+ }) => Promise<AcceptedCredentialResult>;
24
+ //# sourceMappingURL=accept.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accept.d.ts","sourceRoot":"","sources":["../../src/vci/accept.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAA6B,MAAM,gBAAgB,CAAC;AAS5E,OAAO,EACH,4BAA4B,EAC5B,wBAAwB,EACxB,cAAc,EACjB,MAAM,SAAS,CAAC;AAGjB;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB,SAAgB;IAC9C,KAAK,EAAE,eAAe,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,CAAC,EAAE,4BAA4B,CAAC;IACvC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC5B,KAAG,OAAO,CAAC,wBAAwB,CA8InC,CAAC"}