@capxul/sdk 0.1.0-alpha.9 → 0.2.0-alpha.3

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/client.cjs CHANGED
@@ -1,10 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  var server = require('convex/server');
4
- var viem = require('viem');
5
4
  var accounts = require('permissionless/accounts');
5
+ var viem = require('viem');
6
6
  var accountAbstraction = require('viem/account-abstraction');
7
7
  var chains = require('viem/chains');
8
+ var safeDerive = require('@repo/safe-derive');
9
+ var browser = require('convex/browser');
8
10
  var xstate = require('xstate');
9
11
 
10
12
  // src/_generated/api.js
@@ -122,6 +124,159 @@ function identify(userId, traits) {
122
124
  debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
123
125
  }
124
126
 
127
+ // ../config/src/chain.ts
128
+ var CAPXUL_PAYMENTS_ADDRESS = "0xe740ea65521edc9bef0ea75d30b5334711db99f4";
129
+ var TEST_USDC_ADDRESS = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
130
+ var CAPXUL_API_BASE_URL = "https://elated-oyster-269.convex.site";
131
+
132
+ // ../config/src/timing.ts
133
+ var FLOW_INVOKE_TIMEOUT_MS = 3e4;
134
+
135
+ // ../config/src/errors.ts
136
+ var CapxulError2 = class extends Error {
137
+ code;
138
+ details;
139
+ correlationId;
140
+ layer;
141
+ constructor(code, message, options) {
142
+ super(message, options?.cause ? { cause: options.cause } : void 0);
143
+ this.code = code;
144
+ this.details = options?.details;
145
+ this.correlationId = options?.correlationId;
146
+ this.layer = options?.layer;
147
+ }
148
+ };
149
+ var Errors = {
150
+ notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
151
+ profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
152
+ smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
153
+ envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
154
+ openfortApi: (operation, cause) => new CapxulError2(
155
+ "PROVIDER_ERROR",
156
+ `Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
157
+ { cause, details: { provider: "openfort", operation } }
158
+ ),
159
+ shieldApi: (status, detail) => new CapxulError2(
160
+ "PROVIDER_ERROR",
161
+ `Shield API error (${status}): ${detail}`,
162
+ { details: { provider: "shield", status } }
163
+ ),
164
+ providerError: (provider, operation, cause) => (
165
+ // Public `message` is redacted to a fixed shape so provider-side
166
+ // exception text never leaks to the client. The original `cause`
167
+ // is preserved on `Error.cause` for server-side debugging via
168
+ // observability sinks (Sentry, console traces).
169
+ new CapxulError2(
170
+ "PROVIDER_ERROR",
171
+ `Provider error: ${provider} ${operation}`,
172
+ { cause, details: { provider, operation } }
173
+ )
174
+ ),
175
+ invalidInput: (field, reason) => new CapxulError2(
176
+ "INVALID_INPUT",
177
+ `Invalid ${field}: ${reason}`,
178
+ { details: { field, reason } }
179
+ ),
180
+ playerNotFound: (playerId) => new CapxulError2(
181
+ "PLAYER_NOT_FOUND",
182
+ playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
183
+ ),
184
+ accountNotFound: (accountId) => new CapxulError2(
185
+ "ACCOUNT_NOT_FOUND",
186
+ accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
187
+ ),
188
+ invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
189
+ permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
190
+ notFound: (resource, id) => new CapxulError2(
191
+ "NOT_FOUND",
192
+ id ? `${resource} ${id} not found` : `${resource} not found`
193
+ ),
194
+ idempotencyConflict: (details) => new CapxulError2(
195
+ "IDEMPOTENCY_CONFLICT",
196
+ "Idempotency key was already used for a different request",
197
+ { details }
198
+ ),
199
+ emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
200
+ details
201
+ }),
202
+ rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
203
+ details: { ...details }
204
+ }),
205
+ internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
206
+ /**
207
+ * Verification gate. Surfaced when a request hits a verification
208
+ * boundary the actor cannot cross under their current state. Two
209
+ * variants share this code:
210
+ *
211
+ * - Rail gate (Withdrawals v1 W2, #465): the resolved
212
+ * `external_account.kind` routes to a withdrawal rail (e.g.
213
+ * `fiat_offramp`, `card_payout`) that is not yet supported. Carries
214
+ * `details.rail` + `details.currentKind`.
215
+ * - KYC tier gate (legacy / future): the actor's KYC tier is below
216
+ * the required tier. Carries `details.requiredTier`.
217
+ *
218
+ * Code is shared because both expose the same UX shape ("you cannot
219
+ * proceed until verification advances"); the `details.*` keys
220
+ * differentiate the route.
221
+ */
222
+ verificationRequired: (details) => {
223
+ const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
224
+ return new CapxulError2("VERIFICATION_REQUIRED", message, {
225
+ details: { ...details }
226
+ });
227
+ }
228
+ };
229
+
230
+ // ../config/src/safe.ts
231
+ var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
232
+ var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
233
+ var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
234
+ var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
235
+
236
+ // ../config/src/org-roles.ts
237
+ function roleKeyFromLabel(label) {
238
+ const bytes = new TextEncoder().encode(label);
239
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
240
+ return "0x" + hex.padEnd(64, "0");
241
+ }
242
+ roleKeyFromLabel("OWNER");
243
+ roleKeyFromLabel("FINANCE_MANAGER");
244
+ roleKeyFromLabel("PAYMENTS_OPERATOR");
245
+ async function buildSafeAccount(signer, chain) {
246
+ try {
247
+ const publicClient = viem.createPublicClient({
248
+ chain: chains.baseSepolia,
249
+ transport: viem.http(chain.rpcUrl)
250
+ });
251
+ return await accounts.toSafeSmartAccount({
252
+ client: publicClient,
253
+ entryPoint: { address: accountAbstraction.entryPoint07Address, version: "0.7" },
254
+ version: "1.4.1",
255
+ owners: [signer],
256
+ saltNonce: computeSaltNonce(signer.address),
257
+ safeSingletonAddress: SAFE_L2_SINGLETON,
258
+ safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
259
+ safeModuleSetupAddress: SAFE_MODULE_SETUP,
260
+ safe4337ModuleAddress: SAFE_4337_MODULE,
261
+ safeModules: [],
262
+ setupTransactions: []
263
+ });
264
+ } catch (cause) {
265
+ throw new CapxulError({
266
+ code: "NETWORK_ERROR",
267
+ message: cause instanceof Error ? cause.message : String(cause),
268
+ cause,
269
+ details: { chainId: chain.chainId }
270
+ });
271
+ }
272
+ }
273
+ function computeSaltNonce(ownerAddress) {
274
+ return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
275
+ }
276
+ function deriveSafeAddress(signerAddress) {
277
+ return safeDerive.deriveSafeAddress(signerAddress, safeDerive.defaultSafeDeriveConfig);
278
+ }
279
+
125
280
  // ../platform-kernel/src/ids.ts
126
281
  function makePrefixedIdConstructor(prefix, fieldName) {
127
282
  const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
@@ -134,12 +289,24 @@ function makePrefixedIdConstructor(prefix, fieldName) {
134
289
  return raw;
135
290
  };
136
291
  }
292
+ var toSafeId = makePrefixedIdConstructor(
293
+ "safe",
294
+ "safeId"
295
+ );
296
+ var toTreasuryId = makePrefixedIdConstructor(
297
+ "try",
298
+ "treasuryId"
299
+ );
137
300
  var toOperationId = makePrefixedIdConstructor(
138
301
  "op",
139
302
  "operationId"
140
303
  );
141
304
  var toCorrelationId = makePrefixedIdConstructor("ctx", "correlationId");
142
305
  var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
306
+ var toSubAccountId = makePrefixedIdConstructor(
307
+ "sub",
308
+ "subAccountId"
309
+ );
143
310
 
144
311
  // src/core/external-accounts.ts
145
312
  function brandExternalAccount(raw) {
@@ -156,13 +323,13 @@ function brandExternalAccount(raw) {
156
323
  function createExternalAccountsClient(config = {}) {
157
324
  return {
158
325
  retrieve: async (externalAccountId) => {
159
- if (!config.data) {
326
+ if (!config._data) {
160
327
  return stub(
161
328
  "externalAccounts.retrieve"
162
329
  );
163
330
  }
164
331
  const [err, raw] = await tryCatch(
165
- config.data.query(api.externalAccounts.queries.retrievePersonal, {
332
+ config._data.query(api.externalAccounts.queries.retrievePersonal, {
166
333
  externalAccountId
167
334
  })
168
335
  );
@@ -184,11 +351,11 @@ function createExternalAccountsClient(config = {}) {
184
351
  return [null, brandExternalAccount(raw)];
185
352
  },
186
353
  remove: async (externalAccountId) => {
187
- if (!config.data) {
354
+ if (!config._data) {
188
355
  return stub("externalAccounts.remove");
189
356
  }
190
357
  const [err] = await tryCatch(
191
- config.data.mutation(api.externalAccounts.mutations.removePersonal, {
358
+ config._data.mutation(api.externalAccounts.mutations.removePersonal, {
192
359
  externalAccountId
193
360
  })
194
361
  );
@@ -203,17 +370,203 @@ function createExternalAccountsClient(config = {}) {
203
370
  };
204
371
  }
205
372
 
373
+ // src/core/sub-accounts.ts
374
+ function malformedWireError(reason, raw) {
375
+ return new CapxulError({
376
+ code: "PROVIDER_ERROR",
377
+ message: `convex brandSubAccount failed: ${reason}`,
378
+ details: {
379
+ provider: "convex",
380
+ operation: "brandSubAccount",
381
+ reason,
382
+ // PII discipline (`.claude/rules/posthog.md`): user-authored
383
+ // strings on the wire (`name`, `purpose`) are customer-confidential
384
+ // — sub-account names like "Q3 Acquisition Reserve" or
385
+ // "Vendor ABC payments" must not flow into telemetry. We emit a
386
+ // structural keys-only sample via a strict ALLOWLIST so any future
387
+ // wire-shape addition (e.g. `recipientEmail`, `tags`) is dropped
388
+ // by construction rather than leaked through a denylist gap.
389
+ sample: safeSampleShape(raw)
390
+ }
391
+ });
392
+ }
393
+ function safeSampleShape(raw) {
394
+ if (raw === null || typeof raw !== "object") {
395
+ return { type: typeof raw };
396
+ }
397
+ const r = raw;
398
+ const balance = r.balance;
399
+ return {
400
+ object: typeof r.object === "string" ? r.object : typeof r.object,
401
+ idPresent: typeof r.id === "string" && r.id.length > 0,
402
+ // First 4 chars only — enough to distinguish "sub_" prefixed IDs
403
+ // from accidental other resource IDs without leaking the full ID.
404
+ idPrefix: typeof r.id === "string" ? r.id.slice(0, 4) : void 0,
405
+ parentKind: r.parent !== null && typeof r.parent === "object" ? r.parent.kind : typeof r.parent,
406
+ status: r.status,
407
+ hasName: typeof r.name === "string",
408
+ hasPurpose: r.purpose !== void 0,
409
+ balanceShape: balance !== null && typeof balance === "object" ? Object.keys(balance).sort() : typeof balance,
410
+ createdAtType: typeof r.createdAt,
411
+ updatedAtType: typeof r.updatedAt
412
+ };
413
+ }
414
+ function isMoneyShape(v) {
415
+ if (typeof v !== "object" || v === null) return false;
416
+ const m = v;
417
+ return typeof m.value === "string" && typeof m.currency === "string";
418
+ }
419
+ function isParentShape(v) {
420
+ if (typeof v !== "object" || v === null) return false;
421
+ const p = v;
422
+ return (p.kind === "account" || p.kind === "organization") && typeof p.id === "string";
423
+ }
424
+ function isFiniteNonNegativeInteger(v) {
425
+ return typeof v === "number" && Number.isFinite(v) && Number.isInteger(v) && v >= 0;
426
+ }
427
+ function validateWireSubAccount(raw) {
428
+ if (typeof raw !== "object" || raw === null) {
429
+ return { ok: false, reason: "not an object" };
430
+ }
431
+ const r = raw;
432
+ if (r.object !== "sub_account") {
433
+ return { ok: false, reason: `object must be "sub_account" (got ${String(r.object)})` };
434
+ }
435
+ if (typeof r.id !== "string" || r.id.length === 0) {
436
+ return { ok: false, reason: "id must be a non-empty string" };
437
+ }
438
+ if (!isParentShape(r.parent)) {
439
+ return { ok: false, reason: "parent must be { kind: 'account' | 'organization', id: string }" };
440
+ }
441
+ if (typeof r.name !== "string") {
442
+ return { ok: false, reason: "name must be a string" };
443
+ }
444
+ if (r.purpose !== void 0 && typeof r.purpose !== "string") {
445
+ return { ok: false, reason: "purpose must be a string when present" };
446
+ }
447
+ if (r.status !== "active" && r.status !== "archived") {
448
+ return { ok: false, reason: `status must be "active" | "archived" (got ${String(r.status)})` };
449
+ }
450
+ if (!isMoneyShape(r.balance)) {
451
+ return { ok: false, reason: "balance must be { value: string, currency: string }" };
452
+ }
453
+ if (!isFiniteNonNegativeInteger(r.createdAt)) {
454
+ return { ok: false, reason: "createdAt must be a finite non-negative integer (epoch ms)" };
455
+ }
456
+ if (r.updatedAt !== void 0 && !isFiniteNonNegativeInteger(r.updatedAt)) {
457
+ return { ok: false, reason: "updatedAt must be a finite non-negative integer when present" };
458
+ }
459
+ return { ok: true, value: r };
460
+ }
461
+ function brandSubAccount(raw) {
462
+ const result = validateWireSubAccount(raw);
463
+ if (!result.ok) {
464
+ throw malformedWireError(result.reason, raw);
465
+ }
466
+ const wire = result.value;
467
+ return {
468
+ object: wire.object,
469
+ id: toSubAccountId(wire.id),
470
+ parent: wire.parent,
471
+ name: wire.name,
472
+ ...wire.purpose !== void 0 ? { purpose: wire.purpose } : {},
473
+ status: wire.status,
474
+ balance: wire.balance,
475
+ createdAt: new Date(wire.createdAt).toISOString()
476
+ };
477
+ }
478
+ function tryBrandSubAccount(raw) {
479
+ try {
480
+ return [null, brandSubAccount(raw)];
481
+ } catch (err) {
482
+ if (err instanceof CapxulError && err.code === "PROVIDER_ERROR") {
483
+ return [err, null];
484
+ }
485
+ return [
486
+ malformedWireError(
487
+ err instanceof Error ? err.message : String(err),
488
+ raw
489
+ ),
490
+ null
491
+ ];
492
+ }
493
+ }
494
+ function createSubAccountsClient(config = {}) {
495
+ return {
496
+ retrieve: async (subAccountId) => {
497
+ if (!config._data) {
498
+ return stub("subAccounts.retrieve");
499
+ }
500
+ const [err, raw] = await tryCatch(
501
+ config._data.query(api.subAccounts.queries.retrieve, {
502
+ subAccountId
503
+ })
504
+ );
505
+ if (err) {
506
+ return [
507
+ fromConvexError(err),
508
+ null
509
+ ];
510
+ }
511
+ if (!raw) {
512
+ return [
513
+ new CapxulError({
514
+ code: "NOT_FOUND",
515
+ message: `sub_account ${subAccountId} not found`
516
+ }),
517
+ null
518
+ ];
519
+ }
520
+ const [brandErr, branded] = tryBrandSubAccount(raw);
521
+ if (brandErr) {
522
+ return [brandErr, null];
523
+ }
524
+ return [null, branded];
525
+ },
526
+ remove: async (subAccountId) => {
527
+ if (!config._data) {
528
+ return stub("subAccounts.remove");
529
+ }
530
+ const [err, raw] = await tryCatch(
531
+ config._data.mutation(api.subAccounts.mutations.archive, {
532
+ subAccountId
533
+ })
534
+ );
535
+ if (err) {
536
+ return [
537
+ fromConvexError(err),
538
+ null
539
+ ];
540
+ }
541
+ if (!raw) {
542
+ return [
543
+ new CapxulError({
544
+ code: "NOT_FOUND",
545
+ message: `sub_account ${subAccountId} not found`
546
+ }),
547
+ null
548
+ ];
549
+ }
550
+ const [brandErr, branded] = tryBrandSubAccount(raw);
551
+ if (brandErr) {
552
+ return [brandErr, null];
553
+ }
554
+ return [null, branded];
555
+ }
556
+ };
557
+ }
558
+
206
559
  // src/core/accounts.ts
207
560
  function createAccountExternalAccountsClient(config) {
208
561
  return {
209
562
  create: async (input) => {
210
- if (!config.data) {
563
+ if (!config._data) {
211
564
  return stub(
212
565
  "accounts.externalAccounts.create"
213
566
  );
214
567
  }
215
568
  const [err, raw] = await tryCatch(
216
- config.data.mutation(
569
+ config._data.mutation(
217
570
  api.externalAccounts.mutations.createPersonal,
218
571
  {
219
572
  kind: input.kind,
@@ -251,13 +604,13 @@ function createAccountExternalAccountsClient(config) {
251
604
  ];
252
605
  },
253
606
  list: async (input) => {
254
- if (!config.data) {
607
+ if (!config._data) {
255
608
  return stub(
256
609
  "accounts.externalAccounts.list"
257
610
  );
258
611
  }
259
612
  const [err, result] = await tryCatch(
260
- config.data.query(api.externalAccounts.queries.listPersonal, {
613
+ config._data.query(api.externalAccounts.queries.listPersonal, {
261
614
  limit: input.limit,
262
615
  cursor: input.cursor
263
616
  })
@@ -280,13 +633,13 @@ function createAccountExternalAccountsClient(config) {
280
633
  ];
281
634
  },
282
635
  retrieve: async (externalAccountId) => {
283
- if (!config.data) {
636
+ if (!config._data) {
284
637
  return stub(
285
638
  "accounts.externalAccounts.retrieve"
286
639
  );
287
640
  }
288
641
  const [err, raw] = await tryCatch(
289
- config.data.query(api.externalAccounts.queries.retrievePersonal, {
642
+ config._data.query(api.externalAccounts.queries.retrievePersonal, {
290
643
  externalAccountId
291
644
  })
292
645
  );
@@ -313,11 +666,11 @@ function createAccountExternalAccountsClient(config) {
313
666
  ];
314
667
  },
315
668
  remove: async (externalAccountId) => {
316
- if (!config.data) {
669
+ if (!config._data) {
317
670
  return stub("accounts.externalAccounts.remove");
318
671
  }
319
672
  const [err] = await tryCatch(
320
- config.data.mutation(api.externalAccounts.mutations.removePersonal, {
673
+ config._data.mutation(api.externalAccounts.mutations.removePersonal, {
321
674
  externalAccountId
322
675
  })
323
676
  );
@@ -331,14 +684,162 @@ function createAccountExternalAccountsClient(config) {
331
684
  }
332
685
  };
333
686
  }
687
+ function createAccountSubAccountsClient(config) {
688
+ return {
689
+ create: async (input) => {
690
+ if (!config._data) {
691
+ return stub(
692
+ "accounts.subAccounts.create"
693
+ );
694
+ }
695
+ const [err, raw] = await tryCatch(
696
+ config._data.mutation(api.subAccounts.mutations.create, {
697
+ parent: { kind: "account", id: input.accountId },
698
+ name: input.name,
699
+ purpose: input.purpose
700
+ })
701
+ );
702
+ if (err) {
703
+ return [
704
+ fromConvexError(err),
705
+ null
706
+ ];
707
+ }
708
+ if (!raw) {
709
+ return [
710
+ new CapxulError({
711
+ code: "NOT_FOUND",
712
+ message: "sub_account creation returned no resource"
713
+ }),
714
+ null
715
+ ];
716
+ }
717
+ const [brandErr, branded] = tryBrandSubAccount(raw);
718
+ if (brandErr) {
719
+ return [
720
+ brandErr,
721
+ null
722
+ ];
723
+ }
724
+ return [null, branded];
725
+ },
726
+ list: async (input) => {
727
+ if (!config._data) {
728
+ return stub(
729
+ "accounts.subAccounts.list"
730
+ );
731
+ }
732
+ const [err, rows] = await tryCatch(
733
+ config._data.query(api.subAccounts.queries.listByAccount, {
734
+ accountId: input.accountId
735
+ })
736
+ );
737
+ if (err) {
738
+ return [
739
+ fromConvexError(err),
740
+ null
741
+ ];
742
+ }
743
+ const branded = [];
744
+ for (const row of rows) {
745
+ const [brandErr, value] = tryBrandSubAccount(row);
746
+ if (brandErr) {
747
+ return [
748
+ brandErr,
749
+ null
750
+ ];
751
+ }
752
+ branded.push(value);
753
+ }
754
+ return [
755
+ null,
756
+ {
757
+ object: "list",
758
+ data: branded,
759
+ page: { hasMore: false }
760
+ }
761
+ ];
762
+ },
763
+ retrieve: async (subAccountId) => {
764
+ if (!config._data) {
765
+ return stub(
766
+ "accounts.subAccounts.retrieve"
767
+ );
768
+ }
769
+ const [err, raw] = await tryCatch(
770
+ config._data.query(api.subAccounts.queries.retrieve, {
771
+ subAccountId
772
+ })
773
+ );
774
+ if (err) {
775
+ return [
776
+ fromConvexError(err),
777
+ null
778
+ ];
779
+ }
780
+ if (!raw) {
781
+ return [
782
+ new CapxulError({
783
+ code: "NOT_FOUND",
784
+ message: `sub_account ${subAccountId} not found`
785
+ }),
786
+ null
787
+ ];
788
+ }
789
+ const [brandErr, branded] = tryBrandSubAccount(raw);
790
+ if (brandErr) {
791
+ return [
792
+ brandErr,
793
+ null
794
+ ];
795
+ }
796
+ return [null, branded];
797
+ },
798
+ remove: async (subAccountId) => {
799
+ if (!config._data) {
800
+ return stub(
801
+ "accounts.subAccounts.remove"
802
+ );
803
+ }
804
+ const [err, raw] = await tryCatch(
805
+ config._data.mutation(api.subAccounts.mutations.archive, {
806
+ subAccountId
807
+ })
808
+ );
809
+ if (err) {
810
+ return [
811
+ fromConvexError(err),
812
+ null
813
+ ];
814
+ }
815
+ if (!raw) {
816
+ return [
817
+ new CapxulError({
818
+ code: "NOT_FOUND",
819
+ message: `sub_account ${subAccountId} not found`
820
+ }),
821
+ null
822
+ ];
823
+ }
824
+ const [brandErr, branded] = tryBrandSubAccount(raw);
825
+ if (brandErr) {
826
+ return [
827
+ brandErr,
828
+ null
829
+ ];
830
+ }
831
+ return [null, branded];
832
+ }
833
+ };
834
+ }
334
835
  function createAccountsClient(config = {}) {
335
836
  return {
336
837
  retrieve: async (accountId) => {
337
- if (!config.data) {
838
+ if (!config._data) {
338
839
  return stub("accounts.retrieve");
339
840
  }
340
841
  try {
341
- const account = await config.data.query(
842
+ const account = await config._data.query(
342
843
  api.openfort.queries.getMyAccount,
343
844
  {}
344
845
  );
@@ -362,7 +863,7 @@ function createAccountsClient(config = {}) {
362
863
  },
363
864
  lookup: async () => stub("accounts.lookup"),
364
865
  update: async (input) => {
365
- if (!config.data) {
866
+ if (!config._data) {
366
867
  return stub("accounts.update");
367
868
  }
368
869
  if (input.countryCode !== void 0) {
@@ -376,7 +877,7 @@ function createAccountsClient(config = {}) {
376
877
  ];
377
878
  }
378
879
  try {
379
- const current = await config.data.query(
880
+ const current = await config._data.query(
380
881
  api.openfort.queries.getMyAccount,
381
882
  {}
382
883
  );
@@ -393,11 +894,11 @@ function createAccountsClient(config = {}) {
393
894
  null
394
895
  ];
395
896
  }
396
- await config.data.mutation(api.openfort.mutations.updateProfile, {
897
+ await config._data.mutation(api.openfort.mutations.updateProfile, {
397
898
  displayName: input.name,
398
899
  username: input.username
399
900
  });
400
- const updated = await config.data.query(
901
+ const updated = await config._data.query(
401
902
  api.openfort.queries.getMyAccount,
402
903
  {}
403
904
  );
@@ -407,7 +908,7 @@ function createAccountsClient(config = {}) {
407
908
  }
408
909
  },
409
910
  provisionPersonal: async (input) => {
410
- if (!config.data) {
911
+ if (!config._data) {
411
912
  return stub(
412
913
  "accounts.provisionPersonal"
413
914
  );
@@ -422,17 +923,17 @@ function createAccountsClient(config = {}) {
422
923
  ];
423
924
  }
424
925
  try {
425
- await config.data.mutation(
926
+ await config._data.mutation(
426
927
  api.safe.mutations.provisionLocalPersonalAccount,
427
928
  {
428
929
  displayName: input.displayName,
429
930
  username: input.username,
430
931
  countryCode: input.countryCode,
431
932
  eoaAddress: input.signerProvider.signerAddress,
432
- safeAddress: input.signerProvider.safeAddress
933
+ safeAddress: deriveSafeAddress(input.signerProvider.signerAddress)
433
934
  }
434
935
  );
435
- const account = await config.data.query(
936
+ const account = await config._data.query(
436
937
  api.openfort.queries.getMyAccount,
437
938
  {}
438
939
  );
@@ -455,176 +956,99 @@ function createAccountsClient(config = {}) {
455
956
  },
456
957
  safes: {
457
958
  retrieve: async (safeId) => {
458
- if (!config.data) {
959
+ if (!config._data) {
459
960
  return stub("accounts.safes.retrieve");
460
961
  }
461
962
  try {
462
- const safe = await config.data.query(
963
+ const safe = await config._data.query(
463
964
  api.safe.queries.retrieveAccountSafe,
464
965
  { safeId }
465
- );
466
- if (!safe) {
467
- return [
468
- new CapxulError({
469
- code: "NOT_FOUND",
470
- message: `safe ${safeId} not found`
471
- }),
472
- null
473
- ];
474
- }
475
- return [null, safe];
476
- } catch (cause) {
477
- return [
478
- fromConvexError(cause),
479
- null
480
- ];
481
- }
482
- }
483
- },
484
- kycProfiles: {
485
- create: async () => stub("accounts.kycProfiles.create"),
486
- retrieve: async () => stub("accounts.kycProfiles.retrieve")
487
- },
488
- externalAccounts: createAccountExternalAccountsClient(config),
489
- subAccounts: {
490
- create: async () => stub("accounts.subAccounts.create"),
491
- list: async () => stub("accounts.subAccounts.list"),
492
- retrieve: async () => stub("accounts.subAccounts.retrieve"),
493
- remove: async () => stub("accounts.subAccounts.remove")
494
- },
495
- balanceLedger: {
496
- list: async () => stub(
497
- "accounts.balanceLedger.list"
498
- ),
499
- retrieve: async () => stub(
500
- "accounts.balanceLedger.retrieve"
501
- )
502
- }
503
- };
504
- }
505
-
506
- // src/core/api-keys.ts
507
- function createApiKeysClient() {
508
- return {
509
- create: async () => stub("apiKeys.create"),
510
- retrieve: async () => stub("apiKeys.retrieve"),
511
- list: async () => stub("apiKeys.list"),
512
- revoke: async () => stub("apiKeys.revoke")
513
- };
514
- }
515
-
516
- // ../config/src/chain.ts
517
- var CAPXUL_PAYMENTS_ADDRESS = "0xe740ea65521edc9bef0ea75d30b5334711db99f4";
518
- var TEST_USDC_ADDRESS = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
519
- var CAPXUL_API_BASE_URL = "https://elated-oyster-269.convex.site";
520
-
521
- // ../config/src/timing.ts
522
- var FLOW_INVOKE_TIMEOUT_MS = 3e4;
523
-
524
- // ../config/src/errors.ts
525
- var CapxulError2 = class extends Error {
526
- code;
527
- details;
528
- correlationId;
529
- layer;
530
- constructor(code, message, options) {
531
- super(message, options?.cause ? { cause: options.cause } : void 0);
532
- this.code = code;
533
- this.details = options?.details;
534
- this.correlationId = options?.correlationId;
535
- this.layer = options?.layer;
536
- }
537
- };
538
- var Errors = {
539
- notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
540
- profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
541
- smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
542
- envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
543
- openfortApi: (operation, cause) => new CapxulError2(
544
- "PROVIDER_ERROR",
545
- `Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
546
- { cause, details: { provider: "openfort", operation } }
547
- ),
548
- shieldApi: (status, detail) => new CapxulError2(
549
- "PROVIDER_ERROR",
550
- `Shield API error (${status}): ${detail}`,
551
- { details: { provider: "shield", status } }
552
- ),
553
- providerError: (provider, operation, cause) => new CapxulError2(
554
- "PROVIDER_ERROR",
555
- `${provider} ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
556
- { cause, details: { provider, operation } }
557
- ),
558
- invalidInput: (field, reason) => new CapxulError2(
559
- "INVALID_INPUT",
560
- `Invalid ${field}: ${reason}`,
561
- { details: { field, reason } }
562
- ),
563
- playerNotFound: (playerId) => new CapxulError2(
564
- "PLAYER_NOT_FOUND",
565
- playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
566
- ),
567
- accountNotFound: (accountId) => new CapxulError2(
568
- "ACCOUNT_NOT_FOUND",
569
- accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
570
- ),
571
- invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
572
- permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
573
- notFound: (resource, id) => new CapxulError2(
574
- "NOT_FOUND",
575
- id ? `${resource} ${id} not found` : `${resource} not found`
576
- ),
577
- idempotencyConflict: (details) => new CapxulError2(
578
- "IDEMPOTENCY_CONFLICT",
579
- "Idempotency key was already used for a different request",
580
- { details }
581
- ),
582
- emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
583
- details
584
- }),
585
- rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
586
- details: { ...details }
587
- }),
588
- internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
589
- /**
590
- * Verification gate. Surfaced when a request hits a verification
591
- * boundary the actor cannot cross under their current state. Two
592
- * variants share this code:
593
- *
594
- * - Rail gate (Withdrawals v1 W2, #465): the resolved
595
- * `external_account.kind` routes to a withdrawal rail (e.g.
596
- * `fiat_offramp`, `card_payout`) that is not yet supported. Carries
597
- * `details.rail` + `details.currentKind`.
598
- * - KYC tier gate (legacy / future): the actor's KYC tier is below
599
- * the required tier. Carries `details.requiredTier`.
600
- *
601
- * Code is shared because both expose the same UX shape ("you cannot
602
- * proceed until verification advances"); the `details.*` keys
603
- * differentiate the route.
604
- */
605
- verificationRequired: (details) => {
606
- const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
607
- return new CapxulError2("VERIFICATION_REQUIRED", message, {
608
- details: { ...details }
609
- });
610
- }
611
- };
612
-
613
- // ../config/src/safe.ts
614
- var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
615
- var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
616
- var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
617
- var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
966
+ );
967
+ if (!safe) {
968
+ return [
969
+ new CapxulError({
970
+ code: "NOT_FOUND",
971
+ message: `safe ${safeId} not found`
972
+ }),
973
+ null
974
+ ];
975
+ }
976
+ return [null, safe];
977
+ } catch (cause) {
978
+ return [
979
+ fromConvexError(cause),
980
+ null
981
+ ];
982
+ }
983
+ }
984
+ },
985
+ kycProfiles: {
986
+ create: async () => stub("accounts.kycProfiles.create"),
987
+ retrieve: async () => stub("accounts.kycProfiles.retrieve")
988
+ },
989
+ externalAccounts: createAccountExternalAccountsClient(config),
990
+ subAccounts: createAccountSubAccountsClient(config),
991
+ balanceLedger: {
992
+ list: async (input) => {
993
+ if (!config._data) {
994
+ return stub(
995
+ "accounts.balanceLedger.list"
996
+ );
997
+ }
998
+ try {
999
+ const accountId = input.accountId.replace(/^acct_/, "");
1000
+ const page = await config._data.query(
1001
+ api.balanceLedger.queries.listForAccount,
1002
+ { accountId, limit: input.limit, cursor: input.cursor }
1003
+ );
1004
+ return [null, page];
1005
+ } catch (cause) {
1006
+ return [fromConvexError(cause), null];
1007
+ }
1008
+ },
1009
+ retrieve: async (entryId) => {
1010
+ if (!config._data) {
1011
+ return stub(
1012
+ "accounts.balanceLedger.retrieve"
1013
+ );
1014
+ }
1015
+ try {
1016
+ const entry = await config._data.query(
1017
+ api.balanceLedger.queries.retrieve,
1018
+ { entryId }
1019
+ );
1020
+ if (!entry) {
1021
+ return [
1022
+ new CapxulError({
1023
+ code: "NOT_FOUND",
1024
+ message: `balance_ledger_entry ${entryId} not found`
1025
+ }),
1026
+ null
1027
+ ];
1028
+ }
1029
+ return [null, entry];
1030
+ } catch (cause) {
1031
+ return [fromConvexError(cause), null];
1032
+ }
1033
+ }
1034
+ }
1035
+ };
1036
+ }
618
1037
 
619
- // ../config/src/org-roles.ts
620
- function roleKeyFromLabel(label) {
621
- const bytes = new TextEncoder().encode(label);
622
- const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
623
- return "0x" + hex.padEnd(64, "0");
1038
+ // src/core/api-keys.ts
1039
+ function createApiKeysClient() {
1040
+ return {
1041
+ create: async () => stub("apiKeys.create"),
1042
+ retrieve: async () => stub("apiKeys.retrieve"),
1043
+ list: async () => stub("apiKeys.list"),
1044
+ revoke: async () => stub("apiKeys.revoke")
1045
+ };
1046
+ }
1047
+ function createDefaultDataClient(convexUrl, jwt) {
1048
+ const client = new browser.ConvexHttpClient(convexUrl);
1049
+ client.setAuth(jwt);
1050
+ return client;
624
1051
  }
625
- roleKeyFromLabel("OWNER");
626
- roleKeyFromLabel("FINANCE_MANAGER");
627
- roleKeyFromLabel("TEAM_LEAD");
628
1052
 
629
1053
  // src/transport.ts
630
1054
  function makeHttpTransport(config) {
@@ -955,7 +1379,7 @@ function readNonEmptyString(value) {
955
1379
 
956
1380
  // src/core/auth.ts
957
1381
  function createAuthClient(config = {}) {
958
- let dataClient = config.data ?? null;
1382
+ let dataClient = config._data ?? null;
959
1383
  const sessionStore = config.auth?.sessionStore ?? createMemorySessionStore();
960
1384
  const getTransport = createTransportProvider(config);
961
1385
  return {
@@ -1011,11 +1435,20 @@ function createAuthClient(config = {}) {
1011
1435
  ).toISOString()
1012
1436
  };
1013
1437
  sessionStore.set(session);
1014
- if (config.auth?.createDataClient) {
1438
+ if (!dataClient) {
1015
1439
  try {
1016
- dataClient = await config.auth.createDataClient(session);
1017
- mutableConfig(config).data = dataClient;
1018
- transport.markAuthenticated({ dataClient });
1440
+ const convexUrl = transport.convexUrl;
1441
+ if (!convexUrl || !session.convexJwt) {
1442
+ return [
1443
+ new CapxulError({
1444
+ code: "NETWORK_ERROR",
1445
+ message: "Cannot create data client: missing convex URL or JWT."
1446
+ }),
1447
+ null
1448
+ ];
1449
+ }
1450
+ dataClient = createDefaultDataClient(convexUrl, session.convexJwt);
1451
+ mutableConfig(config)._data = dataClient;
1019
1452
  } catch (cause) {
1020
1453
  return [
1021
1454
  new CapxulError({
@@ -1026,7 +1459,15 @@ function createAuthClient(config = {}) {
1026
1459
  null
1027
1460
  ];
1028
1461
  }
1462
+ } else {
1463
+ const injected = dataClient;
1464
+ if (typeof injected.refreshAuth === "function") {
1465
+ injected.refreshAuth();
1466
+ } else if (typeof injected.setAuth === "function" && session.convexJwt) {
1467
+ injected.setAuth(session.convexJwt);
1468
+ }
1029
1469
  }
1470
+ transport.markAuthenticated({ dataClient });
1030
1471
  if (!dataClient) {
1031
1472
  return [
1032
1473
  new CapxulError({
@@ -1054,7 +1495,7 @@ function createAuthClient(config = {}) {
1054
1495
  },
1055
1496
  completeBootstrap: async (input) => {
1056
1497
  const session = sessionStore.get();
1057
- const data = dataClient ?? config.data;
1498
+ const data = dataClient ?? config._data;
1058
1499
  if (!session || !data) {
1059
1500
  return [
1060
1501
  new CapxulError({
@@ -1064,23 +1505,29 @@ function createAuthClient(config = {}) {
1064
1505
  null
1065
1506
  ];
1066
1507
  }
1067
- if (input.signerProvider.kind !== "local-private-key") {
1508
+ const signerAddress = config.signer?.address;
1509
+ if (!signerAddress) {
1068
1510
  return [
1069
1511
  new CapxulError({
1070
1512
  code: "INVALID_INPUT",
1071
- message: "completeBootstrap currently supports local-private-key signer providers only."
1513
+ message: "completeBootstrap requires a signer to be configured on the client."
1072
1514
  }),
1073
1515
  null
1074
1516
  ];
1075
1517
  }
1076
1518
  try {
1519
+ const safeAddress = deriveSafeAddress(signerAddress);
1077
1520
  const result = await data.mutation(api.authBootstrap.completeBootstrap, {
1078
1521
  bootstrapToken: input.bootstrapToken,
1079
1522
  sessionToken: session.token,
1080
1523
  username: input.username,
1081
1524
  displayName: input.displayName,
1082
1525
  countryCode: input.countryCode,
1083
- signerProvider: input.signerProvider
1526
+ signerProvider: {
1527
+ kind: "local-private-key",
1528
+ signerAddress,
1529
+ safeAddress
1530
+ }
1084
1531
  });
1085
1532
  return [null, { kind: "authenticated", session, ...result }];
1086
1533
  } catch (cause) {
@@ -1094,7 +1541,7 @@ function createAuthClient(config = {}) {
1094
1541
  signOut: async () => {
1095
1542
  sessionStore.clear();
1096
1543
  dataClient = null;
1097
- mutableConfig(config).data = void 0;
1544
+ mutableConfig(config)._data = void 0;
1098
1545
  const transport = getTransport();
1099
1546
  transport?.clearAuth();
1100
1547
  return [null, void 0];
@@ -1165,6 +1612,9 @@ async function postBetterAuth(transport, path, body, code, signal) {
1165
1612
  }
1166
1613
  return [null, text ? JSON.parse(text) : void 0];
1167
1614
  } catch (cause) {
1615
+ if (cause instanceof CapxulError) {
1616
+ return [cause, null];
1617
+ }
1168
1618
  return [
1169
1619
  new CapxulError({
1170
1620
  code: "NETWORK_ERROR",
@@ -1203,7 +1653,7 @@ function parseBetterAuthError(text) {
1203
1653
  }
1204
1654
  }
1205
1655
  function isCapxulErrorCode2(code) {
1206
- 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";
1656
+ 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" || code === "INTERNAL_ERROR" || code === "ENV_MISSING" || code === "UNKNOWN" || code === "PROVIDER_ERROR";
1207
1657
  }
1208
1658
  async function exchangeConvexToken(transport, config, token, signal) {
1209
1659
  const path = config.auth?.convexTokenUrl ?? "/convex/token";
@@ -1233,6 +1683,9 @@ async function exchangeConvexToken(transport, config, token, signal) {
1233
1683
  }
1234
1684
  return [null, body.token];
1235
1685
  } catch (cause) {
1686
+ if (cause instanceof CapxulError) {
1687
+ return [cause, null];
1688
+ }
1236
1689
  return [
1237
1690
  new CapxulError({
1238
1691
  code: "NETWORK_ERROR",
@@ -1269,11 +1722,11 @@ function createOrgDocumentsClient() {
1269
1722
  function createMeClient(config = {}) {
1270
1723
  return {
1271
1724
  get: async () => {
1272
- if (!config.data) {
1725
+ if (!config._data) {
1273
1726
  return stub("me.get");
1274
1727
  }
1275
1728
  try {
1276
- const account = await config.data.query(
1729
+ const account = await config._data.query(
1277
1730
  api.openfort.queries.getMyAccount,
1278
1731
  {}
1279
1732
  );
@@ -1283,7 +1736,7 @@ function createMeClient(config = {}) {
1283
1736
  }
1284
1737
  },
1285
1738
  update: async (input) => {
1286
- if (!config.data) {
1739
+ if (!config._data) {
1287
1740
  return stub("me.update");
1288
1741
  }
1289
1742
  if (input.countryCode !== void 0) {
@@ -1297,11 +1750,11 @@ function createMeClient(config = {}) {
1297
1750
  ];
1298
1751
  }
1299
1752
  try {
1300
- await config.data.mutation(api.openfort.mutations.updateProfile, {
1753
+ await config._data.mutation(api.openfort.mutations.updateProfile, {
1301
1754
  displayName: input.name,
1302
1755
  username: input.username
1303
1756
  });
1304
- const account = await config.data.query(
1757
+ const account = await config._data.query(
1305
1758
  api.openfort.queries.getMyAccount,
1306
1759
  {}
1307
1760
  );
@@ -1316,11 +1769,11 @@ function createMeClient(config = {}) {
1316
1769
  // src/core/operations.ts
1317
1770
  function createOperationsClient(config = {}) {
1318
1771
  const retrieve = async (operationId) => {
1319
- if (!config.data) {
1772
+ if (!config._data) {
1320
1773
  return stub("operations.retrieve");
1321
1774
  }
1322
1775
  try {
1323
- const operation = await config.data.query(api.operations.queries.retrieve, {
1776
+ const operation = await config._data.query(api.operations.queries.retrieve, {
1324
1777
  operationId
1325
1778
  });
1326
1779
  if (!operation) {
@@ -1337,7 +1790,7 @@ function createOperationsClient(config = {}) {
1337
1790
  return {
1338
1791
  retrieve,
1339
1792
  wait: async (operationId, input = {}) => {
1340
- if (!config.data) {
1793
+ if (!config._data) {
1341
1794
  return stub("operations.wait");
1342
1795
  }
1343
1796
  const until = new Set(
@@ -1372,49 +1825,22 @@ function toTokenUnits(value, decimals = 6) {
1372
1825
  return viem.parseUnits(value, decimals);
1373
1826
  }
1374
1827
 
1375
- // src/internal/payment-token.ts
1376
- function resolvePaymentTokenAddress(currency) {
1828
+ // src/core/token-registry.ts
1829
+ function resolvePaymentToken(currency) {
1377
1830
  const normalized = currency.trim().toUpperCase();
1378
1831
  if (normalized === "USD" || normalized === "USDC") {
1379
- return TEST_USDC_ADDRESS.toLowerCase();
1832
+ return {
1833
+ address: TEST_USDC_ADDRESS.toLowerCase(),
1834
+ decimals: 6,
1835
+ symbol: "USDC"
1836
+ };
1380
1837
  }
1381
1838
  throw new CapxulError({
1382
- code: "NETWORK_ERROR",
1383
- message: `Currency ${currency} is not configured for on-chain payment submission.`,
1839
+ code: "NOT_IMPLEMENTED",
1840
+ message: `Currency ${currency} is not yet supported by the token registry.`,
1384
1841
  details: { currency: normalized }
1385
1842
  });
1386
1843
  }
1387
- async function buildSafeAccount(signer, chain) {
1388
- try {
1389
- const publicClient = viem.createPublicClient({
1390
- chain: chains.baseSepolia,
1391
- transport: viem.http(chain.rpcUrl)
1392
- });
1393
- return await accounts.toSafeSmartAccount({
1394
- client: publicClient,
1395
- entryPoint: { address: accountAbstraction.entryPoint07Address, version: "0.7" },
1396
- version: "1.4.1",
1397
- owners: [signer],
1398
- saltNonce: computeSaltNonce(signer.address),
1399
- safeSingletonAddress: SAFE_L2_SINGLETON,
1400
- safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
1401
- safeModuleSetupAddress: SAFE_MODULE_SETUP,
1402
- safe4337ModuleAddress: SAFE_4337_MODULE,
1403
- safeModules: [],
1404
- setupTransactions: []
1405
- });
1406
- } catch (cause) {
1407
- throw new CapxulError({
1408
- code: "NETWORK_ERROR",
1409
- message: cause instanceof Error ? cause.message : String(cause),
1410
- cause,
1411
- details: { chainId: chain.chainId }
1412
- });
1413
- }
1414
- }
1415
- function computeSaltNonce(ownerAddress) {
1416
- return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
1417
- }
1418
1844
  function createCapxulBundler(config) {
1419
1845
  const paymaster = accountAbstraction.createPaymasterClient({
1420
1846
  transport: viem.http(config.rpcUrl)
@@ -1521,13 +1947,13 @@ async function transferAsOwner(config, params) {
1521
1947
  function createPaymentsClient(config = {}) {
1522
1948
  return {
1523
1949
  create: async (input) => {
1524
- if (!config.data || !config.signer || !config.signing) {
1950
+ if (!config._data || !config.signer || !config.signing) {
1525
1951
  return stub("payments.create");
1526
1952
  }
1527
1953
  let created = null;
1528
1954
  let submitted = null;
1529
1955
  try {
1530
- created = await config.data.mutation(api.payments.mutations.create, {
1956
+ created = await config._data.mutation(api.payments.mutations.create, {
1531
1957
  to: input.to,
1532
1958
  amount: input.amount,
1533
1959
  reference: input.reference,
@@ -1535,15 +1961,21 @@ function createPaymentsClient(config = {}) {
1535
1961
  source: input.source
1536
1962
  });
1537
1963
  if (!created) {
1538
- return [new CapxulError({
1539
- code: "NETWORK_ERROR",
1540
- message: "payments.create returned no payment resource"
1541
- }), null];
1964
+ return [
1965
+ new CapxulError({
1966
+ code: "NETWORK_ERROR",
1967
+ message: "payments.create returned no payment resource"
1968
+ }),
1969
+ null
1970
+ ];
1542
1971
  }
1543
1972
  if (created.status !== "processing" || created.operation.status !== "processing") {
1544
1973
  return [null, created];
1545
1974
  }
1546
- const currentSigner = await config.data.query(api.safe.queries.getMySignerAddress, {});
1975
+ const currentSigner = await config._data.query(
1976
+ api.safe.queries.getMySignerAddress,
1977
+ {}
1978
+ );
1547
1979
  if (!currentSigner?.address) {
1548
1980
  throw new CapxulError({
1549
1981
  code: "PERMISSION_DENIED",
@@ -1562,9 +1994,12 @@ function createPaymentsClient(config = {}) {
1562
1994
  }
1563
1995
  });
1564
1996
  }
1565
- const submission = await config.data.query(api.payments.queries.prepareSubmission, {
1566
- paymentId: created.id
1567
- });
1997
+ const submission = await config._data.query(
1998
+ api.payments.queries.prepareSubmission,
1999
+ {
2000
+ paymentId: created.id
2001
+ }
2002
+ );
1568
2003
  if (!submission?.recipientAddress) {
1569
2004
  throw new CapxulError({
1570
2005
  code: "NETWORK_ERROR",
@@ -1572,15 +2007,16 @@ function createPaymentsClient(config = {}) {
1572
2007
  details: { paymentId: created.id }
1573
2008
  });
1574
2009
  }
2010
+ const token = resolvePaymentToken(submission.amount.currency);
1575
2011
  const transfer = await transferAsOwner(
1576
2012
  {
1577
2013
  signer: config.signer,
1578
2014
  signing: config.signing
1579
2015
  },
1580
2016
  {
1581
- tokenAddress: resolvePaymentTokenAddress(submission.amount.currency),
2017
+ tokenAddress: token.address,
1582
2018
  recipientAddress: submission.recipientAddress,
1583
- amount: toTokenUnits(submission.amount.value, 6)
2019
+ amount: toTokenUnits(submission.amount.value, token.decimals)
1584
2020
  }
1585
2021
  );
1586
2022
  if (!transfer.success) {
@@ -1598,7 +2034,7 @@ function createPaymentsClient(config = {}) {
1598
2034
  txHash: transfer.txHash,
1599
2035
  userOpHash: transfer.userOpHash
1600
2036
  };
1601
- await config.data.mutation(api.payments.mutations.recordSubmitted, {
2037
+ await config._data.mutation(api.payments.mutations.recordSubmitted, {
1602
2038
  paymentId: created.id,
1603
2039
  txHash: transfer.txHash,
1604
2040
  userOpHash: transfer.userOpHash,
@@ -1608,43 +2044,65 @@ function createPaymentsClient(config = {}) {
1608
2044
  } catch (cause) {
1609
2045
  const error = mapCreateError(fromConvexError(cause));
1610
2046
  if (created?.id && created.status === "processing" && !submitted) {
1611
- await bestEffortMarkFailed({ data: config.data }, created.id, error);
2047
+ await bestEffortMarkFailed({ _data: config._data }, created.id, error);
1612
2048
  }
1613
2049
  if (submitted && created?.id) {
1614
- return [new CapxulError({
1615
- code: "NETWORK_ERROR",
1616
- message: "Payment was submitted on-chain, but backend submission tracking failed.",
1617
- cause,
1618
- details: {
1619
- paymentId: created.id,
1620
- txHash: submitted.txHash,
1621
- userOpHash: submitted.userOpHash
1622
- }
1623
- }), null];
2050
+ return [
2051
+ new CapxulError({
2052
+ code: "NETWORK_ERROR",
2053
+ message: "Payment was submitted on-chain, but backend submission tracking failed.",
2054
+ cause,
2055
+ details: {
2056
+ paymentId: created.id,
2057
+ txHash: submitted.txHash,
2058
+ userOpHash: submitted.userOpHash
2059
+ }
2060
+ }),
2061
+ null
2062
+ ];
1624
2063
  }
1625
2064
  return [error, null];
1626
2065
  }
1627
2066
  },
1628
2067
  retrieve: async (paymentId) => {
1629
- if (!config.data) {
2068
+ if (!config._data) {
1630
2069
  return stub("payments.retrieve");
1631
2070
  }
1632
2071
  try {
1633
- const payment = await config.data.query(api.payments.queries.retrieve, {
1634
- paymentId
1635
- });
2072
+ const payment = await config._data.query(
2073
+ api.payments.queries.retrieve,
2074
+ {
2075
+ paymentId
2076
+ }
2077
+ );
1636
2078
  if (!payment) {
1637
- return [new CapxulError({
1638
- code: "NOT_FOUND",
1639
- message: `payment ${paymentId} not found`
1640
- }), null];
2079
+ return [
2080
+ new CapxulError({
2081
+ code: "NOT_FOUND",
2082
+ message: `payment ${paymentId} not found`
2083
+ }),
2084
+ null
2085
+ ];
1641
2086
  }
1642
2087
  return [null, payment];
1643
2088
  } catch (cause) {
1644
2089
  return [fromConvexError(cause), null];
1645
2090
  }
1646
2091
  },
1647
- list: async () => stub("payments.list")
2092
+ list: async (input) => {
2093
+ if (!config._data) {
2094
+ return stub("payments.list");
2095
+ }
2096
+ try {
2097
+ const page = await config._data.query(api.payments.queries.list, {
2098
+ limit: input?.limit,
2099
+ cursor: input?.cursor
2100
+ });
2101
+ return [null, page];
2102
+ } catch (cause) {
2103
+ return [fromConvexError(cause), null];
2104
+ }
2105
+ }
1648
2106
  };
1649
2107
  }
1650
2108
  function createOrgPaymentsClient() {
@@ -1658,7 +2116,7 @@ function createOrgPaymentsClient() {
1658
2116
  }
1659
2117
  async function bestEffortMarkFailed(config, paymentId, error) {
1660
2118
  try {
1661
- await config.data.mutation(api.payments.mutations.markFailed, {
2119
+ await config._data.mutation(api.payments.mutations.markFailed, {
1662
2120
  paymentId,
1663
2121
  errorCode: error.code,
1664
2122
  errorMessage: error.message,
@@ -1715,11 +2173,11 @@ function createOrgTransfersClient() {
1715
2173
  function createWithdrawalsClient(config = {}) {
1716
2174
  return {
1717
2175
  create: async (input) => {
1718
- if (!config.data) {
2176
+ if (!config._data) {
1719
2177
  return stub("withdrawals.create");
1720
2178
  }
1721
2179
  const [createErr, createdRaw] = await tryCatch(
1722
- config.data.mutation(api.withdrawals.mutations.create, {
2180
+ config._data.mutation(api.withdrawals.mutations.create, {
1723
2181
  amount: input.amount,
1724
2182
  destination: {
1725
2183
  externalAccountId: input.destination.externalAccountId
@@ -1749,18 +2207,18 @@ function createWithdrawalsClient(config = {}) {
1749
2207
  return [null, created];
1750
2208
  }
1751
2209
  const [signerErr, currentSigner] = await tryCatch(
1752
- config.data.query(api.safe.queries.getMySignerAddress, {})
2210
+ config._data.query(api.safe.queries.getMySignerAddress, {})
1753
2211
  );
1754
2212
  if (signerErr) {
1755
2213
  return await handleSubmissionFailure(
1756
- { data: config.data },
2214
+ { _data: config._data },
1757
2215
  created.id,
1758
2216
  mapCreateError2(fromConvexError(signerErr))
1759
2217
  );
1760
2218
  }
1761
2219
  if (!currentSigner?.address) {
1762
2220
  return await handleSubmissionFailure(
1763
- { data: config.data },
2221
+ { _data: config._data },
1764
2222
  created.id,
1765
2223
  new CapxulError({
1766
2224
  code: "PERMISSION_DENIED",
@@ -1771,7 +2229,7 @@ function createWithdrawalsClient(config = {}) {
1771
2229
  }
1772
2230
  if (viem.getAddress(currentSigner.address) !== viem.getAddress(config.signer.address)) {
1773
2231
  return await handleSubmissionFailure(
1774
- { data: config.data },
2232
+ { _data: config._data },
1775
2233
  created.id,
1776
2234
  new CapxulError({
1777
2235
  code: "PERMISSION_DENIED",
@@ -1785,13 +2243,13 @@ function createWithdrawalsClient(config = {}) {
1785
2243
  );
1786
2244
  }
1787
2245
  const [prepErr, submission] = await tryCatch(
1788
- config.data.query(api.withdrawals.queries.prepareSubmission, {
2246
+ config._data.query(api.withdrawals.queries.prepareSubmission, {
1789
2247
  withdrawalId: created.id
1790
2248
  })
1791
2249
  );
1792
2250
  if (prepErr) {
1793
2251
  return await handleSubmissionFailure(
1794
- { data: config.data },
2252
+ { _data: config._data },
1795
2253
  created.id,
1796
2254
  mapCreateError2(fromConvexError(prepErr))
1797
2255
  );
@@ -1799,7 +2257,7 @@ function createWithdrawalsClient(config = {}) {
1799
2257
  const destinationAddress = submission?.destinationAddress;
1800
2258
  if (!submission || !destinationAddress) {
1801
2259
  return await handleSubmissionFailure(
1802
- { data: config.data },
2260
+ { _data: config._data },
1803
2261
  created.id,
1804
2262
  new CapxulError({
1805
2263
  code: "NETWORK_ERROR",
@@ -1808,6 +2266,7 @@ function createWithdrawalsClient(config = {}) {
1808
2266
  })
1809
2267
  );
1810
2268
  }
2269
+ const token = resolvePaymentToken(submission.amount.currency);
1811
2270
  const [transferErr, transferOk] = await tryCatch(
1812
2271
  transferAsOwner(
1813
2272
  {
@@ -1815,22 +2274,22 @@ function createWithdrawalsClient(config = {}) {
1815
2274
  signing: config.signing
1816
2275
  },
1817
2276
  {
1818
- tokenAddress: resolvePaymentTokenAddress(submission.amount.currency),
2277
+ tokenAddress: token.address,
1819
2278
  recipientAddress: destinationAddress,
1820
- amount: toTokenUnits(submission.amount.value, 6)
2279
+ amount: toTokenUnits(submission.amount.value, token.decimals)
1821
2280
  }
1822
2281
  )
1823
2282
  );
1824
2283
  if (transferErr) {
1825
2284
  return await handleSubmissionFailure(
1826
- { data: config.data },
2285
+ { _data: config._data },
1827
2286
  created.id,
1828
2287
  mapCreateError2(fromConvexError(transferErr))
1829
2288
  );
1830
2289
  }
1831
2290
  if (!transferOk.success) {
1832
2291
  return await handleSubmissionFailure(
1833
- { data: config.data },
2292
+ { _data: config._data },
1834
2293
  created.id,
1835
2294
  new CapxulError({
1836
2295
  code: "NETWORK_ERROR",
@@ -1844,7 +2303,7 @@ function createWithdrawalsClient(config = {}) {
1844
2303
  );
1845
2304
  }
1846
2305
  const [recordErr] = await tryCatch(
1847
- config.data.mutation(api.withdrawals.mutations.recordSubmitted, {
2306
+ config._data.mutation(api.withdrawals.mutations.recordSubmitted, {
1848
2307
  withdrawalId: created.id,
1849
2308
  txHash: transferOk.txHash,
1850
2309
  userOpHash: transferOk.userOpHash
@@ -1868,11 +2327,11 @@ function createWithdrawalsClient(config = {}) {
1868
2327
  return [null, created];
1869
2328
  },
1870
2329
  retrieve: async (withdrawalId) => {
1871
- if (!config.data) {
2330
+ if (!config._data) {
1872
2331
  return stub("withdrawals.retrieve");
1873
2332
  }
1874
2333
  const [err, raw] = await tryCatch(
1875
- config.data.query(api.withdrawals.queries.retrieve, { withdrawalId })
2334
+ config._data.query(api.withdrawals.queries.retrieve, { withdrawalId })
1876
2335
  );
1877
2336
  if (err) {
1878
2337
  return [fromConvexError(err), null];
@@ -1890,11 +2349,11 @@ function createWithdrawalsClient(config = {}) {
1890
2349
  return [null, withdrawal];
1891
2350
  },
1892
2351
  list: async (input) => {
1893
- if (!config.data) {
2352
+ if (!config._data) {
1894
2353
  return stub("withdrawals.list");
1895
2354
  }
1896
2355
  const [err, raw] = await tryCatch(
1897
- config.data.query(api.withdrawals.queries.list, {
2356
+ config._data.query(api.withdrawals.queries.list, {
1898
2357
  limit: input?.limit,
1899
2358
  cursor: input?.cursor
1900
2359
  })
@@ -1905,13 +2364,13 @@ function createWithdrawalsClient(config = {}) {
1905
2364
  return [null, raw];
1906
2365
  },
1907
2366
  recordCompleted: async (input) => {
1908
- if (!config.data) {
2367
+ if (!config._data) {
1909
2368
  return stub(
1910
2369
  "withdrawals.recordCompleted"
1911
2370
  );
1912
2371
  }
1913
2372
  const [err] = await tryCatch(
1914
- config.data.mutation(api.withdrawals.mutations.recordCompleted, {
2373
+ config._data.mutation(api.withdrawals.mutations.recordCompleted, {
1915
2374
  withdrawalId: input.withdrawalId,
1916
2375
  txHash: input.txHash
1917
2376
  })
@@ -1936,13 +2395,13 @@ function createOrgWithdrawalsClient(config = {}) {
1936
2395
  * orchestration ships in W3+.
1937
2396
  */
1938
2397
  create: async (input) => {
1939
- if (!config.data) {
2398
+ if (!config._data) {
1940
2399
  return stub(
1941
2400
  "organizations.withdrawals.create"
1942
2401
  );
1943
2402
  }
1944
2403
  const [err, raw] = await tryCatch(
1945
- config.data.mutation(api.withdrawals.mutations.createOrg, {
2404
+ config._data.mutation(api.withdrawals.mutations.createOrg, {
1946
2405
  organizationId: input.organizationId,
1947
2406
  amount: input.amount,
1948
2407
  destination: {
@@ -1969,13 +2428,13 @@ function createOrgWithdrawalsClient(config = {}) {
1969
2428
  return [null, created];
1970
2429
  },
1971
2430
  retrieve: async (input) => {
1972
- if (!config.data) {
2431
+ if (!config._data) {
1973
2432
  return stub(
1974
2433
  "organizations.withdrawals.retrieve"
1975
2434
  );
1976
2435
  }
1977
2436
  const [err, raw] = await tryCatch(
1978
- config.data.query(api.withdrawals.queries.retrieve, {
2437
+ config._data.query(api.withdrawals.queries.retrieve, {
1979
2438
  withdrawalId: input.withdrawalId
1980
2439
  })
1981
2440
  );
@@ -2005,13 +2464,13 @@ function createOrgWithdrawalsClient(config = {}) {
2005
2464
  return [null, withdrawal];
2006
2465
  },
2007
2466
  list: async (input) => {
2008
- if (!config.data) {
2467
+ if (!config._data) {
2009
2468
  return stub(
2010
2469
  "organizations.withdrawals.list"
2011
2470
  );
2012
2471
  }
2013
2472
  const [err, raw] = await tryCatch(
2014
- config.data.query(api.withdrawals.queries.listOrg, {
2473
+ config._data.query(api.withdrawals.queries.listOrg, {
2015
2474
  organizationId: input.organizationId,
2016
2475
  limit: input.limit,
2017
2476
  cursor: input.cursor
@@ -2030,7 +2489,7 @@ async function handleSubmissionFailure(config, withdrawalId, error) {
2030
2489
  }
2031
2490
  async function bestEffortMarkFailed2(config, withdrawalId, error) {
2032
2491
  await tryCatch(
2033
- config.data.mutation(api.withdrawals.mutations.markFailed, {
2492
+ config._data.mutation(api.withdrawals.mutations.markFailed, {
2034
2493
  withdrawalId,
2035
2494
  errorCode: error.code,
2036
2495
  errorMessage: error.message
@@ -2104,28 +2563,131 @@ function createWebhookEventsClient() {
2104
2563
  list: async () => stub("webhookEvents.list")
2105
2564
  };
2106
2565
  }
2107
-
2108
- // src/core/organizations.ts
2109
- function createOrgExternalAccountsClient(config) {
2566
+
2567
+ // src/core/organizations.ts
2568
+ function createOrgExternalAccountsClient(config) {
2569
+ return {
2570
+ create: async (input) => {
2571
+ if (!config._data) {
2572
+ return stub(
2573
+ "organizations.externalAccounts.create"
2574
+ );
2575
+ }
2576
+ const [err, raw] = await tryCatch(
2577
+ config._data.mutation(api.externalAccounts.mutations.createOrg, {
2578
+ organizationId: input.organizationId,
2579
+ kind: input.kind,
2580
+ label: input.label,
2581
+ address: input.address,
2582
+ iban: input.iban,
2583
+ bic: input.bic,
2584
+ accountHolder: input.accountHolder,
2585
+ network: input.network,
2586
+ panToken: input.panToken,
2587
+ last4: input.last4
2588
+ })
2589
+ );
2590
+ if (err) {
2591
+ return [fromConvexError(err), null];
2592
+ }
2593
+ if (!raw) {
2594
+ return [
2595
+ new CapxulError({
2596
+ code: "NOT_FOUND",
2597
+ message: "external_account creation returned no resource"
2598
+ }),
2599
+ null
2600
+ ];
2601
+ }
2602
+ return [null, brandExternalAccount(raw)];
2603
+ },
2604
+ list: async (input) => {
2605
+ if (!config._data) {
2606
+ return stub(
2607
+ "organizations.externalAccounts.list"
2608
+ );
2609
+ }
2610
+ const [err, result] = await tryCatch(
2611
+ config._data.query(api.externalAccounts.queries.listOrg, {
2612
+ organizationId: input.organizationId,
2613
+ limit: input.limit,
2614
+ cursor: input.cursor
2615
+ })
2616
+ );
2617
+ if (err) {
2618
+ return [fromConvexError(err), null];
2619
+ }
2620
+ const branded = result.data.map(
2621
+ (row) => brandExternalAccount(row)
2622
+ );
2623
+ return [
2624
+ null,
2625
+ {
2626
+ object: "list",
2627
+ data: branded,
2628
+ page: result.page
2629
+ }
2630
+ ];
2631
+ },
2632
+ retrieve: async (input) => {
2633
+ if (!config._data) {
2634
+ return stub(
2635
+ "organizations.externalAccounts.retrieve"
2636
+ );
2637
+ }
2638
+ const [err, raw] = await tryCatch(
2639
+ config._data.query(api.externalAccounts.queries.retrieveOrg, {
2640
+ organizationId: input.organizationId,
2641
+ externalAccountId: input.externalAccountId
2642
+ })
2643
+ );
2644
+ if (err) {
2645
+ return [fromConvexError(err), null];
2646
+ }
2647
+ if (!raw) {
2648
+ return [
2649
+ new CapxulError({
2650
+ code: "NOT_FOUND",
2651
+ message: `external_account ${input.externalAccountId} not found`
2652
+ }),
2653
+ null
2654
+ ];
2655
+ }
2656
+ return [null, brandExternalAccount(raw)];
2657
+ },
2658
+ remove: async (input) => {
2659
+ if (!config._data) {
2660
+ return stub("organizations.externalAccounts.remove");
2661
+ }
2662
+ const [err] = await tryCatch(
2663
+ config._data.mutation(api.externalAccounts.mutations.removeOrg, {
2664
+ organizationId: input.organizationId,
2665
+ externalAccountId: input.externalAccountId
2666
+ })
2667
+ );
2668
+ if (err) {
2669
+ return [fromConvexError(err), null];
2670
+ }
2671
+ return [null, void 0];
2672
+ }
2673
+ };
2674
+ }
2675
+ function createOrgSubAccountsClient(config) {
2110
2676
  return {
2111
2677
  create: async (input) => {
2112
- if (!config.data) {
2678
+ if (!config._data) {
2113
2679
  return stub(
2114
- "organizations.externalAccounts.create"
2680
+ "organizations.subAccounts.create"
2115
2681
  );
2116
2682
  }
2117
2683
  const [err, raw] = await tryCatch(
2118
- config.data.mutation(api.externalAccounts.mutations.createOrg, {
2119
- organizationId: input.organizationId,
2120
- kind: input.kind,
2121
- label: input.label,
2122
- address: input.address,
2123
- iban: input.iban,
2124
- bic: input.bic,
2125
- accountHolder: input.accountHolder,
2126
- network: input.network,
2127
- panToken: input.panToken,
2128
- last4: input.last4
2684
+ config._data.mutation(api.subAccounts.mutations.create, {
2685
+ parent: {
2686
+ kind: "organization",
2687
+ id: input.organizationId
2688
+ },
2689
+ name: input.name,
2690
+ purpose: input.purpose
2129
2691
  })
2130
2692
  );
2131
2693
  if (err) {
@@ -2138,58 +2700,60 @@ function createOrgExternalAccountsClient(config) {
2138
2700
  return [
2139
2701
  new CapxulError({
2140
2702
  code: "NOT_FOUND",
2141
- message: "external_account creation returned no resource"
2703
+ message: "sub_account creation returned no resource"
2142
2704
  }),
2143
2705
  null
2144
2706
  ];
2145
2707
  }
2146
- return [
2147
- null,
2148
- brandExternalAccount(
2149
- raw
2150
- )
2151
- ];
2708
+ const [brandErr, branded] = tryBrandSubAccount(raw);
2709
+ if (brandErr) {
2710
+ return [brandErr, null];
2711
+ }
2712
+ return [null, branded];
2152
2713
  },
2153
2714
  list: async (input) => {
2154
- if (!config.data) {
2715
+ if (!config._data) {
2155
2716
  return stub(
2156
- "organizations.externalAccounts.list"
2717
+ "organizations.subAccounts.list"
2157
2718
  );
2158
2719
  }
2159
- const [err, result] = await tryCatch(
2160
- config.data.query(api.externalAccounts.queries.listOrg, {
2161
- organizationId: input.organizationId,
2162
- limit: input.limit,
2163
- cursor: input.cursor
2720
+ const [err, rows] = await tryCatch(
2721
+ config._data.query(api.subAccounts.queries.listByOrganization, {
2722
+ organizationId: input.organizationId
2164
2723
  })
2165
2724
  );
2166
2725
  if (err) {
2167
- return [fromConvexError(err), null];
2726
+ return [
2727
+ fromConvexError(err),
2728
+ null
2729
+ ];
2730
+ }
2731
+ const branded = [];
2732
+ for (const row of rows) {
2733
+ const [brandErr, value] = tryBrandSubAccount(row);
2734
+ if (brandErr) {
2735
+ return [brandErr, null];
2736
+ }
2737
+ branded.push(value);
2168
2738
  }
2169
- const branded = result.data.map(
2170
- (row) => brandExternalAccount(
2171
- row
2172
- )
2173
- );
2174
2739
  return [
2175
2740
  null,
2176
2741
  {
2177
2742
  object: "list",
2178
2743
  data: branded,
2179
- page: result.page
2744
+ page: { hasMore: false }
2180
2745
  }
2181
2746
  ];
2182
2747
  },
2183
2748
  retrieve: async (input) => {
2184
- if (!config.data) {
2749
+ if (!config._data) {
2185
2750
  return stub(
2186
- "organizations.externalAccounts.retrieve"
2751
+ "organizations.subAccounts.retrieve"
2187
2752
  );
2188
2753
  }
2189
2754
  const [err, raw] = await tryCatch(
2190
- config.data.query(api.externalAccounts.queries.retrieveOrg, {
2191
- organizationId: input.organizationId,
2192
- externalAccountId: input.externalAccountId
2755
+ config._data.query(api.subAccounts.queries.retrieve, {
2756
+ subAccountId: input.subAccountId
2193
2757
  })
2194
2758
  );
2195
2759
  if (err) {
@@ -2202,28 +2766,29 @@ function createOrgExternalAccountsClient(config) {
2202
2766
  return [
2203
2767
  new CapxulError({
2204
2768
  code: "NOT_FOUND",
2205
- message: `external_account ${input.externalAccountId} not found`
2769
+ message: `sub_account ${input.subAccountId} not found`
2206
2770
  }),
2207
2771
  null
2208
2772
  ];
2209
2773
  }
2210
- return [
2211
- null,
2212
- brandExternalAccount(
2213
- raw
2214
- )
2215
- ];
2774
+ const [brandErr, branded] = tryBrandSubAccount(raw);
2775
+ if (brandErr) {
2776
+ return [
2777
+ brandErr,
2778
+ null
2779
+ ];
2780
+ }
2781
+ return [null, branded];
2216
2782
  },
2217
2783
  remove: async (input) => {
2218
- if (!config.data) {
2784
+ if (!config._data) {
2219
2785
  return stub(
2220
- "organizations.externalAccounts.remove"
2786
+ "organizations.subAccounts.remove"
2221
2787
  );
2222
2788
  }
2223
- const [err] = await tryCatch(
2224
- config.data.mutation(api.externalAccounts.mutations.removeOrg, {
2225
- organizationId: input.organizationId,
2226
- externalAccountId: input.externalAccountId
2789
+ const [err, raw] = await tryCatch(
2790
+ config._data.mutation(api.subAccounts.mutations.archive, {
2791
+ subAccountId: input.subAccountId
2227
2792
  })
2228
2793
  );
2229
2794
  if (err) {
@@ -2232,23 +2797,139 @@ function createOrgExternalAccountsClient(config) {
2232
2797
  null
2233
2798
  ];
2234
2799
  }
2235
- return [null, void 0];
2800
+ if (!raw) {
2801
+ return [
2802
+ new CapxulError({
2803
+ code: "NOT_FOUND",
2804
+ message: `sub_account ${input.subAccountId} not found`
2805
+ }),
2806
+ null
2807
+ ];
2808
+ }
2809
+ const [brandErr, branded] = tryBrandSubAccount(raw);
2810
+ if (brandErr) {
2811
+ return [
2812
+ brandErr,
2813
+ null
2814
+ ];
2815
+ }
2816
+ return [null, branded];
2236
2817
  }
2237
2818
  };
2238
2819
  }
2239
2820
  function createOrganizationsClient(config = {}) {
2240
2821
  return {
2241
- create: async () => stub("organizations.create"),
2242
- retrieve: async () => stub("organizations.retrieve"),
2243
- list: async () => stub("organizations.list"),
2244
- update: async () => stub("organizations.update"),
2822
+ create: async (input) => {
2823
+ if (!config._data) {
2824
+ return stub("organizations.create");
2825
+ }
2826
+ if (input.country !== void 0) {
2827
+ return [
2828
+ new CapxulError({
2829
+ code: "INVALID_INPUT",
2830
+ message: "organizations.create does not support country yet \u2014 backend mutation only accepts name.",
2831
+ details: { field: "country" }
2832
+ }),
2833
+ null
2834
+ ];
2835
+ }
2836
+ try {
2837
+ const orgId = await config._data.mutation(api.org.mutations.create, {
2838
+ name: input.name
2839
+ });
2840
+ const org = await config._data.query(api.org.queries.retrieve, {
2841
+ orgId
2842
+ });
2843
+ if (!org) {
2844
+ return [
2845
+ new CapxulError({
2846
+ code: "NETWORK_ERROR",
2847
+ message: "organization created but could not be retrieved"
2848
+ }),
2849
+ null
2850
+ ];
2851
+ }
2852
+ return [null, org];
2853
+ } catch (cause) {
2854
+ return [fromConvexError(cause), null];
2855
+ }
2856
+ },
2857
+ retrieve: async (organizationId) => {
2858
+ if (!config._data) {
2859
+ return stub("organizations.retrieve");
2860
+ }
2861
+ try {
2862
+ const orgId = organizationId.replace(/^org_/, "");
2863
+ const org = await config._data.query(api.org.queries.retrieve, {
2864
+ orgId
2865
+ });
2866
+ if (!org) {
2867
+ return [
2868
+ new CapxulError({
2869
+ code: "NOT_FOUND",
2870
+ message: `organization ${organizationId} not found`
2871
+ }),
2872
+ null
2873
+ ];
2874
+ }
2875
+ return [null, org];
2876
+ } catch (cause) {
2877
+ return [fromConvexError(cause), null];
2878
+ }
2879
+ },
2880
+ list: async (input) => {
2881
+ if (!config._data) {
2882
+ return stub("organizations.list");
2883
+ }
2884
+ try {
2885
+ const page = await config._data.query(api.org.queries.list, {
2886
+ limit: input?.limit,
2887
+ cursor: input?.cursor
2888
+ });
2889
+ const result = {
2890
+ object: "list",
2891
+ data: page.data,
2892
+ page: {
2893
+ hasMore: page.hasMore,
2894
+ cursor: page.nextCursor
2895
+ }
2896
+ };
2897
+ return [null, result];
2898
+ } catch (cause) {
2899
+ return [fromConvexError(cause), null];
2900
+ }
2901
+ },
2902
+ update: async (input) => {
2903
+ if (!config._data) {
2904
+ return stub("organizations.update");
2905
+ }
2906
+ try {
2907
+ const orgId = input.organizationId.replace(/^org_/, "");
2908
+ const org = await config._data.mutation(api.org.mutations.update, {
2909
+ orgId,
2910
+ name: input.name
2911
+ });
2912
+ if (!org) {
2913
+ return [
2914
+ new CapxulError({
2915
+ code: "NOT_FOUND",
2916
+ message: `organization ${input.organizationId} not found`
2917
+ }),
2918
+ null
2919
+ ];
2920
+ }
2921
+ return [null, org];
2922
+ } catch (cause) {
2923
+ return [fromConvexError(cause), null];
2924
+ }
2925
+ },
2245
2926
  safes: {
2246
2927
  retrieve: async (input) => {
2247
- if (!config.data) {
2928
+ if (!config._data) {
2248
2929
  return stub("organizations.safes.retrieve");
2249
2930
  }
2250
2931
  try {
2251
- const safe = await config.data.query(
2932
+ const safe = await config._data.query(
2252
2933
  api.safe.queries.retrieveOrganizationSafe,
2253
2934
  input
2254
2935
  );
@@ -2271,34 +2952,243 @@ function createOrganizationsClient(config = {}) {
2271
2952
  }
2272
2953
  },
2273
2954
  treasury: {
2274
- retrieve: async () => stub("organizations.treasury.retrieve")
2955
+ retrieve: async (organizationId) => {
2956
+ if (!config._data) {
2957
+ return stub(
2958
+ "organizations.treasury.retrieve"
2959
+ );
2960
+ }
2961
+ try {
2962
+ const orgId = organizationId.replace(/^org_/, "");
2963
+ const raw = await config._data.query(
2964
+ api.safe.queries.getOrgTreasuryBalance,
2965
+ { orgId }
2966
+ );
2967
+ if (!raw) {
2968
+ return [
2969
+ new CapxulError({
2970
+ code: "NOT_FOUND",
2971
+ message: `treasury for organization ${organizationId} not found`
2972
+ }),
2973
+ null
2974
+ ];
2975
+ }
2976
+ const treasury = {
2977
+ object: "treasury",
2978
+ id: toTreasuryId(`try_${orgId}`),
2979
+ organizationId,
2980
+ status: "active",
2981
+ safeId: toSafeId(
2982
+ `safe_${raw.safeAddress.replace(/^0x/, "").toLowerCase()}`
2983
+ ),
2984
+ totalBalance: { value: "0", currency: "USD" },
2985
+ positions: raw.tokens.map((t) => ({
2986
+ symbol: t.symbol,
2987
+ contractAddress: t.tokenAddress,
2988
+ amount: t.balance
2989
+ })),
2990
+ asOf: raw.lastUpdatedAt ? new Date(raw.lastUpdatedAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
2991
+ };
2992
+ return [null, treasury];
2993
+ } catch (cause) {
2994
+ return [
2995
+ fromConvexError(cause),
2996
+ null
2997
+ ];
2998
+ }
2999
+ }
2275
3000
  },
2276
3001
  members: {
2277
- list: async () => stub("organizations.members.list"),
2278
- retrieve: async () => stub("organizations.members.retrieve"),
2279
- invite: async () => stub("organizations.members.invite"),
2280
- updateRole: async () => stub("organizations.members.updateRole"),
2281
- remove: async () => stub("organizations.members.remove")
3002
+ list: async (input) => {
3003
+ if (!config._data?.action) {
3004
+ return stub("organizations.members.list");
3005
+ }
3006
+ try {
3007
+ const orgId = input.organizationId.replace(/^org_/, "");
3008
+ const page = await config._data.action(api.org.actions.membersList, {
3009
+ organizationId: orgId,
3010
+ status: input.status,
3011
+ limit: input.limit,
3012
+ cursor: input.cursor
3013
+ });
3014
+ return [null, page];
3015
+ } catch (cause) {
3016
+ return [fromConvexError(cause), null];
3017
+ }
3018
+ },
3019
+ retrieve: async (input) => {
3020
+ if (!config._data?.action) {
3021
+ return stub("organizations.members.retrieve");
3022
+ }
3023
+ try {
3024
+ const orgId = input.organizationId.replace(/^org_/, "");
3025
+ const memberId = input.memberId.replace(/^mb_/, "");
3026
+ const member = await config._data.action(
3027
+ api.org.actions.retrieveMember,
3028
+ {
3029
+ organizationId: orgId,
3030
+ memberId
3031
+ }
3032
+ );
3033
+ return [null, member];
3034
+ } catch (cause) {
3035
+ return [fromConvexError(cause), null];
3036
+ }
3037
+ },
3038
+ invite: async (input) => {
3039
+ if (!config._data?.action) {
3040
+ return stub("organizations.members.invite");
3041
+ }
3042
+ try {
3043
+ const orgId = input.organizationId.replace(/^org_/, "");
3044
+ const result = await config._data.action(
3045
+ api.org.actions.inviteMember,
3046
+ {
3047
+ organizationId: orgId,
3048
+ email: input.email,
3049
+ role: input.role
3050
+ }
3051
+ );
3052
+ return [null, result];
3053
+ } catch (cause) {
3054
+ return [fromConvexError(cause), null];
3055
+ }
3056
+ },
3057
+ accept: async (input) => {
3058
+ if (!config._data?.action) {
3059
+ return stub("organizations.members.accept");
3060
+ }
3061
+ try {
3062
+ const member = await config._data.action(
3063
+ api.org.actions.acceptInvitation,
3064
+ { token: input.token }
3065
+ );
3066
+ return [null, member];
3067
+ } catch (cause) {
3068
+ return [fromConvexError(cause), null];
3069
+ }
3070
+ },
3071
+ updateRole: async (input) => {
3072
+ if (!config._data?.action) {
3073
+ return stub("organizations.members.updateRole");
3074
+ }
3075
+ try {
3076
+ const orgId = input.organizationId.replace(/^org_/, "");
3077
+ const memberId = input.memberId.replace(/^mb_/, "");
3078
+ const member = await config._data.action(
3079
+ api.org.actions.updateMemberRole,
3080
+ {
3081
+ organizationId: orgId,
3082
+ memberId,
3083
+ role: input.role
3084
+ }
3085
+ );
3086
+ return [null, member];
3087
+ } catch (cause) {
3088
+ return [fromConvexError(cause), null];
3089
+ }
3090
+ },
3091
+ revoke: async (input) => {
3092
+ if (!config._data?.action) {
3093
+ return stub("organizations.members.revoke");
3094
+ }
3095
+ try {
3096
+ const orgId = input.organizationId.replace(/^org_/, "");
3097
+ const memberId = input.memberId.replace(/^mb_/, "");
3098
+ const member = await config._data.action(
3099
+ api.org.actions.revokeMember,
3100
+ {
3101
+ organizationId: orgId,
3102
+ memberId
3103
+ }
3104
+ );
3105
+ return [null, member];
3106
+ } catch (cause) {
3107
+ return [fromConvexError(cause), null];
3108
+ }
3109
+ },
3110
+ remove: async (input) => {
3111
+ if (!config._data?.action) {
3112
+ return stub("organizations.members.remove");
3113
+ }
3114
+ try {
3115
+ const orgId = input.organizationId.replace(/^org_/, "");
3116
+ const memberId = input.memberId.replace(/^mb_/, "");
3117
+ await config._data.action(api.org.actions.removeMember, {
3118
+ organizationId: orgId,
3119
+ memberId
3120
+ });
3121
+ return [null, void 0];
3122
+ } catch (cause) {
3123
+ return [fromConvexError(cause), null];
3124
+ }
3125
+ },
3126
+ resend: async (input) => {
3127
+ if (!config._data?.action) {
3128
+ return stub("organizations.members.resend");
3129
+ }
3130
+ try {
3131
+ const orgId = input.organizationId.replace(/^org_/, "");
3132
+ const memberId = input.memberId.replace(/^mb_/, "");
3133
+ const result = await config._data.action(
3134
+ api.org.actions.resendInvitation,
3135
+ {
3136
+ organizationId: orgId,
3137
+ memberId
3138
+ }
3139
+ );
3140
+ return [null, result];
3141
+ } catch (cause) {
3142
+ return [fromConvexError(cause), null];
3143
+ }
3144
+ }
2282
3145
  },
2283
3146
  apiKeys: createApiKeysClient(),
2284
- kybProfile: {
2285
- start: async () => stub("organizations.kybProfile.start"),
2286
- retrieve: async () => stub("organizations.kybProfile.retrieve")
2287
- },
2288
- subAccounts: {
2289
- create: async () => stub("organizations.subAccounts.create"),
2290
- list: async () => stub("organizations.subAccounts.list"),
2291
- retrieve: async () => stub("organizations.subAccounts.retrieve"),
2292
- remove: async () => stub("organizations.subAccounts.remove")
2293
- },
3147
+ subAccounts: createOrgSubAccountsClient(config),
2294
3148
  externalAccounts: createOrgExternalAccountsClient(config),
2295
3149
  balanceLedger: {
2296
- list: async () => stub(
2297
- "organizations.balanceLedger.list"
2298
- ),
2299
- retrieve: async () => stub(
2300
- "organizations.balanceLedger.retrieve"
2301
- )
3150
+ list: async (input) => {
3151
+ if (!config._data) {
3152
+ return stub(
3153
+ "organizations.balanceLedger.list"
3154
+ );
3155
+ }
3156
+ try {
3157
+ const orgId = input.organizationId.replace(/^org_/, "");
3158
+ const page = await config._data.query(
3159
+ api.balanceLedger.queries.listForOrg,
3160
+ { orgId, limit: input.limit, cursor: input.cursor }
3161
+ );
3162
+ return [null, page];
3163
+ } catch (cause) {
3164
+ return [fromConvexError(cause), null];
3165
+ }
3166
+ },
3167
+ retrieve: async (input) => {
3168
+ if (!config._data) {
3169
+ return stub(
3170
+ "organizations.balanceLedger.retrieve"
3171
+ );
3172
+ }
3173
+ try {
3174
+ const entry = await config._data.query(
3175
+ api.balanceLedger.queries.retrieve,
3176
+ { entryId: input.entryId }
3177
+ );
3178
+ if (!entry) {
3179
+ return [
3180
+ new CapxulError({
3181
+ code: "NOT_FOUND",
3182
+ message: `balance_ledger_entry ${input.entryId} not found`
3183
+ }),
3184
+ null
3185
+ ];
3186
+ }
3187
+ return [null, entry];
3188
+ } catch (cause) {
3189
+ return [fromConvexError(cause), null];
3190
+ }
3191
+ }
2302
3192
  },
2303
3193
  payments: createOrgPaymentsClient(),
2304
3194
  transfers: createOrgTransfersClient(),
@@ -2309,14 +3199,6 @@ function createOrganizationsClient(config = {}) {
2309
3199
  };
2310
3200
  }
2311
3201
 
2312
- // src/core/sub-accounts.ts
2313
- function createSubAccountsClient() {
2314
- return {
2315
- retrieve: async () => stub("subAccounts.retrieve"),
2316
- remove: async () => stub("subAccounts.remove")
2317
- };
2318
- }
2319
-
2320
3202
  // src/core/token-transfers.ts
2321
3203
  var toTokenTransferId = (raw) => {
2322
3204
  if (typeof raw !== "string" || raw.length === 0) {
@@ -2335,11 +3217,11 @@ function brandRow(row) {
2335
3217
  function createTokenTransfersClient(config = {}) {
2336
3218
  return {
2337
3219
  list: async (input) => {
2338
- if (!config.data) {
3220
+ if (!config._data) {
2339
3221
  return stub("tokenTransfers.list");
2340
3222
  }
2341
3223
  try {
2342
- const raw = await config.data.query(
3224
+ const raw = await config._data.query(
2343
3225
  api.tokenTransfers.queries.list,
2344
3226
  {
2345
3227
  limit: input?.limit,
@@ -2373,11 +3255,11 @@ function createTokenTransfersClient(config = {}) {
2373
3255
  }
2374
3256
  },
2375
3257
  retrieve: async (input) => {
2376
- if (!config.data) {
3258
+ if (!config._data) {
2377
3259
  return stub("tokenTransfers.retrieve");
2378
3260
  }
2379
3261
  try {
2380
- const raw = await config.data.query(
3262
+ const raw = await config._data.query(
2381
3263
  api.tokenTransfers.queries.getByTxLogIndex,
2382
3264
  {
2383
3265
  txHash: input.txHash,
@@ -2714,7 +3596,6 @@ var initialContext = {
2714
3596
  email: null,
2715
3597
  code: null,
2716
3598
  username: null,
2717
- signerProvider: null,
2718
3599
  bootstrapToken: null,
2719
3600
  bootstrapReason: null,
2720
3601
  session: null,
@@ -2912,12 +3793,6 @@ function createAuthBootstrapFlowMachine(client) {
2912
3793
  error: () => null
2913
3794
  })
2914
3795
  },
2915
- ENTER_SIGNER_PROVIDER: {
2916
- actions: xstate.assign({
2917
- signerProvider: ({ event }) => event.signerProvider,
2918
- error: () => null
2919
- })
2920
- },
2921
3796
  COMPLETE_BOOTSTRAP: { target: "completing_bootstrap" },
2922
3797
  BACK: { target: "otp_requested" },
2923
3798
  RESET: { target: "email", actions: xstate.assign(() => initialContext) }
@@ -2928,8 +3803,7 @@ function createAuthBootstrapFlowMachine(client) {
2928
3803
  src: "completeBootstrap",
2929
3804
  input: ({ context }) => ({
2930
3805
  bootstrapToken: requireBootstrapToken(context),
2931
- username: requireUsername(context),
2932
- signerProvider: requireSignerProvider(context)
3806
+ username: requireUsername(context)
2933
3807
  }),
2934
3808
  onDone: {
2935
3809
  target: "authenticated",
@@ -2941,7 +3815,6 @@ function createAuthBootstrapFlowMachine(client) {
2941
3815
  safe: ({ event }) => event.output.safe,
2942
3816
  bootstrapToken: () => null,
2943
3817
  bootstrapReason: () => null,
2944
- signerProvider: () => null,
2945
3818
  email: () => null,
2946
3819
  error: () => null
2947
3820
  }),
@@ -3022,15 +3895,6 @@ function requireUsername(context) {
3022
3895
  }
3023
3896
  return context.username;
3024
3897
  }
3025
- function requireSignerProvider(context) {
3026
- if (!context.signerProvider) {
3027
- throw Errors.invalidInput(
3028
- "signerProvider",
3029
- "Auth bootstrap requires a signer provider."
3030
- );
3031
- }
3032
- return context.signerProvider;
3033
- }
3034
3898
  function errorFromEvent2(event) {
3035
3899
  const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
3036
3900
  if (cause instanceof CapxulError || cause instanceof CapxulError2) {
@@ -3076,7 +3940,7 @@ function createProvisioningMachine(client) {
3076
3940
  const provider = context.input?.signerProvider;
3077
3941
  if (!provider) return;
3078
3942
  track("provisioning_safe_created", {
3079
- safe_address: provider.safeAddress
3943
+ safe_address: deriveSafeAddress(provider.signerAddress)
3080
3944
  });
3081
3945
  }
3082
3946
  }
@@ -3438,7 +4302,7 @@ function createCapxulClient(config = {}) {
3438
4302
  tokenTransfers: createTokenTransfersClient(config),
3439
4303
  withdrawals: createWithdrawalsClient(config),
3440
4304
  documents: createDocumentsClient(),
3441
- subAccounts: createSubAccountsClient(),
4305
+ subAccounts: createSubAccountsClient(config),
3442
4306
  virtualAccounts: createVirtualAccountsClient(),
3443
4307
  virtualCards: createVirtualCardsClient(),
3444
4308
  externalAccounts: createExternalAccountsClient(config),