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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -71,9 +71,79 @@ function fromConvexError(error) {
71
71
  // src/core/accounts.ts
72
72
  function createAccountsClient(config = {}) {
73
73
  return {
74
- retrieve: async () => stub("accounts.retrieve"),
74
+ retrieve: async (accountId) => {
75
+ if (!config.data) {
76
+ return stub("accounts.retrieve");
77
+ }
78
+ try {
79
+ const account = await config.data.query(
80
+ api.openfort.queries.getMyAccount,
81
+ {}
82
+ );
83
+ if (account.id !== accountId) {
84
+ return [
85
+ new CapxulError({
86
+ code: "PERMISSION_DENIED",
87
+ message: "accounts.retrieve currently supports the authenticated caller's own account only.",
88
+ details: {
89
+ requestedAccountId: accountId,
90
+ authenticatedAccountId: account.id
91
+ }
92
+ }),
93
+ null
94
+ ];
95
+ }
96
+ return [null, account];
97
+ } catch (cause) {
98
+ return [fromConvexError(cause), null];
99
+ }
100
+ },
75
101
  lookup: async () => stub("accounts.lookup"),
76
- update: async () => stub("accounts.update"),
102
+ update: async (input) => {
103
+ if (!config.data) {
104
+ return stub("accounts.update");
105
+ }
106
+ if (input.countryCode !== void 0) {
107
+ return [
108
+ new CapxulError({
109
+ code: "INVALID_INPUT",
110
+ message: "accounts.update does not support countryCode yet \u2014 backend mutation only patches displayName and username.",
111
+ details: { field: "countryCode" }
112
+ }),
113
+ null
114
+ ];
115
+ }
116
+ try {
117
+ const current = await config.data.query(
118
+ api.openfort.queries.getMyAccount,
119
+ {}
120
+ );
121
+ if (current.id !== input.accountId) {
122
+ return [
123
+ new CapxulError({
124
+ code: "PERMISSION_DENIED",
125
+ message: "accounts.update currently supports the authenticated caller's own account only.",
126
+ details: {
127
+ requestedAccountId: input.accountId,
128
+ authenticatedAccountId: current.id
129
+ }
130
+ }),
131
+ null
132
+ ];
133
+ }
134
+ await config.data.mutation(api.openfort.mutations.updateProfile, {
135
+ displayName: input.name,
136
+ username: input.username
137
+ });
138
+ const updated = await config.data.query(
139
+ api.openfort.queries.getMyAccount,
140
+ {}
141
+ );
142
+ return [null, updated];
143
+ } catch (cause) {
144
+ return [fromConvexError(cause), null];
145
+ }
146
+ },
77
147
  provisionPersonal: async (input) => {
78
148
  if (!config.data) {
79
149
  return stub(
@@ -697,7 +767,34 @@ function createMeClient(config = {}) {
697
767
  return [fromConvexError(cause), null];
698
768
  }
699
769
  },
700
- update: async () => stub("me.update")
770
+ update: async (input) => {
771
+ if (!config.data) {
772
+ return stub("me.update");
773
+ }
774
+ if (input.countryCode !== void 0) {
775
+ return [
776
+ new CapxulError({
777
+ code: "INVALID_INPUT",
778
+ message: "me.update does not support countryCode yet \u2014 backend mutation only patches displayName and username.",
779
+ details: { field: "countryCode" }
780
+ }),
781
+ null
782
+ ];
783
+ }
784
+ try {
785
+ await config.data.mutation(api.openfort.mutations.updateProfile, {
786
+ displayName: input.name,
787
+ username: input.username
788
+ });
789
+ const account = await config.data.query(
790
+ api.openfort.queries.getMyAccount,
791
+ {}
792
+ );
793
+ return [null, account];
794
+ } catch (cause) {
795
+ return [fromConvexError(cause), null];
796
+ }
797
+ }
701
798
  };
702
799
  }
703
800
 
@@ -1100,24 +1197,298 @@ function createOrgTransfersClient() {
1100
1197
  cancel: async () => stub("organizations.transfers.cancel")
1101
1198
  };
1102
1199
  }
1103
-
1104
- // src/core/withdrawals.ts
1105
- function createWithdrawalsClient() {
1200
+ var EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
1201
+ function createWithdrawalsClient(config = {}) {
1106
1202
  return {
1107
- create: async () => stub("withdrawals.create"),
1108
- retrieve: async () => stub("withdrawals.retrieve"),
1109
- list: async () => stub("withdrawals.list")
1203
+ create: async (input) => {
1204
+ if (!config.data) {
1205
+ return stub("withdrawals.create");
1206
+ }
1207
+ let created = null;
1208
+ let submitted = null;
1209
+ try {
1210
+ created = await config.data.mutation(
1211
+ api.withdrawals.mutations.create,
1212
+ {
1213
+ amount: input.amount,
1214
+ destination: {
1215
+ externalAccountId: input.destination.externalAccountId,
1216
+ kind: input.destination.kind
1217
+ },
1218
+ source: input.source,
1219
+ reference: input.reference,
1220
+ idempotencyKey: input.idempotencyKey
1221
+ }
1222
+ );
1223
+ if (!created) {
1224
+ return [
1225
+ new CapxulError({
1226
+ code: "NETWORK_ERROR",
1227
+ message: "withdrawals.create returned no withdrawal resource"
1228
+ }),
1229
+ null
1230
+ ];
1231
+ }
1232
+ if (created.status !== "processing" || created.operation.status !== "processing") {
1233
+ return [null, created];
1234
+ }
1235
+ if (input.destination.kind !== "evm") {
1236
+ return [null, created];
1237
+ }
1238
+ if (!config.signer || !config.signing) {
1239
+ return [null, created];
1240
+ }
1241
+ if (!EVM_ADDRESS_RE.test(input.destination.externalAccountId)) {
1242
+ throw new CapxulError({
1243
+ code: "INVALID_INPUT",
1244
+ message: "destination.externalAccountId must be a 0x-prefixed EVM address while external_accounts resolution is pending (slice 1).",
1245
+ details: { field: "destination.externalAccountId" }
1246
+ });
1247
+ }
1248
+ const currentSigner = await config.data.query(
1249
+ api.safe.queries.getMySignerAddress,
1250
+ {}
1251
+ );
1252
+ if (!currentSigner?.address) {
1253
+ throw new CapxulError({
1254
+ code: "PERMISSION_DENIED",
1255
+ message: "No signer is registered for the authenticated account.",
1256
+ details: { withdrawalId: created.id }
1257
+ });
1258
+ }
1259
+ if (getAddress(currentSigner.address) !== getAddress(config.signer.address)) {
1260
+ throw new CapxulError({
1261
+ code: "PERMISSION_DENIED",
1262
+ message: "Configured signer does not match the authenticated account signer.",
1263
+ details: {
1264
+ withdrawalId: created.id,
1265
+ expectedSignerAddress: currentSigner.address,
1266
+ actualSignerAddress: config.signer.address
1267
+ }
1268
+ });
1269
+ }
1270
+ const submission = await config.data.query(
1271
+ api.withdrawals.queries.prepareSubmission,
1272
+ { withdrawalId: created.id }
1273
+ );
1274
+ if (!submission?.externalAccountId) {
1275
+ throw new CapxulError({
1276
+ code: "NETWORK_ERROR",
1277
+ message: "withdrawals.prepareSubmission returned no destination.",
1278
+ details: { withdrawalId: created.id }
1279
+ });
1280
+ }
1281
+ const transfer = await transferAsOwner(
1282
+ {
1283
+ signer: config.signer,
1284
+ signing: config.signing
1285
+ },
1286
+ {
1287
+ tokenAddress: resolvePaymentTokenAddress(submission.amount.currency),
1288
+ recipientAddress: submission.externalAccountId,
1289
+ amount: toTokenUnits(submission.amount.value, 6)
1290
+ }
1291
+ );
1292
+ if (!transfer.success) {
1293
+ throw new CapxulError({
1294
+ code: "NETWORK_ERROR",
1295
+ message: "Bundler submission did not succeed.",
1296
+ details: {
1297
+ withdrawalId: created.id,
1298
+ txHash: transfer.txHash,
1299
+ userOpHash: transfer.userOpHash
1300
+ }
1301
+ });
1302
+ }
1303
+ submitted = {
1304
+ txHash: transfer.txHash,
1305
+ userOpHash: transfer.userOpHash
1306
+ };
1307
+ await config.data.mutation(
1308
+ api.withdrawals.mutations.recordSubmitted,
1309
+ {
1310
+ withdrawalId: created.id,
1311
+ txHash: transfer.txHash,
1312
+ userOpHash: transfer.userOpHash
1313
+ }
1314
+ );
1315
+ return [null, created];
1316
+ } catch (cause) {
1317
+ const error = mapCreateError2(fromConvexError(cause));
1318
+ if (created?.id && created.status === "processing" && !submitted) {
1319
+ await bestEffortMarkFailed2({ data: config.data }, created.id, error);
1320
+ }
1321
+ if (submitted && created?.id) {
1322
+ return [
1323
+ new CapxulError({
1324
+ code: "NETWORK_ERROR",
1325
+ message: "Withdrawal was submitted on-chain, but backend submission tracking failed.",
1326
+ cause,
1327
+ details: {
1328
+ withdrawalId: created.id,
1329
+ txHash: submitted.txHash,
1330
+ userOpHash: submitted.userOpHash
1331
+ }
1332
+ }),
1333
+ null
1334
+ ];
1335
+ }
1336
+ return [error, null];
1337
+ }
1338
+ },
1339
+ retrieve: async (withdrawalId) => {
1340
+ if (!config.data) {
1341
+ return stub("withdrawals.retrieve");
1342
+ }
1343
+ try {
1344
+ const withdrawal = await config.data.query(
1345
+ api.withdrawals.queries.retrieve,
1346
+ { withdrawalId }
1347
+ );
1348
+ if (!withdrawal) {
1349
+ return [
1350
+ new CapxulError({
1351
+ code: "NOT_FOUND",
1352
+ message: `withdrawal ${withdrawalId} not found`
1353
+ }),
1354
+ null
1355
+ ];
1356
+ }
1357
+ return [null, withdrawal];
1358
+ } catch (cause) {
1359
+ return [
1360
+ fromConvexError(cause),
1361
+ null
1362
+ ];
1363
+ }
1364
+ },
1365
+ list: async (input) => {
1366
+ if (!config.data) {
1367
+ return stub("withdrawals.list");
1368
+ }
1369
+ try {
1370
+ const result = await config.data.query(
1371
+ api.withdrawals.queries.list,
1372
+ {
1373
+ limit: input?.limit,
1374
+ cursor: input?.cursor
1375
+ }
1376
+ );
1377
+ return [null, result];
1378
+ } catch (cause) {
1379
+ return [
1380
+ fromConvexError(cause),
1381
+ null
1382
+ ];
1383
+ }
1384
+ }
1110
1385
  };
1111
1386
  }
1112
- function createOrgWithdrawalsClient() {
1387
+ function createOrgWithdrawalsClient(config = {}) {
1113
1388
  return {
1389
+ // Slice 1 ships personal-scope only end-to-end; org-scope create
1390
+ // remains stubbed pending org-scoped backend mutation. List + retrieve
1391
+ // are wired through the org-aware query.
1114
1392
  create: async () => stub(
1115
1393
  "organizations.withdrawals.create"
1116
1394
  ),
1117
- retrieve: async () => stub("organizations.withdrawals.retrieve"),
1118
- list: async () => stub("organizations.withdrawals.list")
1395
+ retrieve: async (input) => {
1396
+ if (!config.data) {
1397
+ return stub(
1398
+ "organizations.withdrawals.retrieve"
1399
+ );
1400
+ }
1401
+ try {
1402
+ const withdrawal = await config.data.query(
1403
+ api.withdrawals.queries.retrieve,
1404
+ { withdrawalId: input.withdrawalId }
1405
+ );
1406
+ if (!withdrawal) {
1407
+ return [
1408
+ new CapxulError({
1409
+ code: "NOT_FOUND",
1410
+ message: `withdrawal ${input.withdrawalId} not found`
1411
+ }),
1412
+ null
1413
+ ];
1414
+ }
1415
+ const ownerCheck = withdrawal.owner;
1416
+ if (ownerCheck?.type !== "organization" || ownerCheck.id !== input.organizationId) {
1417
+ return [
1418
+ new CapxulError({
1419
+ code: "NOT_FOUND",
1420
+ message: `withdrawal ${input.withdrawalId} does not belong to organization ${input.organizationId}`
1421
+ }),
1422
+ null
1423
+ ];
1424
+ }
1425
+ return [null, withdrawal];
1426
+ } catch (cause) {
1427
+ return [
1428
+ fromConvexError(cause),
1429
+ null
1430
+ ];
1431
+ }
1432
+ },
1433
+ list: async (input) => {
1434
+ if (!config.data) {
1435
+ return stub(
1436
+ "organizations.withdrawals.list"
1437
+ );
1438
+ }
1439
+ try {
1440
+ const result = await config.data.query(
1441
+ api.withdrawals.queries.listOrg,
1442
+ {
1443
+ organizationId: input.organizationId,
1444
+ limit: input.limit,
1445
+ cursor: input.cursor
1446
+ }
1447
+ );
1448
+ return [null, result];
1449
+ } catch (cause) {
1450
+ return [
1451
+ fromConvexError(cause),
1452
+ null
1453
+ ];
1454
+ }
1455
+ }
1119
1456
  };
1120
1457
  }
1458
+ async function bestEffortMarkFailed2(config, withdrawalId, error) {
1459
+ try {
1460
+ await config.data.mutation(api.withdrawals.mutations.markFailed, {
1461
+ withdrawalId,
1462
+ errorCode: error.code,
1463
+ errorMessage: error.message
1464
+ });
1465
+ } catch {
1466
+ }
1467
+ }
1468
+ function mapCreateError2(error) {
1469
+ switch (error.code) {
1470
+ case "NOT_AUTHENTICATED":
1471
+ case "PERMISSION_DENIED":
1472
+ case "INVALID_INPUT":
1473
+ case "INSUFFICIENT_BALANCE":
1474
+ case "IDEMPOTENCY_CONFLICT":
1475
+ case "KYC_REQUIRED":
1476
+ case "POLICY_DENIED":
1477
+ case "RATE_LIMITED":
1478
+ case "NETWORK_ERROR":
1479
+ return error;
1480
+ default:
1481
+ return new CapxulError({
1482
+ code: "NETWORK_ERROR",
1483
+ message: error.message,
1484
+ cause: error,
1485
+ details: error.details,
1486
+ operationId: error.operationId,
1487
+ correlationId: error.correlationId,
1488
+ retryable: error.retryable
1489
+ });
1490
+ }
1491
+ }
1121
1492
 
1122
1493
  // src/core/webhook-endpoints.ts
1123
1494
  function createWebhookEndpointsClient() {
@@ -1217,7 +1588,7 @@ function createOrganizationsClient(config = {}) {
1217
1588
  },
1218
1589
  payments: createOrgPaymentsClient(),
1219
1590
  transfers: createOrgTransfersClient(),
1220
- withdrawals: createOrgWithdrawalsClient(),
1591
+ withdrawals: createOrgWithdrawalsClient(config),
1221
1592
  documents: createOrgDocumentsClient(),
1222
1593
  webhookEndpoints: createWebhookEndpointsClient(),
1223
1594
  webhookEvents: createWebhookEventsClient()
@@ -1232,6 +1603,96 @@ function createSubAccountsClient() {
1232
1603
  };
1233
1604
  }
1234
1605
 
1606
+ // src/core/token-transfers.ts
1607
+ var toTokenTransferId = (raw) => {
1608
+ if (typeof raw !== "string" || raw.length === 0) {
1609
+ throw new Error(
1610
+ `Invalid tokenTransferId: expected non-empty string, got ${String(raw)}`
1611
+ );
1612
+ }
1613
+ return raw;
1614
+ };
1615
+ function brandRow(row) {
1616
+ return {
1617
+ ...row,
1618
+ id: toTokenTransferId(row.id)
1619
+ };
1620
+ }
1621
+ function createTokenTransfersClient(config = {}) {
1622
+ return {
1623
+ list: async (input) => {
1624
+ if (!config.data) {
1625
+ return stub("tokenTransfers.list");
1626
+ }
1627
+ try {
1628
+ const raw = await config.data.query(
1629
+ api.tokenTransfers.queries.list,
1630
+ {
1631
+ limit: input?.limit,
1632
+ cursor: input?.cursor,
1633
+ direction: input?.direction
1634
+ }
1635
+ );
1636
+ if (!raw) {
1637
+ return [
1638
+ new CapxulError({
1639
+ code: "NOT_AUTHENTICATED",
1640
+ message: "tokenTransfers.list requires an authenticated session."
1641
+ }),
1642
+ null
1643
+ ];
1644
+ }
1645
+ return [
1646
+ null,
1647
+ {
1648
+ object: "list",
1649
+ data: raw.items.map(brandRow),
1650
+ page: {
1651
+ hasMore: raw.hasMore,
1652
+ nextCursor: raw.nextCursor
1653
+ },
1654
+ displayCurrency: raw.displayCurrency
1655
+ }
1656
+ ];
1657
+ } catch (cause) {
1658
+ return [fromConvexError(cause), null];
1659
+ }
1660
+ },
1661
+ retrieve: async (input) => {
1662
+ if (!config.data) {
1663
+ return stub("tokenTransfers.retrieve");
1664
+ }
1665
+ try {
1666
+ const raw = await config.data.query(
1667
+ api.tokenTransfers.queries.getByTxLogIndex,
1668
+ {
1669
+ txHash: input.txHash,
1670
+ logIndex: input.logIndex,
1671
+ chainId: input.chainId
1672
+ }
1673
+ );
1674
+ if (!raw) {
1675
+ return [
1676
+ new CapxulError({
1677
+ code: "NOT_FOUND",
1678
+ message: `tokenTransfer (txHash=${input.txHash}, logIndex=${input.logIndex}) not found or not visible to caller.`,
1679
+ details: {
1680
+ txHash: input.txHash,
1681
+ logIndex: input.logIndex,
1682
+ chainId: input.chainId
1683
+ }
1684
+ }),
1685
+ null
1686
+ ];
1687
+ }
1688
+ return [null, brandRow(raw)];
1689
+ } catch (cause) {
1690
+ return [fromConvexError(cause), null];
1691
+ }
1692
+ }
1693
+ };
1694
+ }
1695
+
1235
1696
  // src/core/virtual-accounts.ts
1236
1697
  function createVirtualAccountsClient() {
1237
1698
  return {
@@ -2083,7 +2544,8 @@ function createCapxulClient(config = {}) {
2083
2544
  organizations: createOrganizationsClient(config),
2084
2545
  payments: createPaymentsClient(config),
2085
2546
  transfers: createTransfersClient(),
2086
- withdrawals: createWithdrawalsClient(),
2547
+ tokenTransfers: createTokenTransfersClient(config),
2548
+ withdrawals: createWithdrawalsClient(config),
2087
2549
  documents: createDocumentsClient(),
2088
2550
  subAccounts: createSubAccountsClient(),
2089
2551
  virtualAccounts: createVirtualAccountsClient(),
@@ -2201,4 +2663,4 @@ function isWebhookEvent(value) {
2201
2663
  return typeof candidate.id === "string" && typeof candidate.type === "string" && typeof candidate.createdAt === "string" && (candidate.operationId === void 0 || typeof candidate.operationId === "string") && (candidate.correlationId === void 0 || typeof candidate.correlationId === "string") && !!candidate.data && typeof candidate.data === "object" && !Array.isArray(candidate.data);
2202
2664
  }
2203
2665
 
2204
- export { CapxulError, createAuthFlowMachine, createCapxulClient, createLocalSigner, createOnboardingFlowMachine, createProvisioningMachine as createProvisioningFlowMachine, makeHttpTransport, matchAction, matchError, matchStatus, toAccountId, toApiKeyId, toBalanceLedgerEntryId, toDocumentId, toEmail, toExternalAccountId, toKybProfileId, toKycProfileId, toMemberId, toOperationId, toOrganizationId, toPaymentId, toPhoneNumber, toSafeId, toSubAccountId, toTransferId, toTreasuryId, toUsername, toVirtualAccountId, toVirtualCardId, toWebhookEndpointId, toWebhookEventId, toWithdrawalId, tryCatch, verifyWebhook };
2666
+ export { CapxulError, createAuthFlowMachine, createCapxulClient, createLocalSigner, createOnboardingFlowMachine, createProvisioningMachine as createProvisioningFlowMachine, makeHttpTransport, matchAction, matchError, matchStatus, toAccountId, toApiKeyId, toBalanceLedgerEntryId, toDocumentId, toEmail, toExternalAccountId, toKybProfileId, toKycProfileId, toMemberId, toOperationId, toOrganizationId, toPaymentId, toPhoneNumber, toSafeId, toSubAccountId, toTokenTransferId, toTransferId, toTreasuryId, toUsername, toVirtualAccountId, toVirtualCardId, toWebhookEndpointId, toWebhookEventId, toWithdrawalId, tryCatch, verifyWebhook };
@@ -155,7 +155,15 @@ type Payment = WithStatus<WirePaymentWithBrand, PaymentStatus>;
155
155
  type CreatePaymentResult = WithStatus<WirePaymentWithBrand, "processing" | "action_required" | "failed">;
156
156
  type PaymentParty = types.PaymentParty;
157
157
  type WireWithdrawalWithBrand = Rebrand<types.Withdrawal, WithdrawalId>;
158
- type WithdrawalStatus = PaymentStatus;
158
+ /**
159
+ * Canon-aligned superset (resources.mdx §withdrawal lifecycle note).
160
+ * Wider than `OperationStatus` because `submitted → completed` is a
161
+ * withdrawal-specific transition driven by external reconciliation
162
+ * the operation envelope cannot witness directly. Slice 1 of
163
+ * Withdrawals v1 (#440) widened this from `PaymentStatus` to match
164
+ * canon.
165
+ */
166
+ type WithdrawalStatus = "draft" | "action_required" | "processing" | "submitted" | "completed" | "failed" | "canceled";
159
167
  type Withdrawal = WithStatus<WireWithdrawalWithBrand, WithdrawalStatus>;
160
168
  type CreateWithdrawalResult = WithStatus<WireWithdrawalWithBrand, "processing" | "action_required" | "failed">;
161
169
  type WireTransferWithBrand = Rebrand<types.Transfer, TransferId>;
@@ -155,7 +155,15 @@ type Payment = WithStatus<WirePaymentWithBrand, PaymentStatus>;
155
155
  type CreatePaymentResult = WithStatus<WirePaymentWithBrand, "processing" | "action_required" | "failed">;
156
156
  type PaymentParty = types.PaymentParty;
157
157
  type WireWithdrawalWithBrand = Rebrand<types.Withdrawal, WithdrawalId>;
158
- type WithdrawalStatus = PaymentStatus;
158
+ /**
159
+ * Canon-aligned superset (resources.mdx §withdrawal lifecycle note).
160
+ * Wider than `OperationStatus` because `submitted → completed` is a
161
+ * withdrawal-specific transition driven by external reconciliation
162
+ * the operation envelope cannot witness directly. Slice 1 of
163
+ * Withdrawals v1 (#440) widened this from `PaymentStatus` to match
164
+ * canon.
165
+ */
166
+ type WithdrawalStatus = "draft" | "action_required" | "processing" | "submitted" | "completed" | "failed" | "canceled";
159
167
  type Withdrawal = WithStatus<WireWithdrawalWithBrand, WithdrawalStatus>;
160
168
  type CreateWithdrawalResult = WithStatus<WireWithdrawalWithBrand, "processing" | "action_required" | "failed">;
161
169
  type WireTransferWithBrand = Rebrand<types.Transfer, TransferId>;
@@ -1,4 +1,4 @@
1
- import { Z as WebhookEvent } from './types-z4VLz9rS.cjs';
1
+ import { Z as WebhookEvent } from './types-DVWojoy4.cjs';
2
2
  import '@repo/api-contract/gen/types';
3
3
  import './next-action-DkrwXYay.cjs';
4
4
 
@@ -1,4 +1,4 @@
1
- import { Z as WebhookEvent } from './types-BE3tVIOI.js';
1
+ import { Z as WebhookEvent } from './types-75UokagF.js';
2
2
  import '@repo/api-contract/gen/types';
3
3
  import './next-action-DkrwXYay.js';
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capxul/sdk",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.4",
4
4
  "description": "Headless TypeScript client for Capxul's /v1/* HTTP contract.",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,
@@ -71,8 +71,8 @@
71
71
  "vitest": "^4.1.2",
72
72
  "zod": "^4.3.6",
73
73
  "@repo/api-contract": "0.0.0",
74
- "@repo/config": "0.0.0",
75
74
  "@repo/backend": "0.0.0",
75
+ "@repo/config": "0.0.0",
76
76
  "@repo/observability": "0.0.0",
77
77
  "@repo/platform-kernel": "0.0.0",
78
78
  "@repo/typescript-config": "0.0.0"