@edge-markets/connect-node 1.9.0 → 1.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -30,25 +30,28 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ACTIVE_EDGE_SCOPES: () => import_connect16.ACTIVE_EDGE_SCOPES,
33
34
  CONNECT_TRANSFER_DIRECTIONS: () => CONNECT_TRANSFER_DIRECTIONS,
34
- EDGE_WEBHOOK_EVENT_TYPES: () => import_connect15.EDGE_WEBHOOK_EVENT_TYPES,
35
- EdgeApiError: () => import_connect14.EdgeApiError,
36
- EdgeAuthenticationError: () => import_connect14.EdgeAuthenticationError,
35
+ EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE: () => import_connect15.EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE,
36
+ EDGE_WEBHOOK_EVENT_TYPES: () => import_connect16.EDGE_WEBHOOK_EVENT_TYPES,
37
+ EdgeApiError: () => import_connect15.EdgeApiError,
38
+ EdgeAuthenticationError: () => import_connect15.EdgeAuthenticationError,
37
39
  EdgeConnectServer: () => EdgeConnectServer,
38
- EdgeConsentRequiredError: () => import_connect14.EdgeConsentRequiredError,
39
- EdgeError: () => import_connect14.EdgeError,
40
- EdgeIdentityVerificationError: () => import_connect14.EdgeIdentityVerificationError,
41
- EdgeInsufficientScopeError: () => import_connect14.EdgeInsufficientScopeError,
42
- EdgeNetworkError: () => import_connect14.EdgeNetworkError,
43
- EdgeNotFoundError: () => import_connect14.EdgeNotFoundError,
44
- EdgeTokenExchangeError: () => import_connect14.EdgeTokenExchangeError,
40
+ EdgeConsentRequiredError: () => import_connect15.EdgeConsentRequiredError,
41
+ EdgeError: () => import_connect15.EdgeError,
42
+ EdgeFeatureUnavailableError: () => import_connect15.EdgeFeatureUnavailableError,
43
+ EdgeIdentityVerificationError: () => import_connect15.EdgeIdentityVerificationError,
44
+ EdgeInsufficientScopeError: () => import_connect15.EdgeInsufficientScopeError,
45
+ EdgeNetworkError: () => import_connect15.EdgeNetworkError,
46
+ EdgeNotFoundError: () => import_connect15.EdgeNotFoundError,
47
+ EdgeTokenExchangeError: () => import_connect15.EdgeTokenExchangeError,
45
48
  EdgeTokenVault: () => EdgeTokenVault,
46
49
  EdgeUserClient: () => EdgeUserClient,
47
50
  EdgeUserSession: () => EdgeUserSession,
48
- EdgeValidationError: () => import_connect14.EdgeValidationError,
51
+ EdgeValidationError: () => import_connect15.EdgeValidationError,
49
52
  EdgeWebhookInbox: () => EdgeWebhookInbox,
50
53
  EdgeWebhookReconciler: () => EdgeWebhookReconciler,
51
- TRANSFER_CATEGORIES: () => import_connect15.TRANSFER_CATEGORIES,
54
+ TRANSFER_CATEGORIES: () => import_connect16.TRANSFER_CATEGORIES,
52
55
  assertSameTransferIntent: () => assertSameTransferIntent,
53
56
  assertTransferEventMatchesIntent: () => assertTransferEventMatchesIntent,
54
57
  assertWebhookMatchesTransfer: () => assertWebhookMatchesTransfer,
