@capxul/sdk 0.1.0-alpha.3 → 0.1.0-alpha.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -68,12 +68,441 @@ function fromConvexError(error) {
68
68
  });
69
69
  }
70
70
 
71
+ // ../observability/src/try-catch.ts
72
+ async function tryCatch(promise) {
73
+ try {
74
+ return [null, await promise];
75
+ } catch (e) {
76
+ return [e instanceof Error ? e : new Error(String(e)), null];
77
+ }
78
+ }
79
+
80
+ // ../observability/src/debug-log.ts
81
+ function isDevelopmentBuild() {
82
+ if (typeof process === "undefined") {
83
+ return false;
84
+ }
85
+ return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
86
+ }
87
+ function debugLog(line) {
88
+ if (!isDevelopmentBuild()) return;
89
+ if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
90
+ console.info(line);
91
+ return;
92
+ }
93
+ if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
94
+ process.stderr.write(`${line}
95
+ `);
96
+ }
97
+ }
98
+ function formatDebugValue(value) {
99
+ if (value === void 0 || value === "") return "";
100
+ if (typeof value === "string") return value;
101
+ try {
102
+ return JSON.stringify(value);
103
+ } catch {
104
+ return String(value);
105
+ }
106
+ }
107
+ function track(...args) {
108
+ const [name, props] = args;
109
+ debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
110
+ }
111
+ function formatDebugValue2(value) {
112
+ if (value === void 0 || value === "") return "";
113
+ if (typeof value === "string") return value;
114
+ try {
115
+ return JSON.stringify(value);
116
+ } catch {
117
+ return String(value);
118
+ }
119
+ }
120
+ function identify(userId, traits) {
121
+ debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
122
+ }
123
+
124
+ // ../platform-kernel/src/ids.ts
125
+ function makePrefixedIdConstructor(prefix, fieldName) {
126
+ const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
127
+ return (raw) => {
128
+ if (typeof raw !== "string" || !re.test(raw)) {
129
+ throw new Error(
130
+ `Invalid ${fieldName}: expected string matching ^${prefix}_[A-Za-z0-9_\\-]+$, got ${String(raw)}`
131
+ );
132
+ }
133
+ return raw;
134
+ };
135
+ }
136
+ var toAccountId = makePrefixedIdConstructor(
137
+ "acct",
138
+ "accountId"
139
+ );
140
+ var toOrganizationId = makePrefixedIdConstructor("org", "organizationId");
141
+ var toMemberId = makePrefixedIdConstructor(
142
+ "mem",
143
+ "memberId"
144
+ );
145
+ var toSafeId = makePrefixedIdConstructor(
146
+ "safe",
147
+ "safeId"
148
+ );
149
+ var toTreasuryId = makePrefixedIdConstructor(
150
+ "try",
151
+ "treasuryId"
152
+ );
153
+ var toApiKeyId = makePrefixedIdConstructor(
154
+ "ak",
155
+ "apiKeyId"
156
+ );
157
+ var toOperationId = makePrefixedIdConstructor(
158
+ "op",
159
+ "operationId"
160
+ );
161
+ var toCorrelationId = makePrefixedIdConstructor("ctx", "correlationId");
162
+ var toKycProfileId = makePrefixedIdConstructor(
163
+ "kyc",
164
+ "kycProfileId"
165
+ );
166
+ var toKybProfileId = makePrefixedIdConstructor(
167
+ "kyb",
168
+ "kybProfileId"
169
+ );
170
+ var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
171
+ var toPaymentId = makePrefixedIdConstructor(
172
+ "pay",
173
+ "paymentId"
174
+ );
175
+ var toWithdrawalId = makePrefixedIdConstructor(
176
+ "wd",
177
+ "withdrawalId"
178
+ );
179
+ var toWebhookEndpointId = makePrefixedIdConstructor("we", "webhookEndpointId");
180
+ var toWebhookEventId = makePrefixedIdConstructor("evt", "webhookEventId");
181
+ var toSubAccountId = makePrefixedIdConstructor(
182
+ "sub",
183
+ "subAccountId"
184
+ );
185
+ var toVirtualAccountId = makePrefixedIdConstructor("va", "virtualAccountId");
186
+ var toVirtualCardId = makePrefixedIdConstructor(
187
+ "vc",
188
+ "virtualCardId"
189
+ );
190
+ var toTransferId = makePrefixedIdConstructor(
191
+ "txfr",
192
+ "transferId"
193
+ );
194
+ var toDocumentId = makePrefixedIdConstructor(
195
+ "doc",
196
+ "documentId"
197
+ );
198
+ var toBalanceLedgerEntryId = makePrefixedIdConstructor("bal", "balanceLedgerEntryId");
199
+
200
+ // ../platform-kernel/src/value-objects.ts
201
+ var PHONE_NUMBER_RE = /^\+[1-9]\d{1,14}$/;
202
+ function toPhoneNumber(raw) {
203
+ if (typeof raw !== "string" || !PHONE_NUMBER_RE.test(raw)) {
204
+ throw new Error(
205
+ `Invalid phoneNumber: expected E.164 string matching ^\\+[1-9]\\d{1,14}$, got ${String(raw)}`
206
+ );
207
+ }
208
+ return raw;
209
+ }
210
+ var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
211
+ function toEmail(raw) {
212
+ if (typeof raw !== "string") {
213
+ throw new Error(
214
+ `Invalid email: expected string, got ${String(raw)}`
215
+ );
216
+ }
217
+ const lowered = raw.trim().toLowerCase();
218
+ if (!EMAIL_RE.test(lowered)) {
219
+ throw new Error(
220
+ `Invalid email: expected local@domain.tld, got ${String(raw)}`
221
+ );
222
+ }
223
+ return lowered;
224
+ }
225
+ var USERNAME_RE = /^[a-z][a-z0-9_-]{2,29}$/;
226
+ function toUsername(raw) {
227
+ if (typeof raw !== "string") {
228
+ throw new Error(
229
+ `Invalid username: expected string, got ${String(raw)}`
230
+ );
231
+ }
232
+ const lowered = raw.toLowerCase();
233
+ if (!USERNAME_RE.test(lowered)) {
234
+ throw new Error(
235
+ `Invalid username: expected 3-30 chars, letter-first, [a-z0-9_-], got ${String(raw)}`
236
+ );
237
+ }
238
+ return lowered;
239
+ }
240
+
241
+ // src/core/external-accounts.ts
242
+ function brandExternalAccount(raw) {
243
+ return {
244
+ ...raw,
245
+ id: toExternalAccountId(raw.id),
246
+ operation: {
247
+ id: toOperationId(raw.operation.id),
248
+ status: raw.operation.status,
249
+ correlationId: toCorrelationId(raw.operation.correlationId)
250
+ }
251
+ };
252
+ }
253
+ function createExternalAccountsClient(config = {}) {
254
+ return {
255
+ retrieve: async (externalAccountId) => {
256
+ if (!config.data) {
257
+ return stub(
258
+ "externalAccounts.retrieve"
259
+ );
260
+ }
261
+ const [err, raw] = await tryCatch(
262
+ config.data.query(api.externalAccounts.queries.retrievePersonal, {
263
+ externalAccountId
264
+ })
265
+ );
266
+ if (err) {
267
+ return [
268
+ fromConvexError(err),
269
+ null
270
+ ];
271
+ }
272
+ if (!raw) {
273
+ return [
274
+ new CapxulError({
275
+ code: "NOT_FOUND",
276
+ message: `external_account ${externalAccountId} not found`
277
+ }),
278
+ null
279
+ ];
280
+ }
281
+ return [null, brandExternalAccount(raw)];
282
+ },
283
+ remove: async (externalAccountId) => {
284
+ if (!config.data) {
285
+ return stub("externalAccounts.remove");
286
+ }
287
+ const [err] = await tryCatch(
288
+ config.data.mutation(api.externalAccounts.mutations.removePersonal, {
289
+ externalAccountId
290
+ })
291
+ );
292
+ if (err) {
293
+ return [
294
+ fromConvexError(err),
295
+ null
296
+ ];
297
+ }
298
+ return [null, void 0];
299
+ }
300
+ };
301
+ }
302
+
71
303
  // src/core/accounts.ts
