@edge-markets/connect-node 1.4.0 → 1.6.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 CHANGED
@@ -6,7 +6,7 @@ Server SDK for EDGE Connect token exchange and API calls.
6
6
 
7
7
  - 🔐 **Secure token exchange** - Exchange codes for tokens with PKCE
8
8
  - 🔄 **Token refresh** - Automatic refresh token handling
9
- - 📡 **Full API client** - User, balance, transfers
9
+ - 📡 **Full API client** - User, balance, transfers via `forUser()` pattern
10
10
  - 🛡️ **Typed errors** - Specific error classes for each scenario
11
11
  - 📝 **TypeScript first** - Complete type definitions
12
12
 
@@ -23,7 +23,7 @@ yarn add @edge-markets/connect-node
23
23
  ## Quick Start
24
24
 
25
25
  ```typescript
26
- import { EdgeConnectServer } from '@edgeboost/edge-connect-server'
26
+ import { EdgeConnectServer } from '@edge-markets/connect-node'
27
27
 
28
28
  // Create instance once (reuse for all requests)
29
29
  const edge = new EdgeConnectServer({
@@ -35,9 +35,10 @@ const edge = new EdgeConnectServer({
35
35
  // Exchange code from EdgeLink for tokens
36
36
  const tokens = await edge.exchangeCode(code, codeVerifier)
37
37
 
38
- // Make API calls
39
- const user = await edge.getUser(tokens.accessToken)
40
- const balance = await edge.getBalance(tokens.accessToken)
38
+ // Create a user-scoped client and make API calls
39
+ const client = edge.forUser(tokens.accessToken)
40
+ const user = await client.getUser()
41
+ const balance = await client.getBalance()
41
42
  ```
42
43
 
43
44
  ## ⚠️ Security
