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