agentic-payments 0.1.14 → 0.1.16

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.
@@ -1,7 +1,18 @@
1
1
  /**
2
2
  * QUIC Transport Integration for Visa TAP
3
3
  *
4
- * Bridges agentic-payments with agentic-flow QUIC transport
4
+ * Bridges agentic-payments with the agentic-flow QUIC transport.
5
+ *
6
+ * No published agentic-flow release ships a working QUIC transport:
7
+ * `agentic-flow/transport/quic` is a placeholder whose `send()` discards the
8
+ * data. This transport therefore refuses to connect unless agentic-flow
9
+ * reports QUIC as available (`getQuicStatus()`), and never reports a payment
10
+ * as sent unless a real response comes back.
11
+ *
12
+ * It deliberately does not fall back to agentic-flow's WebSocket transport:
13
+ * no Visa TAP endpoint speaks that framing, its `send()` has no
14
+ * application-level acknowledgement, and plain `ws://` would carry mandates
15
+ * in cleartext. Failing closed is the only safe behaviour for payments.
5
16
  */
6
17
  // Dynamic import to handle optional dependency gracefully
7
18
  let QuicTransport = null;
@@ -38,16 +49,102 @@ export async function loadQuicTransport() {
38
49
  QuicTransport = mod.QuicTransport;
39
50
  return QuicTransport;
40
51
  }
52
+ /** Error code carried by {@link QuicTransportUnavailableError}. */
53
+ export const QUIC_UNAVAILABLE = 'QUIC_UNAVAILABLE';
54
+ /** Error code carried by {@link PaymentNotDeliveredError}. */
55
+ export const PAYMENT_NOT_DELIVERED = 'PAYMENT_NOT_DELIVERED';
56
+ /**
57
+ * Thrown by {@link VisaTapQuicTransport.connect} when no working QUIC
58
+ * transport is available, so nothing could be delivered.
59
+ */
60
+ export class QuicTransportUnavailableError extends Error {
61
+ reason;
62
+ code = QUIC_UNAVAILABLE;
63
+ constructor(reason) {
64
+ super(`Visa TAP QUIC transport is unavailable: ${reason} No payment data can be sent over it; submit the mandate over HTTPS instead.`);
65
+ this.reason = reason;
66
+ this.name = 'QuicTransportUnavailableError';
67
+ }
68
+ }
69
+ /**
70
+ * Thrown when a send did not produce a confirmed response, so the caller must
71
+ * treat the payment message as not delivered.
72
+ */
73
+ export class PaymentNotDeliveredError extends Error {
74
+ code = PAYMENT_NOT_DELIVERED;
75
+ constructor(message) {
76
+ super(message);
77
+ this.name = 'PaymentNotDeliveredError';
78
+ }
79
+ }
80
+ const NO_PROBE_REASON = 'the installed agentic-flow has no getQuicStatus()/isQuicAvailable() probe, and its ' +
81
+ 'agentic-flow/transport/quic QuicTransport is a placeholder that sends no bytes.';
82
+ /**
83
+ * Ask agentic-flow whether its QUIC transport can actually move data.
84
+ *
85
+ * Fails closed: QUIC counts as available only when agentic-flow exports a
86
+ * probe and that probe says so. Older agentic-flow releases have no probe,
87
+ * and their QuicTransport is the same placeholder, so they are unavailable.
88
+ */
89
+ export async function getQuicTransportStatus(mod) {
90
+ if (!mod) {
91
+ try {
92
+ // @ts-ignore - Dynamic import of optional peer dependency
93
+ mod = await import(AGENTIC_FLOW_QUIC_MODULE);
94
+ }
95
+ catch {
96
+ return {
97
+ available: false,
98
+ reason: `agentic-flow is not installed (npm install agentic-flow@"${AGENTIC_FLOW_PEER_RANGE}").`,
99
+ };
100
+ }
101
+ }
102
+ try {
103
+ if (typeof mod?.getQuicStatus === 'function') {
104
+ const status = await mod.getQuicStatus();
105
+ if (status?.available === true)
106
+ return { available: true };
107
+ return {
108
+ available: false,
109
+ reason: String(status?.reason || 'agentic-flow reports QUIC as unavailable.'),
110
+ };
111
+ }
112
+ if (typeof mod?.isQuicAvailable === 'function') {
113
+ if ((await mod.isQuicAvailable()) === true)
114
+ return { available: true };
115
+ return { available: false, reason: 'agentic-flow reports QUIC as unavailable.' };
116
+ }
117
+ }
118
+ catch (error) {
119
+ return { available: false, reason: `agentic-flow QUIC probe failed: ${String(error)}` };
120
+ }
121
+ return { available: false, reason: NO_PROBE_REASON };
122
+ }
41
123
  /**
42
124
  * Visa TAP QUIC Transport
43
125
  *
44
- * Provides high-performance QUIC transport for Visa TAP payments
45
- * with 0-RTT connection resumption and multiplexed streams.
126
+ * QUIC transport for Visa TAP payments, backed by agentic-flow.
127
+ *
128
+ * `connect()` rejects with {@link QuicTransportUnavailableError} unless
129
+ * agentic-flow reports a working QUIC transport. With every agentic-flow
130
+ * release published so far it rejects. Use {@link VisaTapQuicTransport.create}
131
+ * to construct and check in one step.
46
132
  */