304
+ function createAccountExternalAccountsClient(config) {
305
+ return {
306
+ create: async (input) => {
307
+ if (!config.data) {
308
+ return stub(
309
+ "accounts.externalAccounts.create"
310
+ );
311
+ }
312
+ const [err, raw] = await tryCatch(
313
+ config.data.mutation(
314
+ api.externalAccounts.mutations.createPersonal,
315
+ {
316
+ kind: input.kind,
317
+ label: input.label,
318
+ address: input.address,
319
+ iban: input.iban,
320
+ bic: input.bic,
321
+ accountHolder: input.accountHolder,
322
+ network: input.network,
323
+ panToken: input.panToken,
324
+ last4: input.last4
325
+ }
326
+ )
327
+ );
328
+ if (err) {
329
+ return [
330
+ fromConvexError(err),
331
+ null
332
+ ];
333
+ }
334
+ if (!raw) {
335
+ return [
336
+ new CapxulError({
337
+ code: "NOT_FOUND",
338
+ message: "external_account creation returned no resource"
339
+ }),
340
+ null
341
+ ];
342
+ }
343
+ return [
344
+ null,
345
+ brandExternalAccount(
346
+ raw
347
+ )
348
+ ];
349
+ },
350
+ list: async (input) => {
351
+ if (!config.data) {
352
+ return stub(
353
+ "accounts.externalAccounts.list"
354
+ );
355
+ }
356
+ const [err, result] = await tryCatch(
357
+ config.data.query(api.externalAccounts.queries.listPersonal, {
358
+ limit: input.limit,
359
+ cursor: input.cursor
360
+ })
361
+ );
362
+ if (err) {
363
+ return [fromConvexError(err), null];
364
+ }
365
+ const branded = result.data.map(
366
+ (row) => brandExternalAccount(
367
+ row
368
+ )
369
+ );
370
+ return [
371
+ null,
372
+ {
373
+ object: "list",
374
+ data: branded,
375
+ page: result.page
376
+ }
377
+ ];
378
+ },
379
+ retrieve: async (externalAccountId) => {
380
+ if (!config.data) {
381
+ return stub(
382
+ "accounts.externalAccounts.retrieve"
383
+ );
384
+ }
385
+ const [err, raw] = await tryCatch(
386
+ config.data.query(api.externalAccounts.queries.retrievePersonal, {
387
+ externalAccountId
388
+ })
389
+ );
390
+ if (err) {
391
+ return [
392
+ fromConvexError(err),
393
+ null
394
+ ];
395
+ }
396
+ if (!raw) {
397
+ return [
398
+ new CapxulError({
399
+ code: "NOT_FOUND",
400
+ message: `external_account ${externalAccountId} not found`
401
+ }),
402
+ null
403
+ ];
404
+ }
405
+ return [
406
+ null,
407
+ brandExternalAccount(
408
+ raw
409
+ )
410
+ ];
411
+ },
412
+ remove: async (externalAccountId) => {
413
+ if (!config.data) {
414
+ return stub("accounts.externalAccounts.remove");
415
+ }
416
+ const [err] = await tryCatch(
417
+ config.data.mutation(api.externalAccounts.mutations.removePersonal, {
418
+ externalAccountId
419
+ })
420
+ );
421
+ if (err) {
422
+ return [
423
+ fromConvexError(err),
424
+ null
425
+ ];
426
+ }
427
+ return [null, void 0];
428
+ }
429
+ };
430
+ }
72
431
  function createAccountsClient(config = {}) {
73
432
  return {
74
- retrieve: async () => stub("accounts.retrieve"),
433
+ retrieve: async (accountId) => {
434
+ if (!config.data) {
435
+ return stub("accounts.retrieve");
436
+ }
437
+ try {
438
+ const account = await config.data.query(
439
+ api.openfort.queries.getMyAccount,
440
+ {}
441
+ );
442
+ if (account.id !== accountId) {
443
+ return [
444
+ new CapxulError({
445
+ code: "PERMISSION_DENIED",
446
+ message: "accounts.retrieve currently supports the authenticated caller's own account only.",
447
+ details: {
448
+ requestedAccountId: accountId,
449
+ authenticatedAccountId: account.id
450
+ }
451
+ }),
452
+ null
453
+ ];
454
+ }
455
+ return [null, account];
456
+ } catch (cause) {
457
+ return [fromConvexError(cause), null];
458
+ }
459
+ },
75
460
  lookup: async () => stub("accounts.lookup"),
76
- update: async () => stub("accounts.update"),
461
+ update: async (input) => {
462
+ if (!config.data) {
463
+ return stub("accounts.update");
464
+ }
465
+ if (input.countryCode !== void 0) {
466
+ return [
467
+ new CapxulError({
468
+ code: "INVALID_INPUT",
469
+ message: "accounts.update does not support countryCode yet \u2014 backend mutation only patches displayName and username.",
470
+ details: { field: "countryCode" }
471
+ }),
472
+ null
473
+ ];
474
+ }
475
+ try {
476
+ const current = await config.data.query(
477
+ api.openfort.queries.getMyAccount,
478
+ {}
479
+ );
480
+ if (current.id !== input.accountId) {
481
+ return [
482
+ new CapxulError({
483
+ code: "PERMISSION_DENIED",
484
+ message: "accounts.update currently supports the authenticated caller's own account only.",
485
+ details: {
486
+ requestedAccountId: input.accountId,
487
+ authenticatedAccountId: current.id
488
+ }
489
+ }),
490
+ null
491
+ ];
492
+ }
493
+ await config.data.mutation(api.openfort.mutations.updateProfile, {
494
+ displayName: input.name,
495
+ username: input.username
496
+ });
497
+ const updated = await config.data.query(
498
+ api.openfort.queries.getMyAccount,
499
+ {}
500
+ );
501
+ return [null, updated];
502
+ } catch (cause) {
503
+ return [fromConvexError(cause), null];
504
+ }
505
+ },
77
506
  provisionPersonal: async (input) => {
78
507
  if (!config.data) {
79
508
  return stub(
@@ -153,18 +582,7 @@ function createAccountsClient(config = {}) {
153
582
  create: async () => stub("accounts.kycProfiles.create"),
154
583
  retrieve: async () => stub("accounts.kycProfiles.retrieve")
155
584
  },
156
- externalAccounts: {
157
- create: async () => stub(
158
- "accounts.externalAccounts.create"
159
- ),
160
- list: async () => stub(
161
- "accounts.externalAccounts.list"
162
- ),
163
- retrieve: async () => stub(
164
- "accounts.externalAccounts.retrieve"
165
- ),
166
- remove: async () => stub("accounts.externalAccounts.remove")
167
- },
585
+ externalAccounts: createAccountExternalAccountsClient(config),
168
586
  subAccounts: {
169
587
  create: async () => stub("accounts.subAccounts.create"),
170
588
  list: async () => stub("accounts.subAccounts.list"),
@@ -260,7 +678,29 @@ var Errors = {
260
678
  { details }
261
679
  ),
262
680
  emailDeliveryFailed: (detail) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`),
263
- internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`)
681
+ internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
682
+ /**
683
+ * Verification gate. Surfaced when a request hits a verification
684
+ * boundary the actor cannot cross under their current state. Two
685
+ * variants share this code:
686
+ *
687
+ * - Rail gate (Withdrawals v1 W2, #465): the resolved
688
+ * `external_account.kind` routes to a withdrawal rail (e.g.
689
+ * `fiat_offramp`, `card_payout`) that is not yet supported. Carries
690
+ * `details.rail` + `details.currentKind`.
691
+ * - KYC tier gate (legacy / future): the actor's KYC tier is below
692
+ * the required tier. Carries `details.requiredTier`.
693
+ *
694
+ * Code is shared because both expose the same UX shape ("you cannot
695
+ * proceed until verification advances"); the `details.*` keys
696
+ * differentiate the route.
697
+ */
698
+ verificationRequired: (details) => {
699
+ const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
700
+ return new CapxulError2("VERIFICATION_REQUIRED", message, {
701
+ details: { ...details }
702
+ });
703
+ }
264
704
  };
265
705
 
266
706
  // ../config/src/safe.ts
@@ -672,22 +1112,42 @@ function createOrgDocumentsClient() {
672
1112
  };
673
1113
  }
674
1114
 
675
- // src/core/external-accounts.ts
676
- function createExternalAccountsClient() {
677
- return {
678
- retrieve: async () => stub("externalAccounts.retrieve"),
679
- remove: async () => stub("externalAccounts.remove")
680
- };
681
- }
682
-
683
1115
  // src/core/me.ts
684
1116
  function createMeClient(config = {}) {
685
1117
  return {
686
1118
  get: async () => {
687
1119
  if (!config.data) {
688
- return stub("me.get");
1120
+ return stub("me.get");
1121
+ }
1122
+ try {
1123
+ const account = await config.data.query(
1124
+ api.openfort.queries.getMyAccount,
1125
+ {}
1126
+ );
1127
+ return [null, account];
1128
+ } catch (cause) {
1129
+ return [fromConvexError(cause), null];
1130
+ }
1131
+ },
1132
+ update: async (input) => {
1133
+ if (!config.data) {
1134
+ return stub("me.update");
1135
+ }
1136
+ if (input.countryCode !== void 0) {
1137
+ return [
1138
+ new CapxulError({
1139
+ code: "INVALID_INPUT",
1140
+ message: "me.update does not support countryCode yet \u2014 backend mutation only patches displayName and username.",
1141
+ details: { field: "countryCode" }
1142
+ }),
1143
+ null
1144
+ ];
689
1145
  }
690
1146
  try {
1147
+ await config.data.mutation(api.openfort.mutations.updateProfile, {
1148
+ displayName: input.name,
1149
+ username: input.username
1150
+ });
691
1151
  const account = await config.data.query(
692
1152
  api.openfort.queries.getMyAccount,
693
1153
  {}
@@ -696,8 +1156,7 @@ function createMeClient(config = {}) {
696
1156
  } catch (cause) {
697
1157
  return [fromConvexError(cause), null];
698
1158
  }
699
- },
700
- update: async () => stub("me.update")
1159
+ }
701
1160
  };
702
1161
  }
703
1162
 
@@ -1100,24 +1559,378 @@ function createOrgTransfersClient() {
1100
1559
  cancel: async () => stub("organizations.transfers.cancel")
1101
1560
  };
1102
1561
  }
1103
-
1104
- // src/core/withdrawals.ts
1105
- function createWithdrawalsClient() {
1562
+ function createWithdrawalsClient(config = {}) {
1106
1563
  return {
1107
- create: async () => stub("withdrawals.create"),
1108
- retrieve: async () => stub("withdrawals.retrieve"),
1109
- list: async () => stub("withdrawals.list")
1564
+ create: async (input) => {
1565
+ if (!config.data) {
1566
+ return stub("withdrawals.create");
1567
+ }
1568
+ const [createErr, createdRaw] = await tryCatch(
1569
+ config.data.mutation(api.withdrawals.mutations.create, {
1570
+ amount: input.amount,
1571
+ destination: {
1572
+ externalAccountId: input.destination.externalAccountId
1573
+ },
1574
+ source: input.source,
1575
+ reference: input.reference,
1576
+ idempotencyKey: input.idempotencyKey
1577
+ })
1578
+ );
1579
+ if (createErr) {
1580
+ return [mapCreateError2(fromConvexError(createErr)), null];
1581
+ }
1582
+ const created = createdRaw;
1583
+ if (!created) {
1584
+ return [
1585
+ new CapxulError({
1586
+ code: "NETWORK_ERROR",
1587
+ message: "withdrawals.create returned no withdrawal resource"
1588
+ }),
1589
+ null
1590
+ ];
1591
+ }
1592
+ if (created.status !== "processing" || created.operation.status !== "processing") {
1593
+ return [null, created];
1594
+ }
1595
+ if (!config.signer || !config.signing) {
1596
+ return [null, created];
1597
+ }
1598
+ const [signerErr, currentSigner] = await tryCatch(
1599
+ config.data.query(api.safe.queries.getMySignerAddress, {})
1600
+ );
1601
+ if (signerErr) {
1602
+ return await handleSubmissionFailure(
1603
+ { data: config.data },
1604
+ created.id,
1605
+ mapCreateError2(fromConvexError(signerErr))
1606
+ );
1607
+ }
1608
+ if (!currentSigner?.address) {
1609
+ return await handleSubmissionFailure(
1610
+ { data: config.data },
1611
+ created.id,
1612
+ new CapxulError({
1613
+ code: "PERMISSION_DENIED",
1614
+ message: "No signer is registered for the authenticated account.",
1615
+ details: { withdrawalId: created.id }
1616
+ })
1617
+ );
1618
+ }
1619
+ if (getAddress(currentSigner.address) !== getAddress(config.signer.address)) {
1620
+ return await handleSubmissionFailure(
1621
+ { data: config.data },
1622
+ created.id,
1623
+ new CapxulError({
1624
+ code: "PERMISSION_DENIED",
1625
+ message: "Configured signer does not match the authenticated account signer.",
1626
+ details: {
1627
+ withdrawalId: created.id,
1628
+ expectedSignerAddress: currentSigner.address,
1629
+ actualSignerAddress: config.signer.address
1630
+ }
1631
+ })
1632
+ );
1633
+ }
1634
+ const [prepErr, submission] = await tryCatch(
1635
+ config.data.query(api.withdrawals.queries.prepareSubmission, {
1636
+ withdrawalId: created.id
1637
+ })
1638
+ );
1639
+ if (prepErr) {
1640
+ return await handleSubmissionFailure(
1641
+ { data: config.data },
1642
+ created.id,
1643
+ mapCreateError2(fromConvexError(prepErr))
1644
+ );
1645
+ }
1646
+ const destinationAddress = submission?.destinationAddress;
1647
+ if (!submission || !destinationAddress) {
1648
+ return await handleSubmissionFailure(
1649
+ { data: config.data },
1650
+ created.id,
1651
+ new CapxulError({
1652
+ code: "NETWORK_ERROR",
1653
+ message: "withdrawals.prepareSubmission returned no destination.",
1654
+ details: { withdrawalId: created.id }
1655
+ })
1656
+ );
1657
+ }
1658
+ const [transferErr, transferOk] = await tryCatch(
1659
+ transferAsOwner(
1660
+ {
1661
+ signer: config.signer,
1662
+ signing: config.signing
1663
+ },
1664
+ {
1665
+ tokenAddress: resolvePaymentTokenAddress(submission.amount.currency),
1666
+ recipientAddress: destinationAddress,
1667
+ amount: toTokenUnits(submission.amount.value, 6)
1668
+ }
1669
+ )
1670
+ );
1671
+ if (transferErr) {
1672
+ return await handleSubmissionFailure(
1673
+ { data: config.data },
1674
+ created.id,
1675
+ mapCreateError2(fromConvexError(transferErr))
1676
+ );
1677
+ }
1678
+ if (!transferOk.success) {
1679
+ return await handleSubmissionFailure(
1680
+ { data: config.data },
1681
+ created.id,
1682
+ new CapxulError({
1683
+ code: "NETWORK_ERROR",
1684
+ message: "Bundler submission did not succeed.",
1685
+ details: {
1686
+ withdrawalId: created.id,
1687
+ txHash: transferOk.txHash,
1688
+ userOpHash: transferOk.userOpHash
1689
+ }
1690
+ })
1691
+ );
1692
+ }
1693
+ const [recordErr] = await tryCatch(
1694
+ config.data.mutation(api.withdrawals.mutations.recordSubmitted, {
1695
+ withdrawalId: created.id,
1696
+ txHash: transferOk.txHash,
1697
+ userOpHash: transferOk.userOpHash
1698
+ })
1699
+ );
1700
+ if (recordErr) {
1701
+ return [
1702
+ new CapxulError({
1703
+ code: "NETWORK_ERROR",
1704
+ message: "Withdrawal was submitted on-chain, but backend submission tracking failed.",
1705
+ cause: recordErr,
1706
+ details: {
1707
+ withdrawalId: created.id,
1708
+ txHash: transferOk.txHash,
1709
+ userOpHash: transferOk.userOpHash
1710
+ }
1711
+ }),
1712
+ null
1713
+ ];
1714
+ }
1715
+ return [null, created];
1716
+ },
1717
+ retrieve: async (withdrawalId) => {
1718
+ if (!config.data) {
1719
+ return stub("withdrawals.retrieve");
1720
+ }
1721
+ const [err, raw] = await tryCatch(
1722
+ config.data.query(api.withdrawals.queries.retrieve, { withdrawalId })
1723
+ );
1724
+ if (err) {
1725
+ return [fromConvexError(err), null];
1726
+ }
1727
+ const withdrawal = raw;
1728
+ if (!withdrawal) {
1729
+ return [
1730
+ new CapxulError({
1731
+ code: "NOT_FOUND",
1732
+ message: `withdrawal ${withdrawalId} not found`
1733
+ }),
1734
+ null
1735
+ ];
1736
+ }
1737
+ return [null, withdrawal];
1738
+ },
1739
+ list: async (input) => {
1740
+ if (!config.data) {
1741
+ return stub("withdrawals.list");
1742
+ }
1743
+ const [err, raw] = await tryCatch(
1744
+ config.data.query(api.withdrawals.queries.list, {
1745
+ limit: input?.limit,
1746
+ cursor: input?.cursor
1747
+ })
1748
+ );
1749
+ if (err) {
1750
+ return [fromConvexError(err), null];
1751
+ }
1752
+ return [null, raw];
1753
+ },
1754
+ recordCompleted: async (input) => {
1755
+ if (!config.data) {
1756
+ return stub(
1757
+ "withdrawals.recordCompleted"
1758
+ );
1759
+ }
1760
+ const [err] = await tryCatch(
1761
+ config.data.mutation(api.withdrawals.mutations.recordCompleted, {
1762
+ withdrawalId: input.withdrawalId,
1763
+ txHash: input.txHash
1764
+ })
1765
+ );
1766
+ if (err) {
1767
+ return [
1768
+ mapRecordCompletedError(fromConvexError(err)),
1769
+ null
1770
+ ];
1771
+ }
1772
+ return [null, null];
1773
+ }
1110
1774
  };
1111
1775
  }
1112
- function createOrgWithdrawalsClient() {
1776
+ function createOrgWithdrawalsClient(config = {}) {
1113
1777
  return {
1114
- create: async () => stub(
1115
- "organizations.withdrawals.create"
1116
- ),
1117
- retrieve: async () => stub("organizations.withdrawals.retrieve"),
1118
- list: async () => stub("organizations.withdrawals.list")
1778
+ /**
1779
+ * Org-scope create (Withdrawals v1 W2, #465).
1780
+ *
1781
+ * D6 returns the `processing` row only. No `transferAsOwner`
1782
+ * tail, no `recordSubmitted` call. Org Safe + Zodiac submission
1783
+ * orchestration ships in W3+.
1784
+ */
1785
+ create: async (input) => {
1786
+ if (!config.data) {
1787
+ return stub(
1788
+ "organizations.withdrawals.create"
1789
+ );
1790
+ }
1791
+ const [err, raw] = await tryCatch(
1792
+ config.data.mutation(api.withdrawals.mutations.createOrg, {
1793
+ organizationId: input.organizationId,
1794
+ amount: input.amount,
1795
+ destination: {
1796
+ externalAccountId: input.destination.externalAccountId
1797
+ },
1798
+ source: input.source,
1799
+ reference: input.reference,
1800
+ idempotencyKey: input.idempotencyKey
1801
+ })
1802
+ );
1803
+ if (err) {
1804
+ return [mapCreateError2(fromConvexError(err)), null];
1805
+ }
1806
+ const created = raw;
1807
+ if (!created) {
1808
+ return [
1809
+ new CapxulError({
1810
+ code: "NETWORK_ERROR",
1811
+ message: "organizations.withdrawals.create returned no withdrawal resource"
1812
+ }),
1813
+ null
1814
+ ];
1815
+ }
1816
+ return [null, created];
1817
+ },
1818
+ retrieve: async (input) => {
1819
+ if (!config.data) {
1820
+ return stub(
1821
+ "organizations.withdrawals.retrieve"
1822
+ );
1823
+ }
1824
+ const [err, raw] = await tryCatch(
1825
+ config.data.query(api.withdrawals.queries.retrieve, {
1826
+ withdrawalId: input.withdrawalId
1827
+ })
1828
+ );
1829
+ if (err) {
1830
+ return [fromConvexError(err), null];
1831
+ }
1832
+ const withdrawal = raw;
1833
+ if (!withdrawal) {
1834
+ return [
1835
+ new CapxulError({
1836
+ code: "NOT_FOUND",
1837
+ message: `withdrawal ${input.withdrawalId} not found`
1838
+ }),
1839
+ null
1840
+ ];
1841
+ }
1842
+ const ownerCheck = withdrawal.owner;
1843
+ if (ownerCheck?.type !== "organization" || ownerCheck.id !== input.organizationId) {
1844
+ return [
1845
+ new CapxulError({
1846
+ code: "NOT_FOUND",
1847
+ message: `withdrawal ${input.withdrawalId} does not belong to organization ${input.organizationId}`
1848
+ }),
1849
+ null
1850
+ ];
1851
+ }
1852
+ return [null, withdrawal];
1853
+ },
1854
+ list: async (input) => {
1855
+ if (!config.data) {
1856
+ return stub(
1857
+ "organizations.withdrawals.list"
1858
+ );
1859
+ }
1860
+ const [err, raw] = await tryCatch(
1861
+ config.data.query(api.withdrawals.queries.listOrg, {
1862
+ organizationId: input.organizationId,
1863
+ limit: input.limit,
1864
+ cursor: input.cursor
1865
+ })
1866
+ );
1867
+ if (err) {
1868
+ return [fromConvexError(err), null];
1869
+ }
1870
+ return [null, raw];
1871
+ }
1119
1872
  };
1120
1873
  }
1874
+ async function handleSubmissionFailure(config, withdrawalId, error) {
1875
+ await bestEffortMarkFailed2(config, withdrawalId, error);
1876
+ return [error, null];
1877
+ }
1878
+ async function bestEffortMarkFailed2(config, withdrawalId, error) {
1879
+ await tryCatch(
1880
+ config.data.mutation(api.withdrawals.mutations.markFailed, {
1881
+ withdrawalId,
1882
+ errorCode: error.code,
1883
+ errorMessage: error.message
1884
+ })
1885
+ );
1886
+ }
1887
+ function mapCreateError2(error) {
1888
+ switch (error.code) {
1889
+ case "NOT_AUTHENTICATED":
1890
+ case "PERMISSION_DENIED":
1891
+ case "INVALID_INPUT":
1892
+ case "INSUFFICIENT_BALANCE":
1893
+ case "IDEMPOTENCY_CONFLICT":
1894
+ case "KYC_REQUIRED":
1895
+ case "POLICY_DENIED":
1896
+ case "RATE_LIMITED":
1897
+ case "NETWORK_ERROR":
1898
+ case "NOT_FOUND":
1899
+ case "VERIFICATION_REQUIRED":
1900
+ return error;
1901
+ default:
1902
+ return new CapxulError({
1903
+ code: "NETWORK_ERROR",
1904
+ message: error.message,
1905
+ cause: error,
1906
+ details: error.details,
1907
+ operationId: error.operationId,
1908
+ correlationId: error.correlationId,
1909
+ retryable: error.retryable
1910
+ });
1911
+ }
1912
+ }
1913
+ function mapRecordCompletedError(error) {
1914
+ switch (error.code) {
1915
+ case "NOT_AUTHENTICATED":
1916
+ case "PERMISSION_DENIED":
1917
+ case "INVALID_INPUT":
1918
+ case "NOT_FOUND":
1919
+ case "NETWORK_ERROR":
1920
+ case "INTERNAL_ERROR":
1921
+ return error;
1922
+ default:
1923
+ return new CapxulError({
1924
+ code: "NETWORK_ERROR",
1925
+ message: error.message,
1926
+ cause: error,
1927
+ details: error.details,
1928
+ operationId: error.operationId,
1929
+ correlationId: error.correlationId,
1930
+ retryable: error.retryable
1931
+ });
1932
+ }
1933
+ }
1121
1934
 
1122
1935
  // src/core/webhook-endpoints.ts
1123
1936
  function createWebhookEndpointsClient() {
@@ -1138,8 +1951,138 @@ function createWebhookEventsClient() {
1138
1951
  list: async () => stub("webhookEvents.list")
1139
1952
  };
1140
1953
  }
1141
-
1142
- // src/core/organizations.ts
1954
+
1955
+ // src/core/organizations.ts
1956
+ function createOrgExternalAccountsClient(config) {
1957
+ return {
1958
+ create: async (input) => {
1959
+ if (!config.data) {
1960
+ return stub(
1961
+ "organizations.externalAccounts.create"
1962
+ );
1963
+ }
1964
+ const [err, raw] = await tryCatch(
1965
+ config.data.mutation(api.externalAccounts.mutations.createOrg, {
1966
+ organizationId: input.organizationId,
1967
+ kind: input.kind,
1968
+ label: input.label,
1969
+ address: input.address,
1970
+ iban: input.iban,
1971
+ bic: input.bic,
1972
+ accountHolder: input.accountHolder,
1973
+ network: input.network,
1974
+ panToken: input.panToken,
1975
+ last4: input.last4
1976
+ })
1977
+ );
1978
+ if (err) {
1979
+ return [
1980
+ fromConvexError(err),
1981
+ null
1982
+ ];
1983
+ }
1984
+ if (!raw) {
1985
+ return [
1986
+ new CapxulError({
1987
+ code: "NOT_FOUND",
1988
+ message: "external_account creation returned no resource"
1989
+ }),
1990
+ null
1991
+ ];
1992
+ }
1993
+ return [
1994
+ null,
1995
+ brandExternalAccount(
1996
+ raw
1997
+ )
1998
+ ];
1999
+ },
2000
+ list: async (input) => {
2001
+ if (!config.data) {
2002
+ return stub(
2003
+ "organizations.externalAccounts.list"
2004
+ );
2005
+ }
2006
+ const [err, result] = await tryCatch(
2007
+ config.data.query(api.externalAccounts.queries.listOrg, {
2008
+ organizationId: input.organizationId,
2009
+ limit: input.limit,
2010
+ cursor: input.cursor
2011
+ })
2012
+ );
2013
+ if (err) {
2014
+ return [fromConvexError(err), null];
2015
+ }
2016
+ const branded = result.data.map(
2017
+ (row) => brandExternalAccount(
2018
+ row
2019
+ )
2020
+ );
2021
+ return [
2022
+ null,
2023
+ {
2024
+ object: "list",
2025
+ data: branded,
2026
+ page: result.page
2027
+ }
2028
+ ];
2029
+ },
2030
+ retrieve: async (input) => {
2031
+ if (!config.data) {
2032
+ return stub(
2033
+ "organizations.externalAccounts.retrieve"
2034
+ );
2035
+ }
2036
+ const [err, raw] = await tryCatch(
2037
+ config.data.query(api.externalAccounts.queries.retrieveOrg, {
2038
+ organizationId: input.organizationId,
2039
+ externalAccountId: input.externalAccountId
2040
+ })
2041
+ );
2042
+ if (err) {
2043
+ return [
2044
+ fromConvexError(err),
2045
+ null
2046
+ ];
2047
+ }
2048
+ if (!raw) {
2049
+ return [
2050
+ new CapxulError({
2051
+ code: "NOT_FOUND",
2052
+ message: `external_account ${input.externalAccountId} not found`
2053
+ }),
2054
+ null
2055
+ ];
2056
+ }
2057
+ return [
2058
+ null,
2059
+ brandExternalAccount(
2060
+ raw
2061
+ )
2062
+ ];
2063
+ },
2064
+ remove: async (input) => {
2065
+ if (!config.data) {
2066
+ return stub(
2067
+ "organizations.externalAccounts.remove"
2068
+ );
2069
+ }
2070
+ const [err] = await tryCatch(
2071
+ config.data.mutation(api.externalAccounts.mutations.removeOrg, {
2072
+ organizationId: input.organizationId,
2073
+ externalAccountId: input.externalAccountId
2074
+ })
2075
+ );
2076
+ if (err) {
2077
+ return [
2078
+ fromConvexError(err),
2079
+ null
2080
+ ];
2081
+ }
2082
+ return [null, void 0];
2083
+ }
2084
+ };
2085
+ }
1143
2086
  function createOrganizationsClient(config = {}) {
1144
2087
  return {
1145
2088
  create: async () => stub("organizations.create"),
@@ -1195,18 +2138,7 @@ function createOrganizationsClient(config = {}) {
1195
2138
  retrieve: async () => stub("organizations.subAccounts.retrieve"),
1196
2139
  remove: async () => stub("organizations.subAccounts.remove")
1197
2140
  },
1198
- externalAccounts: {
1199
- create: async () => stub(
1200
- "organizations.externalAccounts.create"
1201
- ),
1202
- list: async () => stub(
1203
- "organizations.externalAccounts.list"
1204
- ),
1205
- retrieve: async () => stub(
1206
- "organizations.externalAccounts.retrieve"
1207
- ),
1208
- remove: async () => stub("organizations.externalAccounts.remove")
1209
- },
2141
+ externalAccounts: createOrgExternalAccountsClient(config),
1210
2142
  balanceLedger: {
1211
2143
  list: async () => stub(
1212
2144
  "organizations.balanceLedger.list"
@@ -1217,7 +2149,7 @@ function createOrganizationsClient(config = {}) {
1217
2149
  },
1218
2150
  payments: createOrgPaymentsClient(),
1219
2151
  transfers: createOrgTransfersClient(),
1220
- withdrawals: createOrgWithdrawalsClient(),
2152
+ withdrawals: createOrgWithdrawalsClient(config),
1221
2153
  documents: createOrgDocumentsClient(),
1222
2154
  webhookEndpoints: createWebhookEndpointsClient(),
1223
2155
  webhookEvents: createWebhookEventsClient()
@@ -1232,6 +2164,96 @@ function createSubAccountsClient() {
1232
2164
  };
1233
2165
  }
1234
2166
 
2167
+ // src/core/token-transfers.ts
2168
+ var toTokenTransferId = (raw) => {
2169
+ if (typeof raw !== "string" || raw.length === 0) {
2170
+ throw new Error(
2171
+ `Invalid tokenTransferId: expected non-empty string, got ${String(raw)}`
2172
+ );
2173
+ }
2174
+ return raw;
2175
+ };
2176
+ function brandRow(row) {
2177
+ return {
2178
+ ...row,
2179
+ id: toTokenTransferId(row.id)
2180
+ };
2181
+ }
2182
+ function createTokenTransfersClient(config = {}) {
2183
+ return {
2184
+ list: async (input) => {
2185
+ if (!config.data) {
2186
+ return stub("tokenTransfers.list");
2187
+ }
2188
+ try {
2189
+ const raw = await config.data.query(
2190
+ api.tokenTransfers.queries.list,
2191
+ {
2192
+ limit: input?.limit,
2193
+ cursor: input?.cursor,
2194
+ direction: input?.direction
2195
+ }
2196
+ );
2197
+ if (!raw) {
2198
+ return [
2199
+ new CapxulError({
2200
+ code: "NOT_AUTHENTICATED",
2201
+ message: "tokenTransfers.list requires an authenticated session."
2202
+ }),
2203
+ null
2204
+ ];
2205
+ }
2206
+ return [
2207
+ null,
2208
+ {
2209
+ object: "list",
2210
+ data: raw.items.map(brandRow),
2211
+ page: {
2212
+ hasMore: raw.hasMore,
2213
+ nextCursor: raw.nextCursor
2214
+ },
2215
+ displayCurrency: raw.displayCurrency
2216
+ }
2217
+ ];
2218
+ } catch (cause) {
2219
+ return [fromConvexError(cause), null];
2220
+ }
2221
+ },
2222
+ retrieve: async (input) => {
2223
+ if (!config.data) {
2224
+ return stub("tokenTransfers.retrieve");
2225
+ }
2226
+ try {
2227
+ const raw = await config.data.query(
2228
+ api.tokenTransfers.queries.getByTxLogIndex,
2229
+ {
2230
+ txHash: input.txHash,
2231
+ logIndex: input.logIndex,
2232
+ chainId: input.chainId
2233
+ }
2234
+ );
2235
+ if (!raw) {
2236
+ return [
2237
+ new CapxulError({
2238
+ code: "NOT_FOUND",
2239
+ message: `tokenTransfer (txHash=${input.txHash}, logIndex=${input.logIndex}) not found or not visible to caller.`,
2240
+ details: {
2241
+ txHash: input.txHash,
2242
+ logIndex: input.logIndex,
2243
+ chainId: input.chainId
2244
+ }
2245
+ }),
2246
+ null
2247
+ ];
2248
+ }
2249
+ return [null, brandRow(raw)];
2250
+ } catch (cause) {
2251
+ return [fromConvexError(cause), null];
2252
+ }
2253
+ }
2254
+ };
2255
+ }
2256
+
1235
2257
  // src/core/virtual-accounts.ts
1236
2258
  function createVirtualAccountsClient() {
1237
2259
  return {
@@ -1253,59 +2275,6 @@ function createVirtualCardsClient() {
1253
2275
  cancel: async () => stub("virtualCards.cancel")
1254
2276
  };
1255
2277
  }
1256
-
1257
- // ../observability/src/try-catch.ts
1258
- async function tryCatch(promise) {
1259
- try {
1260
- return [null, await promise];
1261
- } catch (e) {
1262
- return [e instanceof Error ? e : new Error(String(e)), null];
1263
- }
1264
- }
1265
-
1266
- // ../observability/src/debug-log.ts
1267
- function isDevelopmentBuild() {
1268
- if (typeof process === "undefined") {
1269
- return false;
1270
- }
1271
- return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
1272
- }
1273
- function debugLog(line) {
1274
- if (!isDevelopmentBuild()) return;
1275
- if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
1276
- console.info(line);
1277
- return;
1278
- }
1279
- if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
1280
- process.stderr.write(`${line}
1281
- `);
1282
- }
1283
- }
1284
- function formatDebugValue(value) {
1285
- if (value === void 0 || value === "") return "";
1286
- if (typeof value === "string") return value;
1287
- try {
1288
- return JSON.stringify(value);
1289
- } catch {
1290
- return String(value);
1291
- }
1292
- }
1293
- function track(...args) {
1294
- const [name, props] = args;
1295
- debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
1296
- }
1297
- function formatDebugValue2(value) {
1298
- if (value === void 0 || value === "") return "";
1299
- if (typeof value === "string") return value;
1300
- try {
1301
- return JSON.stringify(value);
1302
- } catch {
1303
- return String(value);
1304
- }
1305
- }
1306
- function identify(userId, traits) {
1307
- debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
1308
- }
1309
2278
  function createAuthFlowMachine(client) {
1310
2279
  return setup({
1311
2280
  types: {},
@@ -1581,122 +2550,6 @@ function emailDomain(email) {
1581
2550
  const domain = email.split("@")[1]?.trim().toLowerCase();
1582
2551
  return domain || "unknown";
1583
2552
  }
1584
-
1585
- // ../platform-kernel/src/ids.ts
1586
- function makePrefixedIdConstructor(prefix, fieldName) {
1587
- const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
1588
- return (raw) => {
1589
- if (typeof raw !== "string" || !re.test(raw)) {
1590
- throw new Error(
1591
- `Invalid ${fieldName}: expected string matching ^${prefix}_[A-Za-z0-9_\\-]+$, got ${String(raw)}`
1592
- );
1593
- }
1594
- return raw;
1595
- };
1596
- }
1597
- var toAccountId = makePrefixedIdConstructor(
1598
- "acct",
1599
- "accountId"
1600
- );
1601
- var toOrganizationId = makePrefixedIdConstructor("org", "organizationId");
1602
- var toMemberId = makePrefixedIdConstructor(
1603
- "mem",
1604
- "memberId"
1605
- );
1606
- var toSafeId = makePrefixedIdConstructor(
1607
- "safe",
1608
- "safeId"
1609
- );
1610
- var toTreasuryId = makePrefixedIdConstructor(
1611
- "try",
1612
- "treasuryId"
1613
- );
1614
- var toApiKeyId = makePrefixedIdConstructor(
1615
- "ak",
1616
- "apiKeyId"
1617
- );
1618
- var toOperationId = makePrefixedIdConstructor(
1619
- "op",
1620
- "operationId"
1621
- );
1622
- var toKycProfileId = makePrefixedIdConstructor(
1623
- "kyc",
1624
- "kycProfileId"
1625
- );
1626
- var toKybProfileId = makePrefixedIdConstructor(
1627
- "kyb",
1628
- "kybProfileId"
1629
- );
1630
- var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
1631
- var toPaymentId = makePrefixedIdConstructor(
1632
- "pay",
1633
- "paymentId"
1634
- );
1635
- var toWithdrawalId = makePrefixedIdConstructor(
1636
- "wd",
1637
- "withdrawalId"
1638
- );
1639
- var toWebhookEndpointId = makePrefixedIdConstructor("we", "webhookEndpointId");
1640
- var toWebhookEventId = makePrefixedIdConstructor("evt", "webhookEventId");
1641
- var toSubAccountId = makePrefixedIdConstructor(
1642
- "sub",
1643
- "subAccountId"
1644
- );
1645
- var toVirtualAccountId = makePrefixedIdConstructor("va", "virtualAccountId");
1646
- var toVirtualCardId = makePrefixedIdConstructor(
1647
- "vc",
1648
- "virtualCardId"
1649
- );
1650
- var toTransferId = makePrefixedIdConstructor(
1651
- "txfr",
1652
- "transferId"
1653
- );
1654
- var toDocumentId = makePrefixedIdConstructor(
1655
- "doc",
1656
- "documentId"
1657
- );
1658
- var toBalanceLedgerEntryId = makePrefixedIdConstructor("bal", "balanceLedgerEntryId");
1659
-
1660
- // ../platform-kernel/src/value-objects.ts
1661
- var PHONE_NUMBER_RE = /^\+[1-9]\d{1,14}$/;
1662
- function toPhoneNumber(raw) {
1663
- if (typeof raw !== "string" || !PHONE_NUMBER_RE.test(raw)) {
1664
- throw new Error(
1665
- `Invalid phoneNumber: expected E.164 string matching ^\\+[1-9]\\d{1,14}$, got ${String(raw)}`
1666
- );
1667
- }
1668
- return raw;
1669
- }
1670
- var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1671
- function toEmail(raw) {
1672
- if (typeof raw !== "string") {
1673
- throw new Error(
1674
- `Invalid email: expected string, got ${String(raw)}`
1675
- );
1676
- }
1677
- const lowered = raw.trim().toLowerCase();
1678
- if (!EMAIL_RE.test(lowered)) {
1679
- throw new Error(
1680
- `Invalid email: expected local@domain.tld, got ${String(raw)}`
1681
- );
1682
- }
1683
- return lowered;
1684
- }
1685
- var USERNAME_RE = /^[a-z][a-z0-9_-]{2,29}$/;
1686
- function toUsername(raw) {
1687
- if (typeof raw !== "string") {
1688
- throw new Error(
1689
- `Invalid username: expected string, got ${String(raw)}`
1690
- );
1691
- }
1692
- const lowered = raw.toLowerCase();
1693
- if (!USERNAME_RE.test(lowered)) {
1694
- throw new Error(
1695
- `Invalid username: expected 3-30 chars, letter-first, [a-z0-9_-], got ${String(raw)}`
1696
- );
1697
- }
1698
- return lowered;
1699
- }
1700
2553
  function createProvisioningMachine(client) {
1701
2554
  return setup({
1702
2555
  types: {},
@@ -2083,12 +2936,13 @@ function createCapxulClient(config = {}) {
2083
2936
  organizations: createOrganizationsClient(config),
2084
2937
  payments: createPaymentsClient(config),
2085
2938
  transfers: createTransfersClient(),
2086
- withdrawals: createWithdrawalsClient(),
2939
+ tokenTransfers: createTokenTransfersClient(config),
2940
+ withdrawals: createWithdrawalsClient(config),
2087
2941
  documents: createDocumentsClient(),
2088
2942
  subAccounts: createSubAccountsClient(),
2089
2943
  virtualAccounts: createVirtualAccountsClient(),
2090
2944
  virtualCards: createVirtualCardsClient(),
2091
- externalAccounts: createExternalAccountsClient(),
2945
+ externalAccounts: createExternalAccountsClient(config),
2092
2946
  operations: createOperationsClient(config),
2093
2947
  webhookEndpoints: createWebhookEndpointsClient(),
2094
2948
  webhookEvents: createWebhookEventsClient(),
@@ -2201,4 +3055,4 @@ function isWebhookEvent(value) {
2201
3055
  return typeof candidate.id === "string" && typeof candidate.type === "string" && typeof candidate.createdAt === "string" && (candidate.operationId === void 0 || typeof candidate.operationId === "string") && (candidate.correlationId === void 0 || typeof candidate.correlationId === "string") && !!candidate.data && typeof candidate.data === "object" && !Array.isArray(candidate.data);
2202
3056
  }
2203
3057
 
2204
- export { CapxulError, createAuthFlowMachine, createCapxulClient, createLocalSigner, createOnboardingFlowMachine, createProvisioningMachine as createProvisioningFlowMachine, makeHttpTransport, matchAction, matchError, matchStatus, toAccountId, toApiKeyId, toBalanceLedgerEntryId, toDocumentId, toEmail, toExternalAccountId, toKybProfileId, toKycProfileId, toMemberId, toOperationId, toOrganizationId, toPaymentId, toPhoneNumber, toSafeId, toSubAccountId, toTransferId, toTreasuryId, toUsername, toVirtualAccountId, toVirtualCardId, toWebhookEndpointId, toWebhookEventId, toWithdrawalId, tryCatch, verifyWebhook };
3058
+ export { CapxulError, createAuthFlowMachine, createCapxulClient, createLocalSigner, createOnboardingFlowMachine, createProvisioningMachine as createProvisioningFlowMachine, makeHttpTransport, matchAction, matchError, matchStatus, toAccountId, toApiKeyId, toBalanceLedgerEntryId, toDocumentId, toEmail, toExternalAccountId, toKybProfileId, toKycProfileId, toMemberId, toOperationId, toOrganizationId, toPaymentId, toPhoneNumber, toSafeId, toSubAccountId, toTokenTransferId, toTransferId, toTreasuryId, toUsername, toVirtualAccountId, toVirtualCardId, toWebhookEndpointId, toWebhookEventId, toWithdrawalId, tryCatch, verifyWebhook };