@@ -68,16 +71,17 @@ __export(index_exports, {
68
71
  getConnectTransferDirection: () => getConnectTransferDirection,
69
72
  getEdgeWebhookRawBody: () => getEdgeWebhookRawBody,
70
73
  getEdgeWebhookSignatureHeader: () => getEdgeWebhookSignatureHeader,
71
- getEnvironmentConfig: () => import_connect15.getEnvironmentConfig,
72
- isApiError: () => import_connect14.isApiError,
73
- isAuthenticationError: () => import_connect14.isAuthenticationError,
74
- isConsentRequiredError: () => import_connect14.isConsentRequiredError,
75
- isEdgeError: () => import_connect14.isEdgeError,
74
+ getEnvironmentConfig: () => import_connect16.getEnvironmentConfig,
75
+ isApiError: () => import_connect15.isApiError,
76
+ isAuthenticationError: () => import_connect15.isAuthenticationError,
77
+ isConsentRequiredError: () => import_connect15.isConsentRequiredError,
78
+ isEdgeError: () => import_connect15.isEdgeError,
76
79
  isEdgeTokenVaultEnvelope: () => isEdgeTokenVaultEnvelope,
77
80
  isEdgeWebhookEvent: () => isEdgeWebhookEvent,
78
- isIdentityVerificationError: () => import_connect14.isIdentityVerificationError,
79
- isNetworkError: () => import_connect14.isNetworkError,
80
- isProductionEnvironment: () => import_connect15.isProductionEnvironment,
81
+ isFeatureUnavailableError: () => import_connect15.isFeatureUnavailableError,
82
+ isIdentityVerificationError: () => import_connect15.isIdentityVerificationError,
83
+ isNetworkError: () => import_connect15.isNetworkError,
84
+ isProductionEnvironment: () => import_connect16.isProductionEnvironment,
81
85
  isTransferWebhookEvent: () => isTransferWebhookEvent,
82
86
  mapTransferStatusToPartnerState: () => mapTransferStatusToPartnerState,
83
87
  moneyAmountsEqual: () => moneyAmountsEqual,
@@ -96,7 +100,10 @@ __export(index_exports, {
96
100
  module.exports = __toCommonJS(index_exports);
97
101
 
98
102
  // src/edge-connect-server.ts
99
- var import_connect4 = require("@edge-markets/connect");
103
+ var import_connect5 = require("@edge-markets/connect");
104
+
105
+ // src/edge-user-client.ts
106
+ var import_connect3 = require("@edge-markets/connect");
100
107
 
101
108
  // src/transfer-helpers.ts
102
109
  var import_connect = require("@edge-markets/connect");
@@ -194,6 +201,7 @@ function mapTransferStatusToPartnerState(status, mapping) {
194
201
  return partnerState;
195
202
  }
196
203
  async function startTransferVerification(client, options) {
204
+ assertTransferFeatureAvailable();
197
205
  const origin = typeof options.origin === "string" ? options.origin.trim() : "";
198
206
  if (!origin) {
199
207
  throw new import_connect.EdgeValidationError("Verification origin is required", {
@@ -213,6 +221,14 @@ async function startTransferVerification(client, options) {
213
221
  const verificationSession = await client.createVerificationSession(transferId, { origin });
214
222
  return { transfer, verificationSession };
215
223
  }
224
+ function assertTransferFeatureAvailable() {
225
+ if (!isTransferFeatureAvailable()) {
226
+ throw new import_connect.EdgeFeatureUnavailableError();
227
+ }
228
+ }
229
+ function isTransferFeatureAvailable() {
230
+ return false;
231
+ }
216
232
  function parseMoneyToCents(value, field, options = {}) {
217
233
  let input;
218
234
  if (typeof value === "number") {
@@ -334,6 +350,7 @@ var EdgeUserClient = class {
334
350
  return this.server._apiRequest("GET", "/balance", this.accessToken);
335
351
  }
336
352
  async initiateTransfer(options) {
353
+ assertTransferFeatureAvailable2();
337
354
  validateTransferOptions(options);
338
355
  const body = {
339
356
  type: options.type,
@@ -346,13 +363,16 @@ var EdgeUserClient = class {
346
363
  return this.server._apiRequest("POST", "/transfer", this.accessToken, body);
347
364
  }
348
365
  async startTransferVerification(options) {
366
+ assertTransferFeatureAvailable2();
349
367
  return startTransferVerification(this, options);
350
368
  }
351
369
  async getTransfer(transferId) {
370
+ assertTransferFeatureAvailable2();
352
371
  validateTransferId(transferId);
353
372
  return this.server._apiRequest("GET", `/transfer/${encodeURIComponent(transferId)}`, this.accessToken);
354
373
  }
355
374
  async listTransfers(params) {
375
+ assertTransferFeatureAvailable2();
356
376
  const queryParams = new URLSearchParams();
357
377
  if (params?.limit) queryParams.set("limit", String(params.limit));
358
378
  if (params?.offset) queryParams.set("offset", String(params.offset));
@@ -365,11 +385,11 @@ var EdgeUserClient = class {
365
385
  return this.server._apiRequest("DELETE", "/consent", this.accessToken);
366
386
  }
367
387
  /**
368
- * Creates an EDGE-hosted transfer verification session.
369
- * Returns a `verificationUrl` to open in an iframe or popup.
370
- * The handoff token is single-use and expires in 120 seconds.
388
+ * Reserved for a future transfer release.
389
+ * Currently throws EdgeFeatureUnavailableError before validation or network I/O.
371
390
  */
372
391
  async createVerificationSession(transferId, options) {
392
+ assertTransferFeatureAvailable2();
373
393
  validateTransferId(transferId);
374
394
  return this.server._apiRequest(
375
395
  "POST",
@@ -379,10 +399,11 @@ var EdgeUserClient = class {
379
399
  );
380
400
  }
381
401
  /**
382
- * Polls the status of a verification session.
383
- * Use as an alternative to postMessage events.
402
+ * Reserved for a future transfer release.
403
+ * Currently throws EdgeFeatureUnavailableError before validation or network I/O.
384
404
  */
385
405
  async getVerificationSessionStatus(transferId, sessionId) {
406
+ assertTransferFeatureAvailable2();
386
407
  validateTransferId(transferId);
387
408
  return this.server._apiRequest(
388
409
  "GET",
@@ -391,6 +412,14 @@ var EdgeUserClient = class {
391
412
  );
392
413
  }
393
414
  };
415
+ function assertTransferFeatureAvailable2() {
416
+ if (!isTransferFeatureAvailable2()) {
417
+ throw new import_connect3.EdgeFeatureUnavailableError();
418
+ }
419
+ }
420
+ function isTransferFeatureAvailable2() {
421
+ return false;
422
+ }
394
423
 
395
424
  // src/mle.ts
396
425
  var import_crypto = require("crypto");
@@ -471,6 +500,7 @@ function fromBase64Url(value) {
471
500
  var import_node_fs = __toESM(require("fs"));
472
501
  var import_node_https = __toESM(require("https"));
473
502
  var import_node_tls = __toESM(require("tls"));
503
+ var import_undici = require("undici");
474
504
  var CERT_PATTERN = /-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g;
475
505
  function normalizeCaBundle(ca) {
476
506
  if (!ca) return [];
@@ -508,9 +538,7 @@ function createHttpsAgent(config) {
508
538
  }
509
539
  function createUndiciDispatcher(config) {
510
540
  const ca = buildServerCaBundle(config.ca);
511
- const moduleName = "undici";
512
- const { Agent } = require(moduleName);
513
- return new Agent({
541
+ return new import_undici.Agent({
514
542
  connect: {
515
543
  cert: config.cert,
516
544
  key: config.key,
@@ -529,28 +557,28 @@ function validateMtlsConfig(config) {
529
557
  }
530
558
 
531
559
  // src/session.ts
532
- var import_connect3 = require("@edge-markets/connect");
560
+ var import_connect4 = require("@edge-markets/connect");
533
561
  var EdgeUserSession = class {
534
562
  constructor(options) {
535
563
  this.refreshPromise = null;
536
564
  if (!options.edge?.forUser || !options.edge?.refreshTokens) {
537
- throw new import_connect3.EdgeValidationError("EdgeUserSession requires an EdgeConnectServer instance", {
565
+ throw new import_connect4.EdgeValidationError("EdgeUserSession requires an EdgeConnectServer instance", {
538
566
  edge: ["Provide edge.forUser and edge.refreshTokens"]
539
567
  });
540
568
  }
541
569
  const subjectId = typeof options.subjectId === "string" ? options.subjectId.trim() : "";
542
570
  if (!subjectId) {
543
- throw new import_connect3.EdgeValidationError("EdgeUserSession subjectId is required", {
571
+ throw new import_connect4.EdgeValidationError("EdgeUserSession subjectId is required", {
544
572
  subjectId: ["Required"]
545
573
  });
546
574
  }
547
575
  if (!options.tokenStore?.load || !options.tokenStore?.save) {
548
- throw new import_connect3.EdgeValidationError("EdgeUserSession tokenStore is required", {
576
+ throw new import_connect4.EdgeValidationError("EdgeUserSession tokenStore is required", {
549
577
  tokenStore: ["Provide load(subjectId) and save(subjectId, value, context)"]
550
578
  });
551
579
  }
552
580
  if (options.refreshSkewMs !== void 0 && (!Number.isFinite(options.refreshSkewMs) || options.refreshSkewMs < 0)) {
553
- throw new import_connect3.EdgeValidationError("refreshSkewMs must be a non-negative number", {
581
+ throw new import_connect4.EdgeValidationError("refreshSkewMs must be a non-negative number", {
554
582
  refreshSkewMs: ["Must be greater than or equal to 0"]
555
583
  });
556
584
  }
@@ -603,13 +631,13 @@ var EdgeUserSession = class {
603
631
  async loadTokens() {
604
632
  const value = await this.tokenStore.load(this.subjectId);
605
633
  if (!value) {
606
- throw new import_connect3.EdgeAuthenticationError("No EDGE tokens are stored for this subject", {
634
+ throw new import_connect4.EdgeAuthenticationError("No EDGE tokens are stored for this subject", {
607
635
  subjectId: this.subjectId
608
636
  });
609
637
  }
610
638
  if (typeof value === "string") {
611
639
  if (!this.tokenVault) {
612
- throw new import_connect3.EdgeAuthenticationError("Encrypted EDGE token envelope loaded but no tokenVault was configured", {
640
+ throw new import_connect4.EdgeAuthenticationError("Encrypted EDGE token envelope loaded but no tokenVault was configured", {
613
641
  subjectId: this.subjectId
614
642
  });
615
643
  }
@@ -695,7 +723,7 @@ function validateTokens(tokens) {
695
723
  }
696
724
  }
697
725
  if (Object.keys(errors).length > 0) {
698
- throw new import_connect3.EdgeValidationError("Invalid EDGE token payload", errors);
726
+ throw new import_connect4.EdgeValidationError("Invalid EDGE token payload", errors);
699
727
  }
700
728
  }
701
729
 
@@ -886,7 +914,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
886
914
  throw new Error("EdgeConnectServer: environment is required");
887
915
  }
888
916
  this.config = config;
889
- const envConfig = (0, import_connect4.getEnvironmentConfig)(config.environment);
917
+ const envConfig = (0, import_connect5.getEnvironmentConfig)(config.environment);
890
918
  this.apiBaseUrl = config.apiBaseUrl || envConfig.apiBaseUrl;
891
919
  this.partnerApiBaseUrl = stripTrailingSlash(config.partnerApiBaseUrl || derivePartnerApiBaseUrl(this.apiBaseUrl));
892
920
  this.oauthBaseUrl = config.oauthBaseUrl || envConfig.oauthBaseUrl;
@@ -931,7 +959,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
931
959
  */
932
960
  forUser(accessToken) {
933
961
  if (!accessToken) {
934
- throw new import_connect4.EdgeAuthenticationError("accessToken is required when calling forUser()");
962
+ throw new import_connect5.EdgeAuthenticationError("accessToken is required when calling forUser()");
935
963
  }
936
964
  return new EdgeUserClient(this, accessToken);
937
965
  }
@@ -968,8 +996,8 @@ var EdgeConnectServer = class _EdgeConnectServer {
968
996
  const data = await response.json();
969
997
  return this.parseTokenResponse(data);
970
998
  } catch (error) {
971
- if (error instanceof import_connect4.EdgeError) throw error;
972
- throw new import_connect4.EdgeNetworkError("Failed to exchange code", error);
999
+ if (error instanceof import_connect5.EdgeError) throw error;
1000
+ throw new import_connect5.EdgeNetworkError("Failed to exchange code", error);
973
1001
  }
974
1002
  }
975
1003
  async refreshTokens(refreshToken) {
@@ -995,7 +1023,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
995
1023
  );
996
1024
  if (!response.ok) {
997
1025
  const error = await response.json().catch(() => ({}));
998
- throw new import_connect4.EdgeAuthenticationError(
1026
+ throw new import_connect5.EdgeAuthenticationError(
999
1027
  error.message || error.error_description || "Token refresh failed. User may need to reconnect.",
1000
1028
  { tokenError: error }
1001
1029
  );
@@ -1003,8 +1031,8 @@ var EdgeConnectServer = class _EdgeConnectServer {
1003
1031
  const data = await response.json();
1004
1032
  return this.parseTokenResponse(data, refreshToken);
1005
1033
  } catch (error) {
1006
- if (error instanceof import_connect4.EdgeError) throw error;
1007
- throw new import_connect4.EdgeNetworkError("Failed to refresh tokens", error);
1034
+ if (error instanceof import_connect5.EdgeError) throw error;
1035
+ throw new import_connect5.EdgeNetworkError("Failed to refresh tokens", error);
1008
1036
  }
1009
1037
  }
1010
1038
  /** @internal Called by {@link EdgeUserClient} — not part of the public API. */
@@ -1046,14 +1074,14 @@ var EdgeConnectServer = class _EdgeConnectServer {
1046
1074
  if (mleEnabled && typeof rawResponseBody?.jwe === "string") {
1047
1075
  responseBody = decryptMle(rawResponseBody.jwe, mleConfig);
1048
1076
  } else if (!mleEnabled && typeof rawResponseBody?.jwe === "string") {
1049
- throw new import_connect4.EdgeApiError(
1077
+ throw new import_connect5.EdgeApiError(
1050
1078
  "mle_required",
1051
1079
  "The API responded with message-level encryption. Enable MLE in SDK config.",
1052
1080
  response.status,
1053
1081
  rawResponseBody
1054
1082
  );
1055
1083
  } else if (mleEnabled && mleConfig?.strictResponseEncryption !== false && response.ok && typeof rawResponseBody?.jwe !== "string") {
1056
- throw new import_connect4.EdgeApiError(
1084
+ throw new import_connect5.EdgeApiError(
1057
1085
  "mle_response_missing",
1058
1086
  "Expected encrypted response payload but received plaintext.",
1059
1087
  response.status,
@@ -1071,8 +1099,8 @@ var EdgeConnectServer = class _EdgeConnectServer {
1071
1099
  }
1072
1100
  return responseBody;
1073
1101
  } catch (error) {
1074
- if (error instanceof import_connect4.EdgeError) {
1075
- if (!(error instanceof import_connect4.EdgeNetworkError) || attempt >= this.retryConfig.maxRetries) {
1102
+ if (error instanceof import_connect5.EdgeError) {
1103
+ if (!(error instanceof import_connect5.EdgeNetworkError) || attempt >= this.retryConfig.maxRetries) {
1076
1104
  throw error;
1077
1105
  }
1078
1106
  lastError = error;
@@ -1080,11 +1108,11 @@ var EdgeConnectServer = class _EdgeConnectServer {
1080
1108
  }
1081
1109
  lastError = error;
1082
1110
  if (attempt >= this.retryConfig.maxRetries) {
1083
- throw new import_connect4.EdgeNetworkError(`API request failed: ${method} ${path}`, lastError);
1111
+ throw new import_connect5.EdgeNetworkError(`API request failed: ${method} ${path}`, lastError);
1084
1112
  }
1085
1113
  }
1086
1114
  }
1087
- throw new import_connect4.EdgeNetworkError(
1115
+ throw new import_connect5.EdgeNetworkError(
1088
1116
  `API request failed after ${this.retryConfig.maxRetries} retries: ${method} ${path}`,
1089
1117
  lastError
1090
1118
  );
@@ -1128,10 +1156,10 @@ var EdgeConnectServer = class _EdgeConnectServer {
1128
1156
  */
1129
1157
  async syncWebhookEvents(options = {}) {
1130
1158
  if (!this.config.partnerClientId) {
1131
- throw new import_connect4.EdgeAuthenticationError("syncWebhookEvents requires `partnerClientId` in EdgeConnectServer config");
1159
+ throw new import_connect5.EdgeAuthenticationError("syncWebhookEvents requires `partnerClientId` in EdgeConnectServer config");
1132
1160
  }
1133
1161
  if (!this.config.partnerClientSecret) {
1134
- throw new import_connect4.EdgeAuthenticationError("syncWebhookEvents requires `partnerClientSecret` in EdgeConnectServer config");
1162
+ throw new import_connect5.EdgeAuthenticationError("syncWebhookEvents requires `partnerClientSecret` in EdgeConnectServer config");
1135
1163
  }
1136
1164
  const normalizedOptions = this.normalizeSyncWebhookEventsOptions(options);
1137
1165
  const url = this.buildSyncUrl(normalizedOptions);
@@ -1162,7 +1190,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
1162
1190
  endpoint: "partner_webhook_sync",
1163
1191
  attempt
1164
1192
  });
1165
- throw new import_connect4.EdgeAuthenticationError(
1193
+ throw new import_connect5.EdgeAuthenticationError(
1166
1194
  body.message || "Partner token rejected after refresh \u2014 check partnerClientId/Secret",
1167
1195
  body
1168
1196
  );
@@ -1179,7 +1207,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
1179
1207
  endpoint: "partner_webhook_sync",
1180
1208
  attempt
1181
1209
  });
1182
- throw new import_connect4.EdgeApiError(
1210
+ throw new import_connect5.EdgeApiError(
1183
1211
  body.error || "sync_failed",
1184
1212
  body.message || `syncWebhookEvents failed with status ${response.status}`,
1185
1213
  response.status,
@@ -1225,7 +1253,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
1225
1253
  }
1226
1254
  if (options.limit !== void 0) {
1227
1255
  if (!Number.isInteger(options.limit) || options.limit < SYNC_WEBHOOK_EVENTS_MIN_LIMIT || options.limit > SYNC_WEBHOOK_EVENTS_MAX_LIMIT) {
1228
- throw new import_connect4.EdgeApiError(
1256
+ throw new import_connect5.EdgeApiError(
1229
1257
  "invalid_sync_options",
1230
1258
  `syncWebhookEvents limit must be an integer between ${SYNC_WEBHOOK_EVENTS_MIN_LIMIT} and ${SYNC_WEBHOOK_EVENTS_MAX_LIMIT}`,
1231
1259
  400,
@@ -1295,11 +1323,11 @@ var EdgeConnectServer = class _EdgeConnectServer {
1295
1323
  } catch (error) {
1296
1324
  lastError = error;
1297
1325
  if (attempt >= this.retryConfig.maxRetries) {
1298
- throw new import_connect4.EdgeNetworkError("syncWebhookEvents network failure", lastError);
1326
+ throw new import_connect5.EdgeNetworkError("syncWebhookEvents network failure", lastError);
1299
1327
  }
1300
1328
  }
1301
1329
  }
1302
- throw new import_connect4.EdgeNetworkError(
1330
+ throw new import_connect5.EdgeNetworkError(
1303
1331
  `syncWebhookEvents network failure after ${this.retryConfig.maxRetries} retries`,
1304
1332
  lastError
1305
1333
  );
@@ -1347,7 +1375,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
1347
1375
  this.dispatcher
1348
1376
  );
1349
1377
  } catch (error) {
1350
- throw new import_connect4.EdgeNetworkError("Partner token request network failure", error);
1378
+ throw new import_connect5.EdgeNetworkError("Partner token request network failure", error);
1351
1379
  }
1352
1380
  const durationMs = Date.now() - startTime;
1353
1381
  const data = await response.json().catch(() => ({}));
@@ -1360,13 +1388,13 @@ var EdgeConnectServer = class _EdgeConnectServer {
1360
1388
  endpoint: "oauth_token"
1361
1389
  });
1362
1390
  if (!response.ok) {
1363
- throw new import_connect4.EdgeAuthenticationError(
1391
+ throw new import_connect5.EdgeAuthenticationError(
1364
1392
  data.message || data.error_description || `Partner token request failed with status ${response.status}`,
1365
1393
  data
1366
1394
  );
1367
1395
  }
1368
1396
  if (!data.access_token || typeof data.expires_in !== "number") {
1369
- throw new import_connect4.EdgeAuthenticationError("Partner token response missing access_token or expires_in");
1397
+ throw new import_connect5.EdgeAuthenticationError("Partner token response missing access_token or expires_in");
1370
1398
  }
1371
1399
  this.partnerTokenCache = {
1372
1400
  token: data.access_token,
@@ -1441,37 +1469,37 @@ var EdgeConnectServer = class _EdgeConnectServer {
1441
1469
  const errorCode = error.error;
1442
1470
  const errorMessage = error.message || error.error_description;
1443
1471
  if (errorCode === "invalid_grant" || errorMessage?.includes("Invalid or expired")) {
1444
- return new import_connect4.EdgeTokenExchangeError("Authorization code is invalid, expired, or already used. Please try again.", {
1472
+ return new import_connect5.EdgeTokenExchangeError("Authorization code is invalid, expired, or already used. Please try again.", {
1445
1473
  edgeBoostError: error
1446
1474
  });
1447
1475
  }
1448
1476
  if (errorCode === "invalid_client" || errorMessage?.includes("Invalid client")) {
1449
- return new import_connect4.EdgeAuthenticationError("Invalid client credentials. Check your client ID and secret.", {
1477
+ return new import_connect5.EdgeAuthenticationError("Invalid client credentials. Check your client ID and secret.", {
1450
1478
  edgeBoostError: error
1451
1479
  });
1452
1480
  }
1453
1481
  if (errorMessage?.includes("code_verifier") || errorMessage?.includes("PKCE")) {
1454
- return new import_connect4.EdgeTokenExchangeError("PKCE verification failed. Please try again.", { edgeBoostError: error });
1482
+ return new import_connect5.EdgeTokenExchangeError("PKCE verification failed. Please try again.", { edgeBoostError: error });
1455
1483
  }
1456
- return new import_connect4.EdgeTokenExchangeError(errorMessage || "Failed to exchange authorization code", {
1484
+ return new import_connect5.EdgeTokenExchangeError(errorMessage || "Failed to exchange authorization code", {
1457
1485
  edgeBoostError: error,
1458
1486
  statusCode: status
1459
1487
  });
1460
1488
  }
1461
1489
  async handleApiErrorFromBody(error, status, path) {
1462
1490
  if (status === 401) {
1463
- return new import_connect4.EdgeAuthenticationError(error.message || "Access token is invalid or expired", error);
1491
+ return new import_connect5.EdgeAuthenticationError(error.message || "Access token is invalid or expired", error);
1464
1492
  }
1465
1493
  if (status === 403) {
1466
1494
  if (error.error === "consent_required") {
1467
- return new import_connect4.EdgeConsentRequiredError(
1495
+ return new import_connect5.EdgeConsentRequiredError(
1468
1496
  this.config.clientId,
1469
1497
  error.consentUrl,
1470
1498
  error.message
1471
1499
  );
1472
1500
  }
1473
1501
  if (error.error === "insufficient_scope" || error.error === "insufficient_consent") {
1474
- return new import_connect4.EdgeInsufficientScopeError(
1502
+ return new import_connect5.EdgeInsufficientScopeError(
1475
1503
  error.missing_scopes || error.missingScopes || [],
1476
1504
  error.message
1477
1505
  );
@@ -1493,15 +1521,15 @@ var EdgeConnectServer = class _EdgeConnectServer {
1493
1521
  } else if (path.includes("/transfer")) {
1494
1522
  resourceType = "Transfer";
1495
1523
  }
1496
- return new import_connect4.EdgeNotFoundError(resourceType, resourceId);
1524
+ return new import_connect5.EdgeNotFoundError(resourceType, resourceId);
1497
1525
  }
1498
1526
  if (status === 422 && error.error === "identity_verification_failed") {
1499
- return new import_connect4.EdgeIdentityVerificationError(
1527
+ return new import_connect5.EdgeIdentityVerificationError(
1500
1528
  error.fieldErrors || {},
1501
1529
  error.message
1502
1530
  );
1503
1531
  }
1504
- return new import_connect4.EdgeApiError(
1532
+ return new import_connect5.EdgeApiError(
1505
1533
  error.error || "api_error",
1506
1534
  error.message || error.error_description || `Request failed with status ${status}`,
1507
1535
  status,
@@ -1511,9 +1539,9 @@ var EdgeConnectServer = class _EdgeConnectServer {
1511
1539
  };
1512
1540
 
1513
1541
  // src/env.ts
1514
- var import_connect5 = require("@edge-markets/connect");
1542
+ var import_connect6 = require("@edge-markets/connect");
1515
1543
  var import_node_fs2 = __toESM(require("fs"));
1516
- var ENVIRONMENT_NAMES = new Set(Object.keys(import_connect5.EDGE_ENVIRONMENTS));
1544
+ var ENVIRONMENT_NAMES = new Set(Object.keys(import_connect6.EDGE_ENVIRONMENTS));
1517
1545
  function readEnv(env, name) {
1518
1546
  const value = env[name];
1519
1547
  if (typeof value !== "string") return void 0;
@@ -1546,7 +1574,7 @@ function readPemValue(env, valueName, pathName, warnings) {
1546
1574
  return normalizePem(import_node_fs2.default.readFileSync(filePath, "utf8"));
1547
1575
  } catch (error) {
1548
1576
  const message = error instanceof Error ? error.message : String(error);
1549
- throw new import_connect5.EdgeValidationError(`Failed to read ${pathName}`, {
1577
+ throw new import_connect6.EdgeValidationError(`Failed to read ${pathName}`, {
1550
1578
  [pathName]: [`Unable to read PEM file "${filePath}": ${message}`]
1551
1579
  });
1552
1580
  }
@@ -1554,19 +1582,29 @@ function readPemValue(env, valueName, pathName, warnings) {
1554
1582
  function readEnvironment(env) {
1555
1583
  const value = readEnv(env, "EDGE_ENVIRONMENT") || "staging";
1556
1584
  if (!ENVIRONMENT_NAMES.has(value)) {
1557
- throw new import_connect5.EdgeValidationError("Invalid EDGE_ENVIRONMENT", {
1585
+ throw new import_connect6.EdgeValidationError("Invalid EDGE_ENVIRONMENT", {
1558
1586
  EDGE_ENVIRONMENT: [`Must be one of: ${Array.from(ENVIRONMENT_NAMES).join(", ")}`]
1559
1587
  });
1560
1588
  }
1561
1589
  return value;
1562
1590
  }
1591
+ function readBooleanEnv(env, name) {
1592
+ const value = readEnv(env, name);
1593
+ if (!value) return void 0;
1594
+ const normalized = value.toLowerCase();
1595
+ if (["true", "1", "yes"].includes(normalized)) return true;
1596
+ if (["false", "0", "no"].includes(normalized)) return false;
1597
+ throw new import_connect6.EdgeValidationError(`Invalid ${name}`, {
1598
+ [name]: ["Must be one of: true, false, 1, 0, yes, no"]
1599
+ });
1600
+ }
1563
1601
  function readTimeout(env, override) {
1564
1602
  if (override !== void 0) return override;
1565
1603
  const value = readFirstEnv(env, ["EDGE_TIMEOUT_MS", "EDGE_REQUEST_TIMEOUT_MS"]);
1566
1604
  if (!value) return void 0;
1567
1605
  const timeout = Number(value);
1568
1606
  if (!Number.isInteger(timeout) || timeout <= 0) {
1569
- throw new import_connect5.EdgeValidationError("Invalid EDGE_TIMEOUT_MS", {
1607
+ throw new import_connect6.EdgeValidationError("Invalid EDGE_TIMEOUT_MS", {
1570
1608
  EDGE_TIMEOUT_MS: ["Must be a positive integer number of milliseconds"]
1571
1609
  });
1572
1610
  }
@@ -1575,10 +1613,15 @@ function readTimeout(env, override) {
1575
1613
  function buildMtlsConfig(env, requireMtls, warnings) {
1576
1614
  const cert = readPemValue(env, "EDGE_MTLS_CERT", "EDGE_MTLS_CERT_PATH", warnings);
1577
1615
  const key = readPemValue(env, "EDGE_MTLS_KEY", "EDGE_MTLS_KEY_PATH", warnings);
1578
- const ca = readPemValue(env, "EDGE_MTLS_CA", "EDGE_MTLS_CA_PATH", warnings);
1616
+ const serverCa = readPemValue(env, "EDGE_SERVER_CA_PEM", "EDGE_SERVER_CA_PEM_PATH", warnings);
1617
+ const hasLegacyCa = !!readFirstEnv(env, ["EDGE_MTLS_CA", "EDGE_MTLS_CA_PATH"]);
1618
+ if (serverCa && hasLegacyCa) {
1619
+ warnings.push("EDGE_SERVER_CA_PEM and EDGE_MTLS_CA are both set; using EDGE_SERVER_CA_PEM");
1620
+ }
1621
+ const ca = serverCa || readPemValue(env, "EDGE_MTLS_CA", "EDGE_MTLS_CA_PATH", warnings);
1579
1622
  if (!cert && !key && !ca) {
1580
1623
  if (requireMtls) {
1581
- throw new import_connect5.EdgeValidationError("mTLS is required but no EDGE_MTLS_CERT or EDGE_MTLS_KEY was provided", {
1624
+ throw new import_connect6.EdgeValidationError("mTLS is required but no EDGE_MTLS_CERT or EDGE_MTLS_KEY was provided", {
1582
1625
  EDGE_MTLS_CERT: ["Required when requireMtls is true"],
1583
1626
  EDGE_MTLS_KEY: ["Required when requireMtls is true"]
1584
1627
  });
@@ -1586,7 +1629,7 @@ function buildMtlsConfig(env, requireMtls, warnings) {
1586
1629
  return void 0;
1587
1630
  }
1588
1631
  if (!cert || !key) {
1589
- throw new import_connect5.EdgeValidationError("Incomplete mTLS configuration", {
1632
+ throw new import_connect6.EdgeValidationError("Incomplete mTLS configuration", {
1590
1633
  EDGE_MTLS_CERT: cert ? [] : ["Required when mTLS is configured"],
1591
1634
  EDGE_MTLS_KEY: key ? [] : ["Required when mTLS is configured"]
1592
1635
  });
@@ -1600,7 +1643,7 @@ function buildMtlsConfig(env, requireMtls, warnings) {
1600
1643
  }
1601
1644
  function inferMtlsRequirement(environment, apiBaseUrl) {
1602
1645
  if (environment === "staging" || environment === "production") return true;
1603
- const resolvedApiBaseUrl = apiBaseUrl || (0, import_connect5.getEnvironmentConfig)(environment).apiBaseUrl;
1646
+ const resolvedApiBaseUrl = apiBaseUrl || (0, import_connect6.getEnvironmentConfig)(environment).apiBaseUrl;
1604
1647
  try {
1605
1648
  const host = new URL(resolvedApiBaseUrl).host;
1606
1649
  return host === "connect-staging.edgeboost.io" || host === "connect.edgeboost.io";
@@ -1614,7 +1657,7 @@ function createEdgeConnectServerFromEnv(options = {}) {
1614
1657
  const environment = readEnvironment(env);
1615
1658
  const apiBaseUrl = readEnv(env, "EDGE_API_BASE_URL");
1616
1659
  const mtlsRequiredByTarget = inferMtlsRequirement(environment, apiBaseUrl);
1617
- const requireMtls = options.requireMtls ?? false;
1660
+ const requireMtls = options.requireMtls ?? readBooleanEnv(env, "EDGE_REQUIRE_MTLS") ?? false;
1618
1661
  const mtls = buildMtlsConfig(env, requireMtls, warnings);
1619
1662
  const timeout = readTimeout(env, options.timeout);
1620
1663
  const clientId = readFirstEnv(env, ["EDGE_CLIENT_ID", "EDGE_CONNECT_CLIENT_ID"]) || "";
@@ -1627,7 +1670,7 @@ function createEdgeConnectServerFromEnv(options = {}) {
1627
1670
  if (!clientId) validationErrors.EDGE_CLIENT_ID = ["Required"];
1628
1671
  if (!clientSecret) validationErrors.EDGE_CLIENT_SECRET = ["Required"];
1629
1672
  if (Object.keys(validationErrors).length > 0) {
1630
- throw new import_connect5.EdgeValidationError("Missing required EDGE Connect environment variables", validationErrors);
1673
+ throw new import_connect6.EdgeValidationError("Missing required EDGE Connect environment variables", validationErrors);
1631
1674
  }
1632
1675
  if (mtlsRequiredByTarget && !mtls) {
1633
1676
  warnings.push(
@@ -1666,32 +1709,35 @@ function createEdgeConnectServerFromEnv(options = {}) {
1666
1709
  }
1667
1710
 
1668
1711
  // src/error-adapter.ts
1669
- var import_connect6 = require("@edge-markets/connect");
1712
+ var import_connect7 = require("@edge-markets/connect");
1670
1713
  function toEdgeHttpError(error) {
1671
1714
  const body = toEdgeProblemJson(error);
1672
1715
  return { status: body.status, body };
1673
1716
  }
1674
1717
  function toEdgeProblemJson(error) {
1675
- if (error instanceof import_connect6.EdgeConsentRequiredError) {
1718
+ if (error instanceof import_connect7.EdgeConsentRequiredError) {
1676
1719
  return problem(error, "Consent required", error.statusCode ?? 403, {
1677
1720
  clientId: error.clientId,
1678
1721
  consentUrl: error.consentUrl
1679
1722
  });
1680
1723
  }
1681
- if (error instanceof import_connect6.EdgeValidationError) {
1724
+ if (error instanceof import_connect7.EdgeValidationError) {
1682
1725
  return problem(error, "Validation failed", error.statusCode ?? 400, {
1683
1726
  validationErrors: error.validationErrors
1684
1727
  });
1685
1728
  }
1686
- if (error instanceof import_connect6.EdgeIdentityVerificationError) {
1729
+ if (error instanceof import_connect7.EdgeIdentityVerificationError) {
1687
1730
  return problem(error, "Identity verification failed", error.statusCode ?? 422, {
1688
1731
  fieldErrors: error.fieldErrors
1689
1732
  });
1690
1733
  }
1691
- if (error instanceof import_connect6.EdgeNetworkError) {
1734
+ if (error instanceof import_connect7.EdgeFeatureUnavailableError) {
1735
+ return problem(error, "Feature unavailable", error.statusCode ?? 501);
1736
+ }
1737
+ if (error instanceof import_connect7.EdgeNetworkError) {
1692
1738
  return problem(error, "EDGE network error", error.statusCode ?? 502);
1693
1739
  }
1694
- if (error instanceof import_connect6.EdgeError) {
1740
+ if (error instanceof import_connect7.EdgeError) {
1695
1741
  return problem(error, edgeTitle(error), error.statusCode ?? 500, error.details);
1696
1742
  }
1697
1743
  const message = error instanceof Error ? error.message : "Unexpected error";
@@ -1718,10 +1764,10 @@ function edgeTitle(error) {
1718
1764
  }
1719
1765
 
1720
1766
  // src/http-helpers.ts
1721
- var import_connect8 = require("@edge-markets/connect");
1767
+ var import_connect9 = require("@edge-markets/connect");
1722
1768
 
1723
1769
  // src/webhook-parser.ts
1724
- var import_connect7 = require("@edge-markets/connect");
1770
+ var import_connect8 = require("@edge-markets/connect");
1725
1771
 
1726
1772
  // src/webhook-signing.ts
1727
1773
  var import_node_crypto2 = __toESM(require("crypto"));
@@ -1753,23 +1799,23 @@ function verifyWebhookSignature(header, body, secret, options = {}) {
1753
1799
  }
1754
1800
 
1755
1801
  // src/webhook-parser.ts
1756
- var EVENT_TYPES = new Set(import_connect7.EDGE_WEBHOOK_EVENT_TYPES);
1802
+ var EVENT_TYPES = new Set(import_connect8.EDGE_WEBHOOK_EVENT_TYPES);
1757
1803
  var TRANSFER_TYPES = /* @__PURE__ */ new Set(["debit", "credit"]);
1758
1804
  function parseAndVerifyWebhook(options) {
1759
1805
  const body = normalizeRawBody(options.rawBody);
1760
1806
  const header = normalizeSignatureHeader(options.signatureHeader);
1761
1807
  const signatureTimestamp = extractWebhookSignatureTimestamp(header);
1762
1808
  if (!header || !signatureTimestamp) {
1763
- throw new import_connect7.EdgeAuthenticationError("Missing or malformed EDGE webhook signature");
1809
+ throw new import_connect8.EdgeAuthenticationError("Missing or malformed EDGE webhook signature");
1764
1810
  }
1765
1811
  if (!verifyWebhookSignature(header, body, options.secret, { toleranceSeconds: options.toleranceSeconds })) {
1766
- throw new import_connect7.EdgeAuthenticationError("Invalid EDGE webhook signature");
1812
+ throw new import_connect8.EdgeAuthenticationError("Invalid EDGE webhook signature");
1767
1813
  }
1768
1814
  let parsed;
1769
1815
  try {
1770
1816
  parsed = JSON.parse(body);
1771
1817
  } catch {
1772
- throw new import_connect7.EdgeValidationError("EDGE webhook body must be valid JSON", {
1818
+ throw new import_connect8.EdgeValidationError("EDGE webhook body must be valid JSON", {
1773
1819
  rawBody: ["Unable to parse JSON after signature verification"]
1774
1820
  });
1775
1821
  }
@@ -1802,7 +1848,7 @@ function isEdgeWebhookEvent(value) {
1802
1848
  function validateEdgeWebhookEvent(value) {
1803
1849
  const errors = {};
1804
1850
  if (!isRecord(value)) {
1805
- throw new import_connect7.EdgeValidationError("EDGE webhook event must be an object", {
1851
+ throw new import_connect8.EdgeValidationError("EDGE webhook event must be an object", {
1806
1852
  event: ["Expected JSON object"]
1807
1853
  });
1808
1854
  }
@@ -1814,7 +1860,7 @@ function validateEdgeWebhookEvent(value) {
1814
1860
  errors.id = ["Required string"];
1815
1861
  }
1816
1862
  if (typeof type !== "string" || !EVENT_TYPES.has(type)) {
1817
- errors.type = [`Must be one of: ${import_connect7.EDGE_WEBHOOK_EVENT_TYPES.join(", ")}`];
1863
+ errors.type = [`Must be one of: ${import_connect8.EDGE_WEBHOOK_EVENT_TYPES.join(", ")}`];
1818
1864
  }
1819
1865
  if (typeof createdAt !== "string" || !createdAt.trim() || Number.isNaN(Date.parse(createdAt))) {
1820
1866
  errors.created_at = ["Required ISO 8601 timestamp string"];
@@ -1826,7 +1872,7 @@ function validateEdgeWebhookEvent(value) {
1826
1872
  validateKnownEventData(type, data, errors);
1827
1873
  }
1828
1874
  if (Object.keys(errors).length > 0) {
1829
- throw new import_connect7.EdgeValidationError("Invalid EDGE webhook event", errors);
1875
+ throw new import_connect8.EdgeValidationError("Invalid EDGE webhook event", errors);
1830
1876
  }
1831
1877
  return value;
1832
1878
  }
@@ -1854,7 +1900,7 @@ function validateKnownEventData(type, data, errors) {
1854
1900
  return;
1855
1901
  default: {
1856
1902
  const exhaustive = type;
1857
- throw new import_connect7.EdgeValidationError("Unsupported EDGE webhook event type", {
1903
+ throw new import_connect8.EdgeValidationError("Unsupported EDGE webhook event type", {
1858
1904
  type: [`Unsupported event type: ${exhaustive}`]
1859
1905
  });
1860
1906
  }
@@ -1887,7 +1933,7 @@ function normalizeRawBody(rawBody) {
1887
1933
  if (Buffer.isBuffer(rawBody) || rawBody instanceof Uint8Array) {
1888
1934
  return Buffer.from(rawBody).toString("utf8");
1889
1935
  }
1890
- throw new import_connect7.EdgeValidationError("EDGE webhook raw body is required", {
1936
+ throw new import_connect8.EdgeValidationError("EDGE webhook raw body is required", {
1891
1937
  rawBody: ["Pass the raw UTF-8 request body, not a parsed JSON object"]
1892
1938
  });
1893
1939
  }
@@ -1908,7 +1954,7 @@ function getEdgeWebhookRawBody(request) {
1908
1954
  if (typeof request.rawBody === "string" || Buffer.isBuffer(request.rawBody) || request.rawBody instanceof Uint8Array) {
1909
1955
  return request.rawBody;
1910
1956
  }
1911
- throw new import_connect8.EdgeValidationError("EDGE webhook raw body is required", {
1957
+ throw new import_connect9.EdgeValidationError("EDGE webhook raw body is required", {
1912
1958
  rawBody: [
1913
1959
  "Configure your framework to expose the raw UTF-8 request body before JSON parsing. Parsed JSON bodies cannot be used for HMAC verification."
1914
1960
  ]
@@ -1935,7 +1981,7 @@ function parseWebhookHttpRequest(options) {
1935
1981
  }
1936
1982
 
1937
1983
  // src/identity.ts
1938
- var import_connect9 = require("@edge-markets/connect");
1984
+ var import_connect10 = require("@edge-markets/connect");
1939
1985
  var DEFAULT_IDENTITY_POLICY = {
1940
1986
  minNameScore: 70,
1941
1987
  minAddressScore: 65,
@@ -1963,7 +2009,7 @@ function buildVerifyIdentityPayload(profile) {
1963
2009
  errors.address = ["At least one address field is required"];
1964
2010
  }
1965
2011
  if (Object.keys(errors).length > 0) {
1966
- throw new import_connect9.EdgeValidationError("Partner identity profile is incomplete", errors);
2012
+ throw new import_connect10.EdgeValidationError("Partner identity profile is incomplete", errors);
1967
2013
  }
1968
2014
  return payload;
1969
2015
  }
@@ -2000,7 +2046,7 @@ function validatePolicy(policy) {
2000
2046
  if (!isScore(policy.minNameScore)) errors.minNameScore = ["Must be between 0 and 100"];
2001
2047
  if (!isScore(policy.minAddressScore)) errors.minAddressScore = ["Must be between 0 and 100"];
2002
2048
  if (Object.keys(errors).length > 0) {
2003
- throw new import_connect9.EdgeValidationError("Invalid identity policy", errors);
2049
+ throw new import_connect10.EdgeValidationError("Invalid identity policy", errors);
2004
2050
  }
2005
2051
  }
2006
2052
  function isScore(value) {
@@ -2017,7 +2063,7 @@ function firstNonEmpty(...values) {
2017
2063
  }
2018
2064
 
2019
2065
  // src/session-store.ts
2020
- var import_connect10 = require("@edge-markets/connect");
2066
+ var import_connect11 = require("@edge-markets/connect");
2021
2067
  function createSessionTokenRecord(subjectId, tokens, tokenVault, options = {}) {
2022
2068
  const normalizedSubjectId = normalizeRequiredString(subjectId, "subjectId");
2023
2069
  validateTokens2(tokens);
@@ -2033,7 +2079,7 @@ function createSessionTokenRecord(subjectId, tokens, tokenVault, options = {}) {
2033
2079
  }
2034
2080
  function parseSessionTokenRecord(record) {
2035
2081
  if (!isRecord2(record)) {
2036
- throw new import_connect10.EdgeValidationError("EDGE session token record must be an object", {
2082
+ throw new import_connect11.EdgeValidationError("EDGE session token record must be an object", {
2037
2083
  record: ["Expected object"]
2038
2084
  });
2039
2085
  }
@@ -2056,7 +2102,7 @@ function encryptLegacySessionTokens(legacyRecord, tokenVault, options) {
2056
2102
  const accessToken = normalizeRequiredString(legacyRecord.accessToken, "accessToken");
2057
2103
  const refreshToken = normalizeRequiredString(legacyRecord.refreshToken, "refreshToken");
2058
2104
  if (!options.allowPlaintext && !tokenVault.isEncrypted(accessToken) && !tokenVault.isEncrypted(refreshToken)) {
2059
- throw new import_connect10.EdgeValidationError("Plaintext token migration requires allowPlaintext: true", {
2105
+ throw new import_connect11.EdgeValidationError("Plaintext token migration requires allowPlaintext: true", {
2060
2106
  allowPlaintext: ["Set allowPlaintext only inside an explicit migration path"]
2061
2107
  });
2062
2108
  }
@@ -2080,7 +2126,7 @@ function normalizeSessionExpiresAt(value) {
2080
2126
  if (value instanceof Date) {
2081
2127
  const time = value.getTime();
2082
2128
  if (!Number.isFinite(time) || time <= 0) {
2083
- throw new import_connect10.EdgeValidationError("Invalid EDGE session expiresAt", {
2129
+ throw new import_connect11.EdgeValidationError("Invalid EDGE session expiresAt", {
2084
2130
  expiresAt: ["Date must be valid"]
2085
2131
  });
2086
2132
  }
@@ -2089,7 +2135,7 @@ function normalizeSessionExpiresAt(value) {
2089
2135
  if (typeof value === "string") {
2090
2136
  const trimmed = value.trim();
2091
2137
  if (!trimmed) {
2092
- throw new import_connect10.EdgeValidationError("Invalid EDGE session expiresAt", {
2138
+ throw new import_connect11.EdgeValidationError("Invalid EDGE session expiresAt", {
2093
2139
  expiresAt: ["Required"]
2094
2140
  });
2095
2141
  }
@@ -2101,18 +2147,18 @@ function normalizeSessionExpiresAt(value) {
2101
2147
  }
2102
2148
  if (typeof value === "number" && Number.isFinite(value)) {
2103
2149
  if (!Number.isInteger(value) || value <= 0) {
2104
- throw new import_connect10.EdgeValidationError("Invalid EDGE session expiresAt", {
2150
+ throw new import_connect11.EdgeValidationError("Invalid EDGE session expiresAt", {
2105
2151
  expiresAt: ["Must be a positive integer timestamp in milliseconds"]
2106
2152
  });
2107
2153
  }
2108
2154
  if (value < 1e10) {
2109
- throw new import_connect10.EdgeValidationError("Ambiguous EDGE session expiresAt", {
2155
+ throw new import_connect11.EdgeValidationError("Ambiguous EDGE session expiresAt", {
2110
2156
  expiresAt: ["Use Unix milliseconds, not seconds"]
2111
2157
  });
2112
2158
  }
2113
2159
  return value;
2114
2160
  }
2115
- throw new import_connect10.EdgeValidationError("Invalid EDGE session expiresAt", {
2161
+ throw new import_connect11.EdgeValidationError("Invalid EDGE session expiresAt", {
2116
2162
  expiresAt: ["Use Unix milliseconds, ISO string, or Date"]
2117
2163
  });
2118
2164
  }
@@ -2136,7 +2182,7 @@ function normalizeScopes(value) {
2136
2182
  if (typeof value === "string") {
2137
2183
  return splitScopes(value);
2138
2184
  }
2139
- throw new import_connect10.EdgeValidationError("Invalid EDGE session scopes", {
2185
+ throw new import_connect11.EdgeValidationError("Invalid EDGE session scopes", {
2140
2186
  scopes: ["Expected array or space-delimited string"]
2141
2187
  });
2142
2188
  }
@@ -2145,7 +2191,7 @@ function splitScopes(value) {
2145
2191
  }
2146
2192
  function normalizeRequiredString(value, field) {
2147
2193
  if (typeof value !== "string" || !value.trim()) {
2148
- throw new import_connect10.EdgeValidationError("Invalid EDGE session token record", {
2194
+ throw new import_connect11.EdgeValidationError("Invalid EDGE session token record", {
2149
2195
  [field]: ["Required string"]
2150
2196
  });
2151
2197
  }
@@ -2163,7 +2209,7 @@ function isRecord2(value) {
2163
2209
  }
2164
2210
 
2165
2211
  // src/token-vault.ts
2166
- var import_connect11 = require("@edge-markets/connect");
2212
+ var import_connect12 = require("@edge-markets/connect");
2167
2213
  var import_node_crypto3 = __toESM(require("crypto"));
2168
2214
  var TOKEN_VAULT_VERSION = "edge_vault_v1";
2169
2215
  var IV_BYTES = 12;
@@ -2176,7 +2222,7 @@ var EdgeTokenVault = class {
2176
2222
  for (const [index, key] of (options.previousKeys ?? []).entries()) {
2177
2223
  const normalized = normalizeVaultKey(key, `previousKeys[${index}]`);
2178
2224
  if (this.keysById.has(normalized.id)) {
2179
- throw new import_connect11.EdgeValidationError("Duplicate token vault key ID", {
2225
+ throw new import_connect12.EdgeValidationError("Duplicate token vault key ID", {
2180
2226
  keyId: [`Duplicate key ID "${normalized.id}"`]
2181
2227
  });
2182
2228
  }
@@ -2204,7 +2250,7 @@ var EdgeTokenVault = class {
2204
2250
  const parsed = parseEnvelope(envelope);
2205
2251
  const key = this.keysById.get(parsed.keyId);
2206
2252
  if (!key) {
2207
- throw new import_connect11.EdgeValidationError("Unknown token vault key ID", {
2253
+ throw new import_connect12.EdgeValidationError("Unknown token vault key ID", {
2208
2254
  keyId: [`No key configured for "${parsed.keyId}"`]
2209
2255
  });
2210
2256
  }
@@ -2217,8 +2263,8 @@ var EdgeTokenVault = class {
2217
2263
  validateEdgeTokens(tokens);
2218
2264
  return tokens;
2219
2265
  } catch (error) {
2220
- if (error instanceof import_connect11.EdgeValidationError) throw error;
2221
- throw new import_connect11.EdgeValidationError("Failed to decrypt EDGE tokens", {
2266
+ if (error instanceof import_connect12.EdgeValidationError) throw error;
2267
+ throw new import_connect12.EdgeValidationError("Failed to decrypt EDGE tokens", {
2222
2268
  tokenEnvelope: ["Envelope is malformed, corrupted, or encrypted with a different key"]
2223
2269
  });
2224
2270
  }
@@ -2236,7 +2282,7 @@ function isEdgeTokenVaultEnvelope(value) {
2236
2282
  function normalizeVaultKey(input, fieldName) {
2237
2283
  const id = typeof input.id === "string" ? input.id.trim() : "";
2238
2284
  if (!id) {
2239
- throw new import_connect11.EdgeValidationError("Token vault key ID is required", {
2285
+ throw new import_connect12.EdgeValidationError("Token vault key ID is required", {
2240
2286
  [`${fieldName}.id`]: ["Required"]
2241
2287
  });
2242
2288
  }
@@ -2267,7 +2313,7 @@ function normalizeKeyMaterial(input, fieldName) {
2267
2313
  }
2268
2314
  const key = candidates.find((candidate) => candidate.length === KEY_BYTES);
2269
2315
  if (!key) {
2270
- throw new import_connect11.EdgeValidationError("Token vault key must decode to 32 bytes", {
2316
+ throw new import_connect12.EdgeValidationError("Token vault key must decode to 32 bytes", {
2271
2317
  [fieldName]: ["Provide a 32-byte key as base64, base64url, hex, Buffer, or Uint8Array"]
2272
2318
  });
2273
2319
  }
@@ -2298,18 +2344,18 @@ function validateEdgeTokens(tokens) {
2298
2344
  }
2299
2345
  }
2300
2346
  if (Object.keys(errors).length > 0) {
2301
- throw new import_connect11.EdgeValidationError("Invalid EDGE token payload", errors);
2347
+ throw new import_connect12.EdgeValidationError("Invalid EDGE token payload", errors);
2302
2348
  }
2303
2349
  }
2304
2350
  function parseEnvelope(envelope) {
2305
2351
  if (typeof envelope !== "string") {
2306
- throw new import_connect11.EdgeValidationError("Token envelope must be a string", {
2352
+ throw new import_connect12.EdgeValidationError("Token envelope must be a string", {
2307
2353
  tokenEnvelope: ["Expected string"]
2308
2354
  });
2309
2355
  }
2310
2356
  const parts = envelope.split(".");
2311
2357
  if (parts.length !== 5 || parts[0] !== TOKEN_VAULT_VERSION) {
2312
- throw new import_connect11.EdgeValidationError("Invalid EDGE token vault envelope", {
2358
+ throw new import_connect12.EdgeValidationError("Invalid EDGE token vault envelope", {
2313
2359
  tokenEnvelope: [`Expected ${TOKEN_VAULT_VERSION}.<keyId>.<iv>.<tag>.<ciphertext>`]
2314
2360
  });
2315
2361
  }
@@ -2324,7 +2370,7 @@ function parseEnvelope(envelope) {
2324
2370
  if (tag.length !== TAG_BYTES) errors.tag = [`Must be ${TAG_BYTES} bytes`];
2325
2371
  if (ciphertext.length === 0) errors.ciphertext = ["Required"];
2326
2372
  if (Object.keys(errors).length > 0) {
2327
- throw new import_connect11.EdgeValidationError("Invalid EDGE token vault envelope", errors);
2373
+ throw new import_connect12.EdgeValidationError("Invalid EDGE token vault envelope", errors);
2328
2374
  }
2329
2375
  return { keyId, iv, tag, ciphertext };
2330
2376
  }
@@ -2338,13 +2384,13 @@ function fromBase64Url2(value) {
2338
2384
  }
2339
2385
 
2340
2386
  // src/webhook-guards.ts
2341
- var import_connect12 = require("@edge-markets/connect");
2387
+ var import_connect13 = require("@edge-markets/connect");
2342
2388
  function isTransferWebhookEvent(event) {
2343
2389
  return event.type.startsWith("transfer.");
2344
2390
  }
2345
2391
  function assertTransferEventMatchesIntent(event, intent) {
2346
2392
  if (!isTransferWebhookEvent(event)) {
2347
- throw new import_connect12.EdgeValidationError("Webhook event is not a transfer event", {
2393
+ throw new import_connect13.EdgeValidationError("Webhook event is not a transfer event", {
2348
2394
  type: [`Received ${event.type}`]
2349
2395
  });
2350
2396
  }
@@ -2367,34 +2413,34 @@ function assertTransferEventMatchesIntent(event, intent) {
2367
2413
  }
2368
2414
  }
2369
2415
  if (Object.keys(errors).length > 0) {
2370
- throw new import_connect12.EdgeValidationError("Webhook transfer event does not match expected transfer intent", errors);
2416
+ throw new import_connect13.EdgeValidationError("Webhook transfer event does not match expected transfer intent", errors);
2371
2417
  }
2372
2418
  }
2373
2419
  var assertWebhookMatchesTransfer = assertTransferEventMatchesIntent;
2374
2420
 
2375
2421
  // src/webhook-inbox.ts
2376
- var import_connect13 = require("@edge-markets/connect");
2422
+ var import_connect14 = require("@edge-markets/connect");
2377
2423
  var import_node_crypto4 = __toESM(require("crypto"));
2378
2424
  var DEFAULT_PROCESSING_TIMEOUT_MS = 10 * 60 * 1e3;
2379
2425
  var EdgeWebhookInbox = class {
2380
2426
  constructor(options) {
2381
2427
  if (!options.store?.insert || !options.store?.find || !options.store?.markProcessing) {
2382
- throw new import_connect13.EdgeValidationError("EdgeWebhookInbox store is incomplete", {
2428
+ throw new import_connect14.EdgeValidationError("EdgeWebhookInbox store is incomplete", {
2383
2429
  store: ["Provide insert, find, markProcessing, markProcessed, and markFailed callbacks"]
2384
2430
  });
2385
2431
  }
2386
2432
  if (!options.store.markProcessed || !options.store.markFailed) {
2387
- throw new import_connect13.EdgeValidationError("EdgeWebhookInbox store is incomplete", {
2433
+ throw new import_connect14.EdgeValidationError("EdgeWebhookInbox store is incomplete", {
2388
2434
  store: ["Provide markProcessed and markFailed callbacks"]
2389
2435
  });
2390
2436
  }
2391
2437
  if (!options.processEvent) {
2392
- throw new import_connect13.EdgeValidationError("EdgeWebhookInbox processEvent callback is required", {
2438
+ throw new import_connect14.EdgeValidationError("EdgeWebhookInbox processEvent callback is required", {
2393
2439
  processEvent: ["Required"]
2394
2440
  });
2395
2441
  }
2396
2442
  if (options.processingTimeoutMs !== void 0 && (!Number.isFinite(options.processingTimeoutMs) || options.processingTimeoutMs <= 0)) {
2397
- throw new import_connect13.EdgeValidationError("processingTimeoutMs must be positive", {
2443
+ throw new import_connect14.EdgeValidationError("processingTimeoutMs must be positive", {
2398
2444
  processingTimeoutMs: ["Must be greater than 0"]
2399
2445
  });
2400
2446
  }
@@ -2554,7 +2600,7 @@ var EdgeWebhookInbox = class {
2554
2600
  status: result.record.status,
2555
2601
  source: options.source
2556
2602
  });
2557
- throw new import_connect13.EdgeValidationError("Duplicate webhook event payload does not match stored event", {
2603
+ throw new import_connect14.EdgeValidationError("Duplicate webhook event payload does not match stored event", {
2558
2604
  eventId: [event.id]
2559
2605
  });
2560
2606
  }
@@ -2590,7 +2636,7 @@ function fingerprintWebhookEvent(event) {
2590
2636
  }
2591
2637
  function normalizeEventId(eventId) {
2592
2638
  if (typeof eventId !== "string" || !eventId.trim()) {
2593
- throw new import_connect13.EdgeValidationError("Webhook event ID is required", {
2639
+ throw new import_connect14.EdgeValidationError("Webhook event ID is required", {
2594
2640
  eventId: ["Required"]
2595
2641
  });
2596
2642
  }
@@ -2607,17 +2653,20 @@ function stableStringify(value) {
2607
2653
  }
2608
2654
 
2609
2655
  // src/index.ts
2610
- var import_connect14 = require("@edge-markets/connect");
2611
2656
  var import_connect15 = require("@edge-markets/connect");
2657
+ var import_connect16 = require("@edge-markets/connect");
2612
2658
  // Annotate the CommonJS export names for ESM import in node:
2613
2659
  0 && (module.exports = {
2660
+ ACTIVE_EDGE_SCOPES,
2614
2661
  CONNECT_TRANSFER_DIRECTIONS,
2662
+ EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE,
2615
2663
  EDGE_WEBHOOK_EVENT_TYPES,
2616
2664
  EdgeApiError,
2617
2665
  EdgeAuthenticationError,
2618
2666
  EdgeConnectServer,
2619
2667
  EdgeConsentRequiredError,
2620
2668
  EdgeError,
2669
+ EdgeFeatureUnavailableError,
2621
2670
  EdgeIdentityVerificationError,
2622
2671
  EdgeInsufficientScopeError,
2623
2672
  EdgeNetworkError,
@@ -2656,6 +2705,7 @@ var import_connect15 = require("@edge-markets/connect");
2656
2705
  isEdgeError,
2657
2706
  isEdgeTokenVaultEnvelope,
2658
2707
  isEdgeWebhookEvent,
2708
+ isFeatureUnavailableError,
2659
2709
  isIdentityVerificationError,
2660
2710
  isNetworkError,
2661
2711
  isProductionEnvironment,