47
133
  export class VisaTapQuicTransport {
48
134
  quic = null;
49
135
  config;
50
136
  connected = false;
137
+ /**
138
+ * Construct a transport and connect it, failing fast when QUIC is
139
+ * unavailable.
140
+ *
141
+ * @throws QuicTransportUnavailableError when no working QUIC transport exists
142
+ */
143
+ static async create(config) {
144
+ const transport = new VisaTapQuicTransport(config);
145
+ await transport.connect();
146
+ return transport;
147
+ }
51
148
  constructor(config) {
52
149
  this.config = {
53
150
  timeout: 30000,
@@ -57,12 +154,18 @@ export class VisaTapQuicTransport {
57
154
  };
58
155
  }
59
156
  /**
60
- * Connect to QUIC server
157
+ * Connect to the QUIC server.
61
158
  *
62
- * Supports 0-RTT connection resumption for sub-millisecond reconnection
159
+ * @throws Error with install instructions when agentic-flow is not installed
160
+ * @throws QuicTransportUnavailableError when agentic-flow has no working QUIC
63
161
  */
64
162
  async connect() {
65
163
  const QuicClient = await loadQuicTransport();
164
+ // @ts-ignore - Dynamic import of optional peer dependency (cached by loadQuicTransport)
165
+ const status = await getQuicTransportStatus(await import(AGENTIC_FLOW_QUIC_MODULE));
166
+ if (!status.available) {
167
+ throw new QuicTransportUnavailableError(status.reason ?? 'unknown reason.');
168
+ }
66
169
  this.quic = new QuicClient({
67
170
  host: this.config.host,
68
171
  port: this.config.port,
@@ -75,7 +178,8 @@ export class VisaTapQuicTransport {
75
178
  * Send payment request over QUIC
76
179
  *
77
180
  * @param signedMandate - Cryptographically signed Active Mandate
78
- * @returns Payment response
181
+ * @returns Payment response returned by the server
182
+ * @throws PaymentNotDeliveredError when no response with a transactionId came back
79
183
  */
80
184
  async sendPayment(signedMandate) {
81
185
  if (!this.connected) {
@@ -92,13 +196,19 @@ export class VisaTapQuicTransport {
92
196
  * Send raw payment data
93
197
  *
94
198
  * @param data - Payment data object
95
- * @returns Response data
199
+ * @returns Response data returned by the server
200
+ * @throws PaymentNotDeliveredError when the transport returned no response
96
201
  */
97
202
  async send(data) {
98
203
  if (!this.connected) {
99
204
  throw new Error('Not connected. Call connect() first.');
100
205
  }
101
- return await this.quic.send(data);
206
+ const response = await this.quic.send(data);
207
+ if (response === undefined || response === null) {
208
+ throw new PaymentNotDeliveredError('The QUIC transport returned no response, so delivery is unconfirmed. ' +
209
+ 'Treat the message as not sent.');
210
+ }
211
+ return response;
102
212
  }
103
213
  /**
104
214
  * Get connection statistics
@@ -137,23 +247,21 @@ export class VisaTapQuicTransport {
137
247
  }
138
248
  }
139
249
  /**
140
- * Parse payment response from QUIC
250
+ * Validate a payment response from the server.
251
+ *
252
+ * Never synthesises a response: a missing response, or one without a
253
+ * transactionId and a known status, means the payment was not confirmed.
141
254
  */
142
255
  parsePaymentResponse(raw) {
143
- // agentic-flow 2.x/3.x QuicTransport.send() resolves to undefined
144
- const response = raw ?? {};
145
- // Handle different response formats
146
- if (response.transactionId) {
147
- return response;
256
+ const transactionId = raw?.transactionId;
257
+ if (raw === undefined || raw === null || typeof transactionId !== 'string' || !transactionId) {
258
+ throw new PaymentNotDeliveredError('The QUIC transport returned no payment response with a transactionId, so the ' +
259
+ 'payment was not confirmed. Treat it as not sent.');
148
260
  }
149
- // Default response format
150
- return {
151
- transactionId: response.id || crypto.randomUUID(),
152
- status: response.status || 'pending',
153
- amount: response.amount || 0,
154
- currency: response.currency || 'USD',
155
- timestamp: new Date().toISOString(),
156
- };
261
+ if (!['approved', 'declined', 'pending'].includes(raw.status)) {
262
+ throw new PaymentNotDeliveredError(`The payment response has an unknown status (${String(raw.status)}); treat it as not confirmed.`);
263
+ }
264
+ return raw;
157
265
  }
158
266
  }
159
267
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"quic-transport.js","sourceRoot":"","sources":["../../src/visa-tap/quic-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"quic-transport.js","sourceRoot":"","sources":["../../src/visa-tap/quic-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Strict parsing and serialization of the RFC 9421 `Signature-Input` and
3
+ * `Signature` fields (RFC 8941 structured-field dictionaries).
4
+ *
5
+ * Only the subset RFC 9421 needs is accepted: dictionary members whose value
6
+ * is an inner list of component identifiers (Signature-Input) or a byte
7
+ * sequence (Signature). Anything else is rejected rather than guessed at.
8
+ */
9
+ /** A signature parameter value (RFC 9421 §2.3). */
10
+ export type SignatureParamValue = number | string;
11
+ /** A parsed Signature-Input member. */
12
+ export interface ParsedSignatureInput {
13
+ label: string;
14
+ /** Covered component identifiers, in the order they were listed. */
15
+ components: string[];
16
+ /** Signature parameters, in the order they were listed. */
17
+ params: Array<[string, SignatureParamValue]>;
18
+ }
19
+ /** Parse every member of a Signature-Input field. Throws on malformed input. */
20
+ export declare function parseSignatureInputField(field: string): Map<string, ParsedSignatureInput>;
21
+ /** Parse every member of a Signature field. Throws on malformed input. */
22
+ export declare function parseSignatureField(field: string): Map<string, Uint8Array>;
23
+ /** Serialize a string as an RFC 8941 sf-string. */
24
+ export declare function serializeString(value: string): string;
25
+ /** Serialize the inner list + parameters, i.e. the `@signature-params` value. */
26
+ export declare function serializeSignatureParams(components: readonly string[], params: ReadonlyArray<readonly [string, SignatureParamValue]>): string;
27
+ /** Validate a dictionary key (signature label). */
28
+ export declare function assertLabel(label: string): void;
29
+ //# sourceMappingURL=rfc9421-fields.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rfc9421-fields.d.ts","sourceRoot":"","sources":["../../src/visa-tap/rfc9421-fields.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,mDAAmD;AACnD,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,MAAM,CAAC;AAElD,uCAAuC;AACvC,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,2DAA2D;IAC3D,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC;CAC9C;AAoJD,gFAAgF;AAChF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAKzF;AAED,0EAA0E;AAC1E,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAE1E;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKrD;AAED,iFAAiF;AACjF,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,GAC5D,MAAM,CAaR;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAE/C"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Strict parsing and serialization of the RFC 9421 `Signature-Input` and
3
+ * `Signature` fields (RFC 8941 structured-field dictionaries).
4
+ *
5
+ * Only the subset RFC 9421 needs is accepted: dictionary members whose value
6
+ * is an inner list of component identifiers (Signature-Input) or a byte
7
+ * sequence (Signature). Anything else is rejected rather than guessed at.
8
+ */
9
+ /** Parameters RFC 9421 §2.3 defines, and the type each must have. */
10
+ const PARAM_TYPES = {
11
+ created: 'integer',
12
+ expires: 'integer',
13
+ nonce: 'string',
14
+ alg: 'string',
15
+ keyid: 'string',
16
+ tag: 'string',
17
+ };
18
+ const KEY_RE = /^[a-z*][a-z0-9_\-.*]*$/;
19
+ const MAX_INTEGER = 999_999_999_999_999;
20
+ class Cursor {
21
+ src;
22
+ pos = 0;
23
+ constructor(src) {
24
+ this.src = src;
25
+ }
26
+ peek() {
27
+ return this.src[this.pos];
28
+ }
29
+ eof() {
30
+ return this.pos >= this.src.length;
31
+ }
32
+ skipSP() {
33
+ while (this.src[this.pos] === ' ')
34
+ this.pos++;
35
+ }
36
+ skipOWS() {
37
+ while (this.src[this.pos] === ' ' || this.src[this.pos] === '\t')
38
+ this.pos++;
39
+ }
40
+ expect(ch) {
41
+ if (this.src[this.pos] !== ch) {
42
+ throw new Error(`expected "${ch}" at offset ${this.pos}`);
43
+ }
44
+ this.pos++;
45
+ }
46
+ }
47
+ function parseKey(c) {
48
+ const start = c.pos;
49
+ while (!c.eof() && /[a-z0-9_\-.*]/.test(c.peek()))
50
+ c.pos++;
51
+ const key = c.src.slice(start, c.pos);
52
+ if (!KEY_RE.test(key))
53
+ throw new Error(`invalid key at offset ${start}`);
54
+ return key;
55
+ }
56
+ function parseString(c) {
57
+ c.expect('"');
58
+ let out = '';
59
+ for (;;) {
60
+ const ch = c.peek();
61
+ if (ch === undefined)
62
+ throw new Error('unterminated string');
63
+ c.pos++;
64
+ if (ch === '"')
65
+ return out;
66
+ if (ch === '\\') {
67
+ const next = c.peek();
68
+ if (next !== '"' && next !== '\\')
69
+ throw new Error('invalid string escape');
70
+ out += next;
71
+ c.pos++;
72
+ continue;
73
+ }
74
+ const code = ch.charCodeAt(0);
75
+ if (code < 0x20 || code > 0x7e)
76
+ throw new Error('invalid character in string');
77
+ out += ch;
78
+ }
79
+ }
80
+ function parseInteger(c) {
81
+ const start = c.pos;
82
+ if (c.peek() === '-')
83
+ c.pos++;
84
+ const digitsStart = c.pos;
85
+ while (!c.eof() && /[0-9]/.test(c.peek()))
86
+ c.pos++;
87
+ const digits = c.pos - digitsStart;
88
+ if (digits === 0 || digits > 15)
89
+ throw new Error(`invalid integer at offset ${start}`);
90
+ if (c.peek() === '.')
91
+ throw new Error('decimals are not allowed here');
92
+ return Number(c.src.slice(start, c.pos));
93
+ }
94
+ function parseParams(c) {
95
+ const params = [];
96
+ const seen = new Set();
97
+ while (c.peek() === ';') {
98
+ c.pos++;
99
+ c.skipSP();
100
+ const key = parseKey(c);
101
+ if (seen.has(key))
102
+ throw new Error(`duplicate parameter "${key}"`);
103
+ seen.add(key);
104
+ const type = PARAM_TYPES[key];
105
+ if (!type)
106
+ throw new Error(`unsupported signature parameter "${key}"`);
107
+ c.expect('=');
108
+ const value = type === 'integer' ? parseInteger(c) : parseString(c);
109
+ params.push([key, value]);
110
+ }
111
+ return params;
112
+ }
113
+ /** Split a structured-field dictionary into raw `[key, valueText]` members. */
114
+ function parseDictionary(field, parseValue) {
115
+ const c = new Cursor(field.trim());
116
+ const out = new Map();
117
+ if (c.eof())
118
+ throw new Error('empty dictionary');
119
+ for (;;) {
120
+ const key = parseKey(c);
121
+ if (out.has(key))
122
+ throw new Error(`duplicate dictionary member "${key}"`);
123
+ c.expect('=');
124
+ out.set(key, parseValue(c));
125
+ c.skipOWS();
126
+ if (c.eof())
127
+ return out;
128
+ c.expect(',');
129
+ c.skipOWS();
130
+ if (c.eof())
131
+ throw new Error('trailing comma in dictionary');
132
+ }
133
+ }
134
+ function parseInnerList(c) {
135
+ c.expect('(');
136
+ const components = [];
137
+ c.skipSP();
138
+ while (c.peek() !== ')') {
139
+ if (c.eof())
140
+ throw new Error('unterminated inner list');
141
+ components.push(parseString(c));
142
+ if (c.peek() === ';')
143
+ throw new Error('component parameters are not supported');
144
+ const before = c.pos;
145
+ c.skipSP();
146
+ if (c.peek() !== ')' && c.pos === before) {
147
+ throw new Error('inner list items must be separated by a space');
148
+ }
149
+ }
150
+ c.pos++;
151
+ return { components, params: parseParams(c) };
152
+ }
153
+ function parseByteSequence(c) {
154
+ c.expect(':');
155
+ const start = c.pos;
156
+ while (!c.eof() && c.peek() !== ':')
157
+ c.pos++;
158
+ const b64 = c.src.slice(start, c.pos);
159
+ c.expect(':');
160
+ if (c.peek() === ';')
161
+ throw new Error('signature parameters are not supported');
162
+ if (!/^[A-Za-z0-9+/]*={0,2}$/.test(b64) || b64.length % 4 !== 0) {
163
+ throw new Error('invalid base64 in byte sequence');
164
+ }
165
+ return new Uint8Array(Buffer.from(b64, 'base64'));
166
+ }
167
+ /** Parse every member of a Signature-Input field. Throws on malformed input. */
168
+ export function parseSignatureInputField(field) {
169
+ const raw = parseDictionary(field, parseInnerList);
170
+ const out = new Map();
171
+ for (const [label, value] of raw)
172
+ out.set(label, { label, ...value });
173
+ return out;
174
+ }
175
+ /** Parse every member of a Signature field. Throws on malformed input. */
176
+ export function parseSignatureField(field) {
177
+ return parseDictionary(field, parseByteSequence);
178
+ }
179
+ /** Serialize a string as an RFC 8941 sf-string. */
180
+ export function serializeString(value) {
181
+ if (!/^[\x20-\x7e]*$/.test(value)) {
182
+ throw new Error('structured-field strings must be printable ASCII');
183
+ }
184
+ return `"${value.replace(/[\\"]/g, (m) => `\\${m}`)}"`;
185
+ }
186
+ /** Serialize the inner list + parameters, i.e. the `@signature-params` value. */
187
+ export function serializeSignatureParams(components, params) {
188
+ const list = `(${components.map(serializeString).join(' ')})`;
189
+ const rendered = params.map(([key, value]) => {
190
+ if (!KEY_RE.test(key))
191
+ throw new Error(`invalid parameter name "${key}"`);
192
+ if (typeof value === 'number') {
193
+ if (!Number.isInteger(value) || Math.abs(value) > MAX_INTEGER) {
194
+ throw new Error(`parameter "${key}" must be an integer`);
195
+ }
196
+ return `;${key}=${value}`;
197
+ }
198
+ return `;${key}=${serializeString(value)}`;
199
+ });
200
+ return list + rendered.join('');
201
+ }
202
+ /** Validate a dictionary key (signature label). */
203
+ export function assertLabel(label) {
204
+ if (!KEY_RE.test(label))
205
+ throw new Error(`invalid signature label "${label}"`);
206
+ }
207
+ //# sourceMappingURL=rfc9421-fields.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rfc9421-fields.js","sourceRoot":"","sources":["../../src/visa-tap/rfc9421-fields.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,37 @@
1
1
  /**
2
- * RFC 9421 HTTP Message Signatures
2
+ * RFC 9421 HTTP Message Signatures (Ed25519)
3
3
  *
4
- * Implements cryptographic signing and verification of HTTP requests per RFC 9421
4
+ * The signer lists every component it signs, in signing order, in the
5
+ * `Signature-Input` field, and the `@signature-params` line of the signature
6
+ * base is byte-identical to that field's value, so any RFC 9421 verifier can
7
+ * rebuild the same base. The verifier is driven by the received
8
+ * `Signature-Input`: it rebuilds the base in the listed order, refuses
9
+ * components the caller relies on but the signer did not cover, and checks
10
+ * `created`, `expires` and `alg`.
5
11
  */
6
- import type { SignatureComponents, SignedHttpMessage } from './types.js';
12
+ import type { SignatureComponents, SignedHttpMessage, SignHttpMessageOptions, VerifiableHttpSignature, VerifyHttpSignatureOptions } from './types.js';
7
13
  /**
8
- * Sign HTTP message per RFC 9421
14
+ * Sign an HTTP request per RFC 9421 with Ed25519.
15
+ *
16
+ * Covers `@method`, `@authority`, `@path`, then `content-digest` when
17
+ * `contentDigest` is given, then every entry of `headers` in insertion order.
18
+ * All of them are listed, in that order, in `Signature-Input`.
9
19
  */
10
- export declare function signHttpMessage(components: SignatureComponents, privateKeyHex: string, keyId: string): Promise<SignedHttpMessage>;
20
+ export declare function signHttpMessage(components: SignatureComponents, privateKeyHex: string, keyId: string, options?: SignHttpMessageOptions): Promise<SignedHttpMessage>;
11
21
  /**
12
- * Verify RFC 9421 HTTP signature
22
+ * Verify an RFC 9421 Ed25519 signature on an HTTP request.
23
+ *
24
+ * `components` is the verifier's view of the received request. The signature
25
+ * base is rebuilt from the received `Signature-Input` (its order, its
26
+ * parameters). Verification fails unless every supplied component, including
27
+ * `contentDigest` and every entry of `headers`, is covered, `created` is
28
+ * present and no older than `maxAgeSeconds` (and not in the future beyond the
29
+ * clock skew), `expires` (if present) has not passed, and `alg` (if present)
30
+ * is `ed25519`. Never throws; returns false on any failure.
13
31
  *
14
- * @param maxAgeSeconds - Maximum age of signature in seconds (default: 300 = 5 minutes)
32
+ * @param maxAgeSeconds - Maximum age of the signature in seconds (default 300)
15
33
  */
16
- export declare function verifyHttpSignature(components: SignatureComponents, signed: SignedHttpMessage, publicKeyHex: string, maxAgeSeconds?: number): Promise<boolean>;
34
+ export declare function verifyHttpSignature(components: SignatureComponents, signed: VerifiableHttpSignature, publicKeyHex: string, maxAgeSeconds?: number, options?: VerifyHttpSignatureOptions): Promise<boolean>;
17
35
  /**
18
36
  * Compute content digest (SHA-256)
19
37
  */
@@ -1 +1 @@
1
- {"version":3,"file":"rfc9421.d.ts","sourceRoot":"","sources":["../../src/visa-tap/rfc9421.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEzE;;GAEG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,mBAAmB,EAC/B,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,iBAAiB,CAAC,CA2C5B;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,iBAAiB,EACzB,YAAY,EAAE,MAAM,EACpB,aAAa,GAAE,MAAY,GAC1B,OAAO,CAAC,OAAO,CAAC,CAwDlB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAI7D"}
1
+ {"version":3,"file":"rfc9421.d.ts","sourceRoot":"","sources":["../../src/visa-tap/rfc9421.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,EACvB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AA4EpB;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,UAAU,EAAE,mBAAmB,EAC/B,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,iBAAiB,CAAC,CAkC5B;AAqED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,uBAAuB,EAC/B,YAAY,EAAE,MAAM,EACpB,aAAa,GAAE,MAAY,EAC3B,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,OAAO,CAAC,CAwBlB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAI7D"}