@@ -56,8 +57,11 @@ interface EdgeConnectServerConfig {
56
57
 
57
58
  // Optional
58
59
  apiBaseUrl?: string // Custom API URL (dev only)
59
- authDomain?: string // Custom Cognito domain (dev only)
60
+ oauthBaseUrl?: string // Custom OAuth URL (dev only)
60
61
  timeout?: number // Request timeout (default: 30000ms)
62
+ retry?: RetryConfig // Retry configuration
63
+ onRequest?: (info) => void // Hook called before each request
64
+ onResponse?: (info) => void // Hook called after each response
61
65
 
62
66
  // Optional: Message Level Encryption (Connect endpoints only)
63
67
  mle?: {
@@ -152,15 +156,19 @@ async function getValidAccessToken(userId: string): Promise<string> {
152
156
 
153
157
  ## API Methods
154
158
 
159
+ All user-scoped API methods live on `EdgeUserClient`, created via `edge.forUser(accessToken)`:
160
+
161
+ ```typescript
162
+ const client = edge.forUser(accessToken)
163
+ ```
164
+
155
165
  ### User & Balance
156
166
 
157
167
  ```typescript
158
- // Get user profile
159
- const user = await edge.getUser(accessToken)
168
+ const user = await client.getUser()
160
169
  // Returns: { id, email, firstName, lastName, createdAt }
161
170
 
162
- // Get balance
163
- const balance = await edge.getBalance(accessToken)
171
+ const balance = await client.getBalance()
164
172
  // Returns: { userId, availableBalance, currency, asOf }
165
173
  ```
166
174
 
@@ -168,7 +176,7 @@ const balance = await edge.getBalance(accessToken)
168
176
 
169
177
  ```typescript
170
178
  // Initiate transfer (requires OTP verification)
171
- const transfer = await edge.initiateTransfer(accessToken, {
179
+ const transfer = await client.initiateTransfer({
172
180
  type: 'debit', // 'debit' = pull from user, 'credit' = push to user
173
181
  amount: '100.00',
174
182
  idempotencyKey: `txn_${userId}_${Date.now()}`,
@@ -176,14 +184,14 @@ const transfer = await edge.initiateTransfer(accessToken, {
176
184
  // Returns: { transferId, status: 'pending_verification', otpMethod }
177
185
 
178
186
  // Verify with OTP
179
- const result = await edge.verifyTransfer(accessToken, transfer.transferId, userOtp)
187
+ const result = await client.verifyTransfer(transfer.transferId, userOtp)
180
188
  // Returns: { transferId, status: 'completed' | 'failed' }
181
189
 
182
190
  // Get transfer status
183
- const status = await edge.getTransfer(accessToken, transferId)
191
+ const status = await client.getTransfer(transferId)
184
192
 
185
193
  // List transfers
186
- const { transfers, total } = await edge.listTransfers(accessToken, {
194
+ const { transfers, total } = await client.listTransfers({
187
195
  status: 'completed',
188
196
  limit: 10,
189
197
  offset: 0,
@@ -194,7 +202,7 @@ const { transfers, total } = await edge.listTransfers(accessToken, {
194
202
 
195
203
  ```typescript
196
204
  // Revoke consent (disconnect user)
197
- await edge.revokeConsent(accessToken)
205
+ await client.revokeConsent()
198
206
 
199
207
  // Clean up stored tokens
200
208
  await db.edgeConnections.delete(userId)
@@ -212,7 +220,8 @@ import {
212
220
  } from '@edge-markets/connect-node'
213
221
 
214
222
  try {
215
- const balance = await edge.getBalance(accessToken)
223
+ const client = edge.forUser(accessToken)
224
+ const balance = await client.getBalance()
216
225
  } catch (error) {
217
226
  if (error instanceof EdgeAuthenticationError) {
218
227
  // Token expired - try refresh or reconnect
@@ -273,7 +282,8 @@ export class EdgeService {
273
282
 
274
283
  async getBalance(accessToken: string) {
275
284
  try {
276
- return await this.edge.getBalance(accessToken)
285
+ const client = this.edge.forUser(accessToken)
286
+ return await client.getBalance()
277
287
  } catch (error) {
278
288
  if (error instanceof EdgeConsentRequiredError) {
279
289
  this.logger.warn('User consent required')
@@ -323,7 +333,8 @@ app.post('/api/edge/exchange', async (req, res) => {
323
333
  app.get('/api/edge/balance', async (req, res) => {
324
334
  try {
325
335
  const accessToken = await getAccessTokenForUser(req.user.id)
326
- const balance = await edge.getBalance(accessToken)
336
+ const client = edge.forUser(accessToken)
337
+ const balance = await client.getBalance()
327
338
  res.json(balance)
328
339
  } catch (error) {
329
340
  // Handle errors...
@@ -339,10 +350,3 @@ app.get('/api/edge/balance', async (req, res) => {
339
350
  ## License
340
351
 
341
352
  MIT
342
-
343
-
344
-
345
-
346
-
347
-
348
-
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
- import { EdgeEnvironment, User, VerifyIdentityOptions, VerifyIdentityResult, Balance, Transfer, ListTransfersParams, TransferList, EdgeTokens } from '@edge-markets/connect';
2
- export { Balance, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, ListTransfersParams, Transfer, TransferList, TransferListItem, TransferStatus, TransferType, User, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isEdgeError, isNetworkError, isProductionEnvironment } from '@edge-markets/connect';
1
+ import * as node_https from 'node:https';
2
+ import { EdgeEnvironment, TransferCategory, SdkGeolocation, User, VerifyIdentityOptions, VerifyIdentityResult, Balance, Transfer, ListTransfersParams, TransferList, CreateVerificationSessionRequest, VerificationSession, VerificationSessionStatusResponse, EdgeTokens } from '@edge-markets/connect';
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';
3
4
 
4
5
  interface RequestInfo {
5
6
  method: string;
@@ -40,11 +41,27 @@ interface EdgeConnectServerConfig {
40
41
  partnerKeyId: string;
41
42
  strictResponseEncryption?: boolean;
42
43
  };
44
+ mtls?: MtlsConfig;
45
+ }
46
+ interface MtlsConfig {
47
+ enabled: boolean;
48
+ cert: string;
49
+ key: string;
50
+ ca?: string;
43
51
  }
44
52
  interface TransferOptions {
45
53
  type: 'debit' | 'credit';
46
54
  amount: string;
47
55
  idempotencyKey: string;
56
+ /** Optional transaction category for settlement window determination */
57
+ category?: TransferCategory;
58
+ }
59
+ /**
60
+ * Options for verifying a transfer with OTP.
61
+ */
62
+ interface VerifyTransferOptions {
63
+ /** SDK-reported geolocation for cross-referencing against IP-based geo */
64
+ sdkGeo?: SdkGeolocation;
48
65
  }
49
66
 
50
67
  /**
@@ -61,12 +78,23 @@ declare class EdgeUserClient {
61
78
  verifyIdentity(options: VerifyIdentityOptions): Promise<VerifyIdentityResult>;
62
79
  getBalance(): Promise<Balance>;
63
80
  initiateTransfer(options: TransferOptions): Promise<Transfer>;
64
- verifyTransfer(transferId: string, otp: string): Promise<Transfer>;
81
+ verifyTransfer(transferId: string, otp: string, options?: VerifyTransferOptions): Promise<Transfer>;
65
82
  getTransfer(transferId: string): Promise<Transfer>;
66
83
  listTransfers(params?: ListTransfersParams): Promise<TransferList>;
67
84
  revokeConsent(): Promise<{
68
85
  revoked: boolean;
69
86
  }>;
87
+ /**
88
+ * Creates an EDGE-hosted transfer verification session.
89
+ * Returns a `verificationUrl` to open in an iframe or popup.
90
+ * The handoff token is single-use and expires in 120 seconds.
91
+ */
92
+ createVerificationSession(transferId: string, options: CreateVerificationSessionRequest): Promise<VerificationSession>;
93
+ /**
94
+ * Polls the status of a verification session.
95
+ * Use as an alternative to postMessage events.
96
+ */
97
+ getVerificationSessionStatus(transferId: string, sessionId: string): Promise<VerificationSessionStatusResponse>;
70
98
  }
71
99
 
72
100
  declare class EdgeConnectServer {
@@ -75,9 +103,16 @@ declare class EdgeConnectServer {
75
103
  private readonly oauthBaseUrl;
76
104
  private readonly timeout;
77
105
  private readonly retryConfig;
106
+ private readonly httpsAgent;
107
+ private readonly dispatcher;
78
108
  static getInstance(config: EdgeConnectServerConfig): EdgeConnectServer;
79
109
  static clearInstances(): void;
80
110
  constructor(config: EdgeConnectServerConfig);
111
+ /**
112
+ * Returns the `node:https.Agent` configured with mTLS client certificates.
113
+ * Use this with axios, got, or other HTTP clients. Returns `undefined` if mTLS is not configured.
114
+ */
115
+ getHttpsAgent(): node_https.Agent | undefined;
81
116
  /**
82
117
  * Create a user-scoped client for making authenticated API calls.
83
118
  *
@@ -97,4 +132,4 @@ declare class EdgeConnectServer {
97
132
  private handleApiErrorFromBody;
98
133
  }
99
134
 
100
- export { EdgeConnectServer, type EdgeConnectServerConfig, EdgeUserClient, type RequestInfo, type ResponseInfo, type RetryConfig, type TransferOptions };
135
+ export { EdgeConnectServer, type EdgeConnectServerConfig, EdgeUserClient, type MtlsConfig, type RequestInfo, type ResponseInfo, type RetryConfig, type TransferOptions, type VerifyTransferOptions };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { EdgeEnvironment, User, VerifyIdentityOptions, VerifyIdentityResult, Balance, Transfer, ListTransfersParams, TransferList, EdgeTokens } from '@edge-markets/connect';
2
- export { Balance, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, ListTransfersParams, Transfer, TransferList, TransferListItem, TransferStatus, TransferType, User, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isEdgeError, isNetworkError, isProductionEnvironment } from '@edge-markets/connect';
1
+ import * as node_https from 'node:https';
2
+ import { EdgeEnvironment, TransferCategory, SdkGeolocation, User, VerifyIdentityOptions, VerifyIdentityResult, Balance, Transfer, ListTransfersParams, TransferList, CreateVerificationSessionRequest, VerificationSession, VerificationSessionStatusResponse, EdgeTokens } from '@edge-markets/connect';
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';
3
4
 
4
5
  interface RequestInfo {
5
6
  method: string;
@@ -40,11 +41,27 @@ interface EdgeConnectServerConfig {
40
41
  partnerKeyId: string;
41
42
  strictResponseEncryption?: boolean;
42
43
  };
44
+ mtls?: MtlsConfig;
45
+ }
46
+ interface MtlsConfig {
47
+ enabled: boolean;
48
+ cert: string;
49
+ key: string;
50
+ ca?: string;
43
51
  }
44
52
  interface TransferOptions {
45
53
  type: 'debit' | 'credit';
46
54
  amount: string;
47
55
  idempotencyKey: string;
56
+ /** Optional transaction category for settlement window determination */
57
+ category?: TransferCategory;
58
+ }
59
+ /**
60
+ * Options for verifying a transfer with OTP.
61
+ */
62
+ interface VerifyTransferOptions {
63
+ /** SDK-reported geolocation for cross-referencing against IP-based geo */
64
+ sdkGeo?: SdkGeolocation;
48
65
  }
49
66
 
50
67
  /**
@@ -61,12 +78,23 @@ declare class EdgeUserClient {
61
78
  verifyIdentity(options: VerifyIdentityOptions): Promise<VerifyIdentityResult>;
62
79
  getBalance(): Promise<Balance>;
63
80
  initiateTransfer(options: TransferOptions): Promise<Transfer>;
64
- verifyTransfer(transferId: string, otp: string): Promise<Transfer>;
81
+ verifyTransfer(transferId: string, otp: string, options?: VerifyTransferOptions): Promise<Transfer>;
65
82
  getTransfer(transferId: string): Promise<Transfer>;
66
83
  listTransfers(params?: ListTransfersParams): Promise<TransferList>;
67
84
  revokeConsent(): Promise<{
68
85
  revoked: boolean;
69
86
  }>;
87
+ /**
88
+ * Creates an EDGE-hosted transfer verification session.
89
+ * Returns a `verificationUrl` to open in an iframe or popup.
90
+ * The handoff token is single-use and expires in 120 seconds.
91
+ */
92
+ createVerificationSession(transferId: string, options: CreateVerificationSessionRequest): Promise<VerificationSession>;
93
+ /**
94
+ * Polls the status of a verification session.
95
+ * Use as an alternative to postMessage events.
96
+ */
97
+ getVerificationSessionStatus(transferId: string, sessionId: string): Promise<VerificationSessionStatusResponse>;
70
98
  }
71
99
 
72
100
  declare class EdgeConnectServer {
@@ -75,9 +103,16 @@ declare class EdgeConnectServer {
75
103
  private readonly oauthBaseUrl;
76
104
  private readonly timeout;
77
105
  private readonly retryConfig;
106
+ private readonly httpsAgent;
107
+ private readonly dispatcher;
78
108
  static getInstance(config: EdgeConnectServerConfig): EdgeConnectServer;
79
109
  static clearInstances(): void;
80
110
  constructor(config: EdgeConnectServerConfig);
111
+ /**
112
+ * Returns the `node:https.Agent` configured with mTLS client certificates.
113
+ * Use this with axios, got, or other HTTP clients. Returns `undefined` if mTLS is not configured.
114
+ */
115
+ getHttpsAgent(): node_https.Agent | undefined;
81
116
  /**
82
117
  * Create a user-scoped client for making authenticated API calls.
83
118
  *
@@ -97,4 +132,4 @@ declare class EdgeConnectServer {
97
132
  private handleApiErrorFromBody;
98
133
  }
99
134
 
100
- export { EdgeConnectServer, type EdgeConnectServerConfig, EdgeUserClient, type RequestInfo, type ResponseInfo, type RetryConfig, type TransferOptions };
135
+ export { EdgeConnectServer, type EdgeConnectServerConfig, EdgeUserClient, type MtlsConfig, type RequestInfo, type ResponseInfo, type RetryConfig, type TransferOptions, type VerifyTransferOptions };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -25,16 +35,19 @@ __export(index_exports, {
25
35
  EdgeConnectServer: () => EdgeConnectServer,
26
36
  EdgeConsentRequiredError: () => import_connect3.EdgeConsentRequiredError,
27
37
  EdgeError: () => import_connect3.EdgeError,
38
+ EdgeIdentityVerificationError: () => import_connect3.EdgeIdentityVerificationError,
28
39
  EdgeInsufficientScopeError: () => import_connect3.EdgeInsufficientScopeError,
29
40
  EdgeNetworkError: () => import_connect3.EdgeNetworkError,
30
41
  EdgeNotFoundError: () => import_connect3.EdgeNotFoundError,
31
42
  EdgeTokenExchangeError: () => import_connect3.EdgeTokenExchangeError,
32
43
  EdgeUserClient: () => EdgeUserClient,
44
+ TRANSFER_CATEGORIES: () => import_connect4.TRANSFER_CATEGORIES,
33
45
  getEnvironmentConfig: () => import_connect4.getEnvironmentConfig,
34
46
  isApiError: () => import_connect3.isApiError,
35
47
  isAuthenticationError: () => import_connect3.isAuthenticationError,
36
48
  isConsentRequiredError: () => import_connect3.isConsentRequiredError,
37
49
  isEdgeError: () => import_connect3.isEdgeError,
50
+ isIdentityVerificationError: () => import_connect3.isIdentityVerificationError,
38
51
  isNetworkError: () => import_connect3.isNetworkError,
39
52
  isProductionEnvironment: () => import_connect4.isProductionEnvironment
40
53
  });
@@ -85,6 +98,9 @@ function validateTransferOptions(options) {
85
98
  } else if (options.idempotencyKey.length > 255) {
86
99
  errors.idempotencyKey = ["Must be 255 characters or less"];
87
100
  }
101
+ if (options.category && !["sportsbook", "casino", "dfs", "sweepstakes"].includes(options.category)) {
102
+ errors.category = ["Must be one of: sportsbook, casino, dfs, sweepstakes"];
103
+ }
88
104
  if (Object.keys(errors).length > 0) {
89
105
  throw new import_connect.EdgeValidationError("Invalid transfer options", errors);
90
106
  }
@@ -113,14 +129,21 @@ var EdgeUserClient = class {
113
129
  amount: options.amount,
114
130
  idempotencyKey: options.idempotencyKey
115
131
  };
132
+ if (options.category) {
133
+ body.category = options.category;
134
+ }
116
135
  return this.server._apiRequest("POST", "/transfer", this.accessToken, body);
117
136
  }
118
- async verifyTransfer(transferId, otp) {
137
+ async verifyTransfer(transferId, otp, options) {
138
+ const body = { otp };
139
+ if (options?.sdkGeo) {
140
+ body.sdkGeo = options.sdkGeo;
141
+ }
119
142
  return this.server._apiRequest(
120
143
  "POST",
121
144
  `/transfer/${encodeURIComponent(transferId)}/verify`,
122
145
  this.accessToken,
123
- { otp }
146
+ body
124
147
  );
125
148
  }
126
149
  async getTransfer(transferId) {
@@ -138,6 +161,30 @@ var EdgeUserClient = class {
138
161
  async revokeConsent() {
139
162
  return this.server._apiRequest("DELETE", "/consent", this.accessToken);
140
163
  }
164
+ /**
165
+ * Creates an EDGE-hosted transfer verification session.
166
+ * Returns a `verificationUrl` to open in an iframe or popup.
167
+ * The handoff token is single-use and expires in 120 seconds.
168
+ */
169
+ async createVerificationSession(transferId, options) {
170
+ return this.server._apiRequest(
171
+ "POST",
172
+ `/transfer/${encodeURIComponent(transferId)}/verification-session`,
173
+ this.accessToken,
174
+ { origin: options.origin }
175
+ );
176
+ }
177
+ /**
178
+ * Polls the status of a verification session.
179
+ * Use as an alternative to postMessage events.
180
+ */
181
+ async getVerificationSessionStatus(transferId, sessionId) {
182
+ return this.server._apiRequest(
183
+ "GET",
184
+ `/transfer/${encodeURIComponent(transferId)}/verification-session/${encodeURIComponent(sessionId)}`,
185
+ this.accessToken
186
+ );
187
+ }
141
188
  };
142
189
 
143
190
  // src/mle.ts
@@ -215,6 +262,37 @@ function fromBase64Url(value) {
215
262
  return Buffer.from(normalized, "base64");
216
263
  }
217
264
 
265
+ // src/mtls.ts
266
+ var import_node_https = __toESM(require("https"));
267
+ function createHttpsAgent(config) {
268
+ return new import_node_https.default.Agent({
269
+ cert: config.cert,
270
+ key: config.key,
271
+ rejectUnauthorized: true,
272
+ ...config.ca ? { ca: config.ca } : {}
273
+ });
274
+ }
275
+ function createUndiciDispatcher(config) {
276
+ const moduleName = "undici";
277
+ const { Agent } = require(moduleName);
278
+ return new Agent({
279
+ connect: {
280
+ cert: config.cert,
281
+ key: config.key,
282
+ rejectUnauthorized: true,
283
+ ...config.ca ? { ca: config.ca } : {}
284
+ }
285
+ });
286
+ }
287
+ function validateMtlsConfig(config) {
288
+ if (!config.cert?.trim()) {
289
+ throw new Error("EdgeConnectServer: mTLS cert is required when enabled");
290
+ }
291
+ if (!config.key?.trim()) {
292
+ throw new Error("EdgeConnectServer: mTLS key is required when enabled");
293
+ }
294
+ }
295
+
218
296
  // src/types.ts
219
297
  var DEFAULT_TIMEOUT = 3e4;
220
298
  var USER_AGENT = "@edge-markets/connect-node/1.0.0";
@@ -261,6 +339,18 @@ var EdgeConnectServer = class _EdgeConnectServer {
261
339
  ...DEFAULT_RETRY_CONFIG,
262
340
  ...config.retry
263
341
  };
342
+ if (config.mtls?.enabled) {
343
+ validateMtlsConfig(config.mtls);
344
+ this.httpsAgent = createHttpsAgent(config.mtls);
345
+ this.dispatcher = createUndiciDispatcher(config.mtls);
346
+ }
347
+ }
348
+ /**
349
+ * Returns the `node:https.Agent` configured with mTLS client certificates.
350
+ * Use this with axios, got, or other HTTP clients. Returns `undefined` if mTLS is not configured.
351
+ */
352
+ getHttpsAgent() {
353
+ return this.httpsAgent;
264
354
  }
265
355
  /**
266
356
  * Create a user-scoped client for making authenticated API calls.
@@ -285,14 +375,18 @@ var EdgeConnectServer = class _EdgeConnectServer {
285
375
  redirect_uri: redirectUri || this.config.redirectUri || ""
286
376
  };
287
377
  try {
288
- const response = await this.fetchWithTimeout(tokenUrl, {
289
- method: "POST",
290
- headers: {
291
- "Content-Type": "application/json",
292
- "User-Agent": USER_AGENT
378
+ const response = await this.fetchWithTimeout(
379
+ tokenUrl,
380
+ {
381
+ method: "POST",
382
+ headers: {
383
+ "Content-Type": "application/json",
384
+ "User-Agent": USER_AGENT
385
+ },
386
+ body: JSON.stringify(body)
293
387
  },
294
- body: JSON.stringify(body)
295
- });
388
+ this.dispatcher
389
+ );
296
390
  if (!response.ok) {
297
391
  const error = await response.json().catch(() => ({}));
298
392
  throw this.handleTokenError(error, response.status);
@@ -313,14 +407,18 @@ var EdgeConnectServer = class _EdgeConnectServer {
313
407
  client_secret: this.config.clientSecret
314
408
  };
315
409
  try {
316
- const response = await this.fetchWithTimeout(tokenUrl, {
317
- method: "POST",
318
- headers: {
319
- "Content-Type": "application/json",
320
- "User-Agent": USER_AGENT
410
+ const response = await this.fetchWithTimeout(
411
+ tokenUrl,
412
+ {
413
+ method: "POST",
414
+ headers: {
415
+ "Content-Type": "application/json",
416
+ "User-Agent": USER_AGENT
417
+ },
418
+ body: JSON.stringify(body)
321
419
  },
322
- body: JSON.stringify(body)
323
- });
420
+ this.dispatcher
421
+ );
324
422
  if (!response.ok) {
325
423
  const error = await response.json().catch(() => ({}));
326
424
  throw new import_connect2.EdgeAuthenticationError(
@@ -360,11 +458,15 @@ var EdgeConnectServer = class _EdgeConnectServer {
360
458
  requestBody = { jwe: encryptMle(body, this.config.clientId, mleConfig) };
361
459
  }
362
460
  }
363
- const response = await this.fetchWithTimeout(url, {
364
- method,
365
- headers: requestHeaders,
366
- body: requestBody !== void 0 ? JSON.stringify(requestBody) : void 0
367
- });
461
+ const response = await this.fetchWithTimeout(
462
+ url,
463
+ {
464
+ method,
465
+ headers: requestHeaders,
466
+ body: requestBody !== void 0 ? JSON.stringify(requestBody) : void 0
467
+ },
468
+ this.dispatcher
469
+ );
368
470
  const rawResponseBody = await response.json().catch(() => ({}));
369
471
  let responseBody = rawResponseBody;
370
472
  if (mleEnabled && typeof rawResponseBody?.jwe === "string") {
@@ -423,14 +525,18 @@ var EdgeConnectServer = class _EdgeConnectServer {
423
525
  async sleep(ms) {
424
526
  return new Promise((resolve) => setTimeout(resolve, ms));
425
527
  }
426
- async fetchWithTimeout(url, options) {
528
+ async fetchWithTimeout(url, options, dispatcher) {
427
529
  const controller = new AbortController();
428
530
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
429
531
  try {
430
- return await fetch(url, {
532
+ const fetchOptions = {
431
533
  ...options,
432
534
  signal: controller.signal
433
- });
535
+ };
536
+ if (dispatcher) {
537
+ fetchOptions.dispatcher = dispatcher;
538
+ }
539
+ return await fetch(url, fetchOptions);
434
540
  } finally {
435
541
  clearTimeout(timeoutId);
436
542
  }
@@ -486,8 +592,21 @@ var EdgeConnectServer = class _EdgeConnectServer {
486
592
  }
487
593
  }
488
594
  if (status === 404) {
489
- const resourceType = path.includes("/transfer") ? "Transfer" : "Resource";
490
- const resourceId = path.split("/").pop() || "unknown";
595
+ let resourceType = "Resource";
596
+ let resourceId = path.split("/").pop() || "unknown";
597
+ if (path.includes("/verification-session/")) {
598
+ resourceType = "VerificationSession";
599
+ const parts = path.split("/");
600
+ const vsIdx = parts.indexOf("verification-session");
601
+ resourceId = vsIdx >= 0 && parts[vsIdx + 1] ? parts[vsIdx + 1] : "unknown";
602
+ } else if (path.includes("/verification-session")) {
603
+ resourceType = "Transfer";
604
+ const parts = path.split("/");
605
+ const txIdx = parts.indexOf("transfer");
606
+ resourceId = txIdx >= 0 && parts[txIdx + 1] ? parts[txIdx + 1] : "unknown";
607
+ } else if (path.includes("/transfer")) {
608
+ resourceType = "Transfer";
609
+ }
491
610
  return new import_connect2.EdgeNotFoundError(resourceType, resourceId);
492
611
  }
493
612
  if (status === 422 && error.error === "identity_verification_failed") {
@@ -515,16 +634,19 @@ var import_connect4 = require("@edge-markets/connect");
515
634
  EdgeConnectServer,
516
635
  EdgeConsentRequiredError,
517
636
  EdgeError,
637
+ EdgeIdentityVerificationError,
518
638
  EdgeInsufficientScopeError,
519
639
  EdgeNetworkError,
520
640
  EdgeNotFoundError,
521
641
  EdgeTokenExchangeError,
522
642
  EdgeUserClient,
643
+ TRANSFER_CATEGORIES,
523
644
  getEnvironmentConfig,
524
645
  isApiError,
525
646
  isAuthenticationError,
526
647
  isConsentRequiredError,
527
648
  isEdgeError,
649
+ isIdentityVerificationError,
528
650
  isNetworkError,
529
651
  isProductionEnvironment
530
652
  });
package/dist/index.mjs CHANGED
@@ -1,3 +1,10 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
1
8
  // src/edge-connect-server.ts
2
9
  import {
3
10
  EdgeApiError,
@@ -54,6 +61,9 @@ function validateTransferOptions(options) {
54
61
  } else if (options.idempotencyKey.length > 255) {
55
62
  errors.idempotencyKey = ["Must be 255 characters or less"];
56
63
  }
64
+ if (options.category && !["sportsbook", "casino", "dfs", "sweepstakes"].includes(options.category)) {
65
+ errors.category = ["Must be one of: sportsbook, casino, dfs, sweepstakes"];
66
+ }
57
67
  if (Object.keys(errors).length > 0) {
58
68
  throw new EdgeValidationError("Invalid transfer options", errors);
59
69
  }
@@ -82,14 +92,21 @@ var EdgeUserClient = class {
82
92
  amount: options.amount,
83
93
  idempotencyKey: options.idempotencyKey
84
94
  };
95
+ if (options.category) {
96
+ body.category = options.category;
97
+ }
85
98
  return this.server._apiRequest("POST", "/transfer", this.accessToken, body);
86
99
  }
87
- async verifyTransfer(transferId, otp) {
100
+ async verifyTransfer(transferId, otp, options) {
101
+ const body = { otp };
102
+ if (options?.sdkGeo) {
103
+ body.sdkGeo = options.sdkGeo;
104
+ }
88
105
  return this.server._apiRequest(
89
106
  "POST",
90
107
  `/transfer/${encodeURIComponent(transferId)}/verify`,
91
108
  this.accessToken,
92
- { otp }
109
+ body
93
110
  );
94
111
  }
95
112
  async getTransfer(transferId) {
@@ -107,6 +124,30 @@ var EdgeUserClient = class {
107
124
  async revokeConsent() {
108
125
  return this.server._apiRequest("DELETE", "/consent", this.accessToken);
109
126
  }
127
+ /**
128
+ * Creates an EDGE-hosted transfer verification session.
129
+ * Returns a `verificationUrl` to open in an iframe or popup.
130
+ * The handoff token is single-use and expires in 120 seconds.
131
+ */
132
+ async createVerificationSession(transferId, options) {
133
+ return this.server._apiRequest(
134
+ "POST",
135
+ `/transfer/${encodeURIComponent(transferId)}/verification-session`,
136
+ this.accessToken,
137
+ { origin: options.origin }
138
+ );
139
+ }
140
+ /**
141
+ * Polls the status of a verification session.
142
+ * Use as an alternative to postMessage events.
143
+ */
144
+ async getVerificationSessionStatus(transferId, sessionId) {
145
+ return this.server._apiRequest(
146
+ "GET",
147
+ `/transfer/${encodeURIComponent(transferId)}/verification-session/${encodeURIComponent(sessionId)}`,
148
+ this.accessToken
149
+ );
150
+ }
110
151
  };
111
152
 
112
153
  // src/mle.ts
@@ -184,6 +225,37 @@ function fromBase64Url(value) {
184
225
  return Buffer.from(normalized, "base64");
185
226
  }
186
227
 
228
+ // src/mtls.ts
229
+ import https from "https";
230
+ function createHttpsAgent(config) {
231
+ return new https.Agent({
232
+ cert: config.cert,
233
+ key: config.key,
234
+ rejectUnauthorized: true,
235
+ ...config.ca ? { ca: config.ca } : {}
236
+ });
237
+ }
238
+ function createUndiciDispatcher(config) {
239
+ const moduleName = "undici";
240
+ const { Agent } = __require(moduleName);
241
+ return new Agent({
242
+ connect: {
243
+ cert: config.cert,
244
+ key: config.key,
245
+ rejectUnauthorized: true,
246
+ ...config.ca ? { ca: config.ca } : {}
247
+ }
248
+ });
249
+ }
250
+ function validateMtlsConfig(config) {
251
+ if (!config.cert?.trim()) {
252
+ throw new Error("EdgeConnectServer: mTLS cert is required when enabled");
253
+ }
254
+ if (!config.key?.trim()) {
255
+ throw new Error("EdgeConnectServer: mTLS key is required when enabled");
256
+ }
257
+ }
258
+
187
259
  // src/types.ts
188
260
  var DEFAULT_TIMEOUT = 3e4;
189
261
  var USER_AGENT = "@edge-markets/connect-node/1.0.0";
@@ -230,6 +302,18 @@ var EdgeConnectServer = class _EdgeConnectServer {
230
302
  ...DEFAULT_RETRY_CONFIG,
231
303
  ...config.retry
232
304
  };
305
+ if (config.mtls?.enabled) {
306
+ validateMtlsConfig(config.mtls);
307
+ this.httpsAgent = createHttpsAgent(config.mtls);
308
+ this.dispatcher = createUndiciDispatcher(config.mtls);
309
+ }
310
+ }
311
+ /**
312
+ * Returns the `node:https.Agent` configured with mTLS client certificates.
313
+ * Use this with axios, got, or other HTTP clients. Returns `undefined` if mTLS is not configured.
314
+ */
315
+ getHttpsAgent() {
316
+ return this.httpsAgent;
233
317
  }
234
318
  /**
235
319
  * Create a user-scoped client for making authenticated API calls.
@@ -254,14 +338,18 @@ var EdgeConnectServer = class _EdgeConnectServer {
254
338
  redirect_uri: redirectUri || this.config.redirectUri || ""
255
339
  };
256
340
  try {
257
- const response = await this.fetchWithTimeout(tokenUrl, {
258
- method: "POST",
259
- headers: {
260
- "Content-Type": "application/json",
261
- "User-Agent": USER_AGENT
341
+ const response = await this.fetchWithTimeout(
342
+ tokenUrl,
343
+ {
344
+ method: "POST",
345
+ headers: {
346
+ "Content-Type": "application/json",
347
+ "User-Agent": USER_AGENT
348
+ },
349
+ body: JSON.stringify(body)
262
350
  },
263
- body: JSON.stringify(body)
264
- });
351
+ this.dispatcher
352
+ );
265
353
  if (!response.ok) {
266
354
  const error = await response.json().catch(() => ({}));
267
355
  throw this.handleTokenError(error, response.status);
@@ -282,14 +370,18 @@ var EdgeConnectServer = class _EdgeConnectServer {
282
370
  client_secret: this.config.clientSecret
283
371
  };
284
372
  try {
285
- const response = await this.fetchWithTimeout(tokenUrl, {
286
- method: "POST",
287
- headers: {
288
- "Content-Type": "application/json",
289
- "User-Agent": USER_AGENT
373
+ const response = await this.fetchWithTimeout(
374
+ tokenUrl,
375
+ {
376
+ method: "POST",
377
+ headers: {
378
+ "Content-Type": "application/json",
379
+ "User-Agent": USER_AGENT
380
+ },
381
+ body: JSON.stringify(body)
290
382
  },
291
- body: JSON.stringify(body)
292
- });
383
+ this.dispatcher
384
+ );
293
385
  if (!response.ok) {
294
386
  const error = await response.json().catch(() => ({}));
295
387
  throw new EdgeAuthenticationError(
@@ -329,11 +421,15 @@ var EdgeConnectServer = class _EdgeConnectServer {
329
421
  requestBody = { jwe: encryptMle(body, this.config.clientId, mleConfig) };
330
422
  }
331
423
  }
332
- const response = await this.fetchWithTimeout(url, {
333
- method,
334
- headers: requestHeaders,
335
- body: requestBody !== void 0 ? JSON.stringify(requestBody) : void 0
336
- });
424
+ const response = await this.fetchWithTimeout(
425
+ url,
426
+ {
427
+ method,
428
+ headers: requestHeaders,
429
+ body: requestBody !== void 0 ? JSON.stringify(requestBody) : void 0
430
+ },
431
+ this.dispatcher
432
+ );
337
433
  const rawResponseBody = await response.json().catch(() => ({}));
338
434
  let responseBody = rawResponseBody;
339
435
  if (mleEnabled && typeof rawResponseBody?.jwe === "string") {
@@ -392,14 +488,18 @@ var EdgeConnectServer = class _EdgeConnectServer {
392
488
  async sleep(ms) {
393
489
  return new Promise((resolve) => setTimeout(resolve, ms));
394
490
  }
395
- async fetchWithTimeout(url, options) {
491
+ async fetchWithTimeout(url, options, dispatcher) {
396
492
  const controller = new AbortController();
397
493
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
398
494
  try {
399
- return await fetch(url, {
495
+ const fetchOptions = {
400
496
  ...options,
401
497
  signal: controller.signal
402
- });
498
+ };
499
+ if (dispatcher) {
500
+ fetchOptions.dispatcher = dispatcher;
501
+ }
502
+ return await fetch(url, fetchOptions);
403
503
  } finally {
404
504
  clearTimeout(timeoutId);
405
505
  }
@@ -455,8 +555,21 @@ var EdgeConnectServer = class _EdgeConnectServer {
455
555
  }
456
556
  }
457
557
  if (status === 404) {
458
- const resourceType = path.includes("/transfer") ? "Transfer" : "Resource";
459
- const resourceId = path.split("/").pop() || "unknown";
558
+ let resourceType = "Resource";
559
+ let resourceId = path.split("/").pop() || "unknown";
560
+ if (path.includes("/verification-session/")) {
561
+ resourceType = "VerificationSession";
562
+ const parts = path.split("/");
563
+ const vsIdx = parts.indexOf("verification-session");
564
+ resourceId = vsIdx >= 0 && parts[vsIdx + 1] ? parts[vsIdx + 1] : "unknown";
565
+ } else if (path.includes("/verification-session")) {
566
+ resourceType = "Transfer";
567
+ const parts = path.split("/");
568
+ const txIdx = parts.indexOf("transfer");
569
+ resourceId = txIdx >= 0 && parts[txIdx + 1] ? parts[txIdx + 1] : "unknown";
570
+ } else if (path.includes("/transfer")) {
571
+ resourceType = "Transfer";
572
+ }
460
573
  return new EdgeNotFoundError(resourceType, resourceId);
461
574
  }
462
575
  if (status === 422 && error.error === "identity_verification_failed") {
@@ -480,6 +593,7 @@ import {
480
593
  EdgeAuthenticationError as EdgeAuthenticationError2,
481
594
  EdgeConsentRequiredError as EdgeConsentRequiredError2,
482
595
  EdgeError as EdgeError2,
596
+ EdgeIdentityVerificationError as EdgeIdentityVerificationError2,
483
597
  EdgeInsufficientScopeError as EdgeInsufficientScopeError2,
484
598
  EdgeNetworkError as EdgeNetworkError2,
485
599
  EdgeNotFoundError as EdgeNotFoundError2,
@@ -488,25 +602,29 @@ import {
488
602
  isAuthenticationError,
489
603
  isConsentRequiredError,
490
604
  isEdgeError,
605
+ isIdentityVerificationError,
491
606
  isNetworkError
492
607
  } from "@edge-markets/connect";
493
- import { getEnvironmentConfig as getEnvironmentConfig2, isProductionEnvironment } from "@edge-markets/connect";
608
+ import { TRANSFER_CATEGORIES, getEnvironmentConfig as getEnvironmentConfig2, isProductionEnvironment } from "@edge-markets/connect";
494
609
  export {
495
610
  EdgeApiError2 as EdgeApiError,
496
611
  EdgeAuthenticationError2 as EdgeAuthenticationError,
497
612
  EdgeConnectServer,
498
613
  EdgeConsentRequiredError2 as EdgeConsentRequiredError,
499
614
  EdgeError2 as EdgeError,
615
+ EdgeIdentityVerificationError2 as EdgeIdentityVerificationError,
500
616
  EdgeInsufficientScopeError2 as EdgeInsufficientScopeError,
501
617
  EdgeNetworkError2 as EdgeNetworkError,
502
618
  EdgeNotFoundError2 as EdgeNotFoundError,
503
619
  EdgeTokenExchangeError2 as EdgeTokenExchangeError,
504
620
  EdgeUserClient,
621
+ TRANSFER_CATEGORIES,
505
622
  getEnvironmentConfig2 as getEnvironmentConfig,
506
623
  isApiError,
507
624
  isAuthenticationError,
508
625
  isConsentRequiredError,
509
626
  isEdgeError,
627
+ isIdentityVerificationError,
510
628
  isNetworkError,
511
629
  isProductionEnvironment
512
630
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edge-markets/connect-node",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "Server SDK for EDGE Connect token exchange and API calls",
5
5
  "author": "Edge Markets",
6
6
  "license": "MIT",
@@ -21,7 +21,7 @@
21
21
  }
22
22
  },
23
23
  "dependencies": {
24
- "@edge-markets/connect": "^1.3.0"
24
+ "@edge-markets/connect": "^1.5.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "tsup": "^8.0.0",