@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/README.md +149 -25
- package/dist/index.d.mts +306 -96
- package/dist/index.d.ts +306 -96
- package/dist/index.js +901 -287
- package/dist/index.mjs +814 -214
- package/package.json +2 -2
package/dist/index.d.ts
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,
|
|
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
|
|
133
|
-
|
|
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
|
-
*
|
|
160
|
-
*
|
|
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
|
-
*
|
|
166
|
-
*
|
|
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
|
|
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 };
|