@edge-markets/connect-node 1.6.1 → 1.8.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 +319 -11
- package/dist/index.d.mts +442 -4
- package/dist/index.d.ts +442 -4
- package/dist/index.js +1509 -62
- package/dist/index.mjs +1473 -34
- package/package.json +3 -2
package/dist/index.d.mts
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
import * as node_https from 'node:https';
|
|
2
|
-
import { EdgeEnvironment, TransferCategory, User, VerifyIdentityOptions, VerifyIdentityResult, Balance,
|
|
3
|
-
export { Balance, CreateVerificationSessionRequest, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeIdentityVerificationError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, ListTransfersParams, SdkGeolocation, TRANSFER_CATEGORIES, Transfer, TransferCategory, TransferList, TransferListItem, 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, 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';
|
|
4
4
|
|
|
5
|
+
type RequestEndpoint = 'connect_api' | 'oauth_token' | 'partner_webhook_sync';
|
|
5
6
|
interface RequestInfo {
|
|
6
7
|
method: string;
|
|
7
8
|
url: string;
|
|
8
9
|
body?: unknown;
|
|
10
|
+
endpoint?: RequestEndpoint;
|
|
11
|
+
attempt?: number;
|
|
9
12
|
}
|
|
10
13
|
interface ResponseInfo {
|
|
11
14
|
status: number;
|
|
12
15
|
body: unknown;
|
|
13
16
|
durationMs: number;
|
|
17
|
+
method?: string;
|
|
18
|
+
url?: string;
|
|
19
|
+
endpoint?: RequestEndpoint;
|
|
20
|
+
attempt?: number;
|
|
14
21
|
}
|
|
15
22
|
interface RetryConfig {
|
|
16
23
|
maxRetries?: number;
|
|
@@ -23,6 +30,17 @@ interface EdgeConnectServerConfig {
|
|
|
23
30
|
clientSecret: string;
|
|
24
31
|
environment: EdgeEnvironment;
|
|
25
32
|
apiBaseUrl?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Override the partner dashboard API base URL.
|
|
35
|
+
*
|
|
36
|
+
* Most integrations should omit this. The SDK derives the dashboard base
|
|
37
|
+
* from `apiBaseUrl` by replacing `/connect/v1` with `/v1`, matching the
|
|
38
|
+
* EDGE Connect gateway layout:
|
|
39
|
+
*
|
|
40
|
+
* - user-scoped API: `https://connect-staging.edgeboost.io/connect/v1`
|
|
41
|
+
* - partner dashboard API: `https://connect-staging.edgeboost.io/v1`
|
|
42
|
+
*/
|
|
43
|
+
partnerApiBaseUrl?: string;
|
|
26
44
|
oauthBaseUrl?: string;
|
|
27
45
|
/**
|
|
28
46
|
* @deprecated cognitoDomain is no longer used. Token exchange now goes through EdgeBoost API.
|
|
@@ -42,12 +60,40 @@ interface EdgeConnectServerConfig {
|
|
|
42
60
|
strictResponseEncryption?: boolean;
|
|
43
61
|
};
|
|
44
62
|
mtls?: MtlsConfig;
|
|
63
|
+
/**
|
|
64
|
+
* Partner-level OAuth client ID for the `client_credentials` grant.
|
|
65
|
+
*
|
|
66
|
+
* Required ONLY when calling {@link EdgeConnectServer.syncWebhookEvents}.
|
|
67
|
+
* This is a different OAuth client than {@link clientId} — it authenticates
|
|
68
|
+
* your backend (not your users) for partner-scoped surfaces like the
|
|
69
|
+
* webhook reconciliation sync endpoint.
|
|
70
|
+
*
|
|
71
|
+
* If omitted, `syncWebhookEvents()` throws on first call but the rest of
|
|
72
|
+
* the SDK (token exchange, user-scoped API calls) continues to work.
|
|
73
|
+
*/
|
|
74
|
+
partnerClientId?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Partner-level OAuth client secret paired with {@link partnerClientId}.
|
|
77
|
+
*
|
|
78
|
+
* Required ONLY when calling {@link EdgeConnectServer.syncWebhookEvents}.
|
|
79
|
+
*/
|
|
80
|
+
partnerClientSecret?: string;
|
|
45
81
|
}
|
|
46
82
|
interface MtlsConfig {
|
|
47
83
|
enabled: boolean;
|
|
84
|
+
/** Client certificate PEM used to authenticate this partner to EDGE Connect. */
|
|
48
85
|
cert: string;
|
|
86
|
+
/** Client private key PEM paired with `cert`. */
|
|
49
87
|
key: string;
|
|
50
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Optional additional server trust root(s), as PEM text.
|
|
90
|
+
*
|
|
91
|
+
* The SDK appends these certificates to Node's default public trust store
|
|
92
|
+
* instead of replacing it. Public EDGE Connect gateways use public ACM
|
|
93
|
+
* certificates, so most partners should omit this unless EDGE provides a
|
|
94
|
+
* private server CA for a non-public endpoint.
|
|
95
|
+
*/
|
|
96
|
+
ca?: string | string[];
|
|
51
97
|
}
|
|
52
98
|
interface TransferOptions {
|
|
53
99
|
type: 'debit' | 'credit';
|
|
@@ -57,6 +103,38 @@ interface TransferOptions {
|
|
|
57
103
|
category?: TransferCategory;
|
|
58
104
|
}
|
|
59
105
|
|
|
106
|
+
interface TransferAmountLimits {
|
|
107
|
+
min?: string | number;
|
|
108
|
+
max?: string | number;
|
|
109
|
+
}
|
|
110
|
+
interface CreateTransferIdempotencyKeyOptions {
|
|
111
|
+
partnerUserId: string;
|
|
112
|
+
type: TransferType;
|
|
113
|
+
amount: string | number;
|
|
114
|
+
category?: TransferCategory;
|
|
115
|
+
externalId?: string;
|
|
116
|
+
nonce?: string;
|
|
117
|
+
namespace?: string;
|
|
118
|
+
}
|
|
119
|
+
interface TransferIntent {
|
|
120
|
+
type: TransferType;
|
|
121
|
+
amount: string | number;
|
|
122
|
+
category?: TransferCategory | null;
|
|
123
|
+
}
|
|
124
|
+
interface StartTransferVerificationOptions {
|
|
125
|
+
transfer: TransferOptions;
|
|
126
|
+
origin: string;
|
|
127
|
+
}
|
|
128
|
+
interface StartTransferVerificationResult {
|
|
129
|
+
transfer: Transfer;
|
|
130
|
+
verificationSession: VerificationSession;
|
|
131
|
+
}
|
|
132
|
+
declare function normalizeMoneyAmount(value: string | number): string;
|
|
133
|
+
declare function validateTransferAmount(value: string | number, limits?: TransferAmountLimits): string;
|
|
134
|
+
declare function createTransferIdempotencyKey(options: CreateTransferIdempotencyKeyOptions): string;
|
|
135
|
+
declare function assertSameTransferIntent(existing: TransferIntent, requested: TransferIntent): void;
|
|
136
|
+
declare function startTransferVerification(client: Pick<EdgeUserClient, 'initiateTransfer' | 'createVerificationSession'>, options: StartTransferVerificationOptions): Promise<StartTransferVerificationResult>;
|
|
137
|
+
|
|
60
138
|
/**
|
|
61
139
|
* A lightweight, user-scoped API client created via {@link EdgeConnectServer.forUser}.
|
|
62
140
|
*
|
|
@@ -71,6 +149,7 @@ declare class EdgeUserClient {
|
|
|
71
149
|
verifyIdentity(options: VerifyIdentityOptions): Promise<VerifyIdentityResult>;
|
|
72
150
|
getBalance(): Promise<Balance>;
|
|
73
151
|
initiateTransfer(options: TransferOptions): Promise<Transfer>;
|
|
152
|
+
startTransferVerification(options: StartTransferVerificationOptions): Promise<StartTransferVerificationResult>;
|
|
74
153
|
getTransfer(transferId: string): Promise<Transfer>;
|
|
75
154
|
listTransfers(params?: ListTransfersParams): Promise<TransferList>;
|
|
76
155
|
revokeConsent(): Promise<{
|
|
@@ -89,14 +168,134 @@ declare class EdgeUserClient {
|
|
|
89
168
|
getVerificationSessionStatus(transferId: string, sessionId: string): Promise<VerificationSessionStatusResponse>;
|
|
90
169
|
}
|
|
91
170
|
|
|
171
|
+
type EdgeTokenVaultKeyMaterial = string | Buffer | Uint8Array;
|
|
172
|
+
interface EdgeTokenVaultKey {
|
|
173
|
+
id: string;
|
|
174
|
+
key: EdgeTokenVaultKeyMaterial;
|
|
175
|
+
}
|
|
176
|
+
interface EdgeTokenVaultOptions {
|
|
177
|
+
currentKey: EdgeTokenVaultKey;
|
|
178
|
+
previousKeys?: EdgeTokenVaultKey[];
|
|
179
|
+
}
|
|
180
|
+
declare class EdgeTokenVault {
|
|
181
|
+
private readonly currentKey;
|
|
182
|
+
private readonly keysById;
|
|
183
|
+
constructor(options: EdgeTokenVaultOptions);
|
|
184
|
+
encryptTokens(tokens: EdgeTokens): string;
|
|
185
|
+
decryptTokens(envelope: string): EdgeTokens;
|
|
186
|
+
isEncrypted(value: unknown): value is string;
|
|
187
|
+
}
|
|
188
|
+
declare function createEdgeTokenVault(options: EdgeTokenVaultOptions): EdgeTokenVault;
|
|
189
|
+
declare function isEdgeTokenVaultEnvelope(value: unknown): value is string;
|
|
190
|
+
|
|
191
|
+
type EdgeTokenStoreValue = EdgeTokens | string;
|
|
192
|
+
interface EdgeTokenStoreSaveContext {
|
|
193
|
+
tokens: EdgeTokens;
|
|
194
|
+
refreshed: boolean;
|
|
195
|
+
}
|
|
196
|
+
interface EdgeTokenStore {
|
|
197
|
+
load: (subjectId: string) => Promise<EdgeTokenStoreValue | null | undefined> | EdgeTokenStoreValue | null | undefined;
|
|
198
|
+
save: (subjectId: string, value: EdgeTokenStoreValue, context: EdgeTokenStoreSaveContext) => Promise<void> | void;
|
|
199
|
+
}
|
|
200
|
+
interface EdgeUserSessionOptions {
|
|
201
|
+
edge: Pick<EdgeConnectServer, 'forUser' | 'refreshTokens'>;
|
|
202
|
+
subjectId: string;
|
|
203
|
+
tokenStore: EdgeTokenStore;
|
|
204
|
+
tokenVault?: Pick<EdgeTokenVault, 'encryptTokens' | 'decryptTokens' | 'isEncrypted'>;
|
|
205
|
+
refreshSkewMs?: number;
|
|
206
|
+
now?: () => number;
|
|
207
|
+
onRefresh?: (tokens: EdgeTokens) => Promise<void> | void;
|
|
208
|
+
}
|
|
209
|
+
interface GetValidTokensOptions {
|
|
210
|
+
forceRefresh?: boolean;
|
|
211
|
+
}
|
|
212
|
+
declare class EdgeUserSession {
|
|
213
|
+
private readonly edge;
|
|
214
|
+
private readonly subjectId;
|
|
215
|
+
private readonly tokenStore;
|
|
216
|
+
private readonly tokenVault?;
|
|
217
|
+
private readonly refreshSkewMs;
|
|
218
|
+
private readonly now;
|
|
219
|
+
private readonly onRefresh?;
|
|
220
|
+
constructor(options: EdgeUserSessionOptions);
|
|
221
|
+
getValidTokens(options?: GetValidTokensOptions): Promise<EdgeTokens>;
|
|
222
|
+
getClient(options?: GetValidTokensOptions): Promise<EdgeUserClient>;
|
|
223
|
+
withClient<T>(callback: (client: EdgeUserClient, tokens: EdgeTokens) => Promise<T> | T): Promise<T>;
|
|
224
|
+
saveTokens(tokens: EdgeTokens, refreshed?: boolean): Promise<void>;
|
|
225
|
+
private loadTokens;
|
|
226
|
+
}
|
|
227
|
+
declare function createEdgeUserSession(options: EdgeUserSessionOptions): EdgeUserSession;
|
|
228
|
+
|
|
229
|
+
interface WebhookReconcilerCursorStore {
|
|
230
|
+
load: () => Promise<string | null | undefined> | string | null | undefined;
|
|
231
|
+
save: (cursor: string) => Promise<void> | void;
|
|
232
|
+
}
|
|
233
|
+
interface WebhookReconcilerOptions {
|
|
234
|
+
edge: Pick<EdgeConnectServer, 'syncWebhookEvents'>;
|
|
235
|
+
cursorStore: WebhookReconcilerCursorStore;
|
|
236
|
+
processEvent: (event: EdgeWebhookEvent) => Promise<void> | void;
|
|
237
|
+
limit?: SyncWebhookEventsOptions['limit'];
|
|
238
|
+
maxPages?: number;
|
|
239
|
+
}
|
|
240
|
+
interface WebhookReconcilerRunResult {
|
|
241
|
+
processed: number;
|
|
242
|
+
pages: number;
|
|
243
|
+
cursor?: string;
|
|
244
|
+
hasMore: boolean;
|
|
245
|
+
skipped: boolean;
|
|
246
|
+
reason?: 'already_running' | 'empty_page_with_has_more' | 'max_pages_reached';
|
|
247
|
+
}
|
|
248
|
+
declare class EdgeWebhookReconciler {
|
|
249
|
+
private readonly options;
|
|
250
|
+
private running;
|
|
251
|
+
constructor(options: WebhookReconcilerOptions);
|
|
252
|
+
run(): Promise<WebhookReconcilerRunResult>;
|
|
253
|
+
private runInternal;
|
|
254
|
+
}
|
|
255
|
+
declare function createWebhookReconciler(options: WebhookReconcilerOptions): EdgeWebhookReconciler;
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Options for {@link EdgeConnectServer.syncWebhookEvents}.
|
|
259
|
+
*/
|
|
260
|
+
interface SyncWebhookEventsOptions {
|
|
261
|
+
/**
|
|
262
|
+
* Cursor token. Pass the `id` of the last event you successfully processed
|
|
263
|
+
* to receive only newer events. Omit on the first call to start from the
|
|
264
|
+
* beginning of the 30-day server-side lookback window.
|
|
265
|
+
*/
|
|
266
|
+
afterEventId?: string;
|
|
267
|
+
/**
|
|
268
|
+
* Maximum events per page (1–100). Defaults to 20 server-side.
|
|
269
|
+
*/
|
|
270
|
+
limit?: number;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Result of {@link EdgeConnectServer.syncWebhookEvents}. Field names are
|
|
274
|
+
* normalized to camelCase from the wire format (`has_more` → `hasMore`).
|
|
275
|
+
*/
|
|
276
|
+
interface SyncWebhookEventsResult {
|
|
277
|
+
/**
|
|
278
|
+
* Events newer than the supplied cursor, in ascending order. Each event
|
|
279
|
+
* is the unwrapped {@link EdgeWebhookEvent} payload (the SDK strips the
|
|
280
|
+
* sync API's outer envelope).
|
|
281
|
+
*/
|
|
282
|
+
events: EdgeWebhookEvent[];
|
|
283
|
+
/**
|
|
284
|
+
* `true` if more events are available beyond this page. Loop while this
|
|
285
|
+
* is truthy, advancing your cursor to the `id` of the last processed event.
|
|
286
|
+
*/
|
|
287
|
+
hasMore: boolean;
|
|
288
|
+
}
|
|
92
289
|
declare class EdgeConnectServer {
|
|
93
290
|
private readonly config;
|
|
94
291
|
private readonly apiBaseUrl;
|
|
292
|
+
private readonly partnerApiBaseUrl;
|
|
95
293
|
private readonly oauthBaseUrl;
|
|
96
294
|
private readonly timeout;
|
|
97
295
|
private readonly retryConfig;
|
|
98
296
|
private readonly httpsAgent;
|
|
99
297
|
private readonly dispatcher;
|
|
298
|
+
private partnerTokenCache;
|
|
100
299
|
static getInstance(config: EdgeConnectServerConfig): EdgeConnectServer;
|
|
101
300
|
static clearInstances(): void;
|
|
102
301
|
constructor(config: EdgeConnectServerConfig);
|
|
@@ -112,10 +311,84 @@ declare class EdgeConnectServer {
|
|
|
112
311
|
* or per user session and discard it when the token changes.
|
|
113
312
|
*/
|
|
114
313
|
forUser(accessToken: string): EdgeUserClient;
|
|
314
|
+
createUserSession(options: Omit<EdgeUserSessionOptions, 'edge'>): EdgeUserSession;
|
|
115
315
|
exchangeCode(code: string, codeVerifier: string, redirectUri?: string): Promise<EdgeTokens>;
|
|
116
316
|
refreshTokens(refreshToken: string): Promise<EdgeTokens>;
|
|
117
317
|
/** @internal Called by {@link EdgeUserClient} — not part of the public API. */
|
|
118
318
|
_apiRequest<T>(method: string, path: string, accessToken: string, body?: unknown): Promise<T>;
|
|
319
|
+
/**
|
|
320
|
+
* Reconcile webhook events from the partner sync endpoint.
|
|
321
|
+
*
|
|
322
|
+
* Use this from a scheduled cron (every ~5 minutes is typical) to catch
|
|
323
|
+
* events your primary webhook receiver missed — partner downtime, retry
|
|
324
|
+
* exhaustion, dead-letter queue. This is the third reliability layer
|
|
325
|
+
* ("Leg 3") on top of HTTP delivery + DLQ.
|
|
326
|
+
*
|
|
327
|
+
* **Authentication.** This method uses the OAuth `client_credentials`
|
|
328
|
+
* grant against {@link EdgeConnectServerConfig.partnerClientId} and
|
|
329
|
+
* {@link EdgeConnectServerConfig.partnerClientSecret}. The token is
|
|
330
|
+
* cached internally and refreshed automatically.
|
|
331
|
+
*
|
|
332
|
+
* **Pagination.** Pass `afterEventId` with the last `id` you processed.
|
|
333
|
+
* Loop while `hasMore` is true. The server enforces a 30-day lookback;
|
|
334
|
+
* cursors older than 30 days return events from 30 days ago, not an error.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* ```typescript
|
|
338
|
+
* let cursor: string | undefined = await loadCursorFromDb()
|
|
339
|
+
*
|
|
340
|
+
* while (true) {
|
|
341
|
+
* const { events, hasMore } = await edge.syncWebhookEvents({ afterEventId: cursor })
|
|
342
|
+
* for (const event of events) {
|
|
343
|
+
* await processEvent(event)
|
|
344
|
+
* cursor = event.id
|
|
345
|
+
* }
|
|
346
|
+
* if (events.length > 0) await saveCursorToDb(cursor!)
|
|
347
|
+
* if (!hasMore) break
|
|
348
|
+
* }
|
|
349
|
+
* ```
|
|
350
|
+
*
|
|
351
|
+
* @throws {EdgeAuthenticationError} If partner credentials are missing
|
|
352
|
+
* or the partner token cannot be obtained / refreshed
|
|
353
|
+
* @throws {EdgeNetworkError} On network failure
|
|
354
|
+
* @throws {EdgeApiError} For other non-2xx responses after retries
|
|
355
|
+
*/
|
|
356
|
+
syncWebhookEvents(options?: SyncWebhookEventsOptions): Promise<SyncWebhookEventsResult>;
|
|
357
|
+
/**
|
|
358
|
+
* Creates a cursor-based webhook reconciler bound to this SDK instance.
|
|
359
|
+
*
|
|
360
|
+
* Use this from cron jobs to process events returned by
|
|
361
|
+
* {@link EdgeConnectServer.syncWebhookEvents} without hand-writing
|
|
362
|
+
* pagination, cursor advancement, or process-level concurrency guards.
|
|
363
|
+
*/
|
|
364
|
+
createWebhookReconciler(options: Omit<WebhookReconcilerOptions, 'edge'>): EdgeWebhookReconciler;
|
|
365
|
+
/**
|
|
366
|
+
* Builds the sync URL with normalized query parameters.
|
|
367
|
+
*/
|
|
368
|
+
private normalizeSyncWebhookEventsOptions;
|
|
369
|
+
private buildSyncUrl;
|
|
370
|
+
/**
|
|
371
|
+
* Issues a GET to the sync endpoint with the partner Bearer token. Kept
|
|
372
|
+
* separate from `_apiRequest` because partner tokens have a different
|
|
373
|
+
* lifecycle (process-wide, client_credentials) than user tokens.
|
|
374
|
+
*/
|
|
375
|
+
private partnerFetch;
|
|
376
|
+
/**
|
|
377
|
+
* Fetches (or returns the cached) partner token via the
|
|
378
|
+
* `client_credentials` grant. Caches with a 60s safety margin so the
|
|
379
|
+
* token is renewed *before* the server-side expiry, never racing it.
|
|
380
|
+
*
|
|
381
|
+
* Side-effects: writes `this.partnerTokenCache` on success.
|
|
382
|
+
*/
|
|
383
|
+
private getPartnerToken;
|
|
384
|
+
/**
|
|
385
|
+
* @internal Test-only: clears the cached partner token so the next call
|
|
386
|
+
* to `syncWebhookEvents` re-fetches it. Not part of the public API.
|
|
387
|
+
*/
|
|
388
|
+
_resetPartnerTokenCache(): void;
|
|
389
|
+
private redactPartnerTokenResponseBody;
|
|
390
|
+
private redactPartnerSyncResponseBody;
|
|
391
|
+
private drainResponseBody;
|
|
119
392
|
private getRetryDelay;
|
|
120
393
|
private sleep;
|
|
121
394
|
private fetchWithTimeout;
|
|
@@ -124,4 +397,169 @@ declare class EdgeConnectServer {
|
|
|
124
397
|
private handleApiErrorFromBody;
|
|
125
398
|
}
|
|
126
399
|
|
|
127
|
-
|
|
400
|
+
type EdgeConnectEnv = Record<string, string | undefined>;
|
|
401
|
+
interface CreateEdgeConnectServerFromEnvOptions {
|
|
402
|
+
env?: EdgeConnectEnv;
|
|
403
|
+
requireMtls?: boolean;
|
|
404
|
+
timeout?: number;
|
|
405
|
+
retry?: RetryConfig;
|
|
406
|
+
onRequest?: (info: RequestInfo) => void;
|
|
407
|
+
onResponse?: (info: ResponseInfo) => void;
|
|
408
|
+
mle?: EdgeConnectServerConfig['mle'];
|
|
409
|
+
}
|
|
410
|
+
interface EdgeConnectServerFromEnvCapabilities {
|
|
411
|
+
mtlsEnabled: boolean;
|
|
412
|
+
webhookSyncConfigured: boolean;
|
|
413
|
+
customApiBaseUrl: boolean;
|
|
414
|
+
customOAuthBaseUrl: boolean;
|
|
415
|
+
customPartnerApiBaseUrl: boolean;
|
|
416
|
+
}
|
|
417
|
+
interface EdgeConnectServerFromEnvResult {
|
|
418
|
+
server: EdgeConnectServer;
|
|
419
|
+
config: EdgeConnectServerConfig;
|
|
420
|
+
capabilities: EdgeConnectServerFromEnvCapabilities;
|
|
421
|
+
warnings: string[];
|
|
422
|
+
}
|
|
423
|
+
declare function createEdgeConnectServerFromEnv(options?: CreateEdgeConnectServerFromEnvOptions): EdgeConnectServerFromEnvResult;
|
|
424
|
+
|
|
425
|
+
interface EdgeProblemJson {
|
|
426
|
+
type: string;
|
|
427
|
+
title: string;
|
|
428
|
+
status: number;
|
|
429
|
+
detail: string;
|
|
430
|
+
code: string;
|
|
431
|
+
details?: Record<string, unknown>;
|
|
432
|
+
}
|
|
433
|
+
interface EdgeHttpError {
|
|
434
|
+
status: number;
|
|
435
|
+
body: EdgeProblemJson;
|
|
436
|
+
}
|
|
437
|
+
declare function toEdgeHttpError(error: unknown): EdgeHttpError;
|
|
438
|
+
declare function toEdgeProblemJson(error: unknown): EdgeProblemJson;
|
|
439
|
+
|
|
440
|
+
interface PartnerIdentityAddress {
|
|
441
|
+
street?: string | null;
|
|
442
|
+
line1?: string | null;
|
|
443
|
+
address1?: string | null;
|
|
444
|
+
city?: string | null;
|
|
445
|
+
state?: string | null;
|
|
446
|
+
zip?: string | null;
|
|
447
|
+
postalCode?: string | null;
|
|
448
|
+
}
|
|
449
|
+
interface PartnerIdentityProfile {
|
|
450
|
+
firstName?: string | null;
|
|
451
|
+
givenName?: string | null;
|
|
452
|
+
lastName?: string | null;
|
|
453
|
+
familyName?: string | null;
|
|
454
|
+
address?: PartnerIdentityAddress | null;
|
|
455
|
+
}
|
|
456
|
+
interface IdentityPolicy {
|
|
457
|
+
minNameScore?: number;
|
|
458
|
+
minAddressScore?: number;
|
|
459
|
+
requireZipMatch?: boolean;
|
|
460
|
+
requireApiVerified?: boolean;
|
|
461
|
+
}
|
|
462
|
+
interface IdentityPolicyEvaluation {
|
|
463
|
+
verified: boolean;
|
|
464
|
+
reasons: string[];
|
|
465
|
+
scores?: VerifyIdentityResult['scores'];
|
|
466
|
+
}
|
|
467
|
+
declare function buildVerifyIdentityPayload(profile: PartnerIdentityProfile): VerifyIdentityOptions;
|
|
468
|
+
declare function evaluateIdentityResult(result: VerifyIdentityResult, policy?: IdentityPolicy): IdentityPolicyEvaluation;
|
|
469
|
+
|
|
470
|
+
interface TransferWebhookIntent {
|
|
471
|
+
transferId: string;
|
|
472
|
+
type?: TransferType;
|
|
473
|
+
amount?: string | number;
|
|
474
|
+
status?: TransferStatus;
|
|
475
|
+
}
|
|
476
|
+
declare function isTransferWebhookEvent(event: EdgeWebhookEvent): event is Extract<EdgeWebhookEvent, {
|
|
477
|
+
type: `transfer.${string}`;
|
|
478
|
+
}>;
|
|
479
|
+
declare function assertTransferEventMatchesIntent(event: EdgeWebhookEvent, intent: TransferWebhookIntent): void;
|
|
480
|
+
|
|
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 };
|