@edge-markets/connect-node 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +182 -131
- package/dist/index.mjs +60 -7
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -92,7 +92,9 @@ Supported environment variables:
|
|
|
92
92
|
| `EDGE_PARTNER_CLIENT_SECRET` | Partner machine-to-machine client secret for webhook sync |
|
|
93
93
|
| `EDGE_MTLS_CERT` / `EDGE_MTLS_CERT_PATH` | Client certificate PEM or file path |
|
|
94
94
|
| `EDGE_MTLS_KEY` / `EDGE_MTLS_KEY_PATH` | Client private key PEM or file path |
|
|
95
|
-
| `
|
|
95
|
+
| `EDGE_SERVER_CA_PEM` / `EDGE_SERVER_CA_PEM_PATH` | Optional extra server trust root PEM or file path |
|
|
96
|
+
| `EDGE_MTLS_CA` / `EDGE_MTLS_CA_PATH` | Legacy alias for optional extra server trust root PEM or file path |
|
|
97
|
+
| `EDGE_REQUIRE_MTLS` | Set to `true` to fail startup unless client cert and key are configured |
|
|
96
98
|
| `EDGE_TIMEOUT_MS` | Optional request timeout in milliseconds |
|
|
97
99
|
|
|
98
100
|
Use inline PEMs with escaped newlines (`\n`) or file paths. If both are set,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as node_https from 'node:https';
|
|
2
2
|
import { EdgeEnvironment, TransferCategory, Transfer, VerificationSession, TransferType, TransferStatus, User, VerifyIdentityOptions, VerifyIdentityResult, Balance, ListTransfersParams, TransferList, CreateVerificationSessionRequest, VerificationSessionStatusResponse, EdgeTokens, EdgeWebhookEvent, EdgeWebhookEventType } from '@edge-markets/connect';
|
|
3
|
-
export { Balance, BaseWebhookEvent, ConsentRevokedEventData, CreateVerificationSessionRequest, EDGE_WEBHOOK_EVENT_TYPES, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeIdentityVerificationError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, EdgeValidationError, EdgeWebhookEvent, EdgeWebhookEventType, ListTransfersParams, SdkGeolocation, TRANSFER_CATEGORIES, Transfer, TransferCategory, TransferCompletedEventData, TransferExpiredEventData, TransferFailedEventData, TransferList, TransferListItem, TransferProcessingEventData, TransferStatus, TransferType, User, UserAddress, VerificationSession, VerificationSessionStatus, VerificationSessionStatusResponse, VerifyIdentityAddress, VerifyIdentityOptions, VerifyIdentityResult, VerifyIdentityScores, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isEdgeError, isIdentityVerificationError, isNetworkError, isProductionEnvironment } from '@edge-markets/connect';
|
|
3
|
+
export { ACTIVE_EDGE_SCOPES, Balance, BaseWebhookEvent, ConsentRevokedEventData, CreateVerificationSessionRequest, EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE, EDGE_WEBHOOK_EVENT_TYPES, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeFeatureUnavailableError, EdgeIdentityVerificationError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, EdgeValidationError, EdgeWebhookEvent, EdgeWebhookEventType, ListTransfersParams, SdkGeolocation, TRANSFER_CATEGORIES, Transfer, TransferCategory, TransferCompletedEventData, TransferExpiredEventData, TransferFailedEventData, TransferList, TransferListItem, TransferProcessingEventData, TransferStatus, TransferType, User, UserAddress, VerificationSession, VerificationSessionStatus, VerificationSessionStatusResponse, VerifyIdentityAddress, VerifyIdentityOptions, VerifyIdentityResult, VerifyIdentityScores, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isEdgeError, isFeatureUnavailableError, isIdentityVerificationError, isNetworkError, isProductionEnvironment } from '@edge-markets/connect';
|
|
4
4
|
|
|
5
5
|
type RequestEndpoint = 'connect_api' | 'oauth_token' | 'partner_webhook_sync';
|
|
6
6
|
interface RequestInfo {
|
|
@@ -175,14 +175,13 @@ declare class EdgeUserClient {
|
|
|
175
175
|
revoked: boolean;
|
|
176
176
|
}>;
|
|
177
177
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* The handoff token is single-use and expires in 120 seconds.
|
|
178
|
+
* Reserved for a future transfer release.
|
|
179
|
+
* Currently throws EdgeFeatureUnavailableError before validation or network I/O.
|
|
181
180
|
*/
|
|
182
181
|
createVerificationSession(transferId: string, options: CreateVerificationSessionRequest): Promise<VerificationSession>;
|
|
183
182
|
/**
|
|
184
|
-
*
|
|
185
|
-
*
|
|
183
|
+
* Reserved for a future transfer release.
|
|
184
|
+
* Currently throws EdgeFeatureUnavailableError before validation or network I/O.
|
|
186
185
|
*/
|
|
187
186
|
getVerificationSessionStatus(transferId: string, sessionId: string): Promise<VerificationSessionStatusResponse>;
|
|
188
187
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as node_https from 'node:https';
|
|
2
2
|
import { EdgeEnvironment, TransferCategory, Transfer, VerificationSession, TransferType, TransferStatus, User, VerifyIdentityOptions, VerifyIdentityResult, Balance, ListTransfersParams, TransferList, CreateVerificationSessionRequest, VerificationSessionStatusResponse, EdgeTokens, EdgeWebhookEvent, EdgeWebhookEventType } from '@edge-markets/connect';
|
|
3
|
-
export { Balance, BaseWebhookEvent, ConsentRevokedEventData, CreateVerificationSessionRequest, EDGE_WEBHOOK_EVENT_TYPES, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeIdentityVerificationError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, EdgeValidationError, EdgeWebhookEvent, EdgeWebhookEventType, ListTransfersParams, SdkGeolocation, TRANSFER_CATEGORIES, Transfer, TransferCategory, TransferCompletedEventData, TransferExpiredEventData, TransferFailedEventData, TransferList, TransferListItem, TransferProcessingEventData, TransferStatus, TransferType, User, UserAddress, VerificationSession, VerificationSessionStatus, VerificationSessionStatusResponse, VerifyIdentityAddress, VerifyIdentityOptions, VerifyIdentityResult, VerifyIdentityScores, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isEdgeError, isIdentityVerificationError, isNetworkError, isProductionEnvironment } from '@edge-markets/connect';
|
|
3
|
+
export { ACTIVE_EDGE_SCOPES, Balance, BaseWebhookEvent, ConsentRevokedEventData, CreateVerificationSessionRequest, EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE, EDGE_WEBHOOK_EVENT_TYPES, EdgeApiError, EdgeAuthenticationError, EdgeConsentRequiredError, EdgeEnvironment, EdgeError, EdgeFeatureUnavailableError, EdgeIdentityVerificationError, EdgeInsufficientScopeError, EdgeNetworkError, EdgeNotFoundError, EdgeTokenExchangeError, EdgeTokens, EdgeValidationError, EdgeWebhookEvent, EdgeWebhookEventType, ListTransfersParams, SdkGeolocation, TRANSFER_CATEGORIES, Transfer, TransferCategory, TransferCompletedEventData, TransferExpiredEventData, TransferFailedEventData, TransferList, TransferListItem, TransferProcessingEventData, TransferStatus, TransferType, User, UserAddress, VerificationSession, VerificationSessionStatus, VerificationSessionStatusResponse, VerifyIdentityAddress, VerifyIdentityOptions, VerifyIdentityResult, VerifyIdentityScores, getEnvironmentConfig, isApiError, isAuthenticationError, isConsentRequiredError, isEdgeError, isFeatureUnavailableError, isIdentityVerificationError, isNetworkError, isProductionEnvironment } from '@edge-markets/connect';
|
|
4
4
|
|
|
5
5
|
type RequestEndpoint = 'connect_api' | 'oauth_token' | 'partner_webhook_sync';
|
|
6
6
|
interface RequestInfo {
|
|
@@ -175,14 +175,13 @@ declare class EdgeUserClient {
|
|
|
175
175
|
revoked: boolean;
|
|
176
176
|
}>;
|
|
177
177
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
* The handoff token is single-use and expires in 120 seconds.
|
|
178
|
+
* Reserved for a future transfer release.
|
|
179
|
+
* Currently throws EdgeFeatureUnavailableError before validation or network I/O.
|
|
181
180
|
*/
|
|
182
181
|
createVerificationSession(transferId: string, options: CreateVerificationSessionRequest): Promise<VerificationSession>;
|
|
183
182
|
/**
|
|
184
|
-
*
|
|
185
|
-
*
|
|
183
|
+
* Reserved for a future transfer release.
|
|
184
|
+
* Currently throws EdgeFeatureUnavailableError before validation or network I/O.
|
|
186
185
|
*/
|
|
187
186
|
getVerificationSessionStatus(transferId: string, sessionId: string): Promise<VerificationSessionStatusResponse>;
|
|
188
187
|
}
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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: () =>
|
|
39
|
-
EdgeError: () =>
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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: () =>
|
|
51
|
+
EdgeValidationError: () => import_connect15.EdgeValidationError,
|
|
49
52
|
EdgeWebhookInbox: () => EdgeWebhookInbox,
|
|
50
53
|
EdgeWebhookReconciler: () => EdgeWebhookReconciler,
|
|
51
|
-
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: () =>
|
|
72
|
-
isApiError: () =>
|
|
73
|
-
isAuthenticationError: () =>
|
|
74
|
-
isConsentRequiredError: () =>
|
|
75
|
-
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
|
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
|
-
*
|
|
369
|
-
*
|
|
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
|
-
*
|
|
383
|
-
*
|
|
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");
|
|
@@ -529,28 +558,28 @@ function validateMtlsConfig(config) {
|
|
|
529
558
|
}
|
|
530
559
|
|
|
531
560
|
// src/session.ts
|
|
532
|
-
var
|
|
561
|
+
var import_connect4 = require("@edge-markets/connect");
|
|
533
562
|
var EdgeUserSession = class {
|
|
534
563
|
constructor(options) {
|
|
535
564
|
this.refreshPromise = null;
|
|
536
565
|
if (!options.edge?.forUser || !options.edge?.refreshTokens) {
|
|
537
|
-
throw new
|
|
566
|
+
throw new import_connect4.EdgeValidationError("EdgeUserSession requires an EdgeConnectServer instance", {
|
|
538
567
|
edge: ["Provide edge.forUser and edge.refreshTokens"]
|
|
539
568
|
});
|
|
540
569
|
}
|
|
541
570
|
const subjectId = typeof options.subjectId === "string" ? options.subjectId.trim() : "";
|
|
542
571
|
if (!subjectId) {
|
|
543
|
-
throw new
|
|
572
|
+
throw new import_connect4.EdgeValidationError("EdgeUserSession subjectId is required", {
|
|
544
573
|
subjectId: ["Required"]
|
|
545
574
|
});
|
|
546
575
|
}
|
|
547
576
|
if (!options.tokenStore?.load || !options.tokenStore?.save) {
|
|
548
|
-
throw new
|
|
577
|
+
throw new import_connect4.EdgeValidationError("EdgeUserSession tokenStore is required", {
|
|
549
578
|
tokenStore: ["Provide load(subjectId) and save(subjectId, value, context)"]
|
|
550
579
|
});
|
|
551
580
|
}
|
|
552
581
|
if (options.refreshSkewMs !== void 0 && (!Number.isFinite(options.refreshSkewMs) || options.refreshSkewMs < 0)) {
|
|
553
|
-
throw new
|
|
582
|
+
throw new import_connect4.EdgeValidationError("refreshSkewMs must be a non-negative number", {
|
|
554
583
|
refreshSkewMs: ["Must be greater than or equal to 0"]
|
|
555
584
|
});
|
|
556
585
|
}
|
|
@@ -603,13 +632,13 @@ var EdgeUserSession = class {
|
|
|
603
632
|
async loadTokens() {
|
|
604
633
|
const value = await this.tokenStore.load(this.subjectId);
|
|
605
634
|
if (!value) {
|
|
606
|
-
throw new
|
|
635
|
+
throw new import_connect4.EdgeAuthenticationError("No EDGE tokens are stored for this subject", {
|
|
607
636
|
subjectId: this.subjectId
|
|
608
637
|
});
|
|
609
638
|
}
|
|
610
639
|
if (typeof value === "string") {
|
|
611
640
|
if (!this.tokenVault) {
|
|
612
|
-
throw new
|
|
641
|
+
throw new import_connect4.EdgeAuthenticationError("Encrypted EDGE token envelope loaded but no tokenVault was configured", {
|
|
613
642
|
subjectId: this.subjectId
|
|
614
643
|
});
|
|
615
644
|
}
|
|
@@ -695,7 +724,7 @@ function validateTokens(tokens) {
|
|
|
695
724
|
}
|
|
696
725
|
}
|
|
697
726
|
if (Object.keys(errors).length > 0) {
|
|
698
|
-
throw new
|
|
727
|
+
throw new import_connect4.EdgeValidationError("Invalid EDGE token payload", errors);
|
|
699
728
|
}
|
|
700
729
|
}
|
|
701
730
|
|
|
@@ -886,7 +915,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
886
915
|
throw new Error("EdgeConnectServer: environment is required");
|
|
887
916
|
}
|
|
888
917
|
this.config = config;
|
|
889
|
-
const envConfig = (0,
|
|
918
|
+
const envConfig = (0, import_connect5.getEnvironmentConfig)(config.environment);
|
|
890
919
|
this.apiBaseUrl = config.apiBaseUrl || envConfig.apiBaseUrl;
|
|
891
920
|
this.partnerApiBaseUrl = stripTrailingSlash(config.partnerApiBaseUrl || derivePartnerApiBaseUrl(this.apiBaseUrl));
|
|
892
921
|
this.oauthBaseUrl = config.oauthBaseUrl || envConfig.oauthBaseUrl;
|
|
@@ -931,7 +960,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
931
960
|
*/
|
|
932
961
|
forUser(accessToken) {
|
|
933
962
|
if (!accessToken) {
|
|
934
|
-
throw new
|
|
963
|
+
throw new import_connect5.EdgeAuthenticationError("accessToken is required when calling forUser()");
|
|
935
964
|
}
|
|
936
965
|
return new EdgeUserClient(this, accessToken);
|
|
937
966
|
}
|
|
@@ -968,8 +997,8 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
968
997
|
const data = await response.json();
|
|
969
998
|
return this.parseTokenResponse(data);
|
|
970
999
|
} catch (error) {
|
|
971
|
-
if (error instanceof
|
|
972
|
-
throw new
|
|
1000
|
+
if (error instanceof import_connect5.EdgeError) throw error;
|
|
1001
|
+
throw new import_connect5.EdgeNetworkError("Failed to exchange code", error);
|
|
973
1002
|
}
|
|
974
1003
|
}
|
|
975
1004
|
async refreshTokens(refreshToken) {
|
|
@@ -995,7 +1024,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
995
1024
|
);
|
|
996
1025
|
if (!response.ok) {
|
|
997
1026
|
const error = await response.json().catch(() => ({}));
|
|
998
|
-
throw new
|
|
1027
|
+
throw new import_connect5.EdgeAuthenticationError(
|
|
999
1028
|
error.message || error.error_description || "Token refresh failed. User may need to reconnect.",
|
|
1000
1029
|
{ tokenError: error }
|
|
1001
1030
|
);
|
|
@@ -1003,8 +1032,8 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1003
1032
|
const data = await response.json();
|
|
1004
1033
|
return this.parseTokenResponse(data, refreshToken);
|
|
1005
1034
|
} catch (error) {
|
|
1006
|
-
if (error instanceof
|
|
1007
|
-
throw new
|
|
1035
|
+
if (error instanceof import_connect5.EdgeError) throw error;
|
|
1036
|
+
throw new import_connect5.EdgeNetworkError("Failed to refresh tokens", error);
|
|
1008
1037
|
}
|
|
1009
1038
|
}
|
|
1010
1039
|
/** @internal Called by {@link EdgeUserClient} — not part of the public API. */
|
|
@@ -1046,14 +1075,14 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1046
1075
|
if (mleEnabled && typeof rawResponseBody?.jwe === "string") {
|
|
1047
1076
|
responseBody = decryptMle(rawResponseBody.jwe, mleConfig);
|
|
1048
1077
|
} else if (!mleEnabled && typeof rawResponseBody?.jwe === "string") {
|
|
1049
|
-
throw new
|
|
1078
|
+
throw new import_connect5.EdgeApiError(
|
|
1050
1079
|
"mle_required",
|
|
1051
1080
|
"The API responded with message-level encryption. Enable MLE in SDK config.",
|
|
1052
1081
|
response.status,
|
|
1053
1082
|
rawResponseBody
|
|
1054
1083
|
);
|
|
1055
1084
|
} else if (mleEnabled && mleConfig?.strictResponseEncryption !== false && response.ok && typeof rawResponseBody?.jwe !== "string") {
|
|
1056
|
-
throw new
|
|
1085
|
+
throw new import_connect5.EdgeApiError(
|
|
1057
1086
|
"mle_response_missing",
|
|
1058
1087
|
"Expected encrypted response payload but received plaintext.",
|
|
1059
1088
|
response.status,
|
|
@@ -1071,8 +1100,8 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1071
1100
|
}
|
|
1072
1101
|
return responseBody;
|
|
1073
1102
|
} catch (error) {
|
|
1074
|
-
if (error instanceof
|
|
1075
|
-
if (!(error instanceof
|
|
1103
|
+
if (error instanceof import_connect5.EdgeError) {
|
|
1104
|
+
if (!(error instanceof import_connect5.EdgeNetworkError) || attempt >= this.retryConfig.maxRetries) {
|
|
1076
1105
|
throw error;
|
|
1077
1106
|
}
|
|
1078
1107
|
lastError = error;
|
|
@@ -1080,11 +1109,11 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1080
1109
|
}
|
|
1081
1110
|
lastError = error;
|
|
1082
1111
|
if (attempt >= this.retryConfig.maxRetries) {
|
|
1083
|
-
throw new
|
|
1112
|
+
throw new import_connect5.EdgeNetworkError(`API request failed: ${method} ${path}`, lastError);
|
|
1084
1113
|
}
|
|
1085
1114
|
}
|
|
1086
1115
|
}
|
|
1087
|
-
throw new
|
|
1116
|
+
throw new import_connect5.EdgeNetworkError(
|
|
1088
1117
|
`API request failed after ${this.retryConfig.maxRetries} retries: ${method} ${path}`,
|
|
1089
1118
|
lastError
|
|
1090
1119
|
);
|
|
@@ -1128,10 +1157,10 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1128
1157
|
*/
|
|
1129
1158
|
async syncWebhookEvents(options = {}) {
|
|
1130
1159
|
if (!this.config.partnerClientId) {
|
|
1131
|
-
throw new
|
|
1160
|
+
throw new import_connect5.EdgeAuthenticationError("syncWebhookEvents requires `partnerClientId` in EdgeConnectServer config");
|
|
1132
1161
|
}
|
|
1133
1162
|
if (!this.config.partnerClientSecret) {
|
|
1134
|
-
throw new
|
|
1163
|
+
throw new import_connect5.EdgeAuthenticationError("syncWebhookEvents requires `partnerClientSecret` in EdgeConnectServer config");
|
|
1135
1164
|
}
|
|
1136
1165
|
const normalizedOptions = this.normalizeSyncWebhookEventsOptions(options);
|
|
1137
1166
|
const url = this.buildSyncUrl(normalizedOptions);
|
|
@@ -1162,7 +1191,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1162
1191
|
endpoint: "partner_webhook_sync",
|
|
1163
1192
|
attempt
|
|
1164
1193
|
});
|
|
1165
|
-
throw new
|
|
1194
|
+
throw new import_connect5.EdgeAuthenticationError(
|
|
1166
1195
|
body.message || "Partner token rejected after refresh \u2014 check partnerClientId/Secret",
|
|
1167
1196
|
body
|
|
1168
1197
|
);
|
|
@@ -1179,7 +1208,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1179
1208
|
endpoint: "partner_webhook_sync",
|
|
1180
1209
|
attempt
|
|
1181
1210
|
});
|
|
1182
|
-
throw new
|
|
1211
|
+
throw new import_connect5.EdgeApiError(
|
|
1183
1212
|
body.error || "sync_failed",
|
|
1184
1213
|
body.message || `syncWebhookEvents failed with status ${response.status}`,
|
|
1185
1214
|
response.status,
|
|
@@ -1225,7 +1254,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1225
1254
|
}
|
|
1226
1255
|
if (options.limit !== void 0) {
|
|
1227
1256
|
if (!Number.isInteger(options.limit) || options.limit < SYNC_WEBHOOK_EVENTS_MIN_LIMIT || options.limit > SYNC_WEBHOOK_EVENTS_MAX_LIMIT) {
|
|
1228
|
-
throw new
|
|
1257
|
+
throw new import_connect5.EdgeApiError(
|
|
1229
1258
|
"invalid_sync_options",
|
|
1230
1259
|
`syncWebhookEvents limit must be an integer between ${SYNC_WEBHOOK_EVENTS_MIN_LIMIT} and ${SYNC_WEBHOOK_EVENTS_MAX_LIMIT}`,
|
|
1231
1260
|
400,
|
|
@@ -1295,11 +1324,11 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1295
1324
|
} catch (error) {
|
|
1296
1325
|
lastError = error;
|
|
1297
1326
|
if (attempt >= this.retryConfig.maxRetries) {
|
|
1298
|
-
throw new
|
|
1327
|
+
throw new import_connect5.EdgeNetworkError("syncWebhookEvents network failure", lastError);
|
|
1299
1328
|
}
|
|
1300
1329
|
}
|
|
1301
1330
|
}
|
|
1302
|
-
throw new
|
|
1331
|
+
throw new import_connect5.EdgeNetworkError(
|
|
1303
1332
|
`syncWebhookEvents network failure after ${this.retryConfig.maxRetries} retries`,
|
|
1304
1333
|
lastError
|
|
1305
1334
|
);
|
|
@@ -1347,7 +1376,7 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1347
1376
|
this.dispatcher
|
|
1348
1377
|
);
|
|
1349
1378
|
} catch (error) {
|
|
1350
|
-
throw new
|
|
1379
|
+
throw new import_connect5.EdgeNetworkError("Partner token request network failure", error);
|
|
1351
1380
|
}
|
|
1352
1381
|
const durationMs = Date.now() - startTime;
|
|
1353
1382
|
const data = await response.json().catch(() => ({}));
|
|
@@ -1360,13 +1389,13 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1360
1389
|
endpoint: "oauth_token"
|
|
1361
1390
|
});
|
|
1362
1391
|
if (!response.ok) {
|
|
1363
|
-
throw new
|
|
1392
|
+
throw new import_connect5.EdgeAuthenticationError(
|
|
1364
1393
|
data.message || data.error_description || `Partner token request failed with status ${response.status}`,
|
|
1365
1394
|
data
|
|
1366
1395
|
);
|
|
1367
1396
|
}
|
|
1368
1397
|
if (!data.access_token || typeof data.expires_in !== "number") {
|
|
1369
|
-
throw new
|
|
1398
|
+
throw new import_connect5.EdgeAuthenticationError("Partner token response missing access_token or expires_in");
|
|
1370
1399
|
}
|
|
1371
1400
|
this.partnerTokenCache = {
|
|
1372
1401
|
token: data.access_token,
|
|
@@ -1441,37 +1470,37 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1441
1470
|
const errorCode = error.error;
|
|
1442
1471
|
const errorMessage = error.message || error.error_description;
|
|
1443
1472
|
if (errorCode === "invalid_grant" || errorMessage?.includes("Invalid or expired")) {
|
|
1444
|
-
return new
|
|
1473
|
+
return new import_connect5.EdgeTokenExchangeError("Authorization code is invalid, expired, or already used. Please try again.", {
|
|
1445
1474
|
edgeBoostError: error
|
|
1446
1475
|
});
|
|
1447
1476
|
}
|
|
1448
1477
|
if (errorCode === "invalid_client" || errorMessage?.includes("Invalid client")) {
|
|
1449
|
-
return new
|
|
1478
|
+
return new import_connect5.EdgeAuthenticationError("Invalid client credentials. Check your client ID and secret.", {
|
|
1450
1479
|
edgeBoostError: error
|
|
1451
1480
|
});
|
|
1452
1481
|
}
|
|
1453
1482
|
if (errorMessage?.includes("code_verifier") || errorMessage?.includes("PKCE")) {
|
|
1454
|
-
return new
|
|
1483
|
+
return new import_connect5.EdgeTokenExchangeError("PKCE verification failed. Please try again.", { edgeBoostError: error });
|
|
1455
1484
|
}
|
|
1456
|
-
return new
|
|
1485
|
+
return new import_connect5.EdgeTokenExchangeError(errorMessage || "Failed to exchange authorization code", {
|
|
1457
1486
|
edgeBoostError: error,
|
|
1458
1487
|
statusCode: status
|
|
1459
1488
|
});
|
|
1460
1489
|
}
|
|
1461
1490
|
async handleApiErrorFromBody(error, status, path) {
|
|
1462
1491
|
if (status === 401) {
|
|
1463
|
-
return new
|
|
1492
|
+
return new import_connect5.EdgeAuthenticationError(error.message || "Access token is invalid or expired", error);
|
|
1464
1493
|
}
|
|
1465
1494
|
if (status === 403) {
|
|
1466
1495
|
if (error.error === "consent_required") {
|
|
1467
|
-
return new
|
|
1496
|
+
return new import_connect5.EdgeConsentRequiredError(
|
|
1468
1497
|
this.config.clientId,
|
|
1469
1498
|
error.consentUrl,
|
|
1470
1499
|
error.message
|
|
1471
1500
|
);
|
|
1472
1501
|
}
|
|
1473
1502
|
if (error.error === "insufficient_scope" || error.error === "insufficient_consent") {
|
|
1474
|
-
return new
|
|
1503
|
+
return new import_connect5.EdgeInsufficientScopeError(
|
|
1475
1504
|
error.missing_scopes || error.missingScopes || [],
|
|
1476
1505
|
error.message
|
|
1477
1506
|
);
|
|
@@ -1493,15 +1522,15 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1493
1522
|
} else if (path.includes("/transfer")) {
|
|
1494
1523
|
resourceType = "Transfer";
|
|
1495
1524
|
}
|
|
1496
|
-
return new
|
|
1525
|
+
return new import_connect5.EdgeNotFoundError(resourceType, resourceId);
|
|
1497
1526
|
}
|
|
1498
1527
|
if (status === 422 && error.error === "identity_verification_failed") {
|
|
1499
|
-
return new
|
|
1528
|
+
return new import_connect5.EdgeIdentityVerificationError(
|
|
1500
1529
|
error.fieldErrors || {},
|
|
1501
1530
|
error.message
|
|
1502
1531
|
);
|
|
1503
1532
|
}
|
|
1504
|
-
return new
|
|
1533
|
+
return new import_connect5.EdgeApiError(
|
|
1505
1534
|
error.error || "api_error",
|
|
1506
1535
|
error.message || error.error_description || `Request failed with status ${status}`,
|
|
1507
1536
|
status,
|
|
@@ -1511,9 +1540,9 @@ var EdgeConnectServer = class _EdgeConnectServer {
|
|
|
1511
1540
|
};
|
|
1512
1541
|
|
|
1513
1542
|
// src/env.ts
|
|
1514
|
-
var
|
|
1543
|
+
var import_connect6 = require("@edge-markets/connect");
|
|
1515
1544
|
var import_node_fs2 = __toESM(require("fs"));
|
|
1516
|
-
var ENVIRONMENT_NAMES = new Set(Object.keys(
|
|
1545
|
+
var ENVIRONMENT_NAMES = new Set(Object.keys(import_connect6.EDGE_ENVIRONMENTS));
|
|
1517
1546
|
function readEnv(env, name) {
|
|
1518
1547
|
const value = env[name];
|
|
1519
1548
|
if (typeof value !== "string") return void 0;
|
|
@@ -1546,7 +1575,7 @@ function readPemValue(env, valueName, pathName, warnings) {
|
|
|
1546
1575
|
return normalizePem(import_node_fs2.default.readFileSync(filePath, "utf8"));
|
|
1547
1576
|
} catch (error) {
|
|
1548
1577
|
const message = error instanceof Error ? error.message : String(error);
|
|
1549
|
-
throw new
|
|
1578
|
+
throw new import_connect6.EdgeValidationError(`Failed to read ${pathName}`, {
|
|
1550
1579
|
[pathName]: [`Unable to read PEM file "${filePath}": ${message}`]
|
|
1551
1580
|
});
|
|
1552
1581
|
}
|
|
@@ -1554,19 +1583,29 @@ function readPemValue(env, valueName, pathName, warnings) {
|
|
|
1554
1583
|
function readEnvironment(env) {
|
|
1555
1584
|
const value = readEnv(env, "EDGE_ENVIRONMENT") || "staging";
|
|
1556
1585
|
if (!ENVIRONMENT_NAMES.has(value)) {
|
|
1557
|
-
throw new
|
|
1586
|
+
throw new import_connect6.EdgeValidationError("Invalid EDGE_ENVIRONMENT", {
|
|
1558
1587
|
EDGE_ENVIRONMENT: [`Must be one of: ${Array.from(ENVIRONMENT_NAMES).join(", ")}`]
|
|
1559
1588
|
});
|
|
1560
1589
|
}
|
|
1561
1590
|
return value;
|
|
1562
1591
|
}
|
|
1592
|
+
function readBooleanEnv(env, name) {
|
|
1593
|
+
const value = readEnv(env, name);
|
|
1594
|
+
if (!value) return void 0;
|
|
1595
|
+
const normalized = value.toLowerCase();
|
|
1596
|
+
if (["true", "1", "yes"].includes(normalized)) return true;
|
|
1597
|
+
if (["false", "0", "no"].includes(normalized)) return false;
|
|
1598
|
+
throw new import_connect6.EdgeValidationError(`Invalid ${name}`, {
|
|
1599
|
+
[name]: ["Must be one of: true, false, 1, 0, yes, no"]
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1563
1602
|
function readTimeout(env, override) {
|
|
1564
1603
|
if (override !== void 0) return override;
|
|
1565
1604
|
const value = readFirstEnv(env, ["EDGE_TIMEOUT_MS", "EDGE_REQUEST_TIMEOUT_MS"]);
|
|
1566
1605
|
if (!value) return void 0;
|
|
1567
1606
|
const timeout = Number(value);
|
|
1568
1607
|
if (!Number.isInteger(timeout) || timeout <= 0) {
|
|
1569
|
-
throw new
|
|
1608
|
+
throw new import_connect6.EdgeValidationError("Invalid EDGE_TIMEOUT_MS", {
|
|
1570
1609
|
EDGE_TIMEOUT_MS: ["Must be a positive integer number of milliseconds"]
|
|
1571
1610
|
});
|
|
1572
1611
|
}
|
|
@@ -1575,10 +1614,15 @@ function readTimeout(env, override) {
|
|
|
1575
1614
|
function buildMtlsConfig(env, requireMtls, warnings) {
|
|
1576
1615
|
const cert = readPemValue(env, "EDGE_MTLS_CERT", "EDGE_MTLS_CERT_PATH", warnings);
|
|
1577
1616
|
const key = readPemValue(env, "EDGE_MTLS_KEY", "EDGE_MTLS_KEY_PATH", warnings);
|
|
1578
|
-
const
|
|
1617
|
+
const serverCa = readPemValue(env, "EDGE_SERVER_CA_PEM", "EDGE_SERVER_CA_PEM_PATH", warnings);
|
|
1618
|
+
const hasLegacyCa = !!readFirstEnv(env, ["EDGE_MTLS_CA", "EDGE_MTLS_CA_PATH"]);
|
|
1619
|
+
if (serverCa && hasLegacyCa) {
|
|
1620
|
+
warnings.push("EDGE_SERVER_CA_PEM and EDGE_MTLS_CA are both set; using EDGE_SERVER_CA_PEM");
|
|
1621
|
+
}
|
|
1622
|
+
const ca = serverCa || readPemValue(env, "EDGE_MTLS_CA", "EDGE_MTLS_CA_PATH", warnings);
|
|
1579
1623
|
if (!cert && !key && !ca) {
|
|
1580
1624
|
if (requireMtls) {
|
|
1581
|
-
throw new
|
|
1625
|
+
throw new import_connect6.EdgeValidationError("mTLS is required but no EDGE_MTLS_CERT or EDGE_MTLS_KEY was provided", {
|
|
1582
1626
|
EDGE_MTLS_CERT: ["Required when requireMtls is true"],
|
|
1583
1627
|
EDGE_MTLS_KEY: ["Required when requireMtls is true"]
|
|
1584
1628
|
});
|
|
@@ -1586,7 +1630,7 @@ function buildMtlsConfig(env, requireMtls, warnings) {
|
|
|
1586
1630
|
return void 0;
|
|
1587
1631
|
}
|
|
1588
1632
|
if (!cert || !key) {
|
|
1589
|
-
throw new
|
|
1633
|
+
throw new import_connect6.EdgeValidationError("Incomplete mTLS configuration", {
|
|
1590
1634
|
EDGE_MTLS_CERT: cert ? [] : ["Required when mTLS is configured"],
|
|
1591
1635
|
EDGE_MTLS_KEY: key ? [] : ["Required when mTLS is configured"]
|
|
1592
1636
|
});
|
|
@@ -1600,7 +1644,7 @@ function buildMtlsConfig(env, requireMtls, warnings) {
|
|
|
1600
1644
|
}
|
|
1601
1645
|
function inferMtlsRequirement(environment, apiBaseUrl) {
|
|
1602
1646
|
if (environment === "staging" || environment === "production") return true;
|
|
1603
|
-
const resolvedApiBaseUrl = apiBaseUrl || (0,
|
|
1647
|
+
const resolvedApiBaseUrl = apiBaseUrl || (0, import_connect6.getEnvironmentConfig)(environment).apiBaseUrl;
|
|
1604
1648
|
try {
|
|
1605
1649
|
const host = new URL(resolvedApiBaseUrl).host;
|
|
1606
1650
|
return host === "connect-staging.edgeboost.io" || host === "connect.edgeboost.io";
|
|
@@ -1614,7 +1658,7 @@ function createEdgeConnectServerFromEnv(options = {}) {
|
|
|
1614
1658
|
const environment = readEnvironment(env);
|
|
1615
1659
|
const apiBaseUrl = readEnv(env, "EDGE_API_BASE_URL");
|
|
1616
1660
|
const mtlsRequiredByTarget = inferMtlsRequirement(environment, apiBaseUrl);
|
|
1617
|
-
const requireMtls = options.requireMtls ?? false;
|
|
1661
|
+
const requireMtls = options.requireMtls ?? readBooleanEnv(env, "EDGE_REQUIRE_MTLS") ?? false;
|
|
1618
1662
|
const mtls = buildMtlsConfig(env, requireMtls, warnings);
|
|
1619
1663
|
const timeout = readTimeout(env, options.timeout);
|
|
1620
1664
|
const clientId = readFirstEnv(env, ["EDGE_CLIENT_ID", "EDGE_CONNECT_CLIENT_ID"]) || "";
|
|
@@ -1627,7 +1671,7 @@ function createEdgeConnectServerFromEnv(options = {}) {
|
|
|
1627
1671
|
if (!clientId) validationErrors.EDGE_CLIENT_ID = ["Required"];
|
|
1628
1672
|
if (!clientSecret) validationErrors.EDGE_CLIENT_SECRET = ["Required"];
|
|
1629
1673
|
if (Object.keys(validationErrors).length > 0) {
|
|
1630
|
-
throw new
|
|
1674
|
+
throw new import_connect6.EdgeValidationError("Missing required EDGE Connect environment variables", validationErrors);
|
|
1631
1675
|
}
|
|
1632
1676
|
if (mtlsRequiredByTarget && !mtls) {
|
|
1633
1677
|
warnings.push(
|
|
@@ -1666,32 +1710,35 @@ function createEdgeConnectServerFromEnv(options = {}) {
|
|
|
1666
1710
|
}
|
|
1667
1711
|
|
|
1668
1712
|
// src/error-adapter.ts
|
|
1669
|
-
var
|
|
1713
|
+
var import_connect7 = require("@edge-markets/connect");
|
|
1670
1714
|
function toEdgeHttpError(error) {
|
|
1671
1715
|
const body = toEdgeProblemJson(error);
|
|
1672
1716
|
return { status: body.status, body };
|
|
1673
1717
|
}
|
|
1674
1718
|
function toEdgeProblemJson(error) {
|
|
1675
|
-
if (error instanceof
|
|
1719
|
+
if (error instanceof import_connect7.EdgeConsentRequiredError) {
|
|
1676
1720
|
return problem(error, "Consent required", error.statusCode ?? 403, {
|
|
1677
1721
|
clientId: error.clientId,
|
|
1678
1722
|
consentUrl: error.consentUrl
|
|
1679
1723
|
});
|
|
1680
1724
|
}
|
|
1681
|
-
if (error instanceof
|
|
1725
|
+
if (error instanceof import_connect7.EdgeValidationError) {
|
|
1682
1726
|
return problem(error, "Validation failed", error.statusCode ?? 400, {
|
|
1683
1727
|
validationErrors: error.validationErrors
|
|
1684
1728
|
});
|
|
1685
1729
|
}
|
|
1686
|
-
if (error instanceof
|
|
1730
|
+
if (error instanceof import_connect7.EdgeIdentityVerificationError) {
|
|
1687
1731
|
return problem(error, "Identity verification failed", error.statusCode ?? 422, {
|
|
1688
1732
|
fieldErrors: error.fieldErrors
|
|
1689
1733
|
});
|
|
1690
1734
|
}
|
|
1691
|
-
if (error instanceof
|
|
1735
|
+
if (error instanceof import_connect7.EdgeFeatureUnavailableError) {
|
|
1736
|
+
return problem(error, "Feature unavailable", error.statusCode ?? 501);
|
|
1737
|
+
}
|
|
1738
|
+
if (error instanceof import_connect7.EdgeNetworkError) {
|
|
1692
1739
|
return problem(error, "EDGE network error", error.statusCode ?? 502);
|
|
1693
1740
|
}
|
|
1694
|
-
if (error instanceof
|
|
1741
|
+
if (error instanceof import_connect7.EdgeError) {
|
|
1695
1742
|
return problem(error, edgeTitle(error), error.statusCode ?? 500, error.details);
|
|
1696
1743
|
}
|
|
1697
1744
|
const message = error instanceof Error ? error.message : "Unexpected error";
|
|
@@ -1718,10 +1765,10 @@ function edgeTitle(error) {
|
|
|
1718
1765
|
}
|
|
1719
1766
|
|
|
1720
1767
|
// src/http-helpers.ts
|
|
1721
|
-
var
|
|
1768
|
+
var import_connect9 = require("@edge-markets/connect");
|
|
1722
1769
|
|
|
1723
1770
|
// src/webhook-parser.ts
|
|
1724
|
-
var
|
|
1771
|
+
var import_connect8 = require("@edge-markets/connect");
|
|
1725
1772
|
|
|
1726
1773
|
// src/webhook-signing.ts
|
|
1727
1774
|
var import_node_crypto2 = __toESM(require("crypto"));
|
|
@@ -1753,23 +1800,23 @@ function verifyWebhookSignature(header, body, secret, options = {}) {
|
|
|
1753
1800
|
}
|
|
1754
1801
|
|
|
1755
1802
|
// src/webhook-parser.ts
|
|
1756
|
-
var EVENT_TYPES = new Set(
|
|
1803
|
+
var EVENT_TYPES = new Set(import_connect8.EDGE_WEBHOOK_EVENT_TYPES);
|
|
1757
1804
|
var TRANSFER_TYPES = /* @__PURE__ */ new Set(["debit", "credit"]);
|
|
1758
1805
|
function parseAndVerifyWebhook(options) {
|
|
1759
1806
|
const body = normalizeRawBody(options.rawBody);
|
|
1760
1807
|
const header = normalizeSignatureHeader(options.signatureHeader);
|
|
1761
1808
|
const signatureTimestamp = extractWebhookSignatureTimestamp(header);
|
|
1762
1809
|
if (!header || !signatureTimestamp) {
|
|
1763
|
-
throw new
|
|
1810
|
+
throw new import_connect8.EdgeAuthenticationError("Missing or malformed EDGE webhook signature");
|
|
1764
1811
|
}
|
|
1765
1812
|
if (!verifyWebhookSignature(header, body, options.secret, { toleranceSeconds: options.toleranceSeconds })) {
|
|
1766
|
-
throw new
|
|
1813
|
+
throw new import_connect8.EdgeAuthenticationError("Invalid EDGE webhook signature");
|
|
1767
1814
|
}
|
|
1768
1815
|
let parsed;
|
|
1769
1816
|
try {
|
|
1770
1817
|
parsed = JSON.parse(body);
|
|
1771
1818
|
} catch {
|
|
1772
|
-
throw new
|
|
1819
|
+
throw new import_connect8.EdgeValidationError("EDGE webhook body must be valid JSON", {
|
|
1773
1820
|
rawBody: ["Unable to parse JSON after signature verification"]
|
|
1774
1821
|
});
|
|
1775
1822
|
}
|
|
@@ -1802,7 +1849,7 @@ function isEdgeWebhookEvent(value) {
|
|
|
1802
1849
|
function validateEdgeWebhookEvent(value) {
|
|
1803
1850
|
const errors = {};
|
|
1804
1851
|
if (!isRecord(value)) {
|
|
1805
|
-
throw new
|
|
1852
|
+
throw new import_connect8.EdgeValidationError("EDGE webhook event must be an object", {
|
|
1806
1853
|
event: ["Expected JSON object"]
|
|
1807
1854
|
});
|
|
1808
1855
|
}
|
|
@@ -1814,7 +1861,7 @@ function validateEdgeWebhookEvent(value) {
|
|
|
1814
1861
|
errors.id = ["Required string"];
|
|
1815
1862
|
}
|
|
1816
1863
|
if (typeof type !== "string" || !EVENT_TYPES.has(type)) {
|
|
1817
|
-
errors.type = [`Must be one of: ${
|
|
1864
|
+
errors.type = [`Must be one of: ${import_connect8.EDGE_WEBHOOK_EVENT_TYPES.join(", ")}`];
|
|
1818
1865
|
}
|
|
1819
1866
|
if (typeof createdAt !== "string" || !createdAt.trim() || Number.isNaN(Date.parse(createdAt))) {
|
|
1820
1867
|
errors.created_at = ["Required ISO 8601 timestamp string"];
|
|
@@ -1826,7 +1873,7 @@ function validateEdgeWebhookEvent(value) {
|
|
|
1826
1873
|
validateKnownEventData(type, data, errors);
|
|
1827
1874
|
}
|
|
1828
1875
|
if (Object.keys(errors).length > 0) {
|
|
1829
|
-
throw new
|
|
1876
|
+
throw new import_connect8.EdgeValidationError("Invalid EDGE webhook event", errors);
|
|
1830
1877
|
}
|
|
1831
1878
|
return value;
|
|
1832
1879
|
}
|
|
@@ -1854,7 +1901,7 @@ function validateKnownEventData(type, data, errors) {
|
|
|
1854
1901
|
return;
|
|
1855
1902
|
default: {
|
|
1856
1903
|
const exhaustive = type;
|
|
1857
|
-
throw new
|
|
1904
|
+
throw new import_connect8.EdgeValidationError("Unsupported EDGE webhook event type", {
|
|
1858
1905
|
type: [`Unsupported event type: ${exhaustive}`]
|
|
1859
1906
|
});
|
|
1860
1907
|
}
|
|
@@ -1887,7 +1934,7 @@ function normalizeRawBody(rawBody) {
|
|
|
1887
1934
|
if (Buffer.isBuffer(rawBody) || rawBody instanceof Uint8Array) {
|
|
1888
1935
|
return Buffer.from(rawBody).toString("utf8");
|
|
1889
1936
|
}
|
|
1890
|
-
throw new
|
|
1937
|
+
throw new import_connect8.EdgeValidationError("EDGE webhook raw body is required", {
|
|
1891
1938
|
rawBody: ["Pass the raw UTF-8 request body, not a parsed JSON object"]
|
|
1892
1939
|
});
|
|
1893
1940
|
}
|
|
@@ -1908,7 +1955,7 @@ function getEdgeWebhookRawBody(request) {
|
|
|
1908
1955
|
if (typeof request.rawBody === "string" || Buffer.isBuffer(request.rawBody) || request.rawBody instanceof Uint8Array) {
|
|
1909
1956
|
return request.rawBody;
|
|
1910
1957
|
}
|
|
1911
|
-
throw new
|
|
1958
|
+
throw new import_connect9.EdgeValidationError("EDGE webhook raw body is required", {
|
|
1912
1959
|
rawBody: [
|
|
1913
1960
|
"Configure your framework to expose the raw UTF-8 request body before JSON parsing. Parsed JSON bodies cannot be used for HMAC verification."
|
|
1914
1961
|
]
|
|
@@ -1935,7 +1982,7 @@ function parseWebhookHttpRequest(options) {
|
|
|
1935
1982
|
}
|
|
1936
1983
|
|
|
1937
1984
|
// src/identity.ts
|
|
1938
|
-
var
|
|
1985
|
+
var import_connect10 = require("@edge-markets/connect");
|
|
1939
1986
|
var DEFAULT_IDENTITY_POLICY = {
|
|
1940
1987
|
minNameScore: 70,
|
|
1941
1988
|
minAddressScore: 65,
|
|
@@ -1963,7 +2010,7 @@ function buildVerifyIdentityPayload(profile) {
|
|
|
1963
2010
|
errors.address = ["At least one address field is required"];
|
|
1964
2011
|
}
|
|
1965
2012
|
if (Object.keys(errors).length > 0) {
|
|
1966
|
-
throw new
|
|
2013
|
+
throw new import_connect10.EdgeValidationError("Partner identity profile is incomplete", errors);
|
|
1967
2014
|
}
|
|
1968
2015
|
return payload;
|
|
1969
2016
|
}
|
|
@@ -2000,7 +2047,7 @@ function validatePolicy(policy) {
|
|
|
2000
2047
|
if (!isScore(policy.minNameScore)) errors.minNameScore = ["Must be between 0 and 100"];
|
|
2001
2048
|
if (!isScore(policy.minAddressScore)) errors.minAddressScore = ["Must be between 0 and 100"];
|
|
2002
2049
|
if (Object.keys(errors).length > 0) {
|
|
2003
|
-
throw new
|
|
2050
|
+
throw new import_connect10.EdgeValidationError("Invalid identity policy", errors);
|
|
2004
2051
|
}
|
|
2005
2052
|
}
|
|
2006
2053
|
function isScore(value) {
|
|
@@ -2017,7 +2064,7 @@ function firstNonEmpty(...values) {
|
|
|
2017
2064
|
}
|
|
2018
2065
|
|
|
2019
2066
|
// src/session-store.ts
|
|
2020
|
-
var
|
|
2067
|
+
var import_connect11 = require("@edge-markets/connect");
|
|
2021
2068
|
function createSessionTokenRecord(subjectId, tokens, tokenVault, options = {}) {
|
|
2022
2069
|
const normalizedSubjectId = normalizeRequiredString(subjectId, "subjectId");
|
|
2023
2070
|
validateTokens2(tokens);
|
|
@@ -2033,7 +2080,7 @@ function createSessionTokenRecord(subjectId, tokens, tokenVault, options = {}) {
|
|
|
2033
2080
|
}
|
|
2034
2081
|
function parseSessionTokenRecord(record) {
|
|
2035
2082
|
if (!isRecord2(record)) {
|
|
2036
|
-
throw new
|
|
2083
|
+
throw new import_connect11.EdgeValidationError("EDGE session token record must be an object", {
|
|
2037
2084
|
record: ["Expected object"]
|
|
2038
2085
|
});
|
|
2039
2086
|
}
|
|
@@ -2056,7 +2103,7 @@ function encryptLegacySessionTokens(legacyRecord, tokenVault, options) {
|
|
|
2056
2103
|
const accessToken = normalizeRequiredString(legacyRecord.accessToken, "accessToken");
|
|
2057
2104
|
const refreshToken = normalizeRequiredString(legacyRecord.refreshToken, "refreshToken");
|
|
2058
2105
|
if (!options.allowPlaintext && !tokenVault.isEncrypted(accessToken) && !tokenVault.isEncrypted(refreshToken)) {
|
|
2059
|
-
throw new
|
|
2106
|
+
throw new import_connect11.EdgeValidationError("Plaintext token migration requires allowPlaintext: true", {
|
|
2060
2107
|
allowPlaintext: ["Set allowPlaintext only inside an explicit migration path"]
|
|
2061
2108
|
});
|
|
2062
2109
|
}
|
|
@@ -2080,7 +2127,7 @@ function normalizeSessionExpiresAt(value) {
|
|
|
2080
2127
|
if (value instanceof Date) {
|
|
2081
2128
|
const time = value.getTime();
|
|
2082
2129
|
if (!Number.isFinite(time) || time <= 0) {
|
|
2083
|
-
throw new
|
|
2130
|
+
throw new import_connect11.EdgeValidationError("Invalid EDGE session expiresAt", {
|
|
2084
2131
|
expiresAt: ["Date must be valid"]
|
|
2085
2132
|
});
|
|
2086
2133
|
}
|
|
@@ -2089,7 +2136,7 @@ function normalizeSessionExpiresAt(value) {
|
|
|
2089
2136
|
if (typeof value === "string") {
|
|
2090
2137
|
const trimmed = value.trim();
|
|
2091
2138
|
if (!trimmed) {
|
|
2092
|
-
throw new
|
|
2139
|
+
throw new import_connect11.EdgeValidationError("Invalid EDGE session expiresAt", {
|
|
2093
2140
|
expiresAt: ["Required"]
|
|
2094
2141
|
});
|
|
2095
2142
|
}
|
|
@@ -2101,18 +2148,18 @@ function normalizeSessionExpiresAt(value) {
|
|
|
2101
2148
|
}
|
|
2102
2149
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2103
2150
|
if (!Number.isInteger(value) || value <= 0) {
|
|
2104
|
-
throw new
|
|
2151
|
+
throw new import_connect11.EdgeValidationError("Invalid EDGE session expiresAt", {
|
|
2105
2152
|
expiresAt: ["Must be a positive integer timestamp in milliseconds"]
|
|
2106
2153
|
});
|
|
2107
2154
|
}
|
|
2108
2155
|
if (value < 1e10) {
|
|
2109
|
-
throw new
|
|
2156
|
+
throw new import_connect11.EdgeValidationError("Ambiguous EDGE session expiresAt", {
|
|
2110
2157
|
expiresAt: ["Use Unix milliseconds, not seconds"]
|
|
2111
2158
|
});
|
|
2112
2159
|
}
|
|
2113
2160
|
return value;
|
|
2114
2161
|
}
|
|
2115
|
-
throw new
|
|
2162
|
+
throw new import_connect11.EdgeValidationError("Invalid EDGE session expiresAt", {
|
|
2116
2163
|
expiresAt: ["Use Unix milliseconds, ISO string, or Date"]
|
|
2117
2164
|
});
|
|
2118
2165
|
}
|
|
@@ -2136,7 +2183,7 @@ function normalizeScopes(value) {
|
|
|
2136
2183
|
if (typeof value === "string") {
|
|
2137
2184
|
return splitScopes(value);
|
|
2138
2185
|
}
|
|
2139
|
-
throw new
|
|
2186
|
+
throw new import_connect11.EdgeValidationError("Invalid EDGE session scopes", {
|
|
2140
2187
|
scopes: ["Expected array or space-delimited string"]
|
|
2141
2188
|
});
|
|
2142
2189
|
}
|
|
@@ -2145,7 +2192,7 @@ function splitScopes(value) {
|
|
|
2145
2192
|
}
|
|
2146
2193
|
function normalizeRequiredString(value, field) {
|
|
2147
2194
|
if (typeof value !== "string" || !value.trim()) {
|
|
2148
|
-
throw new
|
|
2195
|
+
throw new import_connect11.EdgeValidationError("Invalid EDGE session token record", {
|
|
2149
2196
|
[field]: ["Required string"]
|
|
2150
2197
|
});
|
|
2151
2198
|
}
|
|
@@ -2163,7 +2210,7 @@ function isRecord2(value) {
|
|
|
2163
2210
|
}
|
|
2164
2211
|
|
|
2165
2212
|
// src/token-vault.ts
|
|
2166
|
-
var
|
|
2213
|
+
var import_connect12 = require("@edge-markets/connect");
|
|
2167
2214
|
var import_node_crypto3 = __toESM(require("crypto"));
|
|
2168
2215
|
var TOKEN_VAULT_VERSION = "edge_vault_v1";
|
|
2169
2216
|
var IV_BYTES = 12;
|
|
@@ -2176,7 +2223,7 @@ var EdgeTokenVault = class {
|
|
|
2176
2223
|
for (const [index, key] of (options.previousKeys ?? []).entries()) {
|
|
2177
2224
|
const normalized = normalizeVaultKey(key, `previousKeys[${index}]`);
|
|
2178
2225
|
if (this.keysById.has(normalized.id)) {
|
|
2179
|
-
throw new
|
|
2226
|
+
throw new import_connect12.EdgeValidationError("Duplicate token vault key ID", {
|
|
2180
2227
|
keyId: [`Duplicate key ID "${normalized.id}"`]
|
|
2181
2228
|
});
|
|
2182
2229
|
}
|
|
@@ -2204,7 +2251,7 @@ var EdgeTokenVault = class {
|
|
|
2204
2251
|
const parsed = parseEnvelope(envelope);
|
|
2205
2252
|
const key = this.keysById.get(parsed.keyId);
|
|
2206
2253
|
if (!key) {
|
|
2207
|
-
throw new
|
|
2254
|
+
throw new import_connect12.EdgeValidationError("Unknown token vault key ID", {
|
|
2208
2255
|
keyId: [`No key configured for "${parsed.keyId}"`]
|
|
2209
2256
|
});
|
|
2210
2257
|
}
|
|
@@ -2217,8 +2264,8 @@ var EdgeTokenVault = class {
|
|
|
2217
2264
|
validateEdgeTokens(tokens);
|
|
2218
2265
|
return tokens;
|
|
2219
2266
|
} catch (error) {
|
|
2220
|
-
if (error instanceof
|
|
2221
|
-
throw new
|
|
2267
|
+
if (error instanceof import_connect12.EdgeValidationError) throw error;
|
|
2268
|
+
throw new import_connect12.EdgeValidationError("Failed to decrypt EDGE tokens", {
|
|
2222
2269
|
tokenEnvelope: ["Envelope is malformed, corrupted, or encrypted with a different key"]
|
|
2223
2270
|
});
|
|
2224
2271
|
}
|
|
@@ -2236,7 +2283,7 @@ function isEdgeTokenVaultEnvelope(value) {
|
|
|
2236
2283
|
function normalizeVaultKey(input, fieldName) {
|
|
2237
2284
|
const id = typeof input.id === "string" ? input.id.trim() : "";
|
|
2238
2285
|
if (!id) {
|
|
2239
|
-
throw new
|
|
2286
|
+
throw new import_connect12.EdgeValidationError("Token vault key ID is required", {
|
|
2240
2287
|
[`${fieldName}.id`]: ["Required"]
|
|
2241
2288
|
});
|
|
2242
2289
|
}
|
|
@@ -2267,7 +2314,7 @@ function normalizeKeyMaterial(input, fieldName) {
|
|
|
2267
2314
|
}
|
|
2268
2315
|
const key = candidates.find((candidate) => candidate.length === KEY_BYTES);
|
|
2269
2316
|
if (!key) {
|
|
2270
|
-
throw new
|
|
2317
|
+
throw new import_connect12.EdgeValidationError("Token vault key must decode to 32 bytes", {
|
|
2271
2318
|
[fieldName]: ["Provide a 32-byte key as base64, base64url, hex, Buffer, or Uint8Array"]
|
|
2272
2319
|
});
|
|
2273
2320
|
}
|
|
@@ -2298,18 +2345,18 @@ function validateEdgeTokens(tokens) {
|
|
|
2298
2345
|
}
|
|
2299
2346
|
}
|
|
2300
2347
|
if (Object.keys(errors).length > 0) {
|
|
2301
|
-
throw new
|
|
2348
|
+
throw new import_connect12.EdgeValidationError("Invalid EDGE token payload", errors);
|
|
2302
2349
|
}
|
|
2303
2350
|
}
|
|
2304
2351
|
function parseEnvelope(envelope) {
|
|
2305
2352
|
if (typeof envelope !== "string") {
|
|
2306
|
-
throw new
|
|
2353
|
+
throw new import_connect12.EdgeValidationError("Token envelope must be a string", {
|
|
2307
2354
|
tokenEnvelope: ["Expected string"]
|
|
2308
2355
|
});
|
|
2309
2356
|
}
|
|
2310
2357
|
const parts = envelope.split(".");
|
|
2311
2358
|
if (parts.length !== 5 || parts[0] !== TOKEN_VAULT_VERSION) {
|
|
2312
|
-
throw new
|
|
2359
|
+
throw new import_connect12.EdgeValidationError("Invalid EDGE token vault envelope", {
|
|
2313
2360
|
tokenEnvelope: [`Expected ${TOKEN_VAULT_VERSION}.<keyId>.<iv>.<tag>.<ciphertext>`]
|
|
2314
2361
|
});
|
|
2315
2362
|
}
|
|
@@ -2324,7 +2371,7 @@ function parseEnvelope(envelope) {
|
|
|
2324
2371
|
if (tag.length !== TAG_BYTES) errors.tag = [`Must be ${TAG_BYTES} bytes`];
|
|
2325
2372
|
if (ciphertext.length === 0) errors.ciphertext = ["Required"];
|
|
2326
2373
|
if (Object.keys(errors).length > 0) {
|
|
2327
|
-
throw new
|
|
2374
|
+
throw new import_connect12.EdgeValidationError("Invalid EDGE token vault envelope", errors);
|
|
2328
2375
|
}
|
|
2329
2376
|
return { keyId, iv, tag, ciphertext };
|
|
2330
2377
|
}
|
|
@@ -2338,13 +2385,13 @@ function fromBase64Url2(value) {
|
|
|
2338
2385
|
}
|
|
2339
2386
|
|
|
2340
2387
|
// src/webhook-guards.ts
|
|
2341
|
-
var
|
|
2388
|
+
var import_connect13 = require("@edge-markets/connect");
|
|
2342
2389
|
function isTransferWebhookEvent(event) {
|
|
2343
2390
|
return event.type.startsWith("transfer.");
|
|
2344
2391
|
}
|
|
2345
2392
|
function assertTransferEventMatchesIntent(event, intent) {
|
|
2346
2393
|
if (!isTransferWebhookEvent(event)) {
|
|
2347
|
-
throw new
|
|
2394
|
+
throw new import_connect13.EdgeValidationError("Webhook event is not a transfer event", {
|
|
2348
2395
|
type: [`Received ${event.type}`]
|
|
2349
2396
|
});
|
|
2350
2397
|
}
|
|
@@ -2367,34 +2414,34 @@ function assertTransferEventMatchesIntent(event, intent) {
|
|
|
2367
2414
|
}
|
|
2368
2415
|
}
|
|
2369
2416
|
if (Object.keys(errors).length > 0) {
|
|
2370
|
-
throw new
|
|
2417
|
+
throw new import_connect13.EdgeValidationError("Webhook transfer event does not match expected transfer intent", errors);
|
|
2371
2418
|
}
|
|
2372
2419
|
}
|
|
2373
2420
|
var assertWebhookMatchesTransfer = assertTransferEventMatchesIntent;
|
|
2374
2421
|
|
|
2375
2422
|
// src/webhook-inbox.ts
|
|
2376
|
-
var
|
|
2423
|
+
var import_connect14 = require("@edge-markets/connect");
|
|
2377
2424
|
var import_node_crypto4 = __toESM(require("crypto"));
|
|
2378
2425
|
var DEFAULT_PROCESSING_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
2379
2426
|
var EdgeWebhookInbox = class {
|
|
2380
2427
|
constructor(options) {
|
|
2381
2428
|
if (!options.store?.insert || !options.store?.find || !options.store?.markProcessing) {
|
|
2382
|
-
throw new
|
|
2429
|
+
throw new import_connect14.EdgeValidationError("EdgeWebhookInbox store is incomplete", {
|
|
2383
2430
|
store: ["Provide insert, find, markProcessing, markProcessed, and markFailed callbacks"]
|
|
2384
2431
|
});
|
|
2385
2432
|
}
|
|
2386
2433
|
if (!options.store.markProcessed || !options.store.markFailed) {
|
|
2387
|
-
throw new
|
|
2434
|
+
throw new import_connect14.EdgeValidationError("EdgeWebhookInbox store is incomplete", {
|
|
2388
2435
|
store: ["Provide markProcessed and markFailed callbacks"]
|
|
2389
2436
|
});
|
|
2390
2437
|
}
|
|
2391
2438
|
if (!options.processEvent) {
|
|
2392
|
-
throw new
|
|
2439
|
+
throw new import_connect14.EdgeValidationError("EdgeWebhookInbox processEvent callback is required", {
|
|
2393
2440
|
processEvent: ["Required"]
|
|
2394
2441
|
});
|
|
2395
2442
|
}
|
|
2396
2443
|
if (options.processingTimeoutMs !== void 0 && (!Number.isFinite(options.processingTimeoutMs) || options.processingTimeoutMs <= 0)) {
|
|
2397
|
-
throw new
|
|
2444
|
+
throw new import_connect14.EdgeValidationError("processingTimeoutMs must be positive", {
|
|
2398
2445
|
processingTimeoutMs: ["Must be greater than 0"]
|
|
2399
2446
|
});
|
|
2400
2447
|
}
|
|
@@ -2554,7 +2601,7 @@ var EdgeWebhookInbox = class {
|
|
|
2554
2601
|
status: result.record.status,
|
|
2555
2602
|
source: options.source
|
|
2556
2603
|
});
|
|
2557
|
-
throw new
|
|
2604
|
+
throw new import_connect14.EdgeValidationError("Duplicate webhook event payload does not match stored event", {
|
|
2558
2605
|
eventId: [event.id]
|
|
2559
2606
|
});
|
|
2560
2607
|
}
|
|
@@ -2590,7 +2637,7 @@ function fingerprintWebhookEvent(event) {
|
|
|
2590
2637
|
}
|
|
2591
2638
|
function normalizeEventId(eventId) {
|
|
2592
2639
|
if (typeof eventId !== "string" || !eventId.trim()) {
|
|
2593
|
-
throw new
|
|
2640
|
+
throw new import_connect14.EdgeValidationError("Webhook event ID is required", {
|
|
2594
2641
|
eventId: ["Required"]
|
|
2595
2642
|
});
|
|
2596
2643
|
}
|
|
@@ -2607,17 +2654,20 @@ function stableStringify(value) {
|
|
|
2607
2654
|
}
|
|
2608
2655
|
|
|
2609
2656
|
// src/index.ts
|
|
2610
|
-
var import_connect14 = require("@edge-markets/connect");
|
|
2611
2657
|
var import_connect15 = require("@edge-markets/connect");
|
|
2658
|
+
var import_connect16 = require("@edge-markets/connect");
|
|
2612
2659
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2613
2660
|
0 && (module.exports = {
|
|
2661
|
+
ACTIVE_EDGE_SCOPES,
|
|
2614
2662
|
CONNECT_TRANSFER_DIRECTIONS,
|
|
2663
|
+
EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE,
|
|
2615
2664
|
EDGE_WEBHOOK_EVENT_TYPES,
|
|
2616
2665
|
EdgeApiError,
|
|
2617
2666
|
EdgeAuthenticationError,
|
|
2618
2667
|
EdgeConnectServer,
|
|
2619
2668
|
EdgeConsentRequiredError,
|
|
2620
2669
|
EdgeError,
|
|
2670
|
+
EdgeFeatureUnavailableError,
|
|
2621
2671
|
EdgeIdentityVerificationError,
|
|
2622
2672
|
EdgeInsufficientScopeError,
|
|
2623
2673
|
EdgeNetworkError,
|
|
@@ -2656,6 +2706,7 @@ var import_connect15 = require("@edge-markets/connect");
|
|
|
2656
2706
|
isEdgeError,
|
|
2657
2707
|
isEdgeTokenVaultEnvelope,
|
|
2658
2708
|
isEdgeWebhookEvent,
|
|
2709
|
+
isFeatureUnavailableError,
|
|
2659
2710
|
isIdentityVerificationError,
|
|
2660
2711
|
isNetworkError,
|
|
2661
2712
|
isProductionEnvironment,
|
package/dist/index.mjs
CHANGED
|
@@ -19,8 +19,12 @@ import {
|
|
|
19
19
|
getEnvironmentConfig
|
|
20
20
|
} from "@edge-markets/connect";
|
|
21
21
|
|
|
22
|
+
// src/edge-user-client.ts
|
|
23
|
+
import { EdgeFeatureUnavailableError as EdgeFeatureUnavailableError2 } from "@edge-markets/connect";
|
|
24
|
+
|
|
22
25
|
// src/transfer-helpers.ts
|
|
23
26
|
import {
|
|
27
|
+
EdgeFeatureUnavailableError,
|
|
24
28
|
EdgeValidationError
|
|
25
29
|
} from "@edge-markets/connect";
|
|
26
30
|
import crypto from "crypto";
|
|
@@ -117,6 +121,7 @@ function mapTransferStatusToPartnerState(status, mapping) {
|
|
|
117
121
|
return partnerState;
|
|
118
122
|
}
|
|
119
123
|
async function startTransferVerification(client, options) {
|
|
124
|
+
assertTransferFeatureAvailable();
|
|
120
125
|
const origin = typeof options.origin === "string" ? options.origin.trim() : "";
|
|
121
126
|
if (!origin) {
|
|
122
127
|
throw new EdgeValidationError("Verification origin is required", {
|
|
@@ -136,6 +141,14 @@ async function startTransferVerification(client, options) {
|
|
|
136
141
|
const verificationSession = await client.createVerificationSession(transferId, { origin });
|
|
137
142
|
return { transfer, verificationSession };
|
|
138
143
|
}
|
|
144
|
+
function assertTransferFeatureAvailable() {
|
|
145
|
+
if (!isTransferFeatureAvailable()) {
|
|
146
|
+
throw new EdgeFeatureUnavailableError();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function isTransferFeatureAvailable() {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
139
152
|
function parseMoneyToCents(value, field, options = {}) {
|
|
140
153
|
let input;
|
|
141
154
|
if (typeof value === "number") {
|
|
@@ -257,6 +270,7 @@ var EdgeUserClient = class {
|
|
|
257
270
|
return this.server._apiRequest("GET", "/balance", this.accessToken);
|
|
258
271
|
}
|
|
259
272
|
async initiateTransfer(options) {
|
|
273
|
+
assertTransferFeatureAvailable2();
|
|
260
274
|
validateTransferOptions(options);
|
|
261
275
|
const body = {
|
|
262
276
|
type: options.type,
|
|
@@ -269,13 +283,16 @@ var EdgeUserClient = class {
|
|
|
269
283
|
return this.server._apiRequest("POST", "/transfer", this.accessToken, body);
|
|
270
284
|
}
|
|
271
285
|
async startTransferVerification(options) {
|
|
286
|
+
assertTransferFeatureAvailable2();
|
|
272
287
|
return startTransferVerification(this, options);
|
|
273
288
|
}
|
|
274
289
|
async getTransfer(transferId) {
|
|
290
|
+
assertTransferFeatureAvailable2();
|
|
275
291
|
validateTransferId(transferId);
|
|
276
292
|
return this.server._apiRequest("GET", `/transfer/${encodeURIComponent(transferId)}`, this.accessToken);
|
|
277
293
|
}
|
|
278
294
|
async listTransfers(params) {
|
|
295
|
+
assertTransferFeatureAvailable2();
|
|
279
296
|
const queryParams = new URLSearchParams();
|
|
280
297
|
if (params?.limit) queryParams.set("limit", String(params.limit));
|
|
281
298
|
if (params?.offset) queryParams.set("offset", String(params.offset));
|
|
@@ -288,11 +305,11 @@ var EdgeUserClient = class {
|
|
|
288
305
|
return this.server._apiRequest("DELETE", "/consent", this.accessToken);
|
|
289
306
|
}
|
|
290
307
|
/**
|
|
291
|
-
*
|
|
292
|
-
*
|
|
293
|
-
* The handoff token is single-use and expires in 120 seconds.
|
|
308
|
+
* Reserved for a future transfer release.
|
|
309
|
+
* Currently throws EdgeFeatureUnavailableError before validation or network I/O.
|
|
294
310
|
*/
|
|
295
311
|
async createVerificationSession(transferId, options) {
|
|
312
|
+
assertTransferFeatureAvailable2();
|
|
296
313
|
validateTransferId(transferId);
|
|
297
314
|
return this.server._apiRequest(
|
|
298
315
|
"POST",
|
|
@@ -302,10 +319,11 @@ var EdgeUserClient = class {
|
|
|
302
319
|
);
|
|
303
320
|
}
|
|
304
321
|
/**
|
|
305
|
-
*
|
|
306
|
-
*
|
|
322
|
+
* Reserved for a future transfer release.
|
|
323
|
+
* Currently throws EdgeFeatureUnavailableError before validation or network I/O.
|
|
307
324
|
*/
|
|
308
325
|
async getVerificationSessionStatus(transferId, sessionId) {
|
|
326
|
+
assertTransferFeatureAvailable2();
|
|
309
327
|
validateTransferId(transferId);
|
|
310
328
|
return this.server._apiRequest(
|
|
311
329
|
"GET",
|
|
@@ -314,6 +332,14 @@ var EdgeUserClient = class {
|
|
|
314
332
|
);
|
|
315
333
|
}
|
|
316
334
|
};
|
|
335
|
+
function assertTransferFeatureAvailable2() {
|
|
336
|
+
if (!isTransferFeatureAvailable2()) {
|
|
337
|
+
throw new EdgeFeatureUnavailableError2();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function isTransferFeatureAvailable2() {
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
317
343
|
|
|
318
344
|
// src/mle.ts
|
|
319
345
|
import { randomUUID, randomBytes, createCipheriv, createDecipheriv, publicEncrypt, privateDecrypt, constants } from "crypto";
|
|
@@ -1483,6 +1509,16 @@ function readEnvironment(env) {
|
|
|
1483
1509
|
}
|
|
1484
1510
|
return value;
|
|
1485
1511
|
}
|
|
1512
|
+
function readBooleanEnv(env, name) {
|
|
1513
|
+
const value = readEnv(env, name);
|
|
1514
|
+
if (!value) return void 0;
|
|
1515
|
+
const normalized = value.toLowerCase();
|
|
1516
|
+
if (["true", "1", "yes"].includes(normalized)) return true;
|
|
1517
|
+
if (["false", "0", "no"].includes(normalized)) return false;
|
|
1518
|
+
throw new EdgeValidationError4(`Invalid ${name}`, {
|
|
1519
|
+
[name]: ["Must be one of: true, false, 1, 0, yes, no"]
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1486
1522
|
function readTimeout(env, override) {
|
|
1487
1523
|
if (override !== void 0) return override;
|
|
1488
1524
|
const value = readFirstEnv(env, ["EDGE_TIMEOUT_MS", "EDGE_REQUEST_TIMEOUT_MS"]);
|
|
@@ -1498,7 +1534,12 @@ function readTimeout(env, override) {
|
|
|
1498
1534
|
function buildMtlsConfig(env, requireMtls, warnings) {
|
|
1499
1535
|
const cert = readPemValue(env, "EDGE_MTLS_CERT", "EDGE_MTLS_CERT_PATH", warnings);
|
|
1500
1536
|
const key = readPemValue(env, "EDGE_MTLS_KEY", "EDGE_MTLS_KEY_PATH", warnings);
|
|
1501
|
-
const
|
|
1537
|
+
const serverCa = readPemValue(env, "EDGE_SERVER_CA_PEM", "EDGE_SERVER_CA_PEM_PATH", warnings);
|
|
1538
|
+
const hasLegacyCa = !!readFirstEnv(env, ["EDGE_MTLS_CA", "EDGE_MTLS_CA_PATH"]);
|
|
1539
|
+
if (serverCa && hasLegacyCa) {
|
|
1540
|
+
warnings.push("EDGE_SERVER_CA_PEM and EDGE_MTLS_CA are both set; using EDGE_SERVER_CA_PEM");
|
|
1541
|
+
}
|
|
1542
|
+
const ca = serverCa || readPemValue(env, "EDGE_MTLS_CA", "EDGE_MTLS_CA_PATH", warnings);
|
|
1502
1543
|
if (!cert && !key && !ca) {
|
|
1503
1544
|
if (requireMtls) {
|
|
1504
1545
|
throw new EdgeValidationError4("mTLS is required but no EDGE_MTLS_CERT or EDGE_MTLS_KEY was provided", {
|
|
@@ -1537,7 +1578,7 @@ function createEdgeConnectServerFromEnv(options = {}) {
|
|
|
1537
1578
|
const environment = readEnvironment(env);
|
|
1538
1579
|
const apiBaseUrl = readEnv(env, "EDGE_API_BASE_URL");
|
|
1539
1580
|
const mtlsRequiredByTarget = inferMtlsRequirement(environment, apiBaseUrl);
|
|
1540
|
-
const requireMtls = options.requireMtls ?? false;
|
|
1581
|
+
const requireMtls = options.requireMtls ?? readBooleanEnv(env, "EDGE_REQUIRE_MTLS") ?? false;
|
|
1541
1582
|
const mtls = buildMtlsConfig(env, requireMtls, warnings);
|
|
1542
1583
|
const timeout = readTimeout(env, options.timeout);
|
|
1543
1584
|
const clientId = readFirstEnv(env, ["EDGE_CLIENT_ID", "EDGE_CONNECT_CLIENT_ID"]) || "";
|
|
@@ -1592,6 +1633,7 @@ function createEdgeConnectServerFromEnv(options = {}) {
|
|
|
1592
1633
|
import {
|
|
1593
1634
|
EdgeConsentRequiredError as EdgeConsentRequiredError2,
|
|
1594
1635
|
EdgeError as EdgeError2,
|
|
1636
|
+
EdgeFeatureUnavailableError as EdgeFeatureUnavailableError3,
|
|
1595
1637
|
EdgeIdentityVerificationError as EdgeIdentityVerificationError2,
|
|
1596
1638
|
EdgeNetworkError as EdgeNetworkError2,
|
|
1597
1639
|
EdgeValidationError as EdgeValidationError5
|
|
@@ -1617,6 +1659,9 @@ function toEdgeProblemJson(error) {
|
|
|
1617
1659
|
fieldErrors: error.fieldErrors
|
|
1618
1660
|
});
|
|
1619
1661
|
}
|
|
1662
|
+
if (error instanceof EdgeFeatureUnavailableError3) {
|
|
1663
|
+
return problem(error, "Feature unavailable", error.statusCode ?? 501);
|
|
1664
|
+
}
|
|
1620
1665
|
if (error instanceof EdgeNetworkError2) {
|
|
1621
1666
|
return problem(error, "EDGE network error", error.statusCode ?? 502);
|
|
1622
1667
|
}
|
|
@@ -2541,10 +2586,12 @@ function stableStringify(value) {
|
|
|
2541
2586
|
|
|
2542
2587
|
// src/index.ts
|
|
2543
2588
|
import {
|
|
2589
|
+
EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE,
|
|
2544
2590
|
EdgeApiError as EdgeApiError2,
|
|
2545
2591
|
EdgeAuthenticationError as EdgeAuthenticationError4,
|
|
2546
2592
|
EdgeConsentRequiredError as EdgeConsentRequiredError3,
|
|
2547
2593
|
EdgeError as EdgeError3,
|
|
2594
|
+
EdgeFeatureUnavailableError as EdgeFeatureUnavailableError4,
|
|
2548
2595
|
EdgeIdentityVerificationError as EdgeIdentityVerificationError3,
|
|
2549
2596
|
EdgeInsufficientScopeError as EdgeInsufficientScopeError2,
|
|
2550
2597
|
EdgeNetworkError as EdgeNetworkError3,
|
|
@@ -2555,23 +2602,28 @@ import {
|
|
|
2555
2602
|
isAuthenticationError,
|
|
2556
2603
|
isConsentRequiredError,
|
|
2557
2604
|
isEdgeError,
|
|
2605
|
+
isFeatureUnavailableError,
|
|
2558
2606
|
isIdentityVerificationError,
|
|
2559
2607
|
isNetworkError
|
|
2560
2608
|
} from "@edge-markets/connect";
|
|
2561
2609
|
import {
|
|
2610
|
+
ACTIVE_EDGE_SCOPES,
|
|
2562
2611
|
EDGE_WEBHOOK_EVENT_TYPES as EDGE_WEBHOOK_EVENT_TYPES2,
|
|
2563
2612
|
TRANSFER_CATEGORIES,
|
|
2564
2613
|
getEnvironmentConfig as getEnvironmentConfig3,
|
|
2565
2614
|
isProductionEnvironment
|
|
2566
2615
|
} from "@edge-markets/connect";
|
|
2567
2616
|
export {
|
|
2617
|
+
ACTIVE_EDGE_SCOPES,
|
|
2568
2618
|
CONNECT_TRANSFER_DIRECTIONS,
|
|
2619
|
+
EDGE_CONNECT_FEATURE_UNAVAILABLE_MESSAGE,
|
|
2569
2620
|
EDGE_WEBHOOK_EVENT_TYPES2 as EDGE_WEBHOOK_EVENT_TYPES,
|
|
2570
2621
|
EdgeApiError2 as EdgeApiError,
|
|
2571
2622
|
EdgeAuthenticationError4 as EdgeAuthenticationError,
|
|
2572
2623
|
EdgeConnectServer,
|
|
2573
2624
|
EdgeConsentRequiredError3 as EdgeConsentRequiredError,
|
|
2574
2625
|
EdgeError3 as EdgeError,
|
|
2626
|
+
EdgeFeatureUnavailableError4 as EdgeFeatureUnavailableError,
|
|
2575
2627
|
EdgeIdentityVerificationError3 as EdgeIdentityVerificationError,
|
|
2576
2628
|
EdgeInsufficientScopeError2 as EdgeInsufficientScopeError,
|
|
2577
2629
|
EdgeNetworkError3 as EdgeNetworkError,
|
|
@@ -2610,6 +2662,7 @@ export {
|
|
|
2610
2662
|
isEdgeError,
|
|
2611
2663
|
isEdgeTokenVaultEnvelope,
|
|
2612
2664
|
isEdgeWebhookEvent,
|
|
2665
|
+
isFeatureUnavailableError,
|
|
2613
2666
|
isIdentityVerificationError,
|
|
2614
2667
|
isNetworkError,
|
|
2615
2668
|
isProductionEnvironment,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edge-markets/connect-node",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "Server SDK for EDGE Connect token exchange and API calls",
|
|
5
5
|
"author": "Edge Markets",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"undici": "^5.29.0",
|
|
25
|
-
"@edge-markets/connect": "^1.
|
|
25
|
+
"@edge-markets/connect": "^1.8.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"tsup": "^8.0.0",
|