@capxul/sdk 0.1.0-alpha.4 → 0.1.0-alpha.8
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/CHANGELOG.md +21 -0
- package/README.md +87 -5
- package/dist/{client-CcCtq5XO.d.ts → client-ByzDfG98.d.ts} +77 -34
- package/dist/{client-CXRKtbfn.d.cts → client-DDAVWtzJ.d.cts} +77 -34
- package/dist/client.cjs +894 -302
- package/dist/client.d.cts +2 -3
- package/dist/client.d.ts +2 -3
- package/dist/client.js +894 -302
- package/dist/index.cjs +1000 -418
- package/dist/index.d.cts +9 -10
- package/dist/index.d.ts +9 -10
- package/dist/index.js +1000 -418
- package/dist/types-PM4AQRLP.d.ts +1136 -0
- package/dist/types-hfcOE7Oi.d.cts +1136 -0
- package/dist/webhooks.d.cts +1 -2
- package/dist/webhooks.d.ts +1 -2
- package/package.json +5 -5
- package/dist/types-75UokagF.d.ts +0 -202
- package/dist/types-DVWojoy4.d.cts +0 -202
package/dist/client.js
CHANGED
|
@@ -67,7 +67,268 @@ function fromConvexError(error) {
|
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
// ../observability/src/try-catch.ts
|
|
71
|
+
async function tryCatch(promise) {
|
|
72
|
+
try {
|
|
73
|
+
return [null, await promise];
|
|
74
|
+
} catch (e) {
|
|
75
|
+
return [e instanceof Error ? e : new Error(String(e)), null];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ../observability/src/debug-log.ts
|
|
80
|
+
function isDevelopmentBuild() {
|
|
81
|
+
if (typeof process === "undefined") {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
|
|
85
|
+
}
|
|
86
|
+
function debugLog(line) {
|
|
87
|
+
if (!isDevelopmentBuild()) return;
|
|
88
|
+
if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
|
|
89
|
+
console.info(line);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
|
|
93
|
+
process.stderr.write(`${line}
|
|
94
|
+
`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function formatDebugValue(value) {
|
|
98
|
+
if (value === void 0 || value === "") return "";
|
|
99
|
+
if (typeof value === "string") return value;
|
|
100
|
+
try {
|
|
101
|
+
return JSON.stringify(value);
|
|
102
|
+
} catch {
|
|
103
|
+
return String(value);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function track(...args) {
|
|
107
|
+
const [name, props] = args;
|
|
108
|
+
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
109
|
+
}
|
|
110
|
+
function formatDebugValue2(value) {
|
|
111
|
+
if (value === void 0 || value === "") return "";
|
|
112
|
+
if (typeof value === "string") return value;
|
|
113
|
+
try {
|
|
114
|
+
return JSON.stringify(value);
|
|
115
|
+
} catch {
|
|
116
|
+
return String(value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function identify(userId, traits) {
|
|
120
|
+
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ../platform-kernel/src/ids.ts
|
|
124
|
+
function makePrefixedIdConstructor(prefix, fieldName) {
|
|
125
|
+
const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
|
|
126
|
+
return (raw) => {
|
|
127
|
+
if (typeof raw !== "string" || !re.test(raw)) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`Invalid ${fieldName}: expected string matching ^${prefix}_[A-Za-z0-9_\\-]+$, got ${String(raw)}`
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return raw;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
var toOperationId = makePrefixedIdConstructor(
|
|
136
|
+
"op",
|
|
137
|
+
"operationId"
|
|
138
|
+
);
|
|
139
|
+
var toCorrelationId = makePrefixedIdConstructor("ctx", "correlationId");
|
|
140
|
+
var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
|
|
141
|
+
|
|
142
|
+
// src/core/external-accounts.ts
|
|
143
|
+
function brandExternalAccount(raw) {
|
|
144
|
+
return {
|
|
145
|
+
...raw,
|
|
146
|
+
id: toExternalAccountId(raw.id),
|
|
147
|
+
operation: {
|
|
148
|
+
id: toOperationId(raw.operation.id),
|
|
149
|
+
status: raw.operation.status,
|
|
150
|
+
correlationId: toCorrelationId(raw.operation.correlationId)
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function createExternalAccountsClient(config = {}) {
|
|
155
|
+
return {
|
|
156
|
+
retrieve: async (externalAccountId) => {
|
|
157
|
+
if (!config.data) {
|
|
158
|
+
return stub(
|
|
159
|
+
"externalAccounts.retrieve"
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
const [err, raw] = await tryCatch(
|
|
163
|
+
config.data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
164
|
+
externalAccountId
|
|
165
|
+
})
|
|
166
|
+
);
|
|
167
|
+
if (err) {
|
|
168
|
+
return [
|
|
169
|
+
fromConvexError(err),
|
|
170
|
+
null
|
|
171
|
+
];
|
|
172
|
+
}
|
|
173
|
+
if (!raw) {
|
|
174
|
+
return [
|
|
175
|
+
new CapxulError({
|
|
176
|
+
code: "NOT_FOUND",
|
|
177
|
+
message: `external_account ${externalAccountId} not found`
|
|
178
|
+
}),
|
|
179
|
+
null
|
|
180
|
+
];
|
|
181
|
+
}
|
|
182
|
+
return [null, brandExternalAccount(raw)];
|
|
183
|
+
},
|
|
184
|
+
remove: async (externalAccountId) => {
|
|
185
|
+
if (!config.data) {
|
|
186
|
+
return stub("externalAccounts.remove");
|
|
187
|
+
}
|
|
188
|
+
const [err] = await tryCatch(
|
|
189
|
+
config.data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
190
|
+
externalAccountId
|
|
191
|
+
})
|
|
192
|
+
);
|
|
193
|
+
if (err) {
|
|
194
|
+
return [
|
|
195
|
+
fromConvexError(err),
|
|
196
|
+
null
|
|
197
|
+
];
|
|
198
|
+
}
|
|
199
|
+
return [null, void 0];
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
70
204
|
// src/core/accounts.ts
|
|
205
|
+
function createAccountExternalAccountsClient(config) {
|
|
206
|
+
return {
|
|
207
|
+
create: async (input) => {
|
|
208
|
+
if (!config.data) {
|
|
209
|
+
return stub(
|
|
210
|
+
"accounts.externalAccounts.create"
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
const [err, raw] = await tryCatch(
|
|
214
|
+
config.data.mutation(
|
|
215
|
+
api.externalAccounts.mutations.createPersonal,
|
|
216
|
+
{
|
|
217
|
+
kind: input.kind,
|
|
218
|
+
label: input.label,
|
|
219
|
+
address: input.address,
|
|
220
|
+
iban: input.iban,
|
|
221
|
+
bic: input.bic,
|
|
222
|
+
accountHolder: input.accountHolder,
|
|
223
|
+
network: input.network,
|
|
224
|
+
panToken: input.panToken,
|
|
225
|
+
last4: input.last4
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
if (err) {
|
|
230
|
+
return [
|
|
231
|
+
fromConvexError(err),
|
|
232
|
+
null
|
|
233
|
+
];
|
|
234
|
+
}
|
|
235
|
+
if (!raw) {
|
|
236
|
+
return [
|
|
237
|
+
new CapxulError({
|
|
238
|
+
code: "NOT_FOUND",
|
|
239
|
+
message: "external_account creation returned no resource"
|
|
240
|
+
}),
|
|
241
|
+
null
|
|
242
|
+
];
|
|
243
|
+
}
|
|
244
|
+
return [
|
|
245
|
+
null,
|
|
246
|
+
brandExternalAccount(
|
|
247
|
+
raw
|
|
248
|
+
)
|
|
249
|
+
];
|
|
250
|
+
},
|
|
251
|
+
list: async (input) => {
|
|
252
|
+
if (!config.data) {
|
|
253
|
+
return stub(
|
|
254
|
+
"accounts.externalAccounts.list"
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
const [err, result] = await tryCatch(
|
|
258
|
+
config.data.query(api.externalAccounts.queries.listPersonal, {
|
|
259
|
+
limit: input.limit,
|
|
260
|
+
cursor: input.cursor
|
|
261
|
+
})
|
|
262
|
+
);
|
|
263
|
+
if (err) {
|
|
264
|
+
return [fromConvexError(err), null];
|
|
265
|
+
}
|
|
266
|
+
const branded = result.data.map(
|
|
267
|
+
(row) => brandExternalAccount(
|
|
268
|
+
row
|
|
269
|
+
)
|
|
270
|
+
);
|
|
271
|
+
return [
|
|
272
|
+
null,
|
|
273
|
+
{
|
|
274
|
+
object: "list",
|
|
275
|
+
data: branded,
|
|
276
|
+
page: result.page
|
|
277
|
+
}
|
|
278
|
+
];
|
|
279
|
+
},
|
|
280
|
+
retrieve: async (externalAccountId) => {
|
|
281
|
+
if (!config.data) {
|
|
282
|
+
return stub(
|
|
283
|
+
"accounts.externalAccounts.retrieve"
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
const [err, raw] = await tryCatch(
|
|
287
|
+
config.data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
288
|
+
externalAccountId
|
|
289
|
+
})
|
|
290
|
+
);
|
|
291
|
+
if (err) {
|
|
292
|
+
return [
|
|
293
|
+
fromConvexError(err),
|
|
294
|
+
null
|
|
295
|
+
];
|
|
296
|
+
}
|
|
297
|
+
if (!raw) {
|
|
298
|
+
return [
|
|
299
|
+
new CapxulError({
|
|
300
|
+
code: "NOT_FOUND",
|
|
301
|
+
message: `external_account ${externalAccountId} not found`
|
|
302
|
+
}),
|
|
303
|
+
null
|
|
304
|
+
];
|
|
305
|
+
}
|
|
306
|
+
return [
|
|
307
|
+
null,
|
|
308
|
+
brandExternalAccount(
|
|
309
|
+
raw
|
|
310
|
+
)
|
|
311
|
+
];
|
|
312
|
+
},
|
|
313
|
+
remove: async (externalAccountId) => {
|
|
314
|
+
if (!config.data) {
|
|
315
|
+
return stub("accounts.externalAccounts.remove");
|
|
316
|
+
}
|
|
317
|
+
const [err] = await tryCatch(
|
|
318
|
+
config.data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
319
|
+
externalAccountId
|
|
320
|
+
})
|
|
321
|
+
);
|
|
322
|
+
if (err) {
|
|
323
|
+
return [
|
|
324
|
+
fromConvexError(err),
|
|
325
|
+
null
|
|
326
|
+
];
|
|
327
|
+
}
|
|
328
|
+
return [null, void 0];
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
}
|
|
71
332
|
function createAccountsClient(config = {}) {
|
|
72
333
|
return {
|
|
73
334
|
retrieve: async (accountId) => {
|
|
@@ -222,18 +483,7 @@ function createAccountsClient(config = {}) {
|
|
|
222
483
|
create: async () => stub("accounts.kycProfiles.create"),
|
|
223
484
|
retrieve: async () => stub("accounts.kycProfiles.retrieve")
|
|
224
485
|
},
|
|
225
|
-
externalAccounts:
|
|
226
|
-
create: async () => stub(
|
|
227
|
-
"accounts.externalAccounts.create"
|
|
228
|
-
),
|
|
229
|
-
list: async () => stub(
|
|
230
|
-
"accounts.externalAccounts.list"
|
|
231
|
-
),
|
|
232
|
-
retrieve: async () => stub(
|
|
233
|
-
"accounts.externalAccounts.retrieve"
|
|
234
|
-
),
|
|
235
|
-
remove: async () => stub("accounts.externalAccounts.remove")
|
|
236
|
-
},
|
|
486
|
+
externalAccounts: createAccountExternalAccountsClient(config),
|
|
237
487
|
subAccounts: {
|
|
238
488
|
create: async () => stub("accounts.subAccounts.create"),
|
|
239
489
|
list: async () => stub("accounts.subAccounts.list"),
|
|
@@ -327,8 +577,35 @@ var Errors = {
|
|
|
327
577
|
"Idempotency key was already used for a different request",
|
|
328
578
|
{ details }
|
|
329
579
|
),
|
|
330
|
-
emailDeliveryFailed: (detail) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}
|
|
331
|
-
|
|
580
|
+
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
581
|
+
details
|
|
582
|
+
}),
|
|
583
|
+
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
584
|
+
details: { ...details }
|
|
585
|
+
}),
|
|
586
|
+
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
587
|
+
/**
|
|
588
|
+
* Verification gate. Surfaced when a request hits a verification
|
|
589
|
+
* boundary the actor cannot cross under their current state. Two
|
|
590
|
+
* variants share this code:
|
|
591
|
+
*
|
|
592
|
+
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
593
|
+
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
594
|
+
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
595
|
+
* `details.rail` + `details.currentKind`.
|
|
596
|
+
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
597
|
+
* the required tier. Carries `details.requiredTier`.
|
|
598
|
+
*
|
|
599
|
+
* Code is shared because both expose the same UX shape ("you cannot
|
|
600
|
+
* proceed until verification advances"); the `details.*` keys
|
|
601
|
+
* differentiate the route.
|
|
602
|
+
*/
|
|
603
|
+
verificationRequired: (details) => {
|
|
604
|
+
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
605
|
+
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
606
|
+
details: { ...details }
|
|
607
|
+
});
|
|
608
|
+
}
|
|
332
609
|
};
|
|
333
610
|
|
|
334
611
|
// ../config/src/safe.ts
|
|
@@ -378,13 +655,13 @@ function createLifecycle(initial) {
|
|
|
378
655
|
}
|
|
379
656
|
function makeBuildTimeUrlsTransport(config) {
|
|
380
657
|
if (!config.authBaseUrl || config.authBaseUrl.trim().length === 0) {
|
|
381
|
-
throw
|
|
658
|
+
throw invalidConfigError(
|
|
382
659
|
"authBaseUrl",
|
|
383
660
|
"build-time-urls transport requires a non-empty authBaseUrl."
|
|
384
661
|
);
|
|
385
662
|
}
|
|
386
663
|
if (!config.convexUrl || config.convexUrl.trim().length === 0) {
|
|
387
|
-
throw
|
|
664
|
+
throw invalidConfigError(
|
|
388
665
|
"convexUrl",
|
|
389
666
|
"build-time-urls transport requires a non-empty convexUrl."
|
|
390
667
|
);
|
|
@@ -398,6 +675,7 @@ function makeBuildTimeUrlsTransport(config) {
|
|
|
398
675
|
return {
|
|
399
676
|
authBaseUrl,
|
|
400
677
|
convexUrl,
|
|
678
|
+
ensureRuntime: async () => runtime,
|
|
401
679
|
fetch: (path, init) => fetchImpl(resolveUrl(authBaseUrl, path), init),
|
|
402
680
|
getState: lifecycle.getState,
|
|
403
681
|
subscribe: lifecycle.subscribe,
|
|
@@ -413,14 +691,15 @@ function makeBuildTimeUrlsTransport(config) {
|
|
|
413
691
|
};
|
|
414
692
|
}
|
|
415
693
|
function makePublishableKeyTransport(config) {
|
|
416
|
-
|
|
417
|
-
|
|
694
|
+
const publishableKey = config.publishableKey?.trim();
|
|
695
|
+
if (!publishableKey) {
|
|
696
|
+
throw invalidConfigError(
|
|
418
697
|
"publishableKey",
|
|
419
698
|
"publishable-key transport requires a non-empty publishableKey."
|
|
420
699
|
);
|
|
421
700
|
}
|
|
422
701
|
const fetchImpl = config.fetchImpl ?? globalThis.fetch;
|
|
423
|
-
const bootstrapUrl =
|
|
702
|
+
const bootstrapUrl = normalizeBootstrapUrl(
|
|
424
703
|
config.bootstrapUrl ?? `${CAPXUL_API_BASE_URL}/v1/client/bootstrap`
|
|
425
704
|
);
|
|
426
705
|
let authBaseUrl = "";
|
|
@@ -435,23 +714,20 @@ function makePublishableKeyTransport(config) {
|
|
|
435
714
|
const response = await fetchImpl(bootstrapUrl, {
|
|
436
715
|
method: "POST",
|
|
437
716
|
headers: { "content-type": "application/json" },
|
|
438
|
-
body: JSON.stringify({ publishableKey
|
|
717
|
+
body: JSON.stringify({ publishableKey })
|
|
439
718
|
});
|
|
440
719
|
if (!response.ok) {
|
|
441
|
-
throw
|
|
442
|
-
"publishableKey",
|
|
443
|
-
`${bootstrapUrl} failed with HTTP ${response.status}.`
|
|
444
|
-
);
|
|
720
|
+
throw await bootstrapResponseError(response, bootstrapUrl);
|
|
445
721
|
}
|
|
446
|
-
const body = await response
|
|
722
|
+
const body = await readBootstrapSuccessBody(response);
|
|
447
723
|
if (typeof body.authBaseUrl !== "string" || body.authBaseUrl.trim().length === 0) {
|
|
448
|
-
throw
|
|
724
|
+
throw bootstrapContractError(
|
|
449
725
|
"authBaseUrl",
|
|
450
726
|
"/v1/client/bootstrap returned no authBaseUrl."
|
|
451
727
|
);
|
|
452
728
|
}
|
|
453
729
|
if (typeof body.convexUrl !== "string" || body.convexUrl.trim().length === 0) {
|
|
454
|
-
throw
|
|
730
|
+
throw bootstrapContractError(
|
|
455
731
|
"convexUrl",
|
|
456
732
|
"/v1/client/bootstrap returned no convexUrl."
|
|
457
733
|
);
|
|
@@ -463,16 +739,13 @@ function makePublishableKeyTransport(config) {
|
|
|
463
739
|
return runtime;
|
|
464
740
|
})();
|
|
465
741
|
bootstrapPromise = attempt.catch((err) => {
|
|
742
|
+
const error = normalizeBootstrapThrownError(err);
|
|
466
743
|
bootstrapPromise = null;
|
|
467
744
|
lifecycle.setState({
|
|
468
745
|
status: "error",
|
|
469
|
-
error
|
|
470
|
-
code: "UNKNOWN",
|
|
471
|
-
message: "Bootstrap failed without a typed CapxulError.",
|
|
472
|
-
cause: err
|
|
473
|
-
})
|
|
746
|
+
error
|
|
474
747
|
});
|
|
475
|
-
throw
|
|
748
|
+
throw error;
|
|
476
749
|
});
|
|
477
750
|
return await bootstrapPromise;
|
|
478
751
|
}
|
|
@@ -483,6 +756,7 @@ function makePublishableKeyTransport(config) {
|
|
|
483
756
|
get convexUrl() {
|
|
484
757
|
return convexUrl;
|
|
485
758
|
},
|
|
759
|
+
ensureRuntime: ensureBootstrap,
|
|
486
760
|
fetch: async (path, init) => {
|
|
487
761
|
const resolved = await ensureBootstrap();
|
|
488
762
|
return await fetchImpl(resolveUrl(resolved.authBaseUrl, path), init);
|
|
@@ -493,7 +767,7 @@ function makePublishableKeyTransport(config) {
|
|
|
493
767
|
markAuthenticated: ({ dataClient: nextDataClient }) => {
|
|
494
768
|
const current = lifecycle.getState();
|
|
495
769
|
if (current.status !== "ready" && current.status !== "authenticated") {
|
|
496
|
-
throw
|
|
770
|
+
throw internalTransportError(
|
|
497
771
|
`markAuthenticated() called from status="${current.status}". Expected "ready" or "authenticated".`
|
|
498
772
|
);
|
|
499
773
|
}
|
|
@@ -515,6 +789,24 @@ function makePublishableKeyTransport(config) {
|
|
|
515
789
|
function stripTrailingSlash(url) {
|
|
516
790
|
return url.replace(/\/+$/, "");
|
|
517
791
|
}
|
|
792
|
+
function normalizeBootstrapUrl(url) {
|
|
793
|
+
const normalized = stripTrailingSlash(url.trim());
|
|
794
|
+
if (!isAbsoluteHttpUrl(normalized)) {
|
|
795
|
+
throw invalidConfigError(
|
|
796
|
+
"bootstrapUrl",
|
|
797
|
+
"publishable-key transport requires an absolute http(s) bootstrapUrl."
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
return normalized;
|
|
801
|
+
}
|
|
802
|
+
function isAbsoluteHttpUrl(url) {
|
|
803
|
+
try {
|
|
804
|
+
const parsed = new URL(url);
|
|
805
|
+
return parsed.protocol === "http:" || parsed.protocol === "https:";
|
|
806
|
+
} catch {
|
|
807
|
+
return false;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
518
810
|
function resolveUrl(authBaseUrl, path) {
|
|
519
811
|
if (path.startsWith("http://") || path.startsWith("https://")) {
|
|
520
812
|
return path;
|
|
@@ -522,10 +814,142 @@ function resolveUrl(authBaseUrl, path) {
|
|
|
522
814
|
return `${authBaseUrl}${path}`;
|
|
523
815
|
}
|
|
524
816
|
function assertNever(value) {
|
|
525
|
-
throw
|
|
817
|
+
throw internalTransportError(
|
|
526
818
|
`Unhandled BrowserCapxulConfig.mode: ${String(value.mode)}.`
|
|
527
819
|
);
|
|
528
820
|
}
|
|
821
|
+
function invalidConfigError(field, reason) {
|
|
822
|
+
return new CapxulError({
|
|
823
|
+
code: "INVALID_INPUT",
|
|
824
|
+
message: `Invalid ${field}: ${reason}`,
|
|
825
|
+
details: { source: "sdk-config", field, reason }
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
function bootstrapContractError(field, message) {
|
|
829
|
+
return new CapxulError({
|
|
830
|
+
code: "INVALID_INPUT",
|
|
831
|
+
message,
|
|
832
|
+
details: {
|
|
833
|
+
source: "backend-bootstrap",
|
|
834
|
+
phase: "publishable-key-bootstrap",
|
|
835
|
+
field,
|
|
836
|
+
reason: message
|
|
837
|
+
}
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
function internalTransportError(reason) {
|
|
841
|
+
return new CapxulError({
|
|
842
|
+
code: "INTERNAL_ERROR",
|
|
843
|
+
message: `Internal error: ${reason}`,
|
|
844
|
+
details: { source: "sdk-transport", reason }
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
async function bootstrapResponseError(response, bootstrapUrl) {
|
|
848
|
+
const envelope = await readBootstrapErrorEnvelope(response);
|
|
849
|
+
const wireCode = readNonEmptyString(envelope?.error?.code);
|
|
850
|
+
const normalized = normalizeBootstrapErrorCode(wireCode);
|
|
851
|
+
const message = readNonEmptyString(envelope?.error?.message) ?? `${bootstrapUrl} failed with HTTP ${response.status}.`;
|
|
852
|
+
const backendDetails = readRecord(envelope?.error?.details);
|
|
853
|
+
return new CapxulError({
|
|
854
|
+
code: normalized.code,
|
|
855
|
+
message,
|
|
856
|
+
details: {
|
|
857
|
+
...backendDetails,
|
|
858
|
+
source: "backend-bootstrap",
|
|
859
|
+
phase: "publishable-key-bootstrap",
|
|
860
|
+
httpStatus: response.status,
|
|
861
|
+
...normalized.wireCode ? { wireCode: normalized.wireCode } : {}
|
|
862
|
+
},
|
|
863
|
+
operationId: readNonEmptyString(envelope?.error?.operationId),
|
|
864
|
+
correlationId: readNonEmptyString(envelope?.error?.correlationId),
|
|
865
|
+
retryable: typeof envelope?.error?.retryable === "boolean" ? envelope.error.retryable : void 0
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
async function readBootstrapErrorEnvelope(response) {
|
|
869
|
+
try {
|
|
870
|
+
const parsed = await response.json();
|
|
871
|
+
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
872
|
+
} catch {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
async function readBootstrapSuccessBody(response) {
|
|
877
|
+
try {
|
|
878
|
+
const parsed = await response.json();
|
|
879
|
+
return typeof parsed === "object" && parsed !== null ? parsed : {};
|
|
880
|
+
} catch {
|
|
881
|
+
throw bootstrapContractError(
|
|
882
|
+
"body",
|
|
883
|
+
"/v1/client/bootstrap returned invalid JSON."
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
function normalizeBootstrapThrownError(error) {
|
|
888
|
+
if (error instanceof CapxulError) return error;
|
|
889
|
+
return new CapxulError({
|
|
890
|
+
code: "NETWORK_ERROR",
|
|
891
|
+
message: "Publishable-key bootstrap network failure.",
|
|
892
|
+
cause: error,
|
|
893
|
+
details: {
|
|
894
|
+
source: "bootstrap-network",
|
|
895
|
+
phase: "publishable-key-bootstrap"
|
|
896
|
+
}
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
function normalizeBootstrapErrorCode(wireCode) {
|
|
900
|
+
if (wireCode === "INTERNAL_SERVER_ERROR") {
|
|
901
|
+
return { code: "INTERNAL_ERROR", wireCode };
|
|
902
|
+
}
|
|
903
|
+
if (wireCode && isCapxulErrorCode(wireCode)) {
|
|
904
|
+
return { code: wireCode };
|
|
905
|
+
}
|
|
906
|
+
return wireCode ? { code: "UNKNOWN", wireCode } : { code: "UNKNOWN" };
|
|
907
|
+
}
|
|
908
|
+
var CAPXUL_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
909
|
+
"NOT_AUTHENTICATED",
|
|
910
|
+
"EMAIL_DELIVERY_FAILED",
|
|
911
|
+
"PROFILE_NOT_FOUND",
|
|
912
|
+
"SMART_ACCOUNT_MISSING",
|
|
913
|
+
"PLAYER_NOT_FOUND",
|
|
914
|
+
"ACCOUNT_NOT_FOUND",
|
|
915
|
+
"PROVIDER_ERROR",
|
|
916
|
+
"INVALID_INPUT",
|
|
917
|
+
"ENV_MISSING",
|
|
918
|
+
"NOT_IMPLEMENTED",
|
|
919
|
+
"VERIFICATION_REQUIRED",
|
|
920
|
+
"INSUFFICIENT_BALANCE",
|
|
921
|
+
"INVALID_RECIPIENT",
|
|
922
|
+
"TRANSACTION_FAILED",
|
|
923
|
+
"RATE_LIMITED",
|
|
924
|
+
"NETWORK_ERROR",
|
|
925
|
+
"UNKNOWN",
|
|
926
|
+
"PERMISSION_DENIED",
|
|
927
|
+
"API_KEY_INVALID",
|
|
928
|
+
"API_KEY_EXPIRED",
|
|
929
|
+
"IDEMPOTENCY_CONFLICT",
|
|
930
|
+
"NOT_FOUND",
|
|
931
|
+
"OPERATION_CANCELED",
|
|
932
|
+
"OPERATION_TIMEOUT",
|
|
933
|
+
"ACTION_REQUIRED",
|
|
934
|
+
"KYC_REQUIRED",
|
|
935
|
+
"POLICY_DENIED",
|
|
936
|
+
"SAFE_NOT_READY",
|
|
937
|
+
"PROVIDER_UNAVAILABLE",
|
|
938
|
+
"PROVIDER_REJECTED",
|
|
939
|
+
"RECONCILIATION_FAILED",
|
|
940
|
+
"INTERNAL_ERROR",
|
|
941
|
+
"QUOTE_EXPIRED",
|
|
942
|
+
"QUOTE_NOT_FOUND"
|
|
943
|
+
]);
|
|
944
|
+
function isCapxulErrorCode(value) {
|
|
945
|
+
return CAPXUL_ERROR_CODES.has(value);
|
|
946
|
+
}
|
|
947
|
+
function readRecord(value) {
|
|
948
|
+
return typeof value === "object" && value !== null ? value : null;
|
|
949
|
+
}
|
|
950
|
+
function readNonEmptyString(value) {
|
|
951
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
952
|
+
}
|
|
529
953
|
|
|
530
954
|
// src/core/auth.ts
|
|
531
955
|
function createAuthClient(config = {}) {
|
|
@@ -580,13 +1004,16 @@ function createAuthClient(config = {}) {
|
|
|
580
1004
|
email: signIn.user.email,
|
|
581
1005
|
token: signIn.token,
|
|
582
1006
|
convexJwt,
|
|
583
|
-
expiresAt: new Date(
|
|
1007
|
+
expiresAt: new Date(
|
|
1008
|
+
Date.now() + 30 * 24 * 60 * 60 * 1e3
|
|
1009
|
+
).toISOString()
|
|
584
1010
|
};
|
|
585
1011
|
sessionStore.set(session);
|
|
586
1012
|
if (config.auth?.createDataClient) {
|
|
587
1013
|
try {
|
|
588
1014
|
dataClient = await config.auth.createDataClient(session);
|
|
589
1015
|
mutableConfig(config).data = dataClient;
|
|
1016
|
+
transport.markAuthenticated({ dataClient });
|
|
590
1017
|
} catch (cause) {
|
|
591
1018
|
return [
|
|
592
1019
|
new CapxulError({
|
|
@@ -605,6 +1032,8 @@ function createAuthClient(config = {}) {
|
|
|
605
1032
|
sessionStore.clear();
|
|
606
1033
|
dataClient = null;
|
|
607
1034
|
mutableConfig(config).data = void 0;
|
|
1035
|
+
const transport = getTransport();
|
|
1036
|
+
transport?.clearAuth();
|
|
608
1037
|
return [null, void 0];
|
|
609
1038
|
},
|
|
610
1039
|
serviceTokenMint: async () => stub("auth.serviceTokenMint"),
|
|
@@ -658,16 +1087,19 @@ async function postBetterAuth(transport, path, body, code, signal) {
|
|
|
658
1087
|
body: JSON.stringify(body),
|
|
659
1088
|
signal
|
|
660
1089
|
});
|
|
1090
|
+
const text = await response.text();
|
|
661
1091
|
if (!response.ok) {
|
|
1092
|
+
const parsedError = parseBetterAuthError(text);
|
|
662
1093
|
return [
|
|
663
1094
|
new CapxulError({
|
|
664
|
-
code,
|
|
665
|
-
message: `BetterAuth ${path} failed with HTTP ${response.status}
|
|
1095
|
+
code: parsedError.code ?? code,
|
|
1096
|
+
message: parsedError.message ?? `BetterAuth ${path} failed with HTTP ${response.status}.`,
|
|
1097
|
+
details: parsedError.details,
|
|
1098
|
+
retryable: parsedError.retryable
|
|
666
1099
|
}),
|
|
667
1100
|
null
|
|
668
1101
|
];
|
|
669
1102
|
}
|
|
670
|
-
const text = await response.text();
|
|
671
1103
|
return [null, text ? JSON.parse(text) : void 0];
|
|
672
1104
|
} catch (cause) {
|
|
673
1105
|
return [
|
|
@@ -680,6 +1112,36 @@ async function postBetterAuth(transport, path, body, code, signal) {
|
|
|
680
1112
|
];
|
|
681
1113
|
}
|
|
682
1114
|
}
|
|
1115
|
+
function parseBetterAuthError(text) {
|
|
1116
|
+
if (!text.trim()) {
|
|
1117
|
+
return {};
|
|
1118
|
+
}
|
|
1119
|
+
try {
|
|
1120
|
+
const body = JSON.parse(text);
|
|
1121
|
+
if (!body || typeof body !== "object") {
|
|
1122
|
+
return {};
|
|
1123
|
+
}
|
|
1124
|
+
const record = body;
|
|
1125
|
+
const nested = record.error && typeof record.error === "object" ? record.error : record;
|
|
1126
|
+
const code = typeof nested.code === "string" ? nested.code : void 0;
|
|
1127
|
+
const message = typeof nested.message === "string" ? nested.message : void 0;
|
|
1128
|
+
const details = nested.details && typeof nested.details === "object" ? nested.details : void 0;
|
|
1129
|
+
const correlationId = typeof nested.correlationId === "string" ? nested.correlationId : void 0;
|
|
1130
|
+
const retryable = typeof nested.retryable === "boolean" ? nested.retryable : void 0;
|
|
1131
|
+
return {
|
|
1132
|
+
code: isCapxulErrorCode2(code) ? code : void 0,
|
|
1133
|
+
message,
|
|
1134
|
+
details,
|
|
1135
|
+
correlationId,
|
|
1136
|
+
retryable
|
|
1137
|
+
};
|
|
1138
|
+
} catch {
|
|
1139
|
+
return {};
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
function isCapxulErrorCode2(code) {
|
|
1143
|
+
return code === "NOT_AUTHENTICATED" || code === "EMAIL_DELIVERY_FAILED" || code === "INVALID_INPUT" || code === "RATE_LIMITED" || code === "NETWORK_ERROR" || code === "API_KEY_INVALID" || code === "API_KEY_EXPIRED";
|
|
1144
|
+
}
|
|
683
1145
|
async function exchangeConvexToken(transport, config, token, signal) {
|
|
684
1146
|
const path = config.auth?.convexTokenUrl ?? "/convex/token";
|
|
685
1147
|
try {
|
|
@@ -740,14 +1202,6 @@ function createOrgDocumentsClient() {
|
|
|
740
1202
|
};
|
|
741
1203
|
}
|
|
742
1204
|
|
|
743
|
-
// src/core/external-accounts.ts
|
|
744
|
-
function createExternalAccountsClient() {
|
|
745
|
-
return {
|
|
746
|
-
retrieve: async () => stub("externalAccounts.retrieve"),
|
|
747
|
-
remove: async () => stub("externalAccounts.remove")
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
|
|
751
1205
|
// src/core/me.ts
|
|
752
1206
|
function createMeClient(config = {}) {
|
|
753
1207
|
return {
|
|
@@ -1195,67 +1649,68 @@ function createOrgTransfersClient() {
|
|
|
1195
1649
|
cancel: async () => stub("organizations.transfers.cancel")
|
|
1196
1650
|
};
|
|
1197
1651
|
}
|
|
1198
|
-
var EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
1199
1652
|
function createWithdrawalsClient(config = {}) {
|
|
1200
1653
|
return {
|
|
1201
1654
|
create: async (input) => {
|
|
1202
1655
|
if (!config.data) {
|
|
1203
1656
|
return stub("withdrawals.create");
|
|
1204
1657
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
details: { field: "destination.externalAccountId" }
|
|
1244
|
-
});
|
|
1245
|
-
}
|
|
1246
|
-
const currentSigner = await config.data.query(
|
|
1247
|
-
api.safe.queries.getMySignerAddress,
|
|
1248
|
-
{}
|
|
1658
|
+
const [createErr, createdRaw] = await tryCatch(
|
|
1659
|
+
config.data.mutation(api.withdrawals.mutations.create, {
|
|
1660
|
+
amount: input.amount,
|
|
1661
|
+
destination: {
|
|
1662
|
+
externalAccountId: input.destination.externalAccountId
|
|
1663
|
+
},
|
|
1664
|
+
source: input.source,
|
|
1665
|
+
reference: input.reference,
|
|
1666
|
+
idempotencyKey: input.idempotencyKey
|
|
1667
|
+
})
|
|
1668
|
+
);
|
|
1669
|
+
if (createErr) {
|
|
1670
|
+
return [mapCreateError2(fromConvexError(createErr)), null];
|
|
1671
|
+
}
|
|
1672
|
+
const created = createdRaw;
|
|
1673
|
+
if (!created) {
|
|
1674
|
+
return [
|
|
1675
|
+
new CapxulError({
|
|
1676
|
+
code: "NETWORK_ERROR",
|
|
1677
|
+
message: "withdrawals.create returned no withdrawal resource"
|
|
1678
|
+
}),
|
|
1679
|
+
null
|
|
1680
|
+
];
|
|
1681
|
+
}
|
|
1682
|
+
if (created.status !== "processing" || created.operation.status !== "processing") {
|
|
1683
|
+
return [null, created];
|
|
1684
|
+
}
|
|
1685
|
+
if (!config.signer || !config.signing) {
|
|
1686
|
+
return [null, created];
|
|
1687
|
+
}
|
|
1688
|
+
const [signerErr, currentSigner] = await tryCatch(
|
|
1689
|
+
config.data.query(api.safe.queries.getMySignerAddress, {})
|
|
1690
|
+
);
|
|
1691
|
+
if (signerErr) {
|
|
1692
|
+
return await handleSubmissionFailure(
|
|
1693
|
+
{ data: config.data },
|
|
1694
|
+
created.id,
|
|
1695
|
+
mapCreateError2(fromConvexError(signerErr))
|
|
1249
1696
|
);
|
|
1250
|
-
|
|
1251
|
-
|
|
1697
|
+
}
|
|
1698
|
+
if (!currentSigner?.address) {
|
|
1699
|
+
return await handleSubmissionFailure(
|
|
1700
|
+
{ data: config.data },
|
|
1701
|
+
created.id,
|
|
1702
|
+
new CapxulError({
|
|
1252
1703
|
code: "PERMISSION_DENIED",
|
|
1253
1704
|
message: "No signer is registered for the authenticated account.",
|
|
1254
1705
|
details: { withdrawalId: created.id }
|
|
1255
|
-
})
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1706
|
+
})
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
if (getAddress(currentSigner.address) !== getAddress(config.signer.address)) {
|
|
1710
|
+
return await handleSubmissionFailure(
|
|
1711
|
+
{ data: config.data },
|
|
1712
|
+
created.id,
|
|
1713
|
+
new CapxulError({
|
|
1259
1714
|
code: "PERMISSION_DENIED",
|
|
1260
1715
|
message: "Configured signer does not match the authenticated account signer.",
|
|
1261
1716
|
details: {
|
|
@@ -1263,170 +1718,228 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1263
1718
|
expectedSignerAddress: currentSigner.address,
|
|
1264
1719
|
actualSignerAddress: config.signer.address
|
|
1265
1720
|
}
|
|
1266
|
-
})
|
|
1267
|
-
}
|
|
1268
|
-
const submission = await config.data.query(
|
|
1269
|
-
api.withdrawals.queries.prepareSubmission,
|
|
1270
|
-
{ withdrawalId: created.id }
|
|
1721
|
+
})
|
|
1271
1722
|
);
|
|
1272
|
-
|
|
1273
|
-
|
|
1723
|
+
}
|
|
1724
|
+
const [prepErr, submission] = await tryCatch(
|
|
1725
|
+
config.data.query(api.withdrawals.queries.prepareSubmission, {
|
|
1726
|
+
withdrawalId: created.id
|
|
1727
|
+
})
|
|
1728
|
+
);
|
|
1729
|
+
if (prepErr) {
|
|
1730
|
+
return await handleSubmissionFailure(
|
|
1731
|
+
{ data: config.data },
|
|
1732
|
+
created.id,
|
|
1733
|
+
mapCreateError2(fromConvexError(prepErr))
|
|
1734
|
+
);
|
|
1735
|
+
}
|
|
1736
|
+
const destinationAddress = submission?.destinationAddress;
|
|
1737
|
+
if (!submission || !destinationAddress) {
|
|
1738
|
+
return await handleSubmissionFailure(
|
|
1739
|
+
{ data: config.data },
|
|
1740
|
+
created.id,
|
|
1741
|
+
new CapxulError({
|
|
1274
1742
|
code: "NETWORK_ERROR",
|
|
1275
1743
|
message: "withdrawals.prepareSubmission returned no destination.",
|
|
1276
1744
|
details: { withdrawalId: created.id }
|
|
1277
|
-
})
|
|
1278
|
-
|
|
1279
|
-
|
|
1745
|
+
})
|
|
1746
|
+
);
|
|
1747
|
+
}
|
|
1748
|
+
const [transferErr, transferOk] = await tryCatch(
|
|
1749
|
+
transferAsOwner(
|
|
1280
1750
|
{
|
|
1281
1751
|
signer: config.signer,
|
|
1282
1752
|
signing: config.signing
|
|
1283
1753
|
},
|
|
1284
1754
|
{
|
|
1285
1755
|
tokenAddress: resolvePaymentTokenAddress(submission.amount.currency),
|
|
1286
|
-
recipientAddress:
|
|
1756
|
+
recipientAddress: destinationAddress,
|
|
1287
1757
|
amount: toTokenUnits(submission.amount.value, 6)
|
|
1288
1758
|
}
|
|
1759
|
+
)
|
|
1760
|
+
);
|
|
1761
|
+
if (transferErr) {
|
|
1762
|
+
return await handleSubmissionFailure(
|
|
1763
|
+
{ data: config.data },
|
|
1764
|
+
created.id,
|
|
1765
|
+
mapCreateError2(fromConvexError(transferErr))
|
|
1289
1766
|
);
|
|
1290
|
-
|
|
1291
|
-
|
|
1767
|
+
}
|
|
1768
|
+
if (!transferOk.success) {
|
|
1769
|
+
return await handleSubmissionFailure(
|
|
1770
|
+
{ data: config.data },
|
|
1771
|
+
created.id,
|
|
1772
|
+
new CapxulError({
|
|
1292
1773
|
code: "NETWORK_ERROR",
|
|
1293
1774
|
message: "Bundler submission did not succeed.",
|
|
1294
1775
|
details: {
|
|
1295
1776
|
withdrawalId: created.id,
|
|
1296
|
-
txHash:
|
|
1297
|
-
userOpHash:
|
|
1777
|
+
txHash: transferOk.txHash,
|
|
1778
|
+
userOpHash: transferOk.userOpHash
|
|
1298
1779
|
}
|
|
1299
|
-
})
|
|
1300
|
-
}
|
|
1301
|
-
submitted = {
|
|
1302
|
-
txHash: transfer.txHash,
|
|
1303
|
-
userOpHash: transfer.userOpHash
|
|
1304
|
-
};
|
|
1305
|
-
await config.data.mutation(
|
|
1306
|
-
api.withdrawals.mutations.recordSubmitted,
|
|
1307
|
-
{
|
|
1308
|
-
withdrawalId: created.id,
|
|
1309
|
-
txHash: transfer.txHash,
|
|
1310
|
-
userOpHash: transfer.userOpHash
|
|
1311
|
-
}
|
|
1780
|
+
})
|
|
1312
1781
|
);
|
|
1313
|
-
return [null, created];
|
|
1314
|
-
} catch (cause) {
|
|
1315
|
-
const error = mapCreateError2(fromConvexError(cause));
|
|
1316
|
-
if (created?.id && created.status === "processing" && !submitted) {
|
|
1317
|
-
await bestEffortMarkFailed2({ data: config.data }, created.id, error);
|
|
1318
|
-
}
|
|
1319
|
-
if (submitted && created?.id) {
|
|
1320
|
-
return [
|
|
1321
|
-
new CapxulError({
|
|
1322
|
-
code: "NETWORK_ERROR",
|
|
1323
|
-
message: "Withdrawal was submitted on-chain, but backend submission tracking failed.",
|
|
1324
|
-
cause,
|
|
1325
|
-
details: {
|
|
1326
|
-
withdrawalId: created.id,
|
|
1327
|
-
txHash: submitted.txHash,
|
|
1328
|
-
userOpHash: submitted.userOpHash
|
|
1329
|
-
}
|
|
1330
|
-
}),
|
|
1331
|
-
null
|
|
1332
|
-
];
|
|
1333
|
-
}
|
|
1334
|
-
return [error, null];
|
|
1335
1782
|
}
|
|
1783
|
+
const [recordErr] = await tryCatch(
|
|
1784
|
+
config.data.mutation(api.withdrawals.mutations.recordSubmitted, {
|
|
1785
|
+
withdrawalId: created.id,
|
|
1786
|
+
txHash: transferOk.txHash,
|
|
1787
|
+
userOpHash: transferOk.userOpHash
|
|
1788
|
+
})
|
|
1789
|
+
);
|
|
1790
|
+
if (recordErr) {
|
|
1791
|
+
return [
|
|
1792
|
+
new CapxulError({
|
|
1793
|
+
code: "NETWORK_ERROR",
|
|
1794
|
+
message: "Withdrawal was submitted on-chain, but backend submission tracking failed.",
|
|
1795
|
+
cause: recordErr,
|
|
1796
|
+
details: {
|
|
1797
|
+
withdrawalId: created.id,
|
|
1798
|
+
txHash: transferOk.txHash,
|
|
1799
|
+
userOpHash: transferOk.userOpHash
|
|
1800
|
+
}
|
|
1801
|
+
}),
|
|
1802
|
+
null
|
|
1803
|
+
];
|
|
1804
|
+
}
|
|
1805
|
+
return [null, created];
|
|
1336
1806
|
},
|
|
1337
1807
|
retrieve: async (withdrawalId) => {
|
|
1338
1808
|
if (!config.data) {
|
|
1339
1809
|
return stub("withdrawals.retrieve");
|
|
1340
1810
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
);
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
code: "NOT_FOUND",
|
|
1350
|
-
message: `withdrawal ${withdrawalId} not found`
|
|
1351
|
-
}),
|
|
1352
|
-
null
|
|
1353
|
-
];
|
|
1354
|
-
}
|
|
1355
|
-
return [null, withdrawal];
|
|
1356
|
-
} catch (cause) {
|
|
1811
|
+
const [err, raw] = await tryCatch(
|
|
1812
|
+
config.data.query(api.withdrawals.queries.retrieve, { withdrawalId })
|
|
1813
|
+
);
|
|
1814
|
+
if (err) {
|
|
1815
|
+
return [fromConvexError(err), null];
|
|
1816
|
+
}
|
|
1817
|
+
const withdrawal = raw;
|
|
1818
|
+
if (!withdrawal) {
|
|
1357
1819
|
return [
|
|
1358
|
-
|
|
1820
|
+
new CapxulError({
|
|
1821
|
+
code: "NOT_FOUND",
|
|
1822
|
+
message: `withdrawal ${withdrawalId} not found`
|
|
1823
|
+
}),
|
|
1359
1824
|
null
|
|
1360
1825
|
];
|
|
1361
1826
|
}
|
|
1827
|
+
return [null, withdrawal];
|
|
1362
1828
|
},
|
|
1363
1829
|
list: async (input) => {
|
|
1364
1830
|
if (!config.data) {
|
|
1365
1831
|
return stub("withdrawals.list");
|
|
1366
1832
|
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1833
|
+
const [err, raw] = await tryCatch(
|
|
1834
|
+
config.data.query(api.withdrawals.queries.list, {
|
|
1835
|
+
limit: input?.limit,
|
|
1836
|
+
cursor: input?.cursor
|
|
1837
|
+
})
|
|
1838
|
+
);
|
|
1839
|
+
if (err) {
|
|
1840
|
+
return [fromConvexError(err), null];
|
|
1841
|
+
}
|
|
1842
|
+
return [null, raw];
|
|
1843
|
+
},
|
|
1844
|
+
recordCompleted: async (input) => {
|
|
1845
|
+
if (!config.data) {
|
|
1846
|
+
return stub(
|
|
1847
|
+
"withdrawals.recordCompleted"
|
|
1374
1848
|
);
|
|
1375
|
-
|
|
1376
|
-
|
|
1849
|
+
}
|
|
1850
|
+
const [err] = await tryCatch(
|
|
1851
|
+
config.data.mutation(api.withdrawals.mutations.recordCompleted, {
|
|
1852
|
+
withdrawalId: input.withdrawalId,
|
|
1853
|
+
txHash: input.txHash
|
|
1854
|
+
})
|
|
1855
|
+
);
|
|
1856
|
+
if (err) {
|
|
1377
1857
|
return [
|
|
1378
|
-
fromConvexError(
|
|
1858
|
+
mapRecordCompletedError(fromConvexError(err)),
|
|
1379
1859
|
null
|
|
1380
1860
|
];
|
|
1381
1861
|
}
|
|
1862
|
+
return [null, null];
|
|
1382
1863
|
}
|
|
1383
1864
|
};
|
|
1384
1865
|
}
|
|
1385
1866
|
function createOrgWithdrawalsClient(config = {}) {
|
|
1386
1867
|
return {
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1868
|
+
/**
|
|
1869
|
+
* Org-scope create (Withdrawals v1 W2, #465).
|
|
1870
|
+
*
|
|
1871
|
+
* D6 — returns the `processing` row only. No `transferAsOwner`
|
|
1872
|
+
* tail, no `recordSubmitted` call. Org Safe + Zodiac submission
|
|
1873
|
+
* orchestration ships in W3+.
|
|
1874
|
+
*/
|
|
1875
|
+
create: async (input) => {
|
|
1876
|
+
if (!config.data) {
|
|
1877
|
+
return stub(
|
|
1878
|
+
"organizations.withdrawals.create"
|
|
1879
|
+
);
|
|
1880
|
+
}
|
|
1881
|
+
const [err, raw] = await tryCatch(
|
|
1882
|
+
config.data.mutation(api.withdrawals.mutations.createOrg, {
|
|
1883
|
+
organizationId: input.organizationId,
|
|
1884
|
+
amount: input.amount,
|
|
1885
|
+
destination: {
|
|
1886
|
+
externalAccountId: input.destination.externalAccountId
|
|
1887
|
+
},
|
|
1888
|
+
source: input.source,
|
|
1889
|
+
reference: input.reference,
|
|
1890
|
+
idempotencyKey: input.idempotencyKey
|
|
1891
|
+
})
|
|
1892
|
+
);
|
|
1893
|
+
if (err) {
|
|
1894
|
+
return [mapCreateError2(fromConvexError(err)), null];
|
|
1895
|
+
}
|
|
1896
|
+
const created = raw;
|
|
1897
|
+
if (!created) {
|
|
1898
|
+
return [
|
|
1899
|
+
new CapxulError({
|
|
1900
|
+
code: "NETWORK_ERROR",
|
|
1901
|
+
message: "organizations.withdrawals.create returned no withdrawal resource"
|
|
1902
|
+
}),
|
|
1903
|
+
null
|
|
1904
|
+
];
|
|
1905
|
+
}
|
|
1906
|
+
return [null, created];
|
|
1907
|
+
},
|
|
1393
1908
|
retrieve: async (input) => {
|
|
1394
1909
|
if (!config.data) {
|
|
1395
1910
|
return stub(
|
|
1396
1911
|
"organizations.withdrawals.retrieve"
|
|
1397
1912
|
);
|
|
1398
1913
|
}
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
}),
|
|
1410
|
-
null
|
|
1411
|
-
];
|
|
1412
|
-
}
|
|
1413
|
-
const ownerCheck = withdrawal.owner;
|
|
1414
|
-
if (ownerCheck?.type !== "organization" || ownerCheck.id !== input.organizationId) {
|
|
1415
|
-
return [
|
|
1416
|
-
new CapxulError({
|
|
1417
|
-
code: "NOT_FOUND",
|
|
1418
|
-
message: `withdrawal ${input.withdrawalId} does not belong to organization ${input.organizationId}`
|
|
1419
|
-
}),
|
|
1420
|
-
null
|
|
1421
|
-
];
|
|
1422
|
-
}
|
|
1423
|
-
return [null, withdrawal];
|
|
1424
|
-
} catch (cause) {
|
|
1914
|
+
const [err, raw] = await tryCatch(
|
|
1915
|
+
config.data.query(api.withdrawals.queries.retrieve, {
|
|
1916
|
+
withdrawalId: input.withdrawalId
|
|
1917
|
+
})
|
|
1918
|
+
);
|
|
1919
|
+
if (err) {
|
|
1920
|
+
return [fromConvexError(err), null];
|
|
1921
|
+
}
|
|
1922
|
+
const withdrawal = raw;
|
|
1923
|
+
if (!withdrawal) {
|
|
1425
1924
|
return [
|
|
1426
|
-
|
|
1925
|
+
new CapxulError({
|
|
1926
|
+
code: "NOT_FOUND",
|
|
1927
|
+
message: `withdrawal ${input.withdrawalId} not found`
|
|
1928
|
+
}),
|
|
1929
|
+
null
|
|
1930
|
+
];
|
|
1931
|
+
}
|
|
1932
|
+
const ownerCheck = withdrawal.owner;
|
|
1933
|
+
if (ownerCheck?.type !== "organization" || ownerCheck.id !== input.organizationId) {
|
|
1934
|
+
return [
|
|
1935
|
+
new CapxulError({
|
|
1936
|
+
code: "NOT_FOUND",
|
|
1937
|
+
message: `withdrawal ${input.withdrawalId} does not belong to organization ${input.organizationId}`
|
|
1938
|
+
}),
|
|
1427
1939
|
null
|
|
1428
1940
|
];
|
|
1429
1941
|
}
|
|
1942
|
+
return [null, withdrawal];
|
|
1430
1943
|
},
|
|
1431
1944
|
list: async (input) => {
|
|
1432
1945
|
if (!config.data) {
|
|
@@ -1434,34 +1947,32 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1434
1947
|
"organizations.withdrawals.list"
|
|
1435
1948
|
);
|
|
1436
1949
|
}
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
);
|
|
1446
|
-
return [null, result];
|
|
1447
|
-
} catch (cause) {
|
|
1448
|
-
return [
|
|
1449
|
-
fromConvexError(cause),
|
|
1450
|
-
null
|
|
1451
|
-
];
|
|
1950
|
+
const [err, raw] = await tryCatch(
|
|
1951
|
+
config.data.query(api.withdrawals.queries.listOrg, {
|
|
1952
|
+
organizationId: input.organizationId,
|
|
1953
|
+
limit: input.limit,
|
|
1954
|
+
cursor: input.cursor
|
|
1955
|
+
})
|
|
1956
|
+
);
|
|
1957
|
+
if (err) {
|
|
1958
|
+
return [fromConvexError(err), null];
|
|
1452
1959
|
}
|
|
1960
|
+
return [null, raw];
|
|
1453
1961
|
}
|
|
1454
1962
|
};
|
|
1455
1963
|
}
|
|
1964
|
+
async function handleSubmissionFailure(config, withdrawalId, error) {
|
|
1965
|
+
await bestEffortMarkFailed2(config, withdrawalId, error);
|
|
1966
|
+
return [error, null];
|
|
1967
|
+
}
|
|
1456
1968
|
async function bestEffortMarkFailed2(config, withdrawalId, error) {
|
|
1457
|
-
|
|
1458
|
-
|
|
1969
|
+
await tryCatch(
|
|
1970
|
+
config.data.mutation(api.withdrawals.mutations.markFailed, {
|
|
1459
1971
|
withdrawalId,
|
|
1460
1972
|
errorCode: error.code,
|
|
1461
1973
|
errorMessage: error.message
|
|
1462
|
-
})
|
|
1463
|
-
|
|
1464
|
-
}
|
|
1974
|
+
})
|
|
1975
|
+
);
|
|
1465
1976
|
}
|
|
1466
1977
|
function mapCreateError2(error) {
|
|
1467
1978
|
switch (error.code) {
|
|
@@ -1474,6 +1985,29 @@ function mapCreateError2(error) {
|
|
|
1474
1985
|
case "POLICY_DENIED":
|
|
1475
1986
|
case "RATE_LIMITED":
|
|
1476
1987
|
case "NETWORK_ERROR":
|
|
1988
|
+
case "NOT_FOUND":
|
|
1989
|
+
case "VERIFICATION_REQUIRED":
|
|
1990
|
+
return error;
|
|
1991
|
+
default:
|
|
1992
|
+
return new CapxulError({
|
|
1993
|
+
code: "NETWORK_ERROR",
|
|
1994
|
+
message: error.message,
|
|
1995
|
+
cause: error,
|
|
1996
|
+
details: error.details,
|
|
1997
|
+
operationId: error.operationId,
|
|
1998
|
+
correlationId: error.correlationId,
|
|
1999
|
+
retryable: error.retryable
|
|
2000
|
+
});
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
function mapRecordCompletedError(error) {
|
|
2004
|
+
switch (error.code) {
|
|
2005
|
+
case "NOT_AUTHENTICATED":
|
|
2006
|
+
case "PERMISSION_DENIED":
|
|
2007
|
+
case "INVALID_INPUT":
|
|
2008
|
+
case "NOT_FOUND":
|
|
2009
|
+
case "NETWORK_ERROR":
|
|
2010
|
+
case "INTERNAL_ERROR":
|
|
1477
2011
|
return error;
|
|
1478
2012
|
default:
|
|
1479
2013
|
return new CapxulError({
|
|
@@ -1509,6 +2043,136 @@ function createWebhookEventsClient() {
|
|
|
1509
2043
|
}
|
|
1510
2044
|
|
|
1511
2045
|
// src/core/organizations.ts
|
|
2046
|
+
function createOrgExternalAccountsClient(config) {
|
|
2047
|
+
return {
|
|
2048
|
+
create: async (input) => {
|
|
2049
|
+
if (!config.data) {
|
|
2050
|
+
return stub(
|
|
2051
|
+
"organizations.externalAccounts.create"
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
const [err, raw] = await tryCatch(
|
|
2055
|
+
config.data.mutation(api.externalAccounts.mutations.createOrg, {
|
|
2056
|
+
organizationId: input.organizationId,
|
|
2057
|
+
kind: input.kind,
|
|
2058
|
+
label: input.label,
|
|
2059
|
+
address: input.address,
|
|
2060
|
+
iban: input.iban,
|
|
2061
|
+
bic: input.bic,
|
|
2062
|
+
accountHolder: input.accountHolder,
|
|
2063
|
+
network: input.network,
|
|
2064
|
+
panToken: input.panToken,
|
|
2065
|
+
last4: input.last4
|
|
2066
|
+
})
|
|
2067
|
+
);
|
|
2068
|
+
if (err) {
|
|
2069
|
+
return [
|
|
2070
|
+
fromConvexError(err),
|
|
2071
|
+
null
|
|
2072
|
+
];
|
|
2073
|
+
}
|
|
2074
|
+
if (!raw) {
|
|
2075
|
+
return [
|
|
2076
|
+
new CapxulError({
|
|
2077
|
+
code: "NOT_FOUND",
|
|
2078
|
+
message: "external_account creation returned no resource"
|
|
2079
|
+
}),
|
|
2080
|
+
null
|
|
2081
|
+
];
|
|
2082
|
+
}
|
|
2083
|
+
return [
|
|
2084
|
+
null,
|
|
2085
|
+
brandExternalAccount(
|
|
2086
|
+
raw
|
|
2087
|
+
)
|
|
2088
|
+
];
|
|
2089
|
+
},
|
|
2090
|
+
list: async (input) => {
|
|
2091
|
+
if (!config.data) {
|
|
2092
|
+
return stub(
|
|
2093
|
+
"organizations.externalAccounts.list"
|
|
2094
|
+
);
|
|
2095
|
+
}
|
|
2096
|
+
const [err, result] = await tryCatch(
|
|
2097
|
+
config.data.query(api.externalAccounts.queries.listOrg, {
|
|
2098
|
+
organizationId: input.organizationId,
|
|
2099
|
+
limit: input.limit,
|
|
2100
|
+
cursor: input.cursor
|
|
2101
|
+
})
|
|
2102
|
+
);
|
|
2103
|
+
if (err) {
|
|
2104
|
+
return [fromConvexError(err), null];
|
|
2105
|
+
}
|
|
2106
|
+
const branded = result.data.map(
|
|
2107
|
+
(row) => brandExternalAccount(
|
|
2108
|
+
row
|
|
2109
|
+
)
|
|
2110
|
+
);
|
|
2111
|
+
return [
|
|
2112
|
+
null,
|
|
2113
|
+
{
|
|
2114
|
+
object: "list",
|
|
2115
|
+
data: branded,
|
|
2116
|
+
page: result.page
|
|
2117
|
+
}
|
|
2118
|
+
];
|
|
2119
|
+
},
|
|
2120
|
+
retrieve: async (input) => {
|
|
2121
|
+
if (!config.data) {
|
|
2122
|
+
return stub(
|
|
2123
|
+
"organizations.externalAccounts.retrieve"
|
|
2124
|
+
);
|
|
2125
|
+
}
|
|
2126
|
+
const [err, raw] = await tryCatch(
|
|
2127
|
+
config.data.query(api.externalAccounts.queries.retrieveOrg, {
|
|
2128
|
+
organizationId: input.organizationId,
|
|
2129
|
+
externalAccountId: input.externalAccountId
|
|
2130
|
+
})
|
|
2131
|
+
);
|
|
2132
|
+
if (err) {
|
|
2133
|
+
return [
|
|
2134
|
+
fromConvexError(err),
|
|
2135
|
+
null
|
|
2136
|
+
];
|
|
2137
|
+
}
|
|
2138
|
+
if (!raw) {
|
|
2139
|
+
return [
|
|
2140
|
+
new CapxulError({
|
|
2141
|
+
code: "NOT_FOUND",
|
|
2142
|
+
message: `external_account ${input.externalAccountId} not found`
|
|
2143
|
+
}),
|
|
2144
|
+
null
|
|
2145
|
+
];
|
|
2146
|
+
}
|
|
2147
|
+
return [
|
|
2148
|
+
null,
|
|
2149
|
+
brandExternalAccount(
|
|
2150
|
+
raw
|
|
2151
|
+
)
|
|
2152
|
+
];
|
|
2153
|
+
},
|
|
2154
|
+
remove: async (input) => {
|
|
2155
|
+
if (!config.data) {
|
|
2156
|
+
return stub(
|
|
2157
|
+
"organizations.externalAccounts.remove"
|
|
2158
|
+
);
|
|
2159
|
+
}
|
|
2160
|
+
const [err] = await tryCatch(
|
|
2161
|
+
config.data.mutation(api.externalAccounts.mutations.removeOrg, {
|
|
2162
|
+
organizationId: input.organizationId,
|
|
2163
|
+
externalAccountId: input.externalAccountId
|
|
2164
|
+
})
|
|
2165
|
+
);
|
|
2166
|
+
if (err) {
|
|
2167
|
+
return [
|
|
2168
|
+
fromConvexError(err),
|
|
2169
|
+
null
|
|
2170
|
+
];
|
|
2171
|
+
}
|
|
2172
|
+
return [null, void 0];
|
|
2173
|
+
}
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
1512
2176
|
function createOrganizationsClient(config = {}) {
|
|
1513
2177
|
return {
|
|
1514
2178
|
create: async () => stub("organizations.create"),
|
|
@@ -1564,18 +2228,7 @@ function createOrganizationsClient(config = {}) {
|
|
|
1564
2228
|
retrieve: async () => stub("organizations.subAccounts.retrieve"),
|
|
1565
2229
|
remove: async () => stub("organizations.subAccounts.remove")
|
|
1566
2230
|
},
|
|
1567
|
-
externalAccounts:
|
|
1568
|
-
create: async () => stub(
|
|
1569
|
-
"organizations.externalAccounts.create"
|
|
1570
|
-
),
|
|
1571
|
-
list: async () => stub(
|
|
1572
|
-
"organizations.externalAccounts.list"
|
|
1573
|
-
),
|
|
1574
|
-
retrieve: async () => stub(
|
|
1575
|
-
"organizations.externalAccounts.retrieve"
|
|
1576
|
-
),
|
|
1577
|
-
remove: async () => stub("organizations.externalAccounts.remove")
|
|
1578
|
-
},
|
|
2231
|
+
externalAccounts: createOrgExternalAccountsClient(config),
|
|
1579
2232
|
balanceLedger: {
|
|
1580
2233
|
list: async () => stub(
|
|
1581
2234
|
"organizations.balanceLedger.list"
|
|
@@ -1712,50 +2365,6 @@ function createVirtualCardsClient() {
|
|
|
1712
2365
|
cancel: async () => stub("virtualCards.cancel")
|
|
1713
2366
|
};
|
|
1714
2367
|
}
|
|
1715
|
-
|
|
1716
|
-
// ../observability/src/debug-log.ts
|
|
1717
|
-
function isDevelopmentBuild() {
|
|
1718
|
-
if (typeof process === "undefined") {
|
|
1719
|
-
return false;
|
|
1720
|
-
}
|
|
1721
|
-
return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
|
|
1722
|
-
}
|
|
1723
|
-
function debugLog(line) {
|
|
1724
|
-
if (!isDevelopmentBuild()) return;
|
|
1725
|
-
if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
|
|
1726
|
-
console.info(line);
|
|
1727
|
-
return;
|
|
1728
|
-
}
|
|
1729
|
-
if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
|
|
1730
|
-
process.stderr.write(`${line}
|
|
1731
|
-
`);
|
|
1732
|
-
}
|
|
1733
|
-
}
|
|
1734
|
-
function formatDebugValue(value) {
|
|
1735
|
-
if (value === void 0 || value === "") return "";
|
|
1736
|
-
if (typeof value === "string") return value;
|
|
1737
|
-
try {
|
|
1738
|
-
return JSON.stringify(value);
|
|
1739
|
-
} catch {
|
|
1740
|
-
return String(value);
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
function track(...args) {
|
|
1744
|
-
const [name, props] = args;
|
|
1745
|
-
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
1746
|
-
}
|
|
1747
|
-
function formatDebugValue2(value) {
|
|
1748
|
-
if (value === void 0 || value === "") return "";
|
|
1749
|
-
if (typeof value === "string") return value;
|
|
1750
|
-
try {
|
|
1751
|
-
return JSON.stringify(value);
|
|
1752
|
-
} catch {
|
|
1753
|
-
return String(value);
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
function identify(userId, traits) {
|
|
1757
|
-
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
1758
|
-
}
|
|
1759
2368
|
function createAuthFlowMachine(client) {
|
|
1760
2369
|
return setup({
|
|
1761
2370
|
types: {},
|
|
@@ -2031,23 +2640,6 @@ function emailDomain(email) {
|
|
|
2031
2640
|
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
2032
2641
|
return domain || "unknown";
|
|
2033
2642
|
}
|
|
2034
|
-
|
|
2035
|
-
// ../platform-kernel/src/ids.ts
|
|
2036
|
-
function makePrefixedIdConstructor(prefix, fieldName) {
|
|
2037
|
-
const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
|
|
2038
|
-
return (raw) => {
|
|
2039
|
-
if (typeof raw !== "string" || !re.test(raw)) {
|
|
2040
|
-
throw new Error(
|
|
2041
|
-
`Invalid ${fieldName}: expected string matching ^${prefix}_[A-Za-z0-9_\\-]+$, got ${String(raw)}`
|
|
2042
|
-
);
|
|
2043
|
-
}
|
|
2044
|
-
return raw;
|
|
2045
|
-
};
|
|
2046
|
-
}
|
|
2047
|
-
var toOperationId = makePrefixedIdConstructor(
|
|
2048
|
-
"op",
|
|
2049
|
-
"operationId"
|
|
2050
|
-
);
|
|
2051
2643
|
function createProvisioningMachine(client) {
|
|
2052
2644
|
return setup({
|
|
2053
2645
|
types: {},
|
|
@@ -2440,7 +3032,7 @@ function createCapxulClient(config = {}) {
|
|
|
2440
3032
|
subAccounts: createSubAccountsClient(),
|
|
2441
3033
|
virtualAccounts: createVirtualAccountsClient(),
|
|
2442
3034
|
virtualCards: createVirtualCardsClient(),
|
|
2443
|
-
externalAccounts: createExternalAccountsClient(),
|
|
3035
|
+
externalAccounts: createExternalAccountsClient(config),
|
|
2444
3036
|
operations: createOperationsClient(config),
|
|
2445
3037
|
webhookEndpoints: createWebhookEndpointsClient(),
|
|
2446
3038
|
webhookEvents: createWebhookEventsClient(),
|