@edge-markets/connect-node 1.8.0 → 1.10.0

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/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as node_https from 'node:https';
2
- import { EdgeEnvironment, TransferCategory, Transfer, VerificationSession, TransferType, User, VerifyIdentityOptions, VerifyIdentityResult, Balance, ListTransfersParams, TransferList, CreateVerificationSessionRequest, VerificationSessionStatusResponse, EdgeTokens, EdgeWebhookEvent, TransferStatus, EdgeWebhookEventType } from '@edge-markets/connect';
3
- export { Balance, BaseWebhookEvent, ConsentRevokedEventData, CreateVerificationSessionRequest, EDGE_WEBHOOK_EVENT_TYPES, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeIdentityVerificationError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, EdgeValidationError, EdgeWebhookEvent, EdgeWebhookEventType, ListTransfersParams, SdkGeolocation, TRANSFER_CATEGORIES, Transfer, TransferCategory, TransferCompletedEventData, TransferExpiredEventData, TransferFailedEventData, TransferList, TransferListItem, TransferProcessingEventData, TransferStatus, TransferType, User, UserAddress, VerificationSession, VerificationSessionStatus, VerificationSessionStatusResponse, VerifyIdentityAddress, VerifyIdentityOptions, VerifyIdentityResult, VerifyIdentityScores, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isEdgeError, isIdentityVerificationError, isNetworkError, isProductionEnvironment } from '@edge-markets/connect';
2
+ import { EdgeEnvironment, TransferCategory, Transfer, VerificationSession, TransferType, TransferStatus, User, VerifyIdentityOptions, VerifyIdentityResult, Balance, ListTransfersParams, TransferList, CreateVerificationSessionRequest, VerificationSessionStatusResponse, EdgeTokens, EdgeWebhookEvent, EdgeWebhookEventType } from '@edge-markets/connect';
3
+ export { ACTIVE_EDGE_SCOPES, Balance, BaseWebhookEvent, ConsentRevokedEventData, CreateVerificationSessionRequest, EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE, EDGE_WEBHOOK_EVENT_TYPES, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeFeatureUnavailableError, EdgeIdentityVerificationError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, EdgeValidationError, EdgeWebhookEvent, EdgeWebhookEventType, ListTransfersParams, SdkGeolocation, TRANSFER_CATEGORIES, Transfer, TransferCategory, TransferCompletedEventData, TransferExpiredEventData, TransferFailedEventData, TransferList, TransferListItem, TransferProcessingEventData, TransferStatus, TransferType, User, UserAddress, VerificationSession, VerificationSessionStatus, VerificationSessionStatusResponse, VerifyIdentityAddress, VerifyIdentityOptions, VerifyIdentityResult, VerifyIdentityScores, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isEdgeError, isFeatureUnavailableError, isIdentityVerificationError, isNetworkError, isProductionEnvironment } from '@edge-markets/connect';
4
4
 
5
5
  type RequestEndpoint = 'connect_api' | 'oauth_token' | 'partner_webhook_sync';
6
6
  interface RequestInfo {
@@ -107,6 +107,9 @@ interface TransferAmountLimits {
107
107
  min?: string | number;
108
108
  max?: string | number;
109
109
  }
110
+ interface MoneyAmountOptions {
111
+ allowNumber?: boolean;
112
+ }
110
113
  interface CreateTransferIdempotencyKeyOptions {
111
114
  partnerUserId: string;
112
115
  type: TransferType;
@@ -121,6 +124,14 @@ interface TransferIntent {
121
124
  amount: string | number;
122
125
  category?: TransferCategory | null;
123
126
  }
127
+ type ConnectTransferDirection = 'user_to_partner' | 'partner_to_user';
128
+ interface TransferStatusMapping<TPartnerState extends string = string> {
129
+ pending_verification: TPartnerState;
130
+ processing: TPartnerState;
131
+ completed: TPartnerState;
132
+ failed: TPartnerState;
133
+ expired: TPartnerState;
134
+ }
124
135
  interface StartTransferVerificationOptions {
125
136
  transfer: TransferOptions;
126
137
  origin: string;
@@ -129,10 +140,18 @@ interface StartTransferVerificationResult {
129
140
  transfer: Transfer;
130
141
  verificationSession: VerificationSession;
131
142
  }
132
- declare function normalizeMoneyAmount(value: string | number): string;
133
- declare function validateTransferAmount(value: string | number, limits?: TransferAmountLimits): string;
143
+ declare const CONNECT_TRANSFER_DIRECTIONS: {
144
+ readonly debit: "user_to_partner";
145
+ readonly credit: "partner_to_user";
146
+ };
147
+ declare function getConnectTransferDirection(type: TransferType): ConnectTransferDirection;
148
+ declare function normalizeMoneyAmount(value: string | number, options?: MoneyAmountOptions): string;
149
+ declare function validateTransferAmount(value: string | number, limits?: TransferAmountLimits, options?: MoneyAmountOptions): string;
134
150
  declare function createTransferIdempotencyKey(options: CreateTransferIdempotencyKeyOptions): string;
135
151
  declare function assertSameTransferIntent(existing: TransferIntent, requested: TransferIntent): void;
152
+ declare function fingerprintTransferIntent(intent: TransferIntent): string;
153
+ declare function moneyAmountsEqual(left: string | number, right: string | number, options?: MoneyAmountOptions): boolean;
154
+ declare function mapTransferStatusToPartnerState<TPartnerState extends string>(status: TransferStatus, mapping: TransferStatusMapping<TPartnerState>): TPartnerState;
136
155
  declare function startTransferVerification(client: Pick<EdgeUserClient, 'initiateTransfer' | 'createVerificationSession'>, options: StartTransferVerificationOptions): Promise<StartTransferVerificationResult>;
137
156
 
138
157
  /**
@@ -156,14 +175,13 @@ declare class EdgeUserClient {
156
175
  revoked: boolean;
157
176
  }>;
158
177
  /**
159
- * Creates an EDGE-hosted transfer verification session.
160
- * Returns a `verificationUrl` to open in an iframe or popup.
161
- * The handoff token is single-use and expires in 120 seconds.
178
+ * Reserved for a future transfer release.
179
+ * Currently throws EdgeFeatureUnavailableError before validation or network I/O.
162
180
  */
163
181
  createVerificationSession(transferId: string, options: CreateVerificationSessionRequest): Promise<VerificationSession>;
164
182
  /**
165
- * Polls the status of a verification session.
166
- * Use as an alternative to postMessage events.
183
+ * Reserved for a future transfer release.
184
+ * Currently throws EdgeFeatureUnavailableError before validation or network I/O.
167
185
  */
168
186
  getVerificationSessionStatus(transferId: string, sessionId: string): Promise<VerificationSessionStatusResponse>;
169
187
  }
@@ -205,10 +223,22 @@ interface EdgeUserSessionOptions {
205
223
  refreshSkewMs?: number;
206
224
  now?: () => number;
207
225
  onRefresh?: (tokens: EdgeTokens) => Promise<void> | void;
226
+ onEvent?: (event: EdgeUserSessionEvent) => Promise<void> | void;
227
+ singleFlightRefresh?: boolean;
208
228
  }
209
229
  interface GetValidTokensOptions {
210
230
  forceRefresh?: boolean;
211
231
  }
232
+ type EdgeUserSessionEventType = 'session.loaded' | 'session.refresh_started' | 'session.refresh_succeeded' | 'session.refresh_failed' | 'session.saved';
233
+ interface EdgeUserSessionEvent {
234
+ type: EdgeUserSessionEventType;
235
+ subjectId: string;
236
+ refreshed?: boolean;
237
+ encrypted?: boolean;
238
+ expiresAt?: number;
239
+ scope?: string;
240
+ error?: string;
241
+ }
212
242
  declare class EdgeUserSession {
213
243
  private readonly edge;
214
244
  private readonly subjectId;
@@ -217,15 +247,225 @@ declare class EdgeUserSession {
217
247
  private readonly refreshSkewMs;
218
248
  private readonly now;
219
249
  private readonly onRefresh?;
250
+ private readonly onEvent?;
251
+ private readonly singleFlightRefresh;
252
+ private refreshPromise;
220
253
  constructor(options: EdgeUserSessionOptions);
221
254
  getValidTokens(options?: GetValidTokensOptions): Promise<EdgeTokens>;
222
255
  getClient(options?: GetValidTokensOptions): Promise<EdgeUserClient>;
223
- withClient<T>(callback: (client: EdgeUserClient, tokens: EdgeTokens) => Promise<T> | T): Promise<T>;
256
+ withClient<T>(callback: (client: EdgeUserClient, tokens: EdgeTokens) => Promise<T> | T, options?: GetValidTokensOptions): Promise<T>;
224
257
  saveTokens(tokens: EdgeTokens, refreshed?: boolean): Promise<void>;
225
258
  private loadTokens;
259
+ private refreshTokens;
260
+ private emitLoaded;
261
+ private emit;
226
262
  }
227
263
  declare function createEdgeUserSession(options: EdgeUserSessionOptions): EdgeUserSession;
228
264
 
265
+ /**
266
+ * Webhook Signature Verification (SDK-001)
267
+ *
268
+ * HMAC-SHA256 verification for EDGE Connect webhook payloads.
269
+ *
270
+ * Signature header format: `t={timestamp},v1={hex_hmac}`
271
+ * Signed message: `{timestamp}.{raw_json_body}`
272
+ *
273
+ * The timestamp prefix prevents replay attacks — events older than the
274
+ * tolerance window (default 5 minutes) are rejected. The HMAC is verified
275
+ * with constant-time comparison to prevent timing attacks.
276
+ */
277
+ /**
278
+ * Options for {@link verifyWebhookSignature}.
279
+ */
280
+ interface VerifyWebhookSignatureOptions {
281
+ /**
282
+ * Maximum age of the signature timestamp, in seconds.
283
+ *
284
+ * Signatures older than this are rejected as potential replays.
285
+ * Defaults to 300 seconds (5 minutes), matching the producer.
286
+ */
287
+ toleranceSeconds?: number;
288
+ }
289
+ /**
290
+ * Verifies an EDGE Connect webhook signature.
291
+ *
292
+ * **Always pass the raw request body bytes** — never `JSON.stringify(req.body)`.
293
+ * Re-stringifying after the framework parses JSON will reorder keys, change
294
+ * whitespace, and silently break verification with no diagnostic. Capture
295
+ * the raw body via your framework's raw-body middleware:
296
+ *
297
+ * - Express: `express.raw({ type: 'application/json' })`
298
+ * - Fastify: built-in (use `request.rawBody`)
299
+ * - NestJS: `{ rawBody: true }` on `NestFactory.create` + `RawBodyRequest<Request>`
300
+ *
301
+ * @param header - The `X-Edge-Signature` header value (`t=...,v1=...`)
302
+ * @param body - The raw request body as a UTF-8 string (NOT a parsed object)
303
+ * @param secret - The partner's webhook signing secret
304
+ * @param options - Optional overrides
305
+ * @returns `true` if the signature is valid and within the tolerance window,
306
+ * `false` otherwise. Never throws — malformed input returns `false`.
307
+ *
308
+ * @example
309
+ * ```typescript
310
+ * import { verifyWebhookSignature } from '@edge-markets/connect-node'
311
+ *
312
+ * app.post('/webhooks/edge', express.raw({ type: 'application/json' }), (req, res) => {
313
+ * const ok = verifyWebhookSignature(
314
+ * req.headers['x-edge-signature'] as string,
315
+ * req.body.toString('utf8'),
316
+ * process.env.EDGE_WEBHOOK_SECRET!,
317
+ * )
318
+ *
319
+ * if (!ok) return res.status(401).send('invalid signature')
320
+ *
321
+ * const event = JSON.parse(req.body.toString('utf8'))
322
+ * // ... process event
323
+ * res.status(200).send('ok')
324
+ * })
325
+ * ```
326
+ */
327
+ declare function verifyWebhookSignature(header: string, body: string, secret: string, options?: VerifyWebhookSignatureOptions): boolean;
328
+
329
+ type EdgeWebhookRawBody = string | Buffer | Uint8Array;
330
+ type EdgeWebhookSignatureHeader = string | string[] | undefined | null;
331
+ interface ParseAndVerifyWebhookOptions extends VerifyWebhookSignatureOptions {
332
+ rawBody: EdgeWebhookRawBody;
333
+ signatureHeader: EdgeWebhookSignatureHeader;
334
+ secret: string;
335
+ receivedAt?: Date;
336
+ }
337
+ interface ParsedEdgeWebhook {
338
+ event: EdgeWebhookEvent;
339
+ eventId: string;
340
+ eventType: EdgeWebhookEventType;
341
+ signatureTimestamp: number;
342
+ receivedAt: Date;
343
+ }
344
+ declare function parseAndVerifyWebhook(options: ParseAndVerifyWebhookOptions): ParsedEdgeWebhook;
345
+ declare function extractWebhookSignatureTimestamp(header: EdgeWebhookSignatureHeader): number | undefined;
346
+ declare function isEdgeWebhookEvent(value: unknown): value is EdgeWebhookEvent;
347
+ declare function validateEdgeWebhookEvent(value: unknown): EdgeWebhookEvent;
348
+
349
+ type WebhookInboxStatus = 'pending' | 'processing' | 'processed' | 'failed';
350
+ type WebhookInboxSource = 'live_webhook' | 'sync';
351
+ interface WebhookInboxRecord {
352
+ eventId: string;
353
+ eventType: EdgeWebhookEventType;
354
+ event: EdgeWebhookEvent;
355
+ payloadFingerprint: string;
356
+ status: WebhookInboxStatus;
357
+ source: WebhookInboxSource;
358
+ attempts: number;
359
+ receivedAt: Date;
360
+ updatedAt?: Date;
361
+ processedAt?: Date | null;
362
+ lastError?: string | null;
363
+ signatureTimestamp?: number | null;
364
+ signatureHeader?: string | null;
365
+ rawBody?: string | null;
366
+ }
367
+ interface WebhookInboxInsertRecord {
368
+ eventId: string;
369
+ eventType: EdgeWebhookEventType;
370
+ event: EdgeWebhookEvent;
371
+ payloadFingerprint: string;
372
+ source: WebhookInboxSource;
373
+ receivedAt: Date;
374
+ signatureTimestamp?: number | null;
375
+ signatureHeader?: string | null;
376
+ rawBody?: string | null;
377
+ }
378
+ type WebhookInboxInsertResult = {
379
+ inserted: true;
380
+ record: WebhookInboxRecord;
381
+ } | {
382
+ inserted: false;
383
+ record: WebhookInboxRecord;
384
+ };
385
+ interface WebhookInboxListOptions {
386
+ status?: WebhookInboxStatus;
387
+ updatedBefore?: Date;
388
+ limit?: number;
389
+ }
390
+ interface WebhookInboxStore {
391
+ insert: (record: WebhookInboxInsertRecord) => Promise<WebhookInboxInsertResult> | WebhookInboxInsertResult;
392
+ find: (eventId: string) => Promise<WebhookInboxRecord | null | undefined> | WebhookInboxRecord | null | undefined;
393
+ markProcessing: (eventId: string, context: {
394
+ now: Date;
395
+ }) => Promise<WebhookInboxRecord | null | undefined> | WebhookInboxRecord | null | undefined;
396
+ markProcessed: (eventId: string, context: {
397
+ now: Date;
398
+ }) => Promise<WebhookInboxRecord | null | undefined> | WebhookInboxRecord | null | undefined;
399
+ markFailed: (eventId: string, context: {
400
+ now: Date;
401
+ error: string;
402
+ }) => Promise<WebhookInboxRecord | null | undefined> | WebhookInboxRecord | null | undefined;
403
+ markPending?: (eventId: string, context: {
404
+ now: Date;
405
+ reason: string;
406
+ }) => Promise<WebhookInboxRecord | null | undefined> | WebhookInboxRecord | null | undefined;
407
+ list?: (options: WebhookInboxListOptions) => Promise<WebhookInboxRecord[]> | WebhookInboxRecord[];
408
+ }
409
+ interface WebhookInboxOptions {
410
+ store: WebhookInboxStore;
411
+ processEvent: (event: EdgeWebhookEvent, record: WebhookInboxRecord) => Promise<void> | void;
412
+ now?: () => Date;
413
+ storeRawBody?: boolean;
414
+ processingTimeoutMs?: number;
415
+ onEvent?: (event: WebhookInboxLifecycleEvent) => Promise<void> | void;
416
+ }
417
+ interface WebhookInboxLifecycleEvent {
418
+ type: 'webhook.accepted' | 'webhook.duplicate' | 'webhook.payload_mismatch' | 'webhook.processing_started' | 'webhook.processing_succeeded' | 'webhook.processing_failed' | 'webhook.recovered_stale';
419
+ eventId: string;
420
+ eventType?: EdgeWebhookEventType;
421
+ status?: WebhookInboxStatus;
422
+ source?: WebhookInboxSource;
423
+ attempts?: number;
424
+ error?: string;
425
+ }
426
+ interface WebhookInboxAcceptResult {
427
+ eventId: string;
428
+ eventType: EdgeWebhookEventType;
429
+ inserted: boolean;
430
+ duplicate: boolean;
431
+ status: WebhookInboxStatus;
432
+ record: WebhookInboxRecord;
433
+ }
434
+ interface WebhookInboxProcessResult {
435
+ eventId: string;
436
+ status: WebhookInboxStatus;
437
+ processed: boolean;
438
+ skipped: boolean;
439
+ reason?: 'already_processed' | 'not_found' | 'locked';
440
+ record?: WebhookInboxRecord;
441
+ }
442
+ interface WebhookInboxRecoverResult {
443
+ recovered: number;
444
+ skipped: boolean;
445
+ reason?: 'list_not_configured' | 'mark_pending_not_configured';
446
+ }
447
+ declare class EdgeWebhookInbox {
448
+ private readonly store;
449
+ private readonly processEvent;
450
+ private readonly now;
451
+ private readonly storeRawBody;
452
+ private readonly processingTimeoutMs;
453
+ private readonly onEvent?;
454
+ constructor(options: WebhookInboxOptions);
455
+ accept(parsed: ParsedEdgeWebhook): Promise<WebhookInboxAcceptResult>;
456
+ acceptRaw(parsed: ParsedEdgeWebhook, rawBody: string, signatureHeader: string): Promise<WebhookInboxAcceptResult>;
457
+ acceptSyncedEvent(event: EdgeWebhookEvent, receivedAt?: Date): Promise<WebhookInboxAcceptResult>;
458
+ process(eventId: string, options?: {
459
+ force?: boolean;
460
+ }): Promise<WebhookInboxProcessResult>;
461
+ replay(eventId: string): Promise<WebhookInboxProcessResult>;
462
+ recoverStaleProcessing(): Promise<WebhookInboxRecoverResult>;
463
+ private acceptEvent;
464
+ private emit;
465
+ }
466
+ declare function createWebhookInbox(options: WebhookInboxOptions): EdgeWebhookInbox;
467
+ declare function fingerprintWebhookEvent(event: EdgeWebhookEvent): string;
468
+
229
469
  interface WebhookReconcilerCursorStore {
230
470
  load: () => Promise<string | null | undefined> | string | null | undefined;
231
471
  save: (cursor: string) => Promise<void> | void;
@@ -233,12 +473,15 @@ interface WebhookReconcilerCursorStore {
233
473
  interface WebhookReconcilerOptions {
234
474
  edge: Pick<EdgeConnectServer, 'syncWebhookEvents'>;
235
475
  cursorStore: WebhookReconcilerCursorStore;
236
- processEvent: (event: EdgeWebhookEvent) => Promise<void> | void;
476
+ processEvent?: (event: EdgeWebhookEvent) => Promise<void> | void;
477
+ inbox?: Pick<EdgeWebhookInbox, 'acceptSyncedEvent' | 'process'>;
237
478
  limit?: SyncWebhookEventsOptions['limit'];
238
479
  maxPages?: number;
239
480
  }
240
481
  interface WebhookReconcilerRunResult {
241
482
  processed: number;
483
+ accepted?: number;
484
+ duplicates?: number;
242
485
  pages: number;
243
486
  cursor?: string;
244
487
  hasMore: boolean;
@@ -437,6 +680,19 @@ interface EdgeHttpError {
437
680
  declare function toEdgeHttpError(error: unknown): EdgeHttpError;
438
681
  declare function toEdgeProblemJson(error: unknown): EdgeProblemJson;
439
682
 
683
+ interface EdgeWebhookHttpRequestLike {
684
+ headers?: Record<string, unknown>;
685
+ rawBody?: Buffer | Uint8Array | string;
686
+ body?: unknown;
687
+ }
688
+ interface ParseWebhookHttpRequestOptions extends Omit<ParseAndVerifyWebhookOptions, 'rawBody' | 'signatureHeader'> {
689
+ request: EdgeWebhookHttpRequestLike;
690
+ signatureHeaderName?: string;
691
+ }
692
+ declare function getEdgeWebhookRawBody(request: EdgeWebhookHttpRequestLike): EdgeWebhookRawBody;
693
+ declare function getEdgeWebhookSignatureHeader(request: EdgeWebhookHttpRequestLike, headerName?: string): EdgeWebhookSignatureHeader;
694
+ declare function parseWebhookHttpRequest(options: ParseWebhookHttpRequestOptions): ParsedEdgeWebhook;
695
+
440
696
  interface PartnerIdentityAddress {
441
697
  street?: string | null;
442
698
  line1?: string | null;
@@ -467,6 +723,43 @@ interface IdentityPolicyEvaluation {
467
723
  declare function buildVerifyIdentityPayload(profile: PartnerIdentityProfile): VerifyIdentityOptions;
468
724
  declare function evaluateIdentityResult(result: VerifyIdentityResult, policy?: IdentityPolicy): IdentityPolicyEvaluation;
469
725
 
726
+ interface EdgeSessionTokenRecord {
727
+ subjectId: string;
728
+ encryptedTokens: string;
729
+ expiresAt: number;
730
+ scopes?: string[];
731
+ edgeUserId?: string;
732
+ keyId?: string;
733
+ metadata?: Record<string, unknown>;
734
+ }
735
+ interface CreateSessionTokenRecordOptions {
736
+ scopes?: string[];
737
+ edgeUserId?: string;
738
+ keyId?: string;
739
+ metadata?: Record<string, unknown>;
740
+ }
741
+ interface LegacySessionTokenRecord {
742
+ subjectId?: string;
743
+ accessToken?: string | null;
744
+ refreshToken?: string | null;
745
+ idToken?: string | null;
746
+ expiresAt?: unknown;
747
+ expiresIn?: unknown;
748
+ scope?: unknown;
749
+ scopes?: unknown;
750
+ edgeUserId?: string | null;
751
+ metadata?: Record<string, unknown>;
752
+ }
753
+ interface EncryptLegacySessionTokensOptions {
754
+ subjectId: string;
755
+ keyId?: string;
756
+ allowPlaintext?: boolean;
757
+ }
758
+ declare function createSessionTokenRecord(subjectId: string, tokens: EdgeTokens, tokenVault: Pick<EdgeTokenVault, 'encryptTokens'>, options?: CreateSessionTokenRecordOptions): EdgeSessionTokenRecord;
759
+ declare function parseSessionTokenRecord(record: unknown): EdgeSessionTokenRecord;
760
+ declare function encryptLegacySessionTokens(legacyRecord: LegacySessionTokenRecord, tokenVault: Pick<EdgeTokenVault, 'encryptTokens' | 'isEncrypted'>, options: EncryptLegacySessionTokensOptions): EdgeSessionTokenRecord;
761
+ declare function normalizeSessionExpiresAt(value: unknown): number;
762
+
470
763
  interface TransferWebhookIntent {
471
764
  transferId: string;
472
765
  type?: TransferType;
@@ -477,89 +770,6 @@ declare function isTransferWebhookEvent(event: EdgeWebhookEvent): event is Extra
477
770
  type: `transfer.${string}`;
478
771
  }>;
479
772
  declare function assertTransferEventMatchesIntent(event: EdgeWebhookEvent, intent: TransferWebhookIntent): void;
773
+ declare const assertWebhookMatchesTransfer: typeof assertTransferEventMatchesIntent;
480
774
 
481
- /**
482
- * Webhook Signature Verification (SDK-001)
483
- *
484
- * HMAC-SHA256 verification for EDGE Connect webhook payloads.
485
- *
486
- * Signature header format: `t={timestamp},v1={hex_hmac}`
487
- * Signed message: `{timestamp}.{raw_json_body}`
488
- *
489
- * The timestamp prefix prevents replay attacks — events older than the
490
- * tolerance window (default 5 minutes) are rejected. The HMAC is verified
491
- * with constant-time comparison to prevent timing attacks.
492
- */
493
- /**
494
- * Options for {@link verifyWebhookSignature}.
495
- */
496
- interface VerifyWebhookSignatureOptions {
497
- /**
498
- * Maximum age of the signature timestamp, in seconds.
499
- *
500
- * Signatures older than this are rejected as potential replays.
501
- * Defaults to 300 seconds (5 minutes), matching the producer.
502
- */
503
- toleranceSeconds?: number;
504
- }
505
- /**
506
- * Verifies an EDGE Connect webhook signature.
507
- *
508
- * **Always pass the raw request body bytes** — never `JSON.stringify(req.body)`.
509
- * Re-stringifying after the framework parses JSON will reorder keys, change
510
- * whitespace, and silently break verification with no diagnostic. Capture
511
- * the raw body via your framework's raw-body middleware:
512
- *
513
- * - Express: `express.raw({ type: 'application/json' })`
514
- * - Fastify: built-in (use `request.rawBody`)
515
- * - NestJS: `{ rawBody: true }` on `NestFactory.create` + `RawBodyRequest<Request>`
516
- *
517
- * @param header - The `X-Edge-Signature` header value (`t=...,v1=...`)
518
- * @param body - The raw request body as a UTF-8 string (NOT a parsed object)
519
- * @param secret - The partner's webhook signing secret
520
- * @param options - Optional overrides
521
- * @returns `true` if the signature is valid and within the tolerance window,
522
- * `false` otherwise. Never throws — malformed input returns `false`.
523
- *
524
- * @example
525
- * ```typescript
526
- * import { verifyWebhookSignature } from '@edge-markets/connect-node'
527
- *
528
- * app.post('/webhooks/edge', express.raw({ type: 'application/json' }), (req, res) => {
529
- * const ok = verifyWebhookSignature(
530
- * req.headers['x-edge-signature'] as string,
531
- * req.body.toString('utf8'),
532
- * process.env.EDGE_WEBHOOK_SECRET!,
533
- * )
534
- *
535
- * if (!ok) return res.status(401).send('invalid signature')
536
- *
537
- * const event = JSON.parse(req.body.toString('utf8'))
538
- * // ... process event
539
- * res.status(200).send('ok')
540
- * })
541
- * ```
542
- */
543
- declare function verifyWebhookSignature(header: string, body: string, secret: string, options?: VerifyWebhookSignatureOptions): boolean;
544
-
545
- type EdgeWebhookRawBody = string | Buffer | Uint8Array;
546
- type EdgeWebhookSignatureHeader = string | string[] | undefined | null;
547
- interface ParseAndVerifyWebhookOptions extends VerifyWebhookSignatureOptions {
548
- rawBody: EdgeWebhookRawBody;
549
- signatureHeader: EdgeWebhookSignatureHeader;
550
- secret: string;
551
- receivedAt?: Date;
552
- }
553
- interface ParsedEdgeWebhook {
554
- event: EdgeWebhookEvent;
555
- eventId: string;
556
- eventType: EdgeWebhookEventType;
557
- signatureTimestamp: number;
558
- receivedAt: Date;
559
- }
560
- declare function parseAndVerifyWebhook(options: ParseAndVerifyWebhookOptions): ParsedEdgeWebhook;
561
- declare function extractWebhookSignatureTimestamp(header: EdgeWebhookSignatureHeader): number | undefined;
562
- declare function isEdgeWebhookEvent(value: unknown): value is EdgeWebhookEvent;
563
- declare function validateEdgeWebhookEvent(value: unknown): EdgeWebhookEvent;
564
-
565
- export { type CreateEdgeConnectServerFromEnvOptions, type CreateTransferIdempotencyKeyOptions, type EdgeConnectEnv, EdgeConnectServer, type EdgeConnectServerConfig, type EdgeConnectServerFromEnvCapabilities, type EdgeConnectServerFromEnvResult, type EdgeHttpError, type EdgeProblemJson, type EdgeTokenStore, type EdgeTokenStoreSaveContext, type EdgeTokenStoreValue, EdgeTokenVault, type EdgeTokenVaultKey, type EdgeTokenVaultKeyMaterial, type EdgeTokenVaultOptions, EdgeUserClient, EdgeUserSession, type EdgeUserSessionOptions, type EdgeWebhookRawBody, EdgeWebhookReconciler, type EdgeWebhookSignatureHeader, type GetValidTokensOptions, type IdentityPolicy, type IdentityPolicyEvaluation, type MtlsConfig, type ParseAndVerifyWebhookOptions, type ParsedEdgeWebhook, type PartnerIdentityAddress, type PartnerIdentityProfile, type RequestInfo, type ResponseInfo, type RetryConfig, type StartTransferVerificationOptions, type StartTransferVerificationResult, type SyncWebhookEventsOptions, type SyncWebhookEventsResult, type TransferAmountLimits, type TransferIntent, type TransferOptions, type TransferWebhookIntent, type VerifyWebhookSignatureOptions, type WebhookReconcilerCursorStore, type WebhookReconcilerOptions, type WebhookReconcilerRunResult, assertSameTransferIntent, assertTransferEventMatchesIntent, buildVerifyIdentityPayload, createEdgeConnectServerFromEnv, createEdgeTokenVault, createEdgeUserSession, createTransferIdempotencyKey, createWebhookReconciler, evaluateIdentityResult, extractWebhookSignatureTimestamp, isEdgeTokenVaultEnvelope, isEdgeWebhookEvent, isTransferWebhookEvent, normalizeMoneyAmount, parseAndVerifyWebhook, startTransferVerification, toEdgeHttpError, toEdgeProblemJson, validateEdgeWebhookEvent, validateTransferAmount, verifyWebhookSignature };
775
+ export { CONNECT_TRANSFER_DIRECTIONS, type ConnectTransferDirection, type CreateEdgeConnectServerFromEnvOptions, type CreateSessionTokenRecordOptions, type CreateTransferIdempotencyKeyOptions, type EdgeConnectEnv, EdgeConnectServer, type EdgeConnectServerConfig, type EdgeConnectServerFromEnvCapabilities, type EdgeConnectServerFromEnvResult, type EdgeHttpError, type EdgeProblemJson, type EdgeSessionTokenRecord, type EdgeTokenStore, type EdgeTokenStoreSaveContext, type EdgeTokenStoreValue, EdgeTokenVault, type EdgeTokenVaultKey, type EdgeTokenVaultKeyMaterial, type EdgeTokenVaultOptions, EdgeUserClient, EdgeUserSession, type EdgeUserSessionEvent, type EdgeUserSessionEventType, type EdgeUserSessionOptions, type EdgeWebhookHttpRequestLike, EdgeWebhookInbox, type EdgeWebhookRawBody, EdgeWebhookReconciler, type EdgeWebhookSignatureHeader, type EncryptLegacySessionTokensOptions, type GetValidTokensOptions, type IdentityPolicy, type IdentityPolicyEvaluation, type LegacySessionTokenRecord, type MoneyAmountOptions, type MtlsConfig, type ParseAndVerifyWebhookOptions, type ParseWebhookHttpRequestOptions, type ParsedEdgeWebhook, type PartnerIdentityAddress, type PartnerIdentityProfile, type RequestInfo, type ResponseInfo, type RetryConfig, type StartTransferVerificationOptions, type StartTransferVerificationResult, type SyncWebhookEventsOptions, type SyncWebhookEventsResult, type TransferAmountLimits, type TransferIntent, type TransferOptions, type TransferStatusMapping, type TransferWebhookIntent, type VerifyWebhookSignatureOptions, type WebhookInboxAcceptResult, type WebhookInboxInsertRecord, type WebhookInboxInsertResult, type WebhookInboxLifecycleEvent, type WebhookInboxListOptions, type WebhookInboxOptions, type WebhookInboxProcessResult, type WebhookInboxRecord, type WebhookInboxRecoverResult, type WebhookInboxSource, type WebhookInboxStatus, type WebhookInboxStore, type WebhookReconcilerCursorStore, type WebhookReconcilerOptions, type WebhookReconcilerRunResult, assertSameTransferIntent, assertTransferEventMatchesIntent, assertWebhookMatchesTransfer, buildVerifyIdentityPayload, createEdgeConnectServerFromEnv, createEdgeTokenVault, createEdgeUserSession, createSessionTokenRecord, createTransferIdempotencyKey, createWebhookInbox, createWebhookReconciler, encryptLegacySessionTokens, evaluateIdentityResult, extractWebhookSignatureTimestamp, fingerprintTransferIntent, fingerprintWebhookEvent, getConnectTransferDirection, getEdgeWebhookRawBody, getEdgeWebhookSignatureHeader, isEdgeTokenVaultEnvelope, isEdgeWebhookEvent, isTransferWebhookEvent, mapTransferStatusToPartnerState, moneyAmountsEqual, normalizeMoneyAmount, normalizeSessionExpiresAt, parseAndVerifyWebhook, parseSessionTokenRecord, parseWebhookHttpRequest, startTransferVerification, toEdgeHttpError, toEdgeProblemJson, validateEdgeWebhookEvent, validateTransferAmount, verifyWebhookSignature };