@capxul/sdk 0.1.0-alpha.9 → 0.2.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/CHANGELOG.md +126 -0
- package/README.md +103 -16
- package/dist/{client-ChZrdf3R.d.ts → client-CbUeJoM9.d.ts} +84 -235
- package/dist/{client-DG6ODWu6.d.cts → client-UEm2oZbZ.d.cts} +84 -235
- package/dist/client.cjs +1655 -1073
- package/dist/client.d.cts +4 -4
- package/dist/client.d.ts +4 -4
- package/dist/client.js +1655 -1073
- package/dist/{errors-QHD5Tlok.d.ts → errors-CwhCWGxm.d.ts} +1 -1
- package/dist/{errors-GgKrSUKp.d.cts → errors-rqxuUhQP.d.cts} +1 -1
- package/dist/errors.d.cts +2 -2
- package/dist/errors.d.ts +2 -2
- package/dist/index.cjs +1655 -1076
- package/dist/index.d.cts +73 -112
- package/dist/index.d.ts +73 -112
- package/dist/index.js +1654 -1076
- package/dist/{next-action-DkrwXYay.d.cts → next-action-CTGl8wpy.d.cts} +2 -2
- package/dist/{next-action-DkrwXYay.d.ts → next-action-CTGl8wpy.d.ts} +2 -2
- package/dist/{types-PM4AQRLP.d.ts → types-BD4VAQb5.d.ts} +77 -8
- package/dist/{types-hfcOE7Oi.d.cts → types-HlwCIjgQ.d.cts} +77 -8
- package/dist/webhooks.cjs +1 -1
- package/dist/webhooks.d.cts +2 -2
- package/dist/webhooks.d.ts +2 -2
- package/dist/webhooks.js +1 -1
- package/package.json +6 -5
package/dist/client.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
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, encodeFunctionData, encodePacked, keccak256, getContractAddress, createPublicClient, http } from 'viem';
|
|
4
4
|
import { entryPoint07Address, createPaymasterClient, createBundlerClient } from 'viem/account-abstraction';
|
|
5
5
|
import { baseSepolia } from 'viem/chains';
|
|
6
|
+
import { ConvexHttpClient } from 'convex/browser';
|
|
6
7
|
import { setup, fromPromise, assign } from 'xstate';
|
|
7
8
|
|
|
8
9
|
// src/_generated/api.js
|
|
@@ -107,17 +108,270 @@ function track(...args) {
|
|
|
107
108
|
const [name, props] = args;
|
|
108
109
|
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
|
|
112
|
+
// ../config/src/chain.ts
|
|
113
|
+
var CAPXUL_PAYMENTS_ADDRESS = "0xe740ea65521edc9bef0ea75d30b5334711db99f4";
|
|
114
|
+
var TEST_USDC_ADDRESS = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
|
|
115
|
+
var CAPXUL_API_BASE_URL = "https://elated-oyster-269.convex.site";
|
|
116
|
+
|
|
117
|
+
// ../config/src/timing.ts
|
|
118
|
+
var FLOW_INVOKE_TIMEOUT_MS = 3e4;
|
|
119
|
+
|
|
120
|
+
// ../config/src/errors.ts
|
|
121
|
+
var CapxulError2 = class extends Error {
|
|
122
|
+
code;
|
|
123
|
+
details;
|
|
124
|
+
correlationId;
|
|
125
|
+
layer;
|
|
126
|
+
constructor(code, message, options) {
|
|
127
|
+
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
128
|
+
this.code = code;
|
|
129
|
+
this.details = options?.details;
|
|
130
|
+
this.correlationId = options?.correlationId;
|
|
131
|
+
this.layer = options?.layer;
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
var Errors = {
|
|
135
|
+
notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
|
|
136
|
+
profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
|
|
137
|
+
smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
|
|
138
|
+
envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
|
|
139
|
+
openfortApi: (operation, cause) => new CapxulError2(
|
|
140
|
+
"PROVIDER_ERROR",
|
|
141
|
+
`Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
142
|
+
{ cause, details: { provider: "openfort", operation } }
|
|
143
|
+
),
|
|
144
|
+
shieldApi: (status, detail) => new CapxulError2(
|
|
145
|
+
"PROVIDER_ERROR",
|
|
146
|
+
`Shield API error (${status}): ${detail}`,
|
|
147
|
+
{ details: { provider: "shield", status } }
|
|
148
|
+
),
|
|
149
|
+
providerError: (provider, operation, cause) => (
|
|
150
|
+
// Public `message` is redacted to a fixed shape so provider-side
|
|
151
|
+
// exception text never leaks to the client. The original `cause`
|
|
152
|
+
// is preserved on `Error.cause` for server-side debugging via
|
|
153
|
+
// observability sinks (Sentry, console traces).
|
|
154
|
+
new CapxulError2(
|
|
155
|
+
"PROVIDER_ERROR",
|
|
156
|
+
`Provider error: ${provider} ${operation}`,
|
|
157
|
+
{ cause, details: { provider, operation } }
|
|
158
|
+
)
|
|
159
|
+
),
|
|
160
|
+
invalidInput: (field, reason) => new CapxulError2(
|
|
161
|
+
"INVALID_INPUT",
|
|
162
|
+
`Invalid ${field}: ${reason}`,
|
|
163
|
+
{ details: { field, reason } }
|
|
164
|
+
),
|
|
165
|
+
playerNotFound: (playerId) => new CapxulError2(
|
|
166
|
+
"PLAYER_NOT_FOUND",
|
|
167
|
+
playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
|
|
168
|
+
),
|
|
169
|
+
accountNotFound: (accountId) => new CapxulError2(
|
|
170
|
+
"ACCOUNT_NOT_FOUND",
|
|
171
|
+
accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
|
|
172
|
+
),
|
|
173
|
+
invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
|
|
174
|
+
permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
|
|
175
|
+
notFound: (resource, id) => new CapxulError2(
|
|
176
|
+
"NOT_FOUND",
|
|
177
|
+
id ? `${resource} ${id} not found` : `${resource} not found`
|
|
178
|
+
),
|
|
179
|
+
idempotencyConflict: (details) => new CapxulError2(
|
|
180
|
+
"IDEMPOTENCY_CONFLICT",
|
|
181
|
+
"Idempotency key was already used for a different request",
|
|
182
|
+
{ details }
|
|
183
|
+
),
|
|
184
|
+
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
185
|
+
details
|
|
186
|
+
}),
|
|
187
|
+
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
188
|
+
details: { ...details }
|
|
189
|
+
}),
|
|
190
|
+
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
191
|
+
/**
|
|
192
|
+
* Verification gate. Surfaced when a request hits a verification
|
|
193
|
+
* boundary the actor cannot cross under their current state. Two
|
|
194
|
+
* variants share this code:
|
|
195
|
+
*
|
|
196
|
+
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
197
|
+
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
198
|
+
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
199
|
+
* `details.rail` + `details.currentKind`.
|
|
200
|
+
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
201
|
+
* the required tier. Carries `details.requiredTier`.
|
|
202
|
+
*
|
|
203
|
+
* Code is shared because both expose the same UX shape ("you cannot
|
|
204
|
+
* proceed until verification advances"); the `details.*` keys
|
|
205
|
+
* differentiate the route.
|
|
206
|
+
*/
|
|
207
|
+
verificationRequired: (details) => {
|
|
208
|
+
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
209
|
+
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
210
|
+
details: { ...details }
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// ../config/src/safe.ts
|
|
216
|
+
var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
217
|
+
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
218
|
+
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
219
|
+
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
220
|
+
var MULTI_SEND = "0x38869bf66a61cf6bdb996a6ae40d5853fd43b526";
|
|
221
|
+
|
|
222
|
+
// ../config/src/org-roles.ts
|
|
223
|
+
function roleKeyFromLabel(label) {
|
|
224
|
+
const bytes = new TextEncoder().encode(label);
|
|
225
|
+
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
226
|
+
return "0x" + hex.padEnd(64, "0");
|
|
227
|
+
}
|
|
228
|
+
roleKeyFromLabel("OWNER");
|
|
229
|
+
roleKeyFromLabel("FINANCE_MANAGER");
|
|
230
|
+
roleKeyFromLabel("PAYMENTS_OPERATOR");
|
|
231
|
+
var defaultSafeDeriveConfig = {
|
|
232
|
+
safeProxyFactory: SAFE_PROXY_FACTORY,
|
|
233
|
+
safeL2Singleton: SAFE_L2_SINGLETON,
|
|
234
|
+
safeModuleSetup: SAFE_MODULE_SETUP,
|
|
235
|
+
safe4337Module: SAFE_4337_MODULE,
|
|
236
|
+
multiSend: MULTI_SEND
|
|
237
|
+
};
|
|
238
|
+
var SAFE_PROXY_CREATION_CODE = "0x608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564";
|
|
239
|
+
var enableModulesAbi = [
|
|
240
|
+
{
|
|
241
|
+
type: "function",
|
|
242
|
+
name: "enableModules",
|
|
243
|
+
inputs: [{ type: "address[]", name: "modules" }],
|
|
244
|
+
outputs: [],
|
|
245
|
+
stateMutability: "nonpayable"
|
|
246
|
+
}
|
|
247
|
+
];
|
|
248
|
+
var multiSendAbi = [
|
|
249
|
+
{
|
|
250
|
+
type: "function",
|
|
251
|
+
name: "multiSend",
|
|
252
|
+
inputs: [{ type: "bytes", name: "transactions" }],
|
|
253
|
+
outputs: [],
|
|
254
|
+
stateMutability: "payable"
|
|
255
|
+
}
|
|
256
|
+
];
|
|
257
|
+
var setupAbi = [
|
|
258
|
+
{
|
|
259
|
+
type: "function",
|
|
260
|
+
name: "setup",
|
|
261
|
+
inputs: [
|
|
262
|
+
{ type: "address[]", name: "owners" },
|
|
263
|
+
{ type: "uint256", name: "threshold" },
|
|
264
|
+
{ type: "address", name: "to" },
|
|
265
|
+
{ type: "bytes", name: "data" },
|
|
266
|
+
{ type: "address", name: "fallbackHandler" },
|
|
267
|
+
{ type: "address", name: "paymentToken" },
|
|
268
|
+
{ type: "uint256", name: "payment" },
|
|
269
|
+
{ type: "address", name: "paymentReceiver" }
|
|
270
|
+
],
|
|
271
|
+
outputs: [],
|
|
272
|
+
stateMutability: "nonpayable"
|
|
273
|
+
}
|
|
274
|
+
];
|
|
275
|
+
function encodeInternalTransaction(tx) {
|
|
276
|
+
const encoded = encodePacked(
|
|
277
|
+
["uint8", "address", "uint256", "uint256", "bytes"],
|
|
278
|
+
[
|
|
279
|
+
tx.operation,
|
|
280
|
+
tx.to,
|
|
281
|
+
tx.value,
|
|
282
|
+
BigInt(tx.data.slice(2).length / 2),
|
|
283
|
+
tx.data
|
|
284
|
+
]
|
|
285
|
+
);
|
|
286
|
+
return encoded.slice(2);
|
|
287
|
+
}
|
|
288
|
+
function computeSaltNonce(ownerAddress) {
|
|
289
|
+
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
290
|
+
}
|
|
291
|
+
function deriveSafeAddress(signerAddress, config = defaultSafeDeriveConfig) {
|
|
292
|
+
const saltNonce = computeSaltNonce(signerAddress);
|
|
293
|
+
const enableModulesData = encodeFunctionData({
|
|
294
|
+
abi: enableModulesAbi,
|
|
295
|
+
functionName: "enableModules",
|
|
296
|
+
args: [[config.safe4337Module]]
|
|
297
|
+
});
|
|
298
|
+
const innerTx = encodeInternalTransaction({
|
|
299
|
+
operation: 1,
|
|
300
|
+
to: config.safeModuleSetup,
|
|
301
|
+
value: 0n,
|
|
302
|
+
data: enableModulesData
|
|
303
|
+
});
|
|
304
|
+
const multiSendCallData = encodeFunctionData({
|
|
305
|
+
abi: multiSendAbi,
|
|
306
|
+
functionName: "multiSend",
|
|
307
|
+
args: [`0x${innerTx}`]
|
|
308
|
+
});
|
|
309
|
+
const initializer = encodeFunctionData({
|
|
310
|
+
abi: setupAbi,
|
|
311
|
+
functionName: "setup",
|
|
312
|
+
args: [
|
|
313
|
+
[signerAddress],
|
|
314
|
+
1n,
|
|
315
|
+
config.multiSend,
|
|
316
|
+
multiSendCallData,
|
|
317
|
+
config.safe4337Module,
|
|
318
|
+
"0x0000000000000000000000000000000000000000",
|
|
319
|
+
0n,
|
|
320
|
+
"0x0000000000000000000000000000000000000000"
|
|
321
|
+
]
|
|
322
|
+
});
|
|
323
|
+
const deploymentCode = encodePacked(
|
|
324
|
+
["bytes", "uint256"],
|
|
325
|
+
[SAFE_PROXY_CREATION_CODE, BigInt(config.safeL2Singleton)]
|
|
326
|
+
);
|
|
327
|
+
const salt = keccak256(
|
|
328
|
+
encodePacked(
|
|
329
|
+
["bytes32", "uint256"],
|
|
330
|
+
[keccak256(encodePacked(["bytes"], [initializer])), saltNonce]
|
|
331
|
+
)
|
|
332
|
+
);
|
|
333
|
+
return getContractAddress({
|
|
334
|
+
from: config.safeProxyFactory,
|
|
335
|
+
salt,
|
|
336
|
+
bytecode: deploymentCode,
|
|
337
|
+
opcode: "CREATE2"
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/internal/safe/account.ts
|
|
342
|
+
async function buildSafeAccount(signer, chain) {
|
|
113
343
|
try {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
344
|
+
const publicClient = createPublicClient({
|
|
345
|
+
chain: baseSepolia,
|
|
346
|
+
transport: http(chain.rpcUrl)
|
|
347
|
+
});
|
|
348
|
+
return await toSafeSmartAccount({
|
|
349
|
+
client: publicClient,
|
|
350
|
+
entryPoint: { address: entryPoint07Address, version: "0.7" },
|
|
351
|
+
version: "1.4.1",
|
|
352
|
+
owners: [signer],
|
|
353
|
+
saltNonce: computeSaltNonce2(signer.address),
|
|
354
|
+
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
355
|
+
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
356
|
+
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
357
|
+
safe4337ModuleAddress: SAFE_4337_MODULE,
|
|
358
|
+
safeModules: [],
|
|
359
|
+
setupTransactions: []
|
|
360
|
+
});
|
|
361
|
+
} catch (cause) {
|
|
362
|
+
throw new CapxulError({
|
|
363
|
+
code: "NETWORK_ERROR",
|
|
364
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
365
|
+
cause,
|
|
366
|
+
details: { chainId: chain.chainId }
|
|
367
|
+
});
|
|
117
368
|
}
|
|
118
369
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
370
|
+
function computeSaltNonce2(ownerAddress) {
|
|
371
|
+
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
372
|
+
}
|
|
373
|
+
function deriveSafeAddress2(signerAddress) {
|
|
374
|
+
return deriveSafeAddress(signerAddress, defaultSafeDeriveConfig);
|
|
121
375
|
}
|
|
122
376
|
|
|
123
377
|
// ../platform-kernel/src/ids.ts
|
|
@@ -132,12 +386,24 @@ function makePrefixedIdConstructor(prefix, fieldName) {
|
|
|
132
386
|
return raw;
|
|
133
387
|
};
|
|
134
388
|
}
|
|
389
|
+
var toSafeId = makePrefixedIdConstructor(
|
|
390
|
+
"safe",
|
|
391
|
+
"safeId"
|
|
392
|
+
);
|
|
393
|
+
var toTreasuryId = makePrefixedIdConstructor(
|
|
394
|
+
"try",
|
|
395
|
+
"treasuryId"
|
|
396
|
+
);
|
|
135
397
|
var toOperationId = makePrefixedIdConstructor(
|
|
136
398
|
"op",
|
|
137
399
|
"operationId"
|
|
138
400
|
);
|
|
139
401
|
var toCorrelationId = makePrefixedIdConstructor("ctx", "correlationId");
|
|
140
402
|
var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
|
|
403
|
+
var toSubAccountId = makePrefixedIdConstructor(
|
|
404
|
+
"sub",
|
|
405
|
+
"subAccountId"
|
|
406
|
+
);
|
|
141
407
|
|
|
142
408
|
// src/core/external-accounts.ts
|
|
143
409
|
function brandExternalAccount(raw) {
|
|
@@ -154,13 +420,13 @@ function brandExternalAccount(raw) {
|
|
|
154
420
|
function createExternalAccountsClient(config = {}) {
|
|
155
421
|
return {
|
|
156
422
|
retrieve: async (externalAccountId) => {
|
|
157
|
-
if (!config.
|
|
423
|
+
if (!config._data) {
|
|
158
424
|
return stub(
|
|
159
425
|
"externalAccounts.retrieve"
|
|
160
426
|
);
|
|
161
427
|
}
|
|
162
428
|
const [err, raw] = await tryCatch(
|
|
163
|
-
config.
|
|
429
|
+
config._data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
164
430
|
externalAccountId
|
|
165
431
|
})
|
|
166
432
|
);
|
|
@@ -182,11 +448,11 @@ function createExternalAccountsClient(config = {}) {
|
|
|
182
448
|
return [null, brandExternalAccount(raw)];
|
|
183
449
|
},
|
|
184
450
|
remove: async (externalAccountId) => {
|
|
185
|
-
if (!config.
|
|
451
|
+
if (!config._data) {
|
|
186
452
|
return stub("externalAccounts.remove");
|
|
187
453
|
}
|
|
188
454
|
const [err] = await tryCatch(
|
|
189
|
-
config.
|
|
455
|
+
config._data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
190
456
|
externalAccountId
|
|
191
457
|
})
|
|
192
458
|
);
|
|
@@ -201,17 +467,203 @@ function createExternalAccountsClient(config = {}) {
|
|
|
201
467
|
};
|
|
202
468
|
}
|
|
203
469
|
|
|
470
|
+
// src/core/sub-accounts.ts
|
|
471
|
+
function malformedWireError(reason, raw) {
|
|
472
|
+
return new CapxulError({
|
|
473
|
+
code: "PROVIDER_ERROR",
|
|
474
|
+
message: `convex brandSubAccount failed: ${reason}`,
|
|
475
|
+
details: {
|
|
476
|
+
provider: "convex",
|
|
477
|
+
operation: "brandSubAccount",
|
|
478
|
+
reason,
|
|
479
|
+
// PII discipline (`.claude/rules/posthog.md`): user-authored
|
|
480
|
+
// strings on the wire (`name`, `purpose`) are customer-confidential
|
|
481
|
+
// — sub-account names like "Q3 Acquisition Reserve" or
|
|
482
|
+
// "Vendor ABC payments" must not flow into telemetry. We emit a
|
|
483
|
+
// structural keys-only sample via a strict ALLOWLIST so any future
|
|
484
|
+
// wire-shape addition (e.g. `recipientEmail`, `tags`) is dropped
|
|
485
|
+
// by construction rather than leaked through a denylist gap.
|
|
486
|
+
sample: safeSampleShape(raw)
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
function safeSampleShape(raw) {
|
|
491
|
+
if (raw === null || typeof raw !== "object") {
|
|
492
|
+
return { type: typeof raw };
|
|
493
|
+
}
|
|
494
|
+
const r = raw;
|
|
495
|
+
const balance = r.balance;
|
|
496
|
+
return {
|
|
497
|
+
object: typeof r.object === "string" ? r.object : typeof r.object,
|
|
498
|
+
idPresent: typeof r.id === "string" && r.id.length > 0,
|
|
499
|
+
// First 4 chars only — enough to distinguish "sub_" prefixed IDs
|
|
500
|
+
// from accidental other resource IDs without leaking the full ID.
|
|
501
|
+
idPrefix: typeof r.id === "string" ? r.id.slice(0, 4) : void 0,
|
|
502
|
+
parentKind: r.parent !== null && typeof r.parent === "object" ? r.parent.kind : typeof r.parent,
|
|
503
|
+
status: r.status,
|
|
504
|
+
hasName: typeof r.name === "string",
|
|
505
|
+
hasPurpose: r.purpose !== void 0,
|
|
506
|
+
balanceShape: balance !== null && typeof balance === "object" ? Object.keys(balance).sort() : typeof balance,
|
|
507
|
+
createdAtType: typeof r.createdAt,
|
|
508
|
+
updatedAtType: typeof r.updatedAt
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
function isMoneyShape(v) {
|
|
512
|
+
if (typeof v !== "object" || v === null) return false;
|
|
513
|
+
const m = v;
|
|
514
|
+
return typeof m.value === "string" && typeof m.currency === "string";
|
|
515
|
+
}
|
|
516
|
+
function isParentShape(v) {
|
|
517
|
+
if (typeof v !== "object" || v === null) return false;
|
|
518
|
+
const p = v;
|
|
519
|
+
return (p.kind === "account" || p.kind === "organization") && typeof p.id === "string";
|
|
520
|
+
}
|
|
521
|
+
function isFiniteNonNegativeInteger(v) {
|
|
522
|
+
return typeof v === "number" && Number.isFinite(v) && Number.isInteger(v) && v >= 0;
|
|
523
|
+
}
|
|
524
|
+
function validateWireSubAccount(raw) {
|
|
525
|
+
if (typeof raw !== "object" || raw === null) {
|
|
526
|
+
return { ok: false, reason: "not an object" };
|
|
527
|
+
}
|
|
528
|
+
const r = raw;
|
|
529
|
+
if (r.object !== "sub_account") {
|
|
530
|
+
return { ok: false, reason: `object must be "sub_account" (got ${String(r.object)})` };
|
|
531
|
+
}
|
|
532
|
+
if (typeof r.id !== "string" || r.id.length === 0) {
|
|
533
|
+
return { ok: false, reason: "id must be a non-empty string" };
|
|
534
|
+
}
|
|
535
|
+
if (!isParentShape(r.parent)) {
|
|
536
|
+
return { ok: false, reason: "parent must be { kind: 'account' | 'organization', id: string }" };
|
|
537
|
+
}
|
|
538
|
+
if (typeof r.name !== "string") {
|
|
539
|
+
return { ok: false, reason: "name must be a string" };
|
|
540
|
+
}
|
|
541
|
+
if (r.purpose !== void 0 && typeof r.purpose !== "string") {
|
|
542
|
+
return { ok: false, reason: "purpose must be a string when present" };
|
|
543
|
+
}
|
|
544
|
+
if (r.status !== "active" && r.status !== "archived") {
|
|
545
|
+
return { ok: false, reason: `status must be "active" | "archived" (got ${String(r.status)})` };
|
|
546
|
+
}
|
|
547
|
+
if (!isMoneyShape(r.balance)) {
|
|
548
|
+
return { ok: false, reason: "balance must be { value: string, currency: string }" };
|
|
549
|
+
}
|
|
550
|
+
if (!isFiniteNonNegativeInteger(r.createdAt)) {
|
|
551
|
+
return { ok: false, reason: "createdAt must be a finite non-negative integer (epoch ms)" };
|
|
552
|
+
}
|
|
553
|
+
if (r.updatedAt !== void 0 && !isFiniteNonNegativeInteger(r.updatedAt)) {
|
|
554
|
+
return { ok: false, reason: "updatedAt must be a finite non-negative integer when present" };
|
|
555
|
+
}
|
|
556
|
+
return { ok: true, value: r };
|
|
557
|
+
}
|
|
558
|
+
function brandSubAccount(raw) {
|
|
559
|
+
const result = validateWireSubAccount(raw);
|
|
560
|
+
if (!result.ok) {
|
|
561
|
+
throw malformedWireError(result.reason, raw);
|
|
562
|
+
}
|
|
563
|
+
const wire = result.value;
|
|
564
|
+
return {
|
|
565
|
+
object: wire.object,
|
|
566
|
+
id: toSubAccountId(wire.id),
|
|
567
|
+
parent: wire.parent,
|
|
568
|
+
name: wire.name,
|
|
569
|
+
...wire.purpose !== void 0 ? { purpose: wire.purpose } : {},
|
|
570
|
+
status: wire.status,
|
|
571
|
+
balance: wire.balance,
|
|
572
|
+
createdAt: new Date(wire.createdAt).toISOString()
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
function tryBrandSubAccount(raw) {
|
|
576
|
+
try {
|
|
577
|
+
return [null, brandSubAccount(raw)];
|
|
578
|
+
} catch (err) {
|
|
579
|
+
if (err instanceof CapxulError && err.code === "PROVIDER_ERROR") {
|
|
580
|
+
return [err, null];
|
|
581
|
+
}
|
|
582
|
+
return [
|
|
583
|
+
malformedWireError(
|
|
584
|
+
err instanceof Error ? err.message : String(err),
|
|
585
|
+
raw
|
|
586
|
+
),
|
|
587
|
+
null
|
|
588
|
+
];
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
function createSubAccountsClient(config = {}) {
|
|
592
|
+
return {
|
|
593
|
+
retrieve: async (subAccountId) => {
|
|
594
|
+
if (!config._data) {
|
|
595
|
+
return stub("subAccounts.retrieve");
|
|
596
|
+
}
|
|
597
|
+
const [err, raw] = await tryCatch(
|
|
598
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
599
|
+
subAccountId
|
|
600
|
+
})
|
|
601
|
+
);
|
|
602
|
+
if (err) {
|
|
603
|
+
return [
|
|
604
|
+
fromConvexError(err),
|
|
605
|
+
null
|
|
606
|
+
];
|
|
607
|
+
}
|
|
608
|
+
if (!raw) {
|
|
609
|
+
return [
|
|
610
|
+
new CapxulError({
|
|
611
|
+
code: "NOT_FOUND",
|
|
612
|
+
message: `sub_account ${subAccountId} not found`
|
|
613
|
+
}),
|
|
614
|
+
null
|
|
615
|
+
];
|
|
616
|
+
}
|
|
617
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
618
|
+
if (brandErr) {
|
|
619
|
+
return [brandErr, null];
|
|
620
|
+
}
|
|
621
|
+
return [null, branded];
|
|
622
|
+
},
|
|
623
|
+
remove: async (subAccountId) => {
|
|
624
|
+
if (!config._data) {
|
|
625
|
+
return stub("subAccounts.remove");
|
|
626
|
+
}
|
|
627
|
+
const [err, raw] = await tryCatch(
|
|
628
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
629
|
+
subAccountId
|
|
630
|
+
})
|
|
631
|
+
);
|
|
632
|
+
if (err) {
|
|
633
|
+
return [
|
|
634
|
+
fromConvexError(err),
|
|
635
|
+
null
|
|
636
|
+
];
|
|
637
|
+
}
|
|
638
|
+
if (!raw) {
|
|
639
|
+
return [
|
|
640
|
+
new CapxulError({
|
|
641
|
+
code: "NOT_FOUND",
|
|
642
|
+
message: `sub_account ${subAccountId} not found`
|
|
643
|
+
}),
|
|
644
|
+
null
|
|
645
|
+
];
|
|
646
|
+
}
|
|
647
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
648
|
+
if (brandErr) {
|
|
649
|
+
return [brandErr, null];
|
|
650
|
+
}
|
|
651
|
+
return [null, branded];
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
|
|
204
656
|
// src/core/accounts.ts
|
|
205
657
|
function createAccountExternalAccountsClient(config) {
|
|
206
658
|
return {
|
|
207
659
|
create: async (input) => {
|
|
208
|
-
if (!config.
|
|
660
|
+
if (!config._data) {
|
|
209
661
|
return stub(
|
|
210
662
|
"accounts.externalAccounts.create"
|
|
211
663
|
);
|
|
212
664
|
}
|
|
213
665
|
const [err, raw] = await tryCatch(
|
|
214
|
-
config.
|
|
666
|
+
config._data.mutation(
|
|
215
667
|
api.externalAccounts.mutations.createPersonal,
|
|
216
668
|
{
|
|
217
669
|
kind: input.kind,
|
|
@@ -249,13 +701,13 @@ function createAccountExternalAccountsClient(config) {
|
|
|
249
701
|
];
|
|
250
702
|
},
|
|
251
703
|
list: async (input) => {
|
|
252
|
-
if (!config.
|
|
704
|
+
if (!config._data) {
|
|
253
705
|
return stub(
|
|
254
706
|
"accounts.externalAccounts.list"
|
|
255
707
|
);
|
|
256
708
|
}
|
|
257
709
|
const [err, result] = await tryCatch(
|
|
258
|
-
config.
|
|
710
|
+
config._data.query(api.externalAccounts.queries.listPersonal, {
|
|
259
711
|
limit: input.limit,
|
|
260
712
|
cursor: input.cursor
|
|
261
713
|
})
|
|
@@ -278,13 +730,13 @@ function createAccountExternalAccountsClient(config) {
|
|
|
278
730
|
];
|
|
279
731
|
},
|
|
280
732
|
retrieve: async (externalAccountId) => {
|
|
281
|
-
if (!config.
|
|
733
|
+
if (!config._data) {
|
|
282
734
|
return stub(
|
|
283
735
|
"accounts.externalAccounts.retrieve"
|
|
284
736
|
);
|
|
285
737
|
}
|
|
286
738
|
const [err, raw] = await tryCatch(
|
|
287
|
-
config.
|
|
739
|
+
config._data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
288
740
|
externalAccountId
|
|
289
741
|
})
|
|
290
742
|
);
|
|
@@ -311,11 +763,11 @@ function createAccountExternalAccountsClient(config) {
|
|
|
311
763
|
];
|
|
312
764
|
},
|
|
313
765
|
remove: async (externalAccountId) => {
|
|
314
|
-
if (!config.
|
|
766
|
+
if (!config._data) {
|
|
315
767
|
return stub("accounts.externalAccounts.remove");
|
|
316
768
|
}
|
|
317
769
|
const [err] = await tryCatch(
|
|
318
|
-
config.
|
|
770
|
+
config._data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
319
771
|
externalAccountId
|
|
320
772
|
})
|
|
321
773
|
);
|
|
@@ -329,14 +781,162 @@ function createAccountExternalAccountsClient(config) {
|
|
|
329
781
|
}
|
|
330
782
|
};
|
|
331
783
|
}
|
|
332
|
-
function
|
|
784
|
+
function createAccountSubAccountsClient(config) {
|
|
333
785
|
return {
|
|
334
|
-
|
|
335
|
-
if (!config.
|
|
786
|
+
create: async (input) => {
|
|
787
|
+
if (!config._data) {
|
|
788
|
+
return stub(
|
|
789
|
+
"accounts.subAccounts.create"
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
const [err, raw] = await tryCatch(
|
|
793
|
+
config._data.mutation(api.subAccounts.mutations.create, {
|
|
794
|
+
parent: { kind: "account", id: input.accountId },
|
|
795
|
+
name: input.name,
|
|
796
|
+
purpose: input.purpose
|
|
797
|
+
})
|
|
798
|
+
);
|
|
799
|
+
if (err) {
|
|
800
|
+
return [
|
|
801
|
+
fromConvexError(err),
|
|
802
|
+
null
|
|
803
|
+
];
|
|
804
|
+
}
|
|
805
|
+
if (!raw) {
|
|
806
|
+
return [
|
|
807
|
+
new CapxulError({
|
|
808
|
+
code: "NOT_FOUND",
|
|
809
|
+
message: "sub_account creation returned no resource"
|
|
810
|
+
}),
|
|
811
|
+
null
|
|
812
|
+
];
|
|
813
|
+
}
|
|
814
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
815
|
+
if (brandErr) {
|
|
816
|
+
return [
|
|
817
|
+
brandErr,
|
|
818
|
+
null
|
|
819
|
+
];
|
|
820
|
+
}
|
|
821
|
+
return [null, branded];
|
|
822
|
+
},
|
|
823
|
+
list: async (input) => {
|
|
824
|
+
if (!config._data) {
|
|
825
|
+
return stub(
|
|
826
|
+
"accounts.subAccounts.list"
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
const [err, rows] = await tryCatch(
|
|
830
|
+
config._data.query(api.subAccounts.queries.listByAccount, {
|
|
831
|
+
accountId: input.accountId
|
|
832
|
+
})
|
|
833
|
+
);
|
|
834
|
+
if (err) {
|
|
835
|
+
return [
|
|
836
|
+
fromConvexError(err),
|
|
837
|
+
null
|
|
838
|
+
];
|
|
839
|
+
}
|
|
840
|
+
const branded = [];
|
|
841
|
+
for (const row of rows) {
|
|
842
|
+
const [brandErr, value] = tryBrandSubAccount(row);
|
|
843
|
+
if (brandErr) {
|
|
844
|
+
return [
|
|
845
|
+
brandErr,
|
|
846
|
+
null
|
|
847
|
+
];
|
|
848
|
+
}
|
|
849
|
+
branded.push(value);
|
|
850
|
+
}
|
|
851
|
+
return [
|
|
852
|
+
null,
|
|
853
|
+
{
|
|
854
|
+
object: "list",
|
|
855
|
+
data: branded,
|
|
856
|
+
page: { hasMore: false }
|
|
857
|
+
}
|
|
858
|
+
];
|
|
859
|
+
},
|
|
860
|
+
retrieve: async (subAccountId) => {
|
|
861
|
+
if (!config._data) {
|
|
862
|
+
return stub(
|
|
863
|
+
"accounts.subAccounts.retrieve"
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
const [err, raw] = await tryCatch(
|
|
867
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
868
|
+
subAccountId
|
|
869
|
+
})
|
|
870
|
+
);
|
|
871
|
+
if (err) {
|
|
872
|
+
return [
|
|
873
|
+
fromConvexError(err),
|
|
874
|
+
null
|
|
875
|
+
];
|
|
876
|
+
}
|
|
877
|
+
if (!raw) {
|
|
878
|
+
return [
|
|
879
|
+
new CapxulError({
|
|
880
|
+
code: "NOT_FOUND",
|
|
881
|
+
message: `sub_account ${subAccountId} not found`
|
|
882
|
+
}),
|
|
883
|
+
null
|
|
884
|
+
];
|
|
885
|
+
}
|
|
886
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
887
|
+
if (brandErr) {
|
|
888
|
+
return [
|
|
889
|
+
brandErr,
|
|
890
|
+
null
|
|
891
|
+
];
|
|
892
|
+
}
|
|
893
|
+
return [null, branded];
|
|
894
|
+
},
|
|
895
|
+
remove: async (subAccountId) => {
|
|
896
|
+
if (!config._data) {
|
|
897
|
+
return stub(
|
|
898
|
+
"accounts.subAccounts.remove"
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
const [err, raw] = await tryCatch(
|
|
902
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
903
|
+
subAccountId
|
|
904
|
+
})
|
|
905
|
+
);
|
|
906
|
+
if (err) {
|
|
907
|
+
return [
|
|
908
|
+
fromConvexError(err),
|
|
909
|
+
null
|
|
910
|
+
];
|
|
911
|
+
}
|
|
912
|
+
if (!raw) {
|
|
913
|
+
return [
|
|
914
|
+
new CapxulError({
|
|
915
|
+
code: "NOT_FOUND",
|
|
916
|
+
message: `sub_account ${subAccountId} not found`
|
|
917
|
+
}),
|
|
918
|
+
null
|
|
919
|
+
];
|
|
920
|
+
}
|
|
921
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
922
|
+
if (brandErr) {
|
|
923
|
+
return [
|
|
924
|
+
brandErr,
|
|
925
|
+
null
|
|
926
|
+
];
|
|
927
|
+
}
|
|
928
|
+
return [null, branded];
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
function createAccountsClient(config = {}) {
|
|
933
|
+
return {
|
|
934
|
+
retrieve: async (accountId) => {
|
|
935
|
+
if (!config._data) {
|
|
336
936
|
return stub("accounts.retrieve");
|
|
337
937
|
}
|
|
338
938
|
try {
|
|
339
|
-
const account = await config.
|
|
939
|
+
const account = await config._data.query(
|
|
340
940
|
api.openfort.queries.getMyAccount,
|
|
341
941
|
{}
|
|
342
942
|
);
|
|
@@ -360,7 +960,7 @@ function createAccountsClient(config = {}) {
|
|
|
360
960
|
},
|
|
361
961
|
lookup: async () => stub("accounts.lookup"),
|
|
362
962
|
update: async (input) => {
|
|
363
|
-
if (!config.
|
|
963
|
+
if (!config._data) {
|
|
364
964
|
return stub("accounts.update");
|
|
365
965
|
}
|
|
366
966
|
if (input.countryCode !== void 0) {
|
|
@@ -374,7 +974,7 @@ function createAccountsClient(config = {}) {
|
|
|
374
974
|
];
|
|
375
975
|
}
|
|
376
976
|
try {
|
|
377
|
-
const current = await config.
|
|
977
|
+
const current = await config._data.query(
|
|
378
978
|
api.openfort.queries.getMyAccount,
|
|
379
979
|
{}
|
|
380
980
|
);
|
|
@@ -391,11 +991,11 @@ function createAccountsClient(config = {}) {
|
|
|
391
991
|
null
|
|
392
992
|
];
|
|
393
993
|
}
|
|
394
|
-
await config.
|
|
994
|
+
await config._data.mutation(api.openfort.mutations.updateProfile, {
|
|
395
995
|
displayName: input.name,
|
|
396
996
|
username: input.username
|
|
397
997
|
});
|
|
398
|
-
const updated = await config.
|
|
998
|
+
const updated = await config._data.query(
|
|
399
999
|
api.openfort.queries.getMyAccount,
|
|
400
1000
|
{}
|
|
401
1001
|
);
|
|
@@ -405,7 +1005,7 @@ function createAccountsClient(config = {}) {
|
|
|
405
1005
|
}
|
|
406
1006
|
},
|
|
407
1007
|
provisionPersonal: async (input) => {
|
|
408
|
-
if (!config.
|
|
1008
|
+
if (!config._data) {
|
|
409
1009
|
return stub(
|
|
410
1010
|
"accounts.provisionPersonal"
|
|
411
1011
|
);
|
|
@@ -420,17 +1020,17 @@ function createAccountsClient(config = {}) {
|
|
|
420
1020
|
];
|
|
421
1021
|
}
|
|
422
1022
|
try {
|
|
423
|
-
await config.
|
|
1023
|
+
await config._data.mutation(
|
|
424
1024
|
api.safe.mutations.provisionLocalPersonalAccount,
|
|
425
1025
|
{
|
|
426
1026
|
displayName: input.displayName,
|
|
427
1027
|
username: input.username,
|
|
428
1028
|
countryCode: input.countryCode,
|
|
429
1029
|
eoaAddress: input.signerProvider.signerAddress,
|
|
430
|
-
safeAddress: input.signerProvider.
|
|
1030
|
+
safeAddress: deriveSafeAddress2(input.signerProvider.signerAddress)
|
|
431
1031
|
}
|
|
432
1032
|
);
|
|
433
|
-
const account = await config.
|
|
1033
|
+
const account = await config._data.query(
|
|
434
1034
|
api.openfort.queries.getMyAccount,
|
|
435
1035
|
{}
|
|
436
1036
|
);
|
|
@@ -453,11 +1053,11 @@ function createAccountsClient(config = {}) {
|
|
|
453
1053
|
},
|
|
454
1054
|
safes: {
|
|
455
1055
|
retrieve: async (safeId) => {
|
|
456
|
-
if (!config.
|
|
1056
|
+
if (!config._data) {
|
|
457
1057
|
return stub("accounts.safes.retrieve");
|
|
458
1058
|
}
|
|
459
1059
|
try {
|
|
460
|
-
const safe = await config.
|
|
1060
|
+
const safe = await config._data.query(
|
|
461
1061
|
api.safe.queries.retrieveAccountSafe,
|
|
462
1062
|
{ safeId }
|
|
463
1063
|
);
|
|
@@ -484,19 +1084,50 @@ function createAccountsClient(config = {}) {
|
|
|
484
1084
|
retrieve: async () => stub("accounts.kycProfiles.retrieve")
|
|
485
1085
|
},
|
|
486
1086
|
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
|
-
},
|
|
1087
|
+
subAccounts: createAccountSubAccountsClient(config),
|
|
493
1088
|
balanceLedger: {
|
|
494
|
-
list: async () =>
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
1089
|
+
list: async (input) => {
|
|
1090
|
+
if (!config._data) {
|
|
1091
|
+
return stub(
|
|
1092
|
+
"accounts.balanceLedger.list"
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
try {
|
|
1096
|
+
const accountId = input.accountId.replace(/^acct_/, "");
|
|
1097
|
+
const page = await config._data.query(
|
|
1098
|
+
api.balanceLedger.queries.listForAccount,
|
|
1099
|
+
{ accountId, limit: input.limit, cursor: input.cursor }
|
|
1100
|
+
);
|
|
1101
|
+
return [null, page];
|
|
1102
|
+
} catch (cause) {
|
|
1103
|
+
return [fromConvexError(cause), null];
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
retrieve: async (entryId) => {
|
|
1107
|
+
if (!config._data) {
|
|
1108
|
+
return stub(
|
|
1109
|
+
"accounts.balanceLedger.retrieve"
|
|
1110
|
+
);
|
|
1111
|
+
}
|
|
1112
|
+
try {
|
|
1113
|
+
const entry = await config._data.query(
|
|
1114
|
+
api.balanceLedger.queries.retrieve,
|
|
1115
|
+
{ entryId }
|
|
1116
|
+
);
|
|
1117
|
+
if (!entry) {
|
|
1118
|
+
return [
|
|
1119
|
+
new CapxulError({
|
|
1120
|
+
code: "NOT_FOUND",
|
|
1121
|
+
message: `balance_ledger_entry ${entryId} not found`
|
|
1122
|
+
}),
|
|
1123
|
+
null
|
|
1124
|
+
];
|
|
1125
|
+
}
|
|
1126
|
+
return [null, entry];
|
|
1127
|
+
} catch (cause) {
|
|
1128
|
+
return [fromConvexError(cause), null];
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
500
1131
|
}
|
|
501
1132
|
};
|
|
502
1133
|
}
|
|
@@ -510,119 +1141,11 @@ function createApiKeysClient() {
|
|
|
510
1141
|
revoke: async () => stub("apiKeys.revoke")
|
|
511
1142
|
};
|
|
512
1143
|
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
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";
|
|
616
|
-
|
|
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");
|
|
1144
|
+
function createDefaultDataClient(convexUrl, jwt) {
|
|
1145
|
+
const client = new ConvexHttpClient(convexUrl);
|
|
1146
|
+
client.setAuth(jwt);
|
|
1147
|
+
return client;
|
|
622
1148
|
}
|
|
623
|
-
roleKeyFromLabel("OWNER");
|
|
624
|
-
roleKeyFromLabel("FINANCE_MANAGER");
|
|
625
|
-
roleKeyFromLabel("TEAM_LEAD");
|
|
626
1149
|
|
|
627
1150
|
// src/transport.ts
|
|
628
1151
|
function makeHttpTransport(config) {
|
|
@@ -953,7 +1476,7 @@ function readNonEmptyString(value) {
|
|
|
953
1476
|
|
|
954
1477
|
// src/core/auth.ts
|
|
955
1478
|
function createAuthClient(config = {}) {
|
|
956
|
-
let dataClient = config.
|
|
1479
|
+
let dataClient = config._data ?? null;
|
|
957
1480
|
const sessionStore = config.auth?.sessionStore ?? createMemorySessionStore();
|
|
958
1481
|
const getTransport = createTransportProvider(config);
|
|
959
1482
|
return {
|
|
@@ -1009,11 +1532,20 @@ function createAuthClient(config = {}) {
|
|
|
1009
1532
|
).toISOString()
|
|
1010
1533
|
};
|
|
1011
1534
|
sessionStore.set(session);
|
|
1012
|
-
if (
|
|
1535
|
+
if (!dataClient) {
|
|
1013
1536
|
try {
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1537
|
+
const convexUrl = transport.convexUrl;
|
|
1538
|
+
if (!convexUrl || !session.convexJwt) {
|
|
1539
|
+
return [
|
|
1540
|
+
new CapxulError({
|
|
1541
|
+
code: "NETWORK_ERROR",
|
|
1542
|
+
message: "Cannot create data client: missing convex URL or JWT."
|
|
1543
|
+
}),
|
|
1544
|
+
null
|
|
1545
|
+
];
|
|
1546
|
+
}
|
|
1547
|
+
dataClient = createDefaultDataClient(convexUrl, session.convexJwt);
|
|
1548
|
+
mutableConfig(config)._data = dataClient;
|
|
1017
1549
|
} catch (cause) {
|
|
1018
1550
|
return [
|
|
1019
1551
|
new CapxulError({
|
|
@@ -1024,7 +1556,15 @@ function createAuthClient(config = {}) {
|
|
|
1024
1556
|
null
|
|
1025
1557
|
];
|
|
1026
1558
|
}
|
|
1559
|
+
} else {
|
|
1560
|
+
const injected = dataClient;
|
|
1561
|
+
if (typeof injected.refreshAuth === "function") {
|
|
1562
|
+
injected.refreshAuth();
|
|
1563
|
+
} else if (typeof injected.setAuth === "function" && session.convexJwt) {
|
|
1564
|
+
injected.setAuth(session.convexJwt);
|
|
1565
|
+
}
|
|
1027
1566
|
}
|
|
1567
|
+
transport.markAuthenticated({ dataClient });
|
|
1028
1568
|
if (!dataClient) {
|
|
1029
1569
|
return [
|
|
1030
1570
|
new CapxulError({
|
|
@@ -1052,7 +1592,7 @@ function createAuthClient(config = {}) {
|
|
|
1052
1592
|
},
|
|
1053
1593
|
completeBootstrap: async (input) => {
|
|
1054
1594
|
const session = sessionStore.get();
|
|
1055
|
-
const data = dataClient ?? config.
|
|
1595
|
+
const data = dataClient ?? config._data;
|
|
1056
1596
|
if (!session || !data) {
|
|
1057
1597
|
return [
|
|
1058
1598
|
new CapxulError({
|
|
@@ -1062,23 +1602,38 @@ function createAuthClient(config = {}) {
|
|
|
1062
1602
|
null
|
|
1063
1603
|
];
|
|
1064
1604
|
}
|
|
1065
|
-
|
|
1605
|
+
const signerAddress = config.signer?.address;
|
|
1606
|
+
if (!signerAddress) {
|
|
1066
1607
|
return [
|
|
1067
1608
|
new CapxulError({
|
|
1068
1609
|
code: "INVALID_INPUT",
|
|
1069
|
-
message: "completeBootstrap
|
|
1610
|
+
message: "completeBootstrap requires a signer to be configured on the client."
|
|
1070
1611
|
}),
|
|
1071
1612
|
null
|
|
1072
1613
|
];
|
|
1073
1614
|
}
|
|
1074
1615
|
try {
|
|
1075
|
-
const
|
|
1616
|
+
const safeAddress = deriveSafeAddress2(signerAddress);
|
|
1617
|
+
if (!data.action) {
|
|
1618
|
+
return [
|
|
1619
|
+
new CapxulError({
|
|
1620
|
+
code: "INVALID_INPUT",
|
|
1621
|
+
message: "completeBootstrap requires a data client that can execute Convex actions."
|
|
1622
|
+
}),
|
|
1623
|
+
null
|
|
1624
|
+
];
|
|
1625
|
+
}
|
|
1626
|
+
const result = await data.action(api.authBootstrap.completeBootstrap, {
|
|
1076
1627
|
bootstrapToken: input.bootstrapToken,
|
|
1077
1628
|
sessionToken: session.token,
|
|
1078
1629
|
username: input.username,
|
|
1079
1630
|
displayName: input.displayName,
|
|
1080
1631
|
countryCode: input.countryCode,
|
|
1081
|
-
signerProvider:
|
|
1632
|
+
signerProvider: {
|
|
1633
|
+
kind: "local-private-key",
|
|
1634
|
+
signerAddress,
|
|
1635
|
+
safeAddress
|
|
1636
|
+
}
|
|
1082
1637
|
});
|
|
1083
1638
|
return [null, { kind: "authenticated", session, ...result }];
|
|
1084
1639
|
} catch (cause) {
|
|
@@ -1092,7 +1647,7 @@ function createAuthClient(config = {}) {
|
|
|
1092
1647
|
signOut: async () => {
|
|
1093
1648
|
sessionStore.clear();
|
|
1094
1649
|
dataClient = null;
|
|
1095
|
-
mutableConfig(config).
|
|
1650
|
+
mutableConfig(config)._data = void 0;
|
|
1096
1651
|
const transport = getTransport();
|
|
1097
1652
|
transport?.clearAuth();
|
|
1098
1653
|
return [null, void 0];
|
|
@@ -1163,6 +1718,9 @@ async function postBetterAuth(transport, path, body, code, signal) {
|
|
|
1163
1718
|
}
|
|
1164
1719
|
return [null, text ? JSON.parse(text) : void 0];
|
|
1165
1720
|
} catch (cause) {
|
|
1721
|
+
if (cause instanceof CapxulError) {
|
|
1722
|
+
return [cause, null];
|
|
1723
|
+
}
|
|
1166
1724
|
return [
|
|
1167
1725
|
new CapxulError({
|
|
1168
1726
|
code: "NETWORK_ERROR",
|
|
@@ -1201,7 +1759,7 @@ function parseBetterAuthError(text) {
|
|
|
1201
1759
|
}
|
|
1202
1760
|
}
|
|
1203
1761
|
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";
|
|
1762
|
+
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
1763
|
}
|
|
1206
1764
|
async function exchangeConvexToken(transport, config, token, signal) {
|
|
1207
1765
|
const path = config.auth?.convexTokenUrl ?? "/convex/token";
|
|
@@ -1231,6 +1789,9 @@ async function exchangeConvexToken(transport, config, token, signal) {
|
|
|
1231
1789
|
}
|
|
1232
1790
|
return [null, body.token];
|
|
1233
1791
|
} catch (cause) {
|
|
1792
|
+
if (cause instanceof CapxulError) {
|
|
1793
|
+
return [cause, null];
|
|
1794
|
+
}
|
|
1234
1795
|
return [
|
|
1235
1796
|
new CapxulError({
|
|
1236
1797
|
code: "NETWORK_ERROR",
|
|
@@ -1245,16 +1806,227 @@ function mutableConfig(config) {
|
|
|
1245
1806
|
return config;
|
|
1246
1807
|
}
|
|
1247
1808
|
|
|
1809
|
+
// src/core/auth-service.ts
|
|
1810
|
+
var AuthService = class {
|
|
1811
|
+
authClient;
|
|
1812
|
+
sessionStore;
|
|
1813
|
+
config;
|
|
1814
|
+
constructor(config = {}) {
|
|
1815
|
+
this.config = config;
|
|
1816
|
+
this.sessionStore = config.auth?.sessionStore ?? createMemorySessionStore2();
|
|
1817
|
+
this.authClient = createAuthClient({
|
|
1818
|
+
...config,
|
|
1819
|
+
auth: { ...config.auth, sessionStore: this.sessionStore }
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
async sendOtp(email, options) {
|
|
1823
|
+
const [err] = await this.authClient.sendOtp({ email }, options);
|
|
1824
|
+
if (err) throw err;
|
|
1825
|
+
}
|
|
1826
|
+
async verifyOtp(email, otp, options) {
|
|
1827
|
+
const [err, result] = await this.authClient.verifyOtp(
|
|
1828
|
+
{ email, otp },
|
|
1829
|
+
options
|
|
1830
|
+
);
|
|
1831
|
+
if (err) throw err;
|
|
1832
|
+
return result;
|
|
1833
|
+
}
|
|
1834
|
+
async completeBootstrap(params, signer) {
|
|
1835
|
+
if (signer) {
|
|
1836
|
+
const tempClient = createAuthClient({
|
|
1837
|
+
...this.config,
|
|
1838
|
+
signer,
|
|
1839
|
+
auth: { ...this.config.auth, sessionStore: this.sessionStore }
|
|
1840
|
+
});
|
|
1841
|
+
const [err2, result2] = await tempClient.completeBootstrap(params);
|
|
1842
|
+
if (err2) throw err2;
|
|
1843
|
+
return result2;
|
|
1844
|
+
}
|
|
1845
|
+
const [err, result] = await this.authClient.completeBootstrap(params);
|
|
1846
|
+
if (err) throw err;
|
|
1847
|
+
return result;
|
|
1848
|
+
}
|
|
1849
|
+
/**
|
|
1850
|
+
* Clears the persisted session and, when a transport was pre-injected,
|
|
1851
|
+
* drops the cached auth header.
|
|
1852
|
+
*
|
|
1853
|
+
* **Transport safety note:** `clearAuth()` is only invoked when
|
|
1854
|
+
* `config._transport` was supplied at construction (e.g. by the React
|
|
1855
|
+
* provider). If `AuthService` is instantiated directly in a Node/CLI
|
|
1856
|
+
* context without an injected transport, the transport-side auth cache
|
|
1857
|
+
* is the caller's responsibility.
|
|
1858
|
+
*/
|
|
1859
|
+
async signOut() {
|
|
1860
|
+
if (!this.config._transport) {
|
|
1861
|
+
const [err] = await this.authClient.signOut();
|
|
1862
|
+
if (err) throw err;
|
|
1863
|
+
mutableConfig2(this.config)._data = void 0;
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
this.sessionStore.clear();
|
|
1867
|
+
this.config._transport.clearAuth();
|
|
1868
|
+
}
|
|
1869
|
+
async getSession() {
|
|
1870
|
+
const [err, session] = await this.authClient.getSession();
|
|
1871
|
+
if (err) throw err;
|
|
1872
|
+
return session;
|
|
1873
|
+
}
|
|
1874
|
+
};
|
|
1875
|
+
function mutableConfig2(config) {
|
|
1876
|
+
return config;
|
|
1877
|
+
}
|
|
1878
|
+
function createMemorySessionStore2() {
|
|
1879
|
+
let current = null;
|
|
1880
|
+
return {
|
|
1881
|
+
get: () => current,
|
|
1882
|
+
set: (session) => {
|
|
1883
|
+
current = session;
|
|
1884
|
+
},
|
|
1885
|
+
clear: () => {
|
|
1886
|
+
current = null;
|
|
1887
|
+
}
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1248
1891
|
// src/core/documents.ts
|
|
1249
|
-
function
|
|
1892
|
+
function requireInvoiceHash(row) {
|
|
1893
|
+
if (!row.invoiceHash) {
|
|
1894
|
+
throw new CapxulError({
|
|
1895
|
+
code: "INVALID_INPUT",
|
|
1896
|
+
message: `invoice document ${row.documentId ?? row._id} is missing its canonical invoiceHash`
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
return row.invoiceHash;
|
|
1900
|
+
}
|
|
1901
|
+
function mapInvoiceRow(row) {
|
|
1902
|
+
const status = row.status === "cancelled" ? "canceled" : row.status === "pending" ? "open" : row.status === "overdue" ? "expired" : row.status;
|
|
1903
|
+
return {
|
|
1904
|
+
object: "document",
|
|
1905
|
+
id: row.documentId ?? row._id,
|
|
1906
|
+
type: "invoice",
|
|
1907
|
+
owner: {
|
|
1908
|
+
kind: row.scope === "org" ? "organization" : "account",
|
|
1909
|
+
id: row.orgId ?? row.payeeEmail ?? row.payeeLabel
|
|
1910
|
+
},
|
|
1911
|
+
recipient: { email: row.payerEmail },
|
|
1912
|
+
amount: {
|
|
1913
|
+
value: row.amount,
|
|
1914
|
+
currency: row.currency
|
|
1915
|
+
},
|
|
1916
|
+
reference: row.note,
|
|
1917
|
+
lineItems: row.items,
|
|
1918
|
+
invoiceHash: requireInvoiceHash(row),
|
|
1919
|
+
dueAt: row.dueDate,
|
|
1920
|
+
status,
|
|
1921
|
+
createdAt: new Date(row.createdAt).toISOString()
|
|
1922
|
+
};
|
|
1923
|
+
}
|
|
1924
|
+
function mapDocumentError(cause) {
|
|
1925
|
+
return fromConvexError(cause);
|
|
1926
|
+
}
|
|
1927
|
+
function createDocumentsClient(config = {}) {
|
|
1250
1928
|
return {
|
|
1251
|
-
create: async () =>
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1929
|
+
create: async (input) => {
|
|
1930
|
+
if (!config._data) return stub("documents.create");
|
|
1931
|
+
if (input.type !== "invoice") {
|
|
1932
|
+
return [
|
|
1933
|
+
new CapxulError({
|
|
1934
|
+
code: "INVALID_INPUT",
|
|
1935
|
+
message: "documents.create currently supports personal invoice documents only."
|
|
1936
|
+
}),
|
|
1937
|
+
null
|
|
1938
|
+
];
|
|
1939
|
+
}
|
|
1940
|
+
if (!("email" in input.recipient)) {
|
|
1941
|
+
return [
|
|
1942
|
+
new CapxulError({
|
|
1943
|
+
code: "INVALID_INPUT",
|
|
1944
|
+
message: "personal invoice documents currently require an email recipient."
|
|
1945
|
+
}),
|
|
1946
|
+
null
|
|
1947
|
+
];
|
|
1948
|
+
}
|
|
1949
|
+
try {
|
|
1950
|
+
const created = await config._data.mutation(
|
|
1951
|
+
api.paymentRecords.mutations.createInvoice,
|
|
1952
|
+
{
|
|
1953
|
+
scope: "personal",
|
|
1954
|
+
payerEmail: input.recipient.email,
|
|
1955
|
+
amount: input.amount.value,
|
|
1956
|
+
currency: input.amount.currency,
|
|
1957
|
+
dueDate: input.dueAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1958
|
+
note: input.reference,
|
|
1959
|
+
items: input.lineItems
|
|
1960
|
+
}
|
|
1961
|
+
);
|
|
1962
|
+
const row = await config._data.query(
|
|
1963
|
+
api.paymentRecords.queries.getInvoiceByDocumentId,
|
|
1964
|
+
{ documentId: created.documentId }
|
|
1965
|
+
);
|
|
1966
|
+
if (!row) throw new Error("created invoice was not readable");
|
|
1967
|
+
return [null, mapInvoiceRow(row)];
|
|
1968
|
+
} catch (cause) {
|
|
1969
|
+
return [mapDocumentError(cause), null];
|
|
1970
|
+
}
|
|
1971
|
+
},
|
|
1972
|
+
retrieve: async (documentId) => {
|
|
1973
|
+
if (!config._data)
|
|
1974
|
+
return stub("documents.retrieve");
|
|
1975
|
+
try {
|
|
1976
|
+
const row = await config._data.query(
|
|
1977
|
+
api.paymentRecords.queries.getInvoiceByDocumentId,
|
|
1978
|
+
{ documentId }
|
|
1979
|
+
);
|
|
1980
|
+
if (!row) {
|
|
1981
|
+
return [
|
|
1982
|
+
new CapxulError({
|
|
1983
|
+
code: "NOT_FOUND",
|
|
1984
|
+
message: `document ${documentId} not found`
|
|
1985
|
+
}),
|
|
1986
|
+
null
|
|
1987
|
+
];
|
|
1988
|
+
}
|
|
1989
|
+
return [null, mapInvoiceRow(row)];
|
|
1990
|
+
} catch (cause) {
|
|
1991
|
+
return [mapDocumentError(cause), null];
|
|
1992
|
+
}
|
|
1993
|
+
},
|
|
1994
|
+
list: async (input = {}) => {
|
|
1995
|
+
if (!config._data)
|
|
1996
|
+
return stub("documents.list");
|
|
1997
|
+
try {
|
|
1998
|
+
if (input.type && input.type !== "invoice") {
|
|
1999
|
+
return [null, { object: "list", data: [], page: { hasMore: false } }];
|
|
2000
|
+
}
|
|
2001
|
+
const rows = await config._data.query(
|
|
2002
|
+
api.paymentRecords.queries.listMyInvoices,
|
|
2003
|
+
{
|
|
2004
|
+
limit: input.limit,
|
|
2005
|
+
cursor: input.cursor
|
|
2006
|
+
}
|
|
2007
|
+
);
|
|
2008
|
+
const page = rows;
|
|
2009
|
+
const data = page.data.map((row) => mapInvoiceRow(row));
|
|
2010
|
+
return [null, { object: "list", data, page: page.page }];
|
|
2011
|
+
} catch (cause) {
|
|
2012
|
+
return [mapDocumentError(cause), null];
|
|
2013
|
+
}
|
|
2014
|
+
},
|
|
2015
|
+
cancel: async (documentId) => {
|
|
2016
|
+
if (!config._data) return stub("documents.cancel");
|
|
2017
|
+
try {
|
|
2018
|
+
const row = await config._data.mutation(
|
|
2019
|
+
api.paymentRecords.mutations.cancelInvoice,
|
|
2020
|
+
{ documentId }
|
|
2021
|
+
);
|
|
2022
|
+
return [null, mapInvoiceRow(row)];
|
|
2023
|
+
} catch (cause) {
|
|
2024
|
+
return [mapDocumentError(cause), null];
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
1255
2027
|
};
|
|
1256
2028
|
}
|
|
1257
|
-
function createOrgDocumentsClient() {
|
|
2029
|
+
function createOrgDocumentsClient(_config = {}) {
|
|
1258
2030
|
return {
|
|
1259
2031
|
create: async () => stub("organizations.documents.create"),
|
|
1260
2032
|
retrieve: async () => stub("organizations.documents.retrieve"),
|
|
@@ -1267,11 +2039,11 @@ function createOrgDocumentsClient() {
|
|
|
1267
2039
|
function createMeClient(config = {}) {
|
|
1268
2040
|
return {
|
|
1269
2041
|
get: async () => {
|
|
1270
|
-
if (!config.
|
|
2042
|
+
if (!config._data) {
|
|
1271
2043
|
return stub("me.get");
|
|
1272
2044
|
}
|
|
1273
2045
|
try {
|
|
1274
|
-
const account = await config.
|
|
2046
|
+
const account = await config._data.query(
|
|
1275
2047
|
api.openfort.queries.getMyAccount,
|
|
1276
2048
|
{}
|
|
1277
2049
|
);
|
|
@@ -1281,7 +2053,7 @@ function createMeClient(config = {}) {
|
|
|
1281
2053
|
}
|
|
1282
2054
|
},
|
|
1283
2055
|
update: async (input) => {
|
|
1284
|
-
if (!config.
|
|
2056
|
+
if (!config._data) {
|
|
1285
2057
|
return stub("me.update");
|
|
1286
2058
|
}
|
|
1287
2059
|
if (input.countryCode !== void 0) {
|
|
@@ -1295,11 +2067,11 @@ function createMeClient(config = {}) {
|
|
|
1295
2067
|
];
|
|
1296
2068
|
}
|
|
1297
2069
|
try {
|
|
1298
|
-
await config.
|
|
2070
|
+
await config._data.mutation(api.openfort.mutations.updateProfile, {
|
|
1299
2071
|
displayName: input.name,
|
|
1300
2072
|
username: input.username
|
|
1301
2073
|
});
|
|
1302
|
-
const account = await config.
|
|
2074
|
+
const account = await config._data.query(
|
|
1303
2075
|
api.openfort.queries.getMyAccount,
|
|
1304
2076
|
{}
|
|
1305
2077
|
);
|
|
@@ -1314,11 +2086,11 @@ function createMeClient(config = {}) {
|
|
|
1314
2086
|
// src/core/operations.ts
|
|
1315
2087
|
function createOperationsClient(config = {}) {
|
|
1316
2088
|
const retrieve = async (operationId) => {
|
|
1317
|
-
if (!config.
|
|
2089
|
+
if (!config._data) {
|
|
1318
2090
|
return stub("operations.retrieve");
|
|
1319
2091
|
}
|
|
1320
2092
|
try {
|
|
1321
|
-
const operation = await config.
|
|
2093
|
+
const operation = await config._data.query(api.operations.queries.retrieve, {
|
|
1322
2094
|
operationId
|
|
1323
2095
|
});
|
|
1324
2096
|
if (!operation) {
|
|
@@ -1335,7 +2107,7 @@ function createOperationsClient(config = {}) {
|
|
|
1335
2107
|
return {
|
|
1336
2108
|
retrieve,
|
|
1337
2109
|
wait: async (operationId, input = {}) => {
|
|
1338
|
-
if (!config.
|
|
2110
|
+
if (!config._data) {
|
|
1339
2111
|
return stub("operations.wait");
|
|
1340
2112
|
}
|
|
1341
2113
|
const until = new Set(
|
|
@@ -1370,49 +2142,22 @@ function toTokenUnits(value, decimals = 6) {
|
|
|
1370
2142
|
return parseUnits(value, decimals);
|
|
1371
2143
|
}
|
|
1372
2144
|
|
|
1373
|
-
// src/
|
|
1374
|
-
function
|
|
2145
|
+
// src/core/token-registry.ts
|
|
2146
|
+
function resolvePaymentToken(currency) {
|
|
1375
2147
|
const normalized = currency.trim().toUpperCase();
|
|
1376
2148
|
if (normalized === "USD" || normalized === "USDC") {
|
|
1377
|
-
return
|
|
2149
|
+
return {
|
|
2150
|
+
address: TEST_USDC_ADDRESS.toLowerCase(),
|
|
2151
|
+
decimals: 6,
|
|
2152
|
+
symbol: "USDC"
|
|
2153
|
+
};
|
|
1378
2154
|
}
|
|
1379
2155
|
throw new CapxulError({
|
|
1380
|
-
code: "
|
|
1381
|
-
message: `Currency ${currency} is not
|
|
2156
|
+
code: "NOT_IMPLEMENTED",
|
|
2157
|
+
message: `Currency ${currency} is not yet supported by the token registry.`,
|
|
1382
2158
|
details: { currency: normalized }
|
|
1383
2159
|
});
|
|
1384
2160
|
}
|
|
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
2161
|
function createCapxulBundler(config) {
|
|
1417
2162
|
const paymaster = createPaymasterClient({
|
|
1418
2163
|
transport: http(config.rpcUrl)
|
|
@@ -1519,13 +2264,13 @@ async function transferAsOwner(config, params) {
|
|
|
1519
2264
|
function createPaymentsClient(config = {}) {
|
|
1520
2265
|
return {
|
|
1521
2266
|
create: async (input) => {
|
|
1522
|
-
if (!config.
|
|
2267
|
+
if (!config._data || !config.signer || !config.signing) {
|
|
1523
2268
|
return stub("payments.create");
|
|
1524
2269
|
}
|
|
1525
2270
|
let created = null;
|
|
1526
2271
|
let submitted = null;
|
|
1527
2272
|
try {
|
|
1528
|
-
created = await config.
|
|
2273
|
+
created = await config._data.mutation(api.payments.mutations.create, {
|
|
1529
2274
|
to: input.to,
|
|
1530
2275
|
amount: input.amount,
|
|
1531
2276
|
reference: input.reference,
|
|
@@ -1533,15 +2278,21 @@ function createPaymentsClient(config = {}) {
|
|
|
1533
2278
|
source: input.source
|
|
1534
2279
|
});
|
|
1535
2280
|
if (!created) {
|
|
1536
|
-
return [
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
2281
|
+
return [
|
|
2282
|
+
new CapxulError({
|
|
2283
|
+
code: "NETWORK_ERROR",
|
|
2284
|
+
message: "payments.create returned no payment resource"
|
|
2285
|
+
}),
|
|
2286
|
+
null
|
|
2287
|
+
];
|
|
1540
2288
|
}
|
|
1541
2289
|
if (created.status !== "processing" || created.operation.status !== "processing") {
|
|
1542
2290
|
return [null, created];
|
|
1543
2291
|
}
|
|
1544
|
-
const currentSigner = await config.
|
|
2292
|
+
const currentSigner = await config._data.query(
|
|
2293
|
+
api.safe.queries.getMySignerAddress,
|
|
2294
|
+
{}
|
|
2295
|
+
);
|
|
1545
2296
|
if (!currentSigner?.address) {
|
|
1546
2297
|
throw new CapxulError({
|
|
1547
2298
|
code: "PERMISSION_DENIED",
|
|
@@ -1560,9 +2311,12 @@ function createPaymentsClient(config = {}) {
|
|
|
1560
2311
|
}
|
|
1561
2312
|
});
|
|
1562
2313
|
}
|
|
1563
|
-
const submission = await config.
|
|
1564
|
-
|
|
1565
|
-
|
|
2314
|
+
const submission = await config._data.query(
|
|
2315
|
+
api.payments.queries.prepareSubmission,
|
|
2316
|
+
{
|
|
2317
|
+
paymentId: created.id
|
|
2318
|
+
}
|
|
2319
|
+
);
|
|
1566
2320
|
if (!submission?.recipientAddress) {
|
|
1567
2321
|
throw new CapxulError({
|
|
1568
2322
|
code: "NETWORK_ERROR",
|
|
@@ -1570,15 +2324,16 @@ function createPaymentsClient(config = {}) {
|
|
|
1570
2324
|
details: { paymentId: created.id }
|
|
1571
2325
|
});
|
|
1572
2326
|
}
|
|
2327
|
+
const token = resolvePaymentToken(submission.amount.currency);
|
|
1573
2328
|
const transfer = await transferAsOwner(
|
|
1574
2329
|
{
|
|
1575
2330
|
signer: config.signer,
|
|
1576
2331
|
signing: config.signing
|
|
1577
2332
|
},
|
|
1578
2333
|
{
|
|
1579
|
-
tokenAddress:
|
|
2334
|
+
tokenAddress: token.address,
|
|
1580
2335
|
recipientAddress: submission.recipientAddress,
|
|
1581
|
-
amount: toTokenUnits(submission.amount.value,
|
|
2336
|
+
amount: toTokenUnits(submission.amount.value, token.decimals)
|
|
1582
2337
|
}
|
|
1583
2338
|
);
|
|
1584
2339
|
if (!transfer.success) {
|
|
@@ -1596,7 +2351,7 @@ function createPaymentsClient(config = {}) {
|
|
|
1596
2351
|
txHash: transfer.txHash,
|
|
1597
2352
|
userOpHash: transfer.userOpHash
|
|
1598
2353
|
};
|
|
1599
|
-
await config.
|
|
2354
|
+
await config._data.mutation(api.payments.mutations.recordSubmitted, {
|
|
1600
2355
|
paymentId: created.id,
|
|
1601
2356
|
txHash: transfer.txHash,
|
|
1602
2357
|
userOpHash: transfer.userOpHash,
|
|
@@ -1606,43 +2361,65 @@ function createPaymentsClient(config = {}) {
|
|
|
1606
2361
|
} catch (cause) {
|
|
1607
2362
|
const error = mapCreateError(fromConvexError(cause));
|
|
1608
2363
|
if (created?.id && created.status === "processing" && !submitted) {
|
|
1609
|
-
await bestEffortMarkFailed({
|
|
2364
|
+
await bestEffortMarkFailed({ _data: config._data }, created.id, error);
|
|
1610
2365
|
}
|
|
1611
2366
|
if (submitted && created?.id) {
|
|
1612
|
-
return [
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
2367
|
+
return [
|
|
2368
|
+
new CapxulError({
|
|
2369
|
+
code: "NETWORK_ERROR",
|
|
2370
|
+
message: "Payment was submitted on-chain, but backend submission tracking failed.",
|
|
2371
|
+
cause,
|
|
2372
|
+
details: {
|
|
2373
|
+
paymentId: created.id,
|
|
2374
|
+
txHash: submitted.txHash,
|
|
2375
|
+
userOpHash: submitted.userOpHash
|
|
2376
|
+
}
|
|
2377
|
+
}),
|
|
2378
|
+
null
|
|
2379
|
+
];
|
|
1622
2380
|
}
|
|
1623
2381
|
return [error, null];
|
|
1624
2382
|
}
|
|
1625
2383
|
},
|
|
1626
2384
|
retrieve: async (paymentId) => {
|
|
1627
|
-
if (!config.
|
|
2385
|
+
if (!config._data) {
|
|
1628
2386
|
return stub("payments.retrieve");
|
|
1629
2387
|
}
|
|
1630
2388
|
try {
|
|
1631
|
-
const payment = await config.
|
|
1632
|
-
|
|
1633
|
-
|
|
2389
|
+
const payment = await config._data.query(
|
|
2390
|
+
api.payments.queries.retrieve,
|
|
2391
|
+
{
|
|
2392
|
+
paymentId
|
|
2393
|
+
}
|
|
2394
|
+
);
|
|
1634
2395
|
if (!payment) {
|
|
1635
|
-
return [
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
2396
|
+
return [
|
|
2397
|
+
new CapxulError({
|
|
2398
|
+
code: "NOT_FOUND",
|
|
2399
|
+
message: `payment ${paymentId} not found`
|
|
2400
|
+
}),
|
|
2401
|
+
null
|
|
2402
|
+
];
|
|
1639
2403
|
}
|
|
1640
2404
|
return [null, payment];
|
|
1641
2405
|
} catch (cause) {
|
|
1642
2406
|
return [fromConvexError(cause), null];
|
|
1643
2407
|
}
|
|
1644
2408
|
},
|
|
1645
|
-
list: async () =>
|
|
2409
|
+
list: async (input) => {
|
|
2410
|
+
if (!config._data) {
|
|
2411
|
+
return stub("payments.list");
|
|
2412
|
+
}
|
|
2413
|
+
try {
|
|
2414
|
+
const page = await config._data.query(api.payments.queries.list, {
|
|
2415
|
+
limit: input?.limit,
|
|
2416
|
+
cursor: input?.cursor
|
|
2417
|
+
});
|
|
2418
|
+
return [null, page];
|
|
2419
|
+
} catch (cause) {
|
|
2420
|
+
return [fromConvexError(cause), null];
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
1646
2423
|
};
|
|
1647
2424
|
}
|
|
1648
2425
|
function createOrgPaymentsClient() {
|
|
@@ -1656,7 +2433,7 @@ function createOrgPaymentsClient() {
|
|
|
1656
2433
|
}
|
|
1657
2434
|
async function bestEffortMarkFailed(config, paymentId, error) {
|
|
1658
2435
|
try {
|
|
1659
|
-
await config.
|
|
2436
|
+
await config._data.mutation(api.payments.mutations.markFailed, {
|
|
1660
2437
|
paymentId,
|
|
1661
2438
|
errorCode: error.code,
|
|
1662
2439
|
errorMessage: error.message,
|
|
@@ -1713,11 +2490,11 @@ function createOrgTransfersClient() {
|
|
|
1713
2490
|
function createWithdrawalsClient(config = {}) {
|
|
1714
2491
|
return {
|
|
1715
2492
|
create: async (input) => {
|
|
1716
|
-
if (!config.
|
|
2493
|
+
if (!config._data) {
|
|
1717
2494
|
return stub("withdrawals.create");
|
|
1718
2495
|
}
|
|
1719
2496
|
const [createErr, createdRaw] = await tryCatch(
|
|
1720
|
-
config.
|
|
2497
|
+
config._data.mutation(api.withdrawals.mutations.create, {
|
|
1721
2498
|
amount: input.amount,
|
|
1722
2499
|
destination: {
|
|
1723
2500
|
externalAccountId: input.destination.externalAccountId
|
|
@@ -1747,18 +2524,18 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1747
2524
|
return [null, created];
|
|
1748
2525
|
}
|
|
1749
2526
|
const [signerErr, currentSigner] = await tryCatch(
|
|
1750
|
-
config.
|
|
2527
|
+
config._data.query(api.safe.queries.getMySignerAddress, {})
|
|
1751
2528
|
);
|
|
1752
2529
|
if (signerErr) {
|
|
1753
2530
|
return await handleSubmissionFailure(
|
|
1754
|
-
{
|
|
2531
|
+
{ _data: config._data },
|
|
1755
2532
|
created.id,
|
|
1756
2533
|
mapCreateError2(fromConvexError(signerErr))
|
|
1757
2534
|
);
|
|
1758
2535
|
}
|
|
1759
2536
|
if (!currentSigner?.address) {
|
|
1760
2537
|
return await handleSubmissionFailure(
|
|
1761
|
-
{
|
|
2538
|
+
{ _data: config._data },
|
|
1762
2539
|
created.id,
|
|
1763
2540
|
new CapxulError({
|
|
1764
2541
|
code: "PERMISSION_DENIED",
|
|
@@ -1769,7 +2546,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1769
2546
|
}
|
|
1770
2547
|
if (getAddress(currentSigner.address) !== getAddress(config.signer.address)) {
|
|
1771
2548
|
return await handleSubmissionFailure(
|
|
1772
|
-
{
|
|
2549
|
+
{ _data: config._data },
|
|
1773
2550
|
created.id,
|
|
1774
2551
|
new CapxulError({
|
|
1775
2552
|
code: "PERMISSION_DENIED",
|
|
@@ -1783,13 +2560,13 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1783
2560
|
);
|
|
1784
2561
|
}
|
|
1785
2562
|
const [prepErr, submission] = await tryCatch(
|
|
1786
|
-
config.
|
|
2563
|
+
config._data.query(api.withdrawals.queries.prepareSubmission, {
|
|
1787
2564
|
withdrawalId: created.id
|
|
1788
2565
|
})
|
|
1789
2566
|
);
|
|
1790
2567
|
if (prepErr) {
|
|
1791
2568
|
return await handleSubmissionFailure(
|
|
1792
|
-
{
|
|
2569
|
+
{ _data: config._data },
|
|
1793
2570
|
created.id,
|
|
1794
2571
|
mapCreateError2(fromConvexError(prepErr))
|
|
1795
2572
|
);
|
|
@@ -1797,7 +2574,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1797
2574
|
const destinationAddress = submission?.destinationAddress;
|
|
1798
2575
|
if (!submission || !destinationAddress) {
|
|
1799
2576
|
return await handleSubmissionFailure(
|
|
1800
|
-
{
|
|
2577
|
+
{ _data: config._data },
|
|
1801
2578
|
created.id,
|
|
1802
2579
|
new CapxulError({
|
|
1803
2580
|
code: "NETWORK_ERROR",
|
|
@@ -1806,6 +2583,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1806
2583
|
})
|
|
1807
2584
|
);
|
|
1808
2585
|
}
|
|
2586
|
+
const token = resolvePaymentToken(submission.amount.currency);
|
|
1809
2587
|
const [transferErr, transferOk] = await tryCatch(
|
|
1810
2588
|
transferAsOwner(
|
|
1811
2589
|
{
|
|
@@ -1813,22 +2591,22 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1813
2591
|
signing: config.signing
|
|
1814
2592
|
},
|
|
1815
2593
|
{
|
|
1816
|
-
tokenAddress:
|
|
2594
|
+
tokenAddress: token.address,
|
|
1817
2595
|
recipientAddress: destinationAddress,
|
|
1818
|
-
amount: toTokenUnits(submission.amount.value,
|
|
2596
|
+
amount: toTokenUnits(submission.amount.value, token.decimals)
|
|
1819
2597
|
}
|
|
1820
2598
|
)
|
|
1821
2599
|
);
|
|
1822
2600
|
if (transferErr) {
|
|
1823
2601
|
return await handleSubmissionFailure(
|
|
1824
|
-
{
|
|
2602
|
+
{ _data: config._data },
|
|
1825
2603
|
created.id,
|
|
1826
2604
|
mapCreateError2(fromConvexError(transferErr))
|
|
1827
2605
|
);
|
|
1828
2606
|
}
|
|
1829
2607
|
if (!transferOk.success) {
|
|
1830
2608
|
return await handleSubmissionFailure(
|
|
1831
|
-
{
|
|
2609
|
+
{ _data: config._data },
|
|
1832
2610
|
created.id,
|
|
1833
2611
|
new CapxulError({
|
|
1834
2612
|
code: "NETWORK_ERROR",
|
|
@@ -1842,7 +2620,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1842
2620
|
);
|
|
1843
2621
|
}
|
|
1844
2622
|
const [recordErr] = await tryCatch(
|
|
1845
|
-
config.
|
|
2623
|
+
config._data.mutation(api.withdrawals.mutations.recordSubmitted, {
|
|
1846
2624
|
withdrawalId: created.id,
|
|
1847
2625
|
txHash: transferOk.txHash,
|
|
1848
2626
|
userOpHash: transferOk.userOpHash
|
|
@@ -1866,11 +2644,11 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1866
2644
|
return [null, created];
|
|
1867
2645
|
},
|
|
1868
2646
|
retrieve: async (withdrawalId) => {
|
|
1869
|
-
if (!config.
|
|
2647
|
+
if (!config._data) {
|
|
1870
2648
|
return stub("withdrawals.retrieve");
|
|
1871
2649
|
}
|
|
1872
2650
|
const [err, raw] = await tryCatch(
|
|
1873
|
-
config.
|
|
2651
|
+
config._data.query(api.withdrawals.queries.retrieve, { withdrawalId })
|
|
1874
2652
|
);
|
|
1875
2653
|
if (err) {
|
|
1876
2654
|
return [fromConvexError(err), null];
|
|
@@ -1888,11 +2666,11 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1888
2666
|
return [null, withdrawal];
|
|
1889
2667
|
},
|
|
1890
2668
|
list: async (input) => {
|
|
1891
|
-
if (!config.
|
|
2669
|
+
if (!config._data) {
|
|
1892
2670
|
return stub("withdrawals.list");
|
|
1893
2671
|
}
|
|
1894
2672
|
const [err, raw] = await tryCatch(
|
|
1895
|
-
config.
|
|
2673
|
+
config._data.query(api.withdrawals.queries.list, {
|
|
1896
2674
|
limit: input?.limit,
|
|
1897
2675
|
cursor: input?.cursor
|
|
1898
2676
|
})
|
|
@@ -1903,13 +2681,13 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1903
2681
|
return [null, raw];
|
|
1904
2682
|
},
|
|
1905
2683
|
recordCompleted: async (input) => {
|
|
1906
|
-
if (!config.
|
|
2684
|
+
if (!config._data) {
|
|
1907
2685
|
return stub(
|
|
1908
2686
|
"withdrawals.recordCompleted"
|
|
1909
2687
|
);
|
|
1910
2688
|
}
|
|
1911
2689
|
const [err] = await tryCatch(
|
|
1912
|
-
config.
|
|
2690
|
+
config._data.mutation(api.withdrawals.mutations.recordCompleted, {
|
|
1913
2691
|
withdrawalId: input.withdrawalId,
|
|
1914
2692
|
txHash: input.txHash
|
|
1915
2693
|
})
|
|
@@ -1934,13 +2712,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1934
2712
|
* orchestration ships in W3+.
|
|
1935
2713
|
*/
|
|
1936
2714
|
create: async (input) => {
|
|
1937
|
-
if (!config.
|
|
2715
|
+
if (!config._data) {
|
|
1938
2716
|
return stub(
|
|
1939
2717
|
"organizations.withdrawals.create"
|
|
1940
2718
|
);
|
|
1941
2719
|
}
|
|
1942
2720
|
const [err, raw] = await tryCatch(
|
|
1943
|
-
config.
|
|
2721
|
+
config._data.mutation(api.withdrawals.mutations.createOrg, {
|
|
1944
2722
|
organizationId: input.organizationId,
|
|
1945
2723
|
amount: input.amount,
|
|
1946
2724
|
destination: {
|
|
@@ -1967,13 +2745,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1967
2745
|
return [null, created];
|
|
1968
2746
|
},
|
|
1969
2747
|
retrieve: async (input) => {
|
|
1970
|
-
if (!config.
|
|
2748
|
+
if (!config._data) {
|
|
1971
2749
|
return stub(
|
|
1972
2750
|
"organizations.withdrawals.retrieve"
|
|
1973
2751
|
);
|
|
1974
2752
|
}
|
|
1975
2753
|
const [err, raw] = await tryCatch(
|
|
1976
|
-
config.
|
|
2754
|
+
config._data.query(api.withdrawals.queries.retrieve, {
|
|
1977
2755
|
withdrawalId: input.withdrawalId
|
|
1978
2756
|
})
|
|
1979
2757
|
);
|
|
@@ -2003,13 +2781,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
2003
2781
|
return [null, withdrawal];
|
|
2004
2782
|
},
|
|
2005
2783
|
list: async (input) => {
|
|
2006
|
-
if (!config.
|
|
2784
|
+
if (!config._data) {
|
|
2007
2785
|
return stub(
|
|
2008
2786
|
"organizations.withdrawals.list"
|
|
2009
2787
|
);
|
|
2010
2788
|
}
|
|
2011
2789
|
const [err, raw] = await tryCatch(
|
|
2012
|
-
config.
|
|
2790
|
+
config._data.query(api.withdrawals.queries.listOrg, {
|
|
2013
2791
|
organizationId: input.organizationId,
|
|
2014
2792
|
limit: input.limit,
|
|
2015
2793
|
cursor: input.cursor
|
|
@@ -2028,7 +2806,7 @@ async function handleSubmissionFailure(config, withdrawalId, error) {
|
|
|
2028
2806
|
}
|
|
2029
2807
|
async function bestEffortMarkFailed2(config, withdrawalId, error) {
|
|
2030
2808
|
await tryCatch(
|
|
2031
|
-
config.
|
|
2809
|
+
config._data.mutation(api.withdrawals.mutations.markFailed, {
|
|
2032
2810
|
withdrawalId,
|
|
2033
2811
|
errorCode: error.code,
|
|
2034
2812
|
errorMessage: error.message
|
|
@@ -2107,13 +2885,13 @@ function createWebhookEventsClient() {
|
|
|
2107
2885
|
function createOrgExternalAccountsClient(config) {
|
|
2108
2886
|
return {
|
|
2109
2887
|
create: async (input) => {
|
|
2110
|
-
if (!config.
|
|
2888
|
+
if (!config._data) {
|
|
2111
2889
|
return stub(
|
|
2112
2890
|
"organizations.externalAccounts.create"
|
|
2113
2891
|
);
|
|
2114
2892
|
}
|
|
2115
2893
|
const [err, raw] = await tryCatch(
|
|
2116
|
-
config.
|
|
2894
|
+
config._data.mutation(api.externalAccounts.mutations.createOrg, {
|
|
2117
2895
|
organizationId: input.organizationId,
|
|
2118
2896
|
kind: input.kind,
|
|
2119
2897
|
label: input.label,
|
|
@@ -2127,10 +2905,7 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2127
2905
|
})
|
|
2128
2906
|
);
|
|
2129
2907
|
if (err) {
|
|
2130
|
-
return [
|
|
2131
|
-
fromConvexError(err),
|
|
2132
|
-
null
|
|
2133
|
-
];
|
|
2908
|
+
return [fromConvexError(err), null];
|
|
2134
2909
|
}
|
|
2135
2910
|
if (!raw) {
|
|
2136
2911
|
return [
|
|
@@ -2141,21 +2916,16 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2141
2916
|
null
|
|
2142
2917
|
];
|
|
2143
2918
|
}
|
|
2144
|
-
return [
|
|
2145
|
-
null,
|
|
2146
|
-
brandExternalAccount(
|
|
2147
|
-
raw
|
|
2148
|
-
)
|
|
2149
|
-
];
|
|
2919
|
+
return [null, brandExternalAccount(raw)];
|
|
2150
2920
|
},
|
|
2151
2921
|
list: async (input) => {
|
|
2152
|
-
if (!config.
|
|
2922
|
+
if (!config._data) {
|
|
2153
2923
|
return stub(
|
|
2154
2924
|
"organizations.externalAccounts.list"
|
|
2155
2925
|
);
|
|
2156
2926
|
}
|
|
2157
2927
|
const [err, result] = await tryCatch(
|
|
2158
|
-
config.
|
|
2928
|
+
config._data.query(api.externalAccounts.queries.listOrg, {
|
|
2159
2929
|
organizationId: input.organizationId,
|
|
2160
2930
|
limit: input.limit,
|
|
2161
2931
|
cursor: input.cursor
|
|
@@ -2165,9 +2935,7 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2165
2935
|
return [fromConvexError(err), null];
|
|
2166
2936
|
}
|
|
2167
2937
|
const branded = result.data.map(
|
|
2168
|
-
(row) => brandExternalAccount(
|
|
2169
|
-
row
|
|
2170
|
-
)
|
|
2938
|
+
(row) => brandExternalAccount(row)
|
|
2171
2939
|
);
|
|
2172
2940
|
return [
|
|
2173
2941
|
null,
|
|
@@ -2179,17 +2947,66 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2179
2947
|
];
|
|
2180
2948
|
},
|
|
2181
2949
|
retrieve: async (input) => {
|
|
2182
|
-
if (!config.
|
|
2950
|
+
if (!config._data) {
|
|
2183
2951
|
return stub(
|
|
2184
2952
|
"organizations.externalAccounts.retrieve"
|
|
2185
2953
|
);
|
|
2186
2954
|
}
|
|
2187
2955
|
const [err, raw] = await tryCatch(
|
|
2188
|
-
config.
|
|
2956
|
+
config._data.query(api.externalAccounts.queries.retrieveOrg, {
|
|
2957
|
+
organizationId: input.organizationId,
|
|
2958
|
+
externalAccountId: input.externalAccountId
|
|
2959
|
+
})
|
|
2960
|
+
);
|
|
2961
|
+
if (err) {
|
|
2962
|
+
return [fromConvexError(err), null];
|
|
2963
|
+
}
|
|
2964
|
+
if (!raw) {
|
|
2965
|
+
return [
|
|
2966
|
+
new CapxulError({
|
|
2967
|
+
code: "NOT_FOUND",
|
|
2968
|
+
message: `external_account ${input.externalAccountId} not found`
|
|
2969
|
+
}),
|
|
2970
|
+
null
|
|
2971
|
+
];
|
|
2972
|
+
}
|
|
2973
|
+
return [null, brandExternalAccount(raw)];
|
|
2974
|
+
},
|
|
2975
|
+
remove: async (input) => {
|
|
2976
|
+
if (!config._data) {
|
|
2977
|
+
return stub("organizations.externalAccounts.remove");
|
|
2978
|
+
}
|
|
2979
|
+
const [err] = await tryCatch(
|
|
2980
|
+
config._data.mutation(api.externalAccounts.mutations.removeOrg, {
|
|
2189
2981
|
organizationId: input.organizationId,
|
|
2190
2982
|
externalAccountId: input.externalAccountId
|
|
2191
2983
|
})
|
|
2192
2984
|
);
|
|
2985
|
+
if (err) {
|
|
2986
|
+
return [fromConvexError(err), null];
|
|
2987
|
+
}
|
|
2988
|
+
return [null, void 0];
|
|
2989
|
+
}
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
function createOrgSubAccountsClient(config) {
|
|
2993
|
+
return {
|
|
2994
|
+
create: async (input) => {
|
|
2995
|
+
if (!config._data) {
|
|
2996
|
+
return stub(
|
|
2997
|
+
"organizations.subAccounts.create"
|
|
2998
|
+
);
|
|
2999
|
+
}
|
|
3000
|
+
const [err, raw] = await tryCatch(
|
|
3001
|
+
config._data.mutation(api.subAccounts.mutations.create, {
|
|
3002
|
+
parent: {
|
|
3003
|
+
kind: "organization",
|
|
3004
|
+
id: input.organizationId
|
|
3005
|
+
},
|
|
3006
|
+
name: input.name,
|
|
3007
|
+
purpose: input.purpose
|
|
3008
|
+
})
|
|
3009
|
+
);
|
|
2193
3010
|
if (err) {
|
|
2194
3011
|
return [
|
|
2195
3012
|
fromConvexError(err),
|
|
@@ -2200,28 +3017,60 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2200
3017
|
return [
|
|
2201
3018
|
new CapxulError({
|
|
2202
3019
|
code: "NOT_FOUND",
|
|
2203
|
-
message:
|
|
3020
|
+
message: "sub_account creation returned no resource"
|
|
2204
3021
|
}),
|
|
2205
3022
|
null
|
|
2206
3023
|
];
|
|
2207
3024
|
}
|
|
3025
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
3026
|
+
if (brandErr) {
|
|
3027
|
+
return [brandErr, null];
|
|
3028
|
+
}
|
|
3029
|
+
return [null, branded];
|
|
3030
|
+
},
|
|
3031
|
+
list: async (input) => {
|
|
3032
|
+
if (!config._data) {
|
|
3033
|
+
return stub(
|
|
3034
|
+
"organizations.subAccounts.list"
|
|
3035
|
+
);
|
|
3036
|
+
}
|
|
3037
|
+
const [err, rows] = await tryCatch(
|
|
3038
|
+
config._data.query(api.subAccounts.queries.listByOrganization, {
|
|
3039
|
+
organizationId: input.organizationId
|
|
3040
|
+
})
|
|
3041
|
+
);
|
|
3042
|
+
if (err) {
|
|
3043
|
+
return [
|
|
3044
|
+
fromConvexError(err),
|
|
3045
|
+
null
|
|
3046
|
+
];
|
|
3047
|
+
}
|
|
3048
|
+
const branded = [];
|
|
3049
|
+
for (const row of rows) {
|
|
3050
|
+
const [brandErr, value] = tryBrandSubAccount(row);
|
|
3051
|
+
if (brandErr) {
|
|
3052
|
+
return [brandErr, null];
|
|
3053
|
+
}
|
|
3054
|
+
branded.push(value);
|
|
3055
|
+
}
|
|
2208
3056
|
return [
|
|
2209
3057
|
null,
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
3058
|
+
{
|
|
3059
|
+
object: "list",
|
|
3060
|
+
data: branded,
|
|
3061
|
+
page: { hasMore: false }
|
|
3062
|
+
}
|
|
2213
3063
|
];
|
|
2214
3064
|
},
|
|
2215
|
-
|
|
2216
|
-
if (!config.
|
|
3065
|
+
retrieve: async (input) => {
|
|
3066
|
+
if (!config._data) {
|
|
2217
3067
|
return stub(
|
|
2218
|
-
"organizations.
|
|
3068
|
+
"organizations.subAccounts.retrieve"
|
|
2219
3069
|
);
|
|
2220
3070
|
}
|
|
2221
|
-
const [err] = await tryCatch(
|
|
2222
|
-
config.
|
|
2223
|
-
|
|
2224
|
-
externalAccountId: input.externalAccountId
|
|
3071
|
+
const [err, raw] = await tryCatch(
|
|
3072
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
3073
|
+
subAccountId: input.subAccountId
|
|
2225
3074
|
})
|
|
2226
3075
|
);
|
|
2227
3076
|
if (err) {
|
|
@@ -2230,822 +3079,557 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2230
3079
|
null
|
|
2231
3080
|
];
|
|
2232
3081
|
}
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
list: async () => stub("organizations.list"),
|
|
2242
|
-
update: async () => stub("organizations.update"),
|
|
2243
|
-
safes: {
|
|
2244
|
-
retrieve: async (input) => {
|
|
2245
|
-
if (!config.data) {
|
|
2246
|
-
return stub("organizations.safes.retrieve");
|
|
2247
|
-
}
|
|
2248
|
-
try {
|
|
2249
|
-
const safe = await config.data.query(
|
|
2250
|
-
api.safe.queries.retrieveOrganizationSafe,
|
|
2251
|
-
input
|
|
2252
|
-
);
|
|
2253
|
-
if (!safe) {
|
|
2254
|
-
return [
|
|
2255
|
-
new CapxulError({
|
|
2256
|
-
code: "NOT_FOUND",
|
|
2257
|
-
message: `safe ${input.safeId} not found`
|
|
2258
|
-
}),
|
|
2259
|
-
null
|
|
2260
|
-
];
|
|
2261
|
-
}
|
|
2262
|
-
return [null, safe];
|
|
2263
|
-
} catch (cause) {
|
|
2264
|
-
return [
|
|
2265
|
-
fromConvexError(cause),
|
|
2266
|
-
null
|
|
2267
|
-
];
|
|
2268
|
-
}
|
|
3082
|
+
if (!raw) {
|
|
3083
|
+
return [
|
|
3084
|
+
new CapxulError({
|
|
3085
|
+
code: "NOT_FOUND",
|
|
3086
|
+
message: `sub_account ${input.subAccountId} not found`
|
|
3087
|
+
}),
|
|
3088
|
+
null
|
|
3089
|
+
];
|
|
2269
3090
|
}
|
|
3091
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
3092
|
+
if (brandErr) {
|
|
3093
|
+
return [
|
|
3094
|
+
brandErr,
|
|
3095
|
+
null
|
|
3096
|
+
];
|
|
3097
|
+
}
|
|
3098
|
+
return [null, branded];
|
|
2270
3099
|
},
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
webhookEvents: createWebhookEventsClient()
|
|
2307
|
-
};
|
|
2308
|
-
}
|
|
2309
|
-
|
|
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
|
-
// src/core/token-transfers.ts
|
|
2319
|
-
var toTokenTransferId = (raw) => {
|
|
2320
|
-
if (typeof raw !== "string" || raw.length === 0) {
|
|
2321
|
-
throw new Error(
|
|
2322
|
-
`Invalid tokenTransferId: expected non-empty string, got ${String(raw)}`
|
|
2323
|
-
);
|
|
2324
|
-
}
|
|
2325
|
-
return raw;
|
|
2326
|
-
};
|
|
2327
|
-
function brandRow(row) {
|
|
2328
|
-
return {
|
|
2329
|
-
...row,
|
|
2330
|
-
id: toTokenTransferId(row.id)
|
|
3100
|
+
remove: async (input) => {
|
|
3101
|
+
if (!config._data) {
|
|
3102
|
+
return stub(
|
|
3103
|
+
"organizations.subAccounts.remove"
|
|
3104
|
+
);
|
|
3105
|
+
}
|
|
3106
|
+
const [err, raw] = await tryCatch(
|
|
3107
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
3108
|
+
subAccountId: input.subAccountId
|
|
3109
|
+
})
|
|
3110
|
+
);
|
|
3111
|
+
if (err) {
|
|
3112
|
+
return [
|
|
3113
|
+
fromConvexError(err),
|
|
3114
|
+
null
|
|
3115
|
+
];
|
|
3116
|
+
}
|
|
3117
|
+
if (!raw) {
|
|
3118
|
+
return [
|
|
3119
|
+
new CapxulError({
|
|
3120
|
+
code: "NOT_FOUND",
|
|
3121
|
+
message: `sub_account ${input.subAccountId} not found`
|
|
3122
|
+
}),
|
|
3123
|
+
null
|
|
3124
|
+
];
|
|
3125
|
+
}
|
|
3126
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
3127
|
+
if (brandErr) {
|
|
3128
|
+
return [
|
|
3129
|
+
brandErr,
|
|
3130
|
+
null
|
|
3131
|
+
];
|
|
3132
|
+
}
|
|
3133
|
+
return [null, branded];
|
|
3134
|
+
}
|
|
2331
3135
|
};
|
|
2332
3136
|
}
|
|
2333
|
-
function
|
|
3137
|
+
function createOrganizationsClient(config = {}) {
|
|
2334
3138
|
return {
|
|
2335
|
-
|
|
2336
|
-
if (!config.
|
|
2337
|
-
return stub("
|
|
3139
|
+
create: async (input) => {
|
|
3140
|
+
if (!config._data) {
|
|
3141
|
+
return stub("organizations.create");
|
|
3142
|
+
}
|
|
3143
|
+
if (input.country !== void 0) {
|
|
3144
|
+
return [
|
|
3145
|
+
new CapxulError({
|
|
3146
|
+
code: "INVALID_INPUT",
|
|
3147
|
+
message: "organizations.create does not support country yet \u2014 backend mutation only accepts name.",
|
|
3148
|
+
details: { field: "country" }
|
|
3149
|
+
}),
|
|
3150
|
+
null
|
|
3151
|
+
];
|
|
2338
3152
|
}
|
|
2339
3153
|
try {
|
|
2340
|
-
const
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
);
|
|
2348
|
-
if (!raw) {
|
|
3154
|
+
const orgId = await config._data.mutation(api.org.mutations.create, {
|
|
3155
|
+
name: input.name
|
|
3156
|
+
});
|
|
3157
|
+
const org = await config._data.query(api.org.queries.retrieve, {
|
|
3158
|
+
orgId
|
|
3159
|
+
});
|
|
3160
|
+
if (!org) {
|
|
2349
3161
|
return [
|
|
2350
3162
|
new CapxulError({
|
|
2351
|
-
code: "
|
|
2352
|
-
message: "
|
|
3163
|
+
code: "NETWORK_ERROR",
|
|
3164
|
+
message: "organization created but could not be retrieved"
|
|
2353
3165
|
}),
|
|
2354
3166
|
null
|
|
2355
3167
|
];
|
|
2356
3168
|
}
|
|
2357
|
-
return [
|
|
2358
|
-
null,
|
|
2359
|
-
{
|
|
2360
|
-
object: "list",
|
|
2361
|
-
data: raw.items.map(brandRow),
|
|
2362
|
-
page: {
|
|
2363
|
-
hasMore: raw.hasMore,
|
|
2364
|
-
nextCursor: raw.nextCursor
|
|
2365
|
-
},
|
|
2366
|
-
displayCurrency: raw.displayCurrency
|
|
2367
|
-
}
|
|
2368
|
-
];
|
|
3169
|
+
return [null, org];
|
|
2369
3170
|
} catch (cause) {
|
|
2370
3171
|
return [fromConvexError(cause), null];
|
|
2371
3172
|
}
|
|
2372
3173
|
},
|
|
2373
|
-
retrieve: async (
|
|
2374
|
-
if (!config.
|
|
2375
|
-
return stub("
|
|
3174
|
+
retrieve: async (organizationId) => {
|
|
3175
|
+
if (!config._data) {
|
|
3176
|
+
return stub("organizations.retrieve");
|
|
2376
3177
|
}
|
|
2377
3178
|
try {
|
|
2378
|
-
const
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
chainId: input.chainId
|
|
2384
|
-
}
|
|
2385
|
-
);
|
|
2386
|
-
if (!raw) {
|
|
3179
|
+
const orgId = organizationId.replace(/^org_/, "");
|
|
3180
|
+
const org = await config._data.query(api.org.queries.retrieve, {
|
|
3181
|
+
orgId
|
|
3182
|
+
});
|
|
3183
|
+
if (!org) {
|
|
2387
3184
|
return [
|
|
2388
3185
|
new CapxulError({
|
|
2389
3186
|
code: "NOT_FOUND",
|
|
2390
|
-
message: `
|
|
2391
|
-
details: {
|
|
2392
|
-
txHash: input.txHash,
|
|
2393
|
-
logIndex: input.logIndex,
|
|
2394
|
-
chainId: input.chainId
|
|
2395
|
-
}
|
|
3187
|
+
message: `organization ${organizationId} not found`
|
|
2396
3188
|
}),
|
|
2397
3189
|
null
|
|
2398
3190
|
];
|
|
2399
3191
|
}
|
|
2400
|
-
return [null,
|
|
3192
|
+
return [null, org];
|
|
2401
3193
|
} catch (cause) {
|
|
2402
3194
|
return [fromConvexError(cause), null];
|
|
2403
3195
|
}
|
|
2404
|
-
}
|
|
2405
|
-
};
|
|
2406
|
-
}
|
|
2407
|
-
|
|
2408
|
-
// src/core/virtual-accounts.ts
|
|
2409
|
-
function createVirtualAccountsClient() {
|
|
2410
|
-
return {
|
|
2411
|
-
create: async () => stub("virtualAccounts.create"),
|
|
2412
|
-
retrieve: async () => stub("virtualAccounts.retrieve"),
|
|
2413
|
-
list: async () => stub("virtualAccounts.list"),
|
|
2414
|
-
remove: async () => stub("virtualAccounts.remove")
|
|
2415
|
-
};
|
|
2416
|
-
}
|
|
2417
|
-
|
|
2418
|
-
// src/core/virtual-cards.ts
|
|
2419
|
-
function createVirtualCardsClient() {
|
|
2420
|
-
return {
|
|
2421
|
-
create: async () => stub("virtualCards.create"),
|
|
2422
|
-
retrieve: async () => stub("virtualCards.retrieve"),
|
|
2423
|
-
list: async () => stub("virtualCards.list"),
|
|
2424
|
-
freeze: async () => stub("virtualCards.freeze"),
|
|
2425
|
-
unfreeze: async () => stub("virtualCards.unfreeze"),
|
|
2426
|
-
cancel: async () => stub("virtualCards.cancel")
|
|
2427
|
-
};
|
|
2428
|
-
}
|
|
2429
|
-
function createAuthFlowMachine(client) {
|
|
2430
|
-
return setup({
|
|
2431
|
-
types: {},
|
|
2432
|
-
actors: {
|
|
2433
|
-
// XState v5's `fromPromise` injects an `AbortSignal` that aborts
|
|
2434
|
-
// when the actor is stopped (parent transition fires, machine is
|
|
2435
|
-
// disposed, etc.). Plumbing it through `client.auth.sendOtp` /
|
|
2436
|
-
// `client.auth.verifyOtp` makes the in-flight HTTP request
|
|
2437
|
-
// cancellable: stale responses can't race a state machine
|
|
2438
|
-
// that's already moved on. See PR #406 S5.
|
|
2439
|
-
sendOtp: fromPromise(async ({ input, signal }) => {
|
|
2440
|
-
const [error] = await client.auth.sendOtp(
|
|
2441
|
-
{ email: input.email },
|
|
2442
|
-
{ signal }
|
|
2443
|
-
);
|
|
2444
|
-
if (error) throw error;
|
|
2445
|
-
}),
|
|
2446
|
-
verifyOtp: fromPromise(
|
|
2447
|
-
async ({ input, signal }) => {
|
|
2448
|
-
const [error, result] = await client.auth.verifyOtp(
|
|
2449
|
-
{
|
|
2450
|
-
email: input.email,
|
|
2451
|
-
otp: input.code
|
|
2452
|
-
},
|
|
2453
|
-
{ signal }
|
|
2454
|
-
);
|
|
2455
|
-
if (error) throw error;
|
|
2456
|
-
if (result.kind === "bootstrap_required") {
|
|
2457
|
-
throw new CapxulError({
|
|
2458
|
-
code: "ACTION_REQUIRED",
|
|
2459
|
-
message: "OTP verified but auth bootstrap is required. Use createAuthBootstrapFlowMachine for product sign-up.",
|
|
2460
|
-
details: { reason: result.reason }
|
|
2461
|
-
});
|
|
2462
|
-
}
|
|
2463
|
-
return result.session;
|
|
2464
|
-
}
|
|
2465
|
-
),
|
|
2466
|
-
signOut: fromPromise(async () => {
|
|
2467
|
-
const [error] = await client.auth.signOut();
|
|
2468
|
-
if (error) throw error;
|
|
2469
|
-
})
|
|
2470
3196
|
},
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
track("auth_otp_requested", {
|
|
2475
|
-
email_domain: emailDomain(context.email)
|
|
2476
|
-
});
|
|
2477
|
-
},
|
|
2478
|
-
trackOtpFailed: ({ event }) => {
|
|
2479
|
-
const error = errorFromEvent(event);
|
|
2480
|
-
track("auth_failed", {
|
|
2481
|
-
auth_type: "email_otp",
|
|
2482
|
-
reason: error.code
|
|
2483
|
-
});
|
|
2484
|
-
},
|
|
2485
|
-
trackTimeoutFailed: () => {
|
|
2486
|
-
track("auth_failed", {
|
|
2487
|
-
auth_type: "email_otp",
|
|
2488
|
-
reason: "timeout"
|
|
2489
|
-
});
|
|
2490
|
-
},
|
|
2491
|
-
trackVerified: () => {
|
|
2492
|
-
track("auth_verified", { auth_type: "email_otp" });
|
|
2493
|
-
},
|
|
2494
|
-
identifyAndTrack: ({ context }) => {
|
|
2495
|
-
if (!context.session) return;
|
|
2496
|
-
identify(context.session.authUserId, {
|
|
2497
|
-
email_domain: emailDomain(context.session.email)
|
|
2498
|
-
});
|
|
2499
|
-
track("auth_identified", {
|
|
2500
|
-
email_domain: emailDomain(context.session.email)
|
|
2501
|
-
});
|
|
2502
|
-
},
|
|
2503
|
-
trackSignedOut: () => {
|
|
2504
|
-
track("auth_signed_out");
|
|
3197
|
+
list: async (input) => {
|
|
3198
|
+
if (!config._data) {
|
|
3199
|
+
return stub("organizations.list");
|
|
2505
3200
|
}
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
email: ({ event }) => event.email,
|
|
2518
|
-
error: () => null
|
|
2519
|
-
})
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
},
|
|
2523
|
-
sending_otp: {
|
|
2524
|
-
invoke: {
|
|
2525
|
-
src: "sendOtp",
|
|
2526
|
-
input: ({ context }) => ({ email: requireEmail(context) }),
|
|
2527
|
-
onDone: {
|
|
2528
|
-
target: "otp_requested",
|
|
2529
|
-
actions: ["trackOtpRequested"]
|
|
2530
|
-
},
|
|
2531
|
-
onError: {
|
|
2532
|
-
target: "error",
|
|
2533
|
-
actions: [
|
|
2534
|
-
assign({ error: ({ event }) => errorFromEvent(event) }),
|
|
2535
|
-
"trackOtpFailed"
|
|
2536
|
-
]
|
|
2537
|
-
}
|
|
2538
|
-
},
|
|
2539
|
-
after: {
|
|
2540
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2541
|
-
target: "error",
|
|
2542
|
-
actions: [
|
|
2543
|
-
assign({
|
|
2544
|
-
error: () => timeoutError("sending_otp")
|
|
2545
|
-
}),
|
|
2546
|
-
"trackTimeoutFailed"
|
|
2547
|
-
]
|
|
3201
|
+
try {
|
|
3202
|
+
const page = await config._data.query(api.org.queries.list, {
|
|
3203
|
+
limit: input?.limit,
|
|
3204
|
+
cursor: input?.cursor
|
|
3205
|
+
});
|
|
3206
|
+
const result = {
|
|
3207
|
+
object: "list",
|
|
3208
|
+
data: page.data,
|
|
3209
|
+
page: {
|
|
3210
|
+
hasMore: page.hasMore,
|
|
3211
|
+
cursor: page.nextCursor
|
|
2548
3212
|
}
|
|
3213
|
+
};
|
|
3214
|
+
return [null, result];
|
|
3215
|
+
} catch (cause) {
|
|
3216
|
+
return [fromConvexError(cause), null];
|
|
3217
|
+
}
|
|
3218
|
+
},
|
|
3219
|
+
update: async (input) => {
|
|
3220
|
+
if (!config._data) {
|
|
3221
|
+
return stub("organizations.update");
|
|
3222
|
+
}
|
|
3223
|
+
try {
|
|
3224
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3225
|
+
const org = await config._data.mutation(api.org.mutations.update, {
|
|
3226
|
+
orgId,
|
|
3227
|
+
name: input.name
|
|
3228
|
+
});
|
|
3229
|
+
if (!org) {
|
|
3230
|
+
return [
|
|
3231
|
+
new CapxulError({
|
|
3232
|
+
code: "NOT_FOUND",
|
|
3233
|
+
message: `organization ${input.organizationId} not found`
|
|
3234
|
+
}),
|
|
3235
|
+
null
|
|
3236
|
+
];
|
|
2549
3237
|
}
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
3238
|
+
return [null, org];
|
|
3239
|
+
} catch (cause) {
|
|
3240
|
+
return [fromConvexError(cause), null];
|
|
3241
|
+
}
|
|
3242
|
+
},
|
|
3243
|
+
safes: {
|
|
3244
|
+
retrieve: async (input) => {
|
|
3245
|
+
if (!config._data) {
|
|
3246
|
+
return stub("organizations.safes.retrieve");
|
|
2558
3247
|
}
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
actions: [
|
|
2570
|
-
// Scrub the duplicate `context.email` (input value
|
|
2571
|
-
// captured during sendOtp) since the verified
|
|
2572
|
-
// `session.email` is now the canonical source
|
|
2573
|
-
// post-authentication. The session's email is
|
|
2574
|
-
// intentionally retained — it's the auth result, not
|
|
2575
|
-
// lingering input. See PR #406 S2.
|
|
2576
|
-
assign({
|
|
2577
|
-
session: ({ event }) => event.output,
|
|
2578
|
-
email: () => null
|
|
2579
|
-
}),
|
|
2580
|
-
"trackVerified",
|
|
2581
|
-
"identifyAndTrack"
|
|
2582
|
-
]
|
|
2583
|
-
},
|
|
2584
|
-
onError: {
|
|
2585
|
-
target: "error",
|
|
2586
|
-
actions: [
|
|
2587
|
-
assign({ error: ({ event }) => errorFromEvent(event) }),
|
|
2588
|
-
"trackOtpFailed"
|
|
2589
|
-
]
|
|
2590
|
-
}
|
|
2591
|
-
},
|
|
2592
|
-
after: {
|
|
2593
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2594
|
-
target: "error",
|
|
2595
|
-
actions: [
|
|
2596
|
-
assign({
|
|
2597
|
-
error: () => timeoutError("verifying")
|
|
3248
|
+
try {
|
|
3249
|
+
const safe = await config._data.query(
|
|
3250
|
+
api.safe.queries.retrieveOrganizationSafe,
|
|
3251
|
+
input
|
|
3252
|
+
);
|
|
3253
|
+
if (!safe) {
|
|
3254
|
+
return [
|
|
3255
|
+
new CapxulError({
|
|
3256
|
+
code: "NOT_FOUND",
|
|
3257
|
+
message: `safe ${input.safeId} not found`
|
|
2598
3258
|
}),
|
|
2599
|
-
|
|
2600
|
-
]
|
|
3259
|
+
null
|
|
3260
|
+
];
|
|
2601
3261
|
}
|
|
3262
|
+
return [null, safe];
|
|
3263
|
+
} catch (cause) {
|
|
3264
|
+
return [
|
|
3265
|
+
fromConvexError(cause),
|
|
3266
|
+
null
|
|
3267
|
+
];
|
|
2602
3268
|
}
|
|
2603
|
-
}
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
3269
|
+
}
|
|
3270
|
+
},
|
|
3271
|
+
treasury: {
|
|
3272
|
+
retrieve: async (organizationId) => {
|
|
3273
|
+
if (!config._data) {
|
|
3274
|
+
return stub(
|
|
3275
|
+
"organizations.treasury.retrieve"
|
|
3276
|
+
);
|
|
2607
3277
|
}
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
3278
|
+
try {
|
|
3279
|
+
const orgId = organizationId.replace(/^org_/, "");
|
|
3280
|
+
const raw = await config._data.query(
|
|
3281
|
+
api.safe.queries.getOrgTreasuryBalance,
|
|
3282
|
+
{ orgId }
|
|
3283
|
+
);
|
|
3284
|
+
if (!raw) {
|
|
3285
|
+
return [
|
|
3286
|
+
new CapxulError({
|
|
3287
|
+
code: "NOT_FOUND",
|
|
3288
|
+
message: `treasury for organization ${organizationId} not found`
|
|
2619
3289
|
}),
|
|
2620
|
-
|
|
2621
|
-
]
|
|
2622
|
-
},
|
|
2623
|
-
onError: {
|
|
2624
|
-
target: "error",
|
|
2625
|
-
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2628
|
-
},
|
|
2629
|
-
error: {
|
|
2630
|
-
on: {
|
|
2631
|
-
RESET: {
|
|
2632
|
-
target: "idle",
|
|
2633
|
-
actions: assign({ error: () => null })
|
|
3290
|
+
null
|
|
3291
|
+
];
|
|
2634
3292
|
}
|
|
3293
|
+
const treasury = {
|
|
3294
|
+
object: "treasury",
|
|
3295
|
+
id: toTreasuryId(`try_${orgId}`),
|
|
3296
|
+
organizationId,
|
|
3297
|
+
status: "active",
|
|
3298
|
+
safeId: toSafeId(
|
|
3299
|
+
`safe_${raw.safeAddress.replace(/^0x/, "").toLowerCase()}`
|
|
3300
|
+
),
|
|
3301
|
+
totalBalance: { value: "0", currency: "USD" },
|
|
3302
|
+
positions: raw.tokens.map((t) => ({
|
|
3303
|
+
symbol: t.symbol,
|
|
3304
|
+
contractAddress: t.tokenAddress,
|
|
3305
|
+
amount: t.balance
|
|
3306
|
+
})),
|
|
3307
|
+
asOf: raw.lastUpdatedAt ? new Date(raw.lastUpdatedAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
3308
|
+
};
|
|
3309
|
+
return [null, treasury];
|
|
3310
|
+
} catch (cause) {
|
|
3311
|
+
return [
|
|
3312
|
+
fromConvexError(cause),
|
|
3313
|
+
null
|
|
3314
|
+
];
|
|
2635
3315
|
}
|
|
2636
3316
|
}
|
|
2637
|
-
}
|
|
2638
|
-
});
|
|
2639
|
-
}
|
|
2640
|
-
function requireEmail(context) {
|
|
2641
|
-
if (!context.email) {
|
|
2642
|
-
throw Errors.invalidInput(
|
|
2643
|
-
"email",
|
|
2644
|
-
"Auth flow advanced without an email captured in context."
|
|
2645
|
-
);
|
|
2646
|
-
}
|
|
2647
|
-
return context.email;
|
|
2648
|
-
}
|
|
2649
|
-
function requireCodeFromEvent(event) {
|
|
2650
|
-
if (event.type !== "VERIFY") {
|
|
2651
|
-
throw Errors.invalidInput(
|
|
2652
|
-
"code",
|
|
2653
|
-
`Auth flow's verifying state requires a VERIFY event, got ${event.type}.`
|
|
2654
|
-
);
|
|
2655
|
-
}
|
|
2656
|
-
return event.code;
|
|
2657
|
-
}
|
|
2658
|
-
function errorFromEvent(event) {
|
|
2659
|
-
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
2660
|
-
if (cause instanceof CapxulError) {
|
|
2661
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
2662
|
-
return new CapxulError({
|
|
2663
|
-
code: cause.code,
|
|
2664
|
-
message: redactEmail(cause.message),
|
|
2665
|
-
cause,
|
|
2666
|
-
details: cause.details,
|
|
2667
|
-
operationId: cause.operationId,
|
|
2668
|
-
correlationId: cause.correlationId,
|
|
2669
|
-
retryable: cause.retryable
|
|
2670
|
-
});
|
|
2671
|
-
}
|
|
2672
|
-
if (cause instanceof CapxulError2) {
|
|
2673
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
2674
|
-
return new CapxulError2(cause.code, redactEmail(cause.message), {
|
|
2675
|
-
cause,
|
|
2676
|
-
details: cause.details,
|
|
2677
|
-
correlationId: cause.correlationId,
|
|
2678
|
-
layer: cause.layer
|
|
2679
|
-
});
|
|
2680
|
-
}
|
|
2681
|
-
return Errors.providerError("auth", "flow", redactCauseEmail(cause));
|
|
2682
|
-
}
|
|
2683
|
-
var EMAIL_MATCH_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
|
|
2684
|
-
var EMAIL_REDACT_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
|
|
2685
|
-
function redactEmail(message) {
|
|
2686
|
-
return message.replace(EMAIL_REDACT_PATTERN, "<redacted>");
|
|
2687
|
-
}
|
|
2688
|
-
function redactCauseEmail(cause) {
|
|
2689
|
-
if (cause instanceof Error) {
|
|
2690
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
2691
|
-
const redacted = new Error(redactEmail(cause.message));
|
|
2692
|
-
redacted.cause = cause;
|
|
2693
|
-
return redacted;
|
|
2694
|
-
}
|
|
2695
|
-
if (typeof cause === "string") {
|
|
2696
|
-
return redactEmail(cause);
|
|
2697
|
-
}
|
|
2698
|
-
return cause;
|
|
2699
|
-
}
|
|
2700
|
-
function timeoutError(state) {
|
|
2701
|
-
return Errors.providerError(
|
|
2702
|
-
"auth",
|
|
2703
|
-
"flow",
|
|
2704
|
-
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
2705
|
-
);
|
|
2706
|
-
}
|
|
2707
|
-
function emailDomain(email) {
|
|
2708
|
-
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
2709
|
-
return domain || "unknown";
|
|
2710
|
-
}
|
|
2711
|
-
var initialContext = {
|
|
2712
|
-
email: null,
|
|
2713
|
-
code: null,
|
|
2714
|
-
username: null,
|
|
2715
|
-
signerProvider: null,
|
|
2716
|
-
bootstrapToken: null,
|
|
2717
|
-
bootstrapReason: null,
|
|
2718
|
-
session: null,
|
|
2719
|
-
account: null,
|
|
2720
|
-
safe: null,
|
|
2721
|
-
error: null
|
|
2722
|
-
};
|
|
2723
|
-
function createAuthBootstrapFlowMachine(client) {
|
|
2724
|
-
return setup({
|
|
2725
|
-
types: {},
|
|
2726
|
-
actors: {
|
|
2727
|
-
sendOtp: fromPromise(async ({ input, signal }) => {
|
|
2728
|
-
const [error] = await client.auth.sendOtp(
|
|
2729
|
-
{ email: input.email },
|
|
2730
|
-
{ signal }
|
|
2731
|
-
);
|
|
2732
|
-
if (error) throw error;
|
|
2733
|
-
}),
|
|
2734
|
-
verifyOtp: fromPromise(
|
|
2735
|
-
async ({ input, signal }) => {
|
|
2736
|
-
const [error, result] = await client.auth.verifyOtp(
|
|
2737
|
-
{ email: input.email, otp: input.code },
|
|
2738
|
-
{ signal }
|
|
2739
|
-
);
|
|
2740
|
-
if (error) throw error;
|
|
2741
|
-
return result;
|
|
2742
|
-
}
|
|
2743
|
-
),
|
|
2744
|
-
completeBootstrap: fromPromise(async ({ input }) => {
|
|
2745
|
-
const [error, result] = await client.auth.completeBootstrap(input);
|
|
2746
|
-
if (error) throw error;
|
|
2747
|
-
return result;
|
|
2748
|
-
}),
|
|
2749
|
-
signOut: fromPromise(async () => {
|
|
2750
|
-
const [error] = await client.auth.signOut();
|
|
2751
|
-
if (error) throw error;
|
|
2752
|
-
})
|
|
2753
3317
|
},
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
if (!
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
reason: "timeout"
|
|
2771
|
-
});
|
|
2772
|
-
},
|
|
2773
|
-
trackVerified: () => {
|
|
2774
|
-
track("auth_verified", { auth_type: "email_otp" });
|
|
2775
|
-
},
|
|
2776
|
-
trackBootstrapRequired: ({ context }) => {
|
|
2777
|
-
track("auth_verified", {
|
|
2778
|
-
auth_type: "email_otp",
|
|
2779
|
-
auth_mode: context.bootstrapReason ?? "bootstrap_required"
|
|
2780
|
-
});
|
|
2781
|
-
},
|
|
2782
|
-
identifyAndTrack: ({ context }) => {
|
|
2783
|
-
if (!context.session) return;
|
|
2784
|
-
identify(context.session.authUserId, {
|
|
2785
|
-
email_domain: emailDomain2(context.session.email)
|
|
2786
|
-
});
|
|
2787
|
-
track("auth_identified", {
|
|
2788
|
-
email_domain: emailDomain2(context.session.email)
|
|
2789
|
-
});
|
|
2790
|
-
},
|
|
2791
|
-
trackSignedOut: () => {
|
|
2792
|
-
track("auth_signed_out");
|
|
2793
|
-
}
|
|
2794
|
-
}
|
|
2795
|
-
}).createMachine({
|
|
2796
|
-
id: "authBootstrap",
|
|
2797
|
-
initial: "email",
|
|
2798
|
-
context: initialContext,
|
|
2799
|
-
states: {
|
|
2800
|
-
email: {
|
|
2801
|
-
on: {
|
|
2802
|
-
ENTER_EMAIL: {
|
|
2803
|
-
actions: assign({
|
|
2804
|
-
email: ({ event }) => event.email,
|
|
2805
|
-
error: () => null
|
|
2806
|
-
})
|
|
2807
|
-
},
|
|
2808
|
-
REQUEST_OTP: { target: "sending_otp" }
|
|
3318
|
+
members: {
|
|
3319
|
+
list: async (input) => {
|
|
3320
|
+
if (!config._data?.action) {
|
|
3321
|
+
return stub("organizations.members.list");
|
|
3322
|
+
}
|
|
3323
|
+
try {
|
|
3324
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3325
|
+
const page = await config._data.action(api.org.actions.membersList, {
|
|
3326
|
+
organizationId: orgId,
|
|
3327
|
+
status: input.status,
|
|
3328
|
+
limit: input.limit,
|
|
3329
|
+
cursor: input.cursor
|
|
3330
|
+
});
|
|
3331
|
+
return [null, page];
|
|
3332
|
+
} catch (cause) {
|
|
3333
|
+
return [fromConvexError(cause), null];
|
|
2809
3334
|
}
|
|
2810
3335
|
},
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
input: ({ context }) => ({ email: requireEmail2(context) }),
|
|
2815
|
-
onDone: { target: "otp_requested", actions: "trackOtpRequested" },
|
|
2816
|
-
onError: {
|
|
2817
|
-
target: "otp_requested",
|
|
2818
|
-
actions: [
|
|
2819
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
2820
|
-
"trackFailed"
|
|
2821
|
-
]
|
|
2822
|
-
}
|
|
2823
|
-
},
|
|
2824
|
-
after: {
|
|
2825
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2826
|
-
target: "otp_requested",
|
|
2827
|
-
actions: [
|
|
2828
|
-
assign({ error: () => timeoutError2("sending_otp") }),
|
|
2829
|
-
"trackTimeoutFailed"
|
|
2830
|
-
]
|
|
2831
|
-
}
|
|
3336
|
+
retrieve: async (input) => {
|
|
3337
|
+
if (!config._data?.action) {
|
|
3338
|
+
return stub("organizations.members.retrieve");
|
|
2832
3339
|
}
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
actions
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
3340
|
+
try {
|
|
3341
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3342
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3343
|
+
const member = await config._data.action(
|
|
3344
|
+
api.org.actions.retrieveMember,
|
|
3345
|
+
{
|
|
3346
|
+
organizationId: orgId,
|
|
3347
|
+
memberId
|
|
3348
|
+
}
|
|
3349
|
+
);
|
|
3350
|
+
return [null, member];
|
|
3351
|
+
} catch (cause) {
|
|
3352
|
+
return [fromConvexError(cause), null];
|
|
2845
3353
|
}
|
|
2846
3354
|
},
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
target: "authenticated",
|
|
2858
|
-
actions: [
|
|
2859
|
-
assign({
|
|
2860
|
-
session: ({ event }) => event.output.session,
|
|
2861
|
-
account: ({ event }) => event.output.kind === "existing_member" ? event.output.account : null,
|
|
2862
|
-
username: ({ event }) => event.output.kind === "existing_member" ? event.output.username : null,
|
|
2863
|
-
safe: ({ event }) => event.output.kind === "existing_member" ? event.output.safe : null,
|
|
2864
|
-
email: () => null,
|
|
2865
|
-
error: () => null
|
|
2866
|
-
}),
|
|
2867
|
-
"trackVerified",
|
|
2868
|
-
"identifyAndTrack"
|
|
2869
|
-
]
|
|
2870
|
-
},
|
|
3355
|
+
invite: async (input) => {
|
|
3356
|
+
if (!config._data?.action) {
|
|
3357
|
+
return stub(
|
|
3358
|
+
"organizations.members.invite"
|
|
3359
|
+
);
|
|
3360
|
+
}
|
|
3361
|
+
try {
|
|
3362
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3363
|
+
const result = await config._data.action(
|
|
3364
|
+
api.org.actions.inviteMember,
|
|
2871
3365
|
{
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
session: ({ event }) => event.output.session,
|
|
2876
|
-
bootstrapToken: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.bootstrapToken : null,
|
|
2877
|
-
bootstrapReason: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.reason : null,
|
|
2878
|
-
username: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.username ?? null : null,
|
|
2879
|
-
email: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.email : null,
|
|
2880
|
-
error: () => null
|
|
2881
|
-
}),
|
|
2882
|
-
"trackVerified",
|
|
2883
|
-
"trackBootstrapRequired"
|
|
2884
|
-
]
|
|
3366
|
+
organizationId: orgId,
|
|
3367
|
+
email: input.email,
|
|
3368
|
+
role: input.role
|
|
2885
3369
|
}
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
2891
|
-
"trackFailed"
|
|
2892
|
-
]
|
|
2893
|
-
}
|
|
2894
|
-
},
|
|
2895
|
-
after: {
|
|
2896
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2897
|
-
target: "otp_requested",
|
|
2898
|
-
actions: [
|
|
2899
|
-
assign({ error: () => timeoutError2("verifying_otp") }),
|
|
2900
|
-
"trackTimeoutFailed"
|
|
2901
|
-
]
|
|
2902
|
-
}
|
|
3370
|
+
);
|
|
3371
|
+
return [null, result];
|
|
3372
|
+
} catch (cause) {
|
|
3373
|
+
return [fromConvexError(cause), null];
|
|
2903
3374
|
}
|
|
2904
3375
|
},
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
})
|
|
2918
|
-
},
|
|
2919
|
-
COMPLETE_BOOTSTRAP: { target: "completing_bootstrap" },
|
|
2920
|
-
BACK: { target: "otp_requested" },
|
|
2921
|
-
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3376
|
+
accept: async (input) => {
|
|
3377
|
+
if (!config._data?.action) {
|
|
3378
|
+
return stub("organizations.members.accept");
|
|
3379
|
+
}
|
|
3380
|
+
try {
|
|
3381
|
+
const member = await config._data.action(
|
|
3382
|
+
api.org.actions.acceptInvitation,
|
|
3383
|
+
{ token: input.token }
|
|
3384
|
+
);
|
|
3385
|
+
return [null, member];
|
|
3386
|
+
} catch (cause) {
|
|
3387
|
+
return [fromConvexError(cause), null];
|
|
2922
3388
|
}
|
|
2923
3389
|
},
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
signerProvider: () => null,
|
|
2943
|
-
email: () => null,
|
|
2944
|
-
error: () => null
|
|
2945
|
-
}),
|
|
2946
|
-
"identifyAndTrack"
|
|
2947
|
-
]
|
|
2948
|
-
},
|
|
2949
|
-
onError: {
|
|
2950
|
-
target: "bootstrap_required",
|
|
2951
|
-
actions: [
|
|
2952
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
2953
|
-
"trackFailed"
|
|
2954
|
-
]
|
|
2955
|
-
}
|
|
2956
|
-
},
|
|
2957
|
-
after: {
|
|
2958
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2959
|
-
target: "bootstrap_required",
|
|
2960
|
-
actions: [
|
|
2961
|
-
assign({ error: () => timeoutError2("completing_bootstrap") }),
|
|
2962
|
-
"trackTimeoutFailed"
|
|
2963
|
-
]
|
|
2964
|
-
}
|
|
3390
|
+
updateRole: async (input) => {
|
|
3391
|
+
if (!config._data?.action) {
|
|
3392
|
+
return stub("organizations.members.updateRole");
|
|
3393
|
+
}
|
|
3394
|
+
try {
|
|
3395
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3396
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3397
|
+
const member = await config._data.action(
|
|
3398
|
+
api.org.actions.updateMemberRole,
|
|
3399
|
+
{
|
|
3400
|
+
organizationId: orgId,
|
|
3401
|
+
memberId,
|
|
3402
|
+
role: input.role
|
|
3403
|
+
}
|
|
3404
|
+
);
|
|
3405
|
+
return [null, member];
|
|
3406
|
+
} catch (cause) {
|
|
3407
|
+
return [fromConvexError(cause), null];
|
|
2965
3408
|
}
|
|
2966
3409
|
},
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
3410
|
+
revoke: async (input) => {
|
|
3411
|
+
if (!config._data?.action) {
|
|
3412
|
+
return stub("organizations.members.revoke");
|
|
3413
|
+
}
|
|
3414
|
+
try {
|
|
3415
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3416
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3417
|
+
const member = await config._data.action(
|
|
3418
|
+
api.org.actions.revokeMember,
|
|
3419
|
+
{
|
|
3420
|
+
organizationId: orgId,
|
|
3421
|
+
memberId
|
|
3422
|
+
}
|
|
3423
|
+
);
|
|
3424
|
+
return [null, member];
|
|
3425
|
+
} catch (cause) {
|
|
3426
|
+
return [fromConvexError(cause), null];
|
|
2970
3427
|
}
|
|
2971
3428
|
},
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3429
|
+
remove: async (input) => {
|
|
3430
|
+
if (!config._data?.action) {
|
|
3431
|
+
return stub("organizations.members.remove");
|
|
3432
|
+
}
|
|
3433
|
+
try {
|
|
3434
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3435
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3436
|
+
await config._data.action(api.org.actions.removeMember, {
|
|
3437
|
+
organizationId: orgId,
|
|
3438
|
+
memberId
|
|
3439
|
+
});
|
|
3440
|
+
return [null, void 0];
|
|
3441
|
+
} catch (cause) {
|
|
3442
|
+
return [fromConvexError(cause), null];
|
|
2986
3443
|
}
|
|
2987
3444
|
},
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
3445
|
+
resend: async (input) => {
|
|
3446
|
+
if (!config._data?.action) {
|
|
3447
|
+
return stub(
|
|
3448
|
+
"organizations.members.resend"
|
|
3449
|
+
);
|
|
3450
|
+
}
|
|
3451
|
+
try {
|
|
3452
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3453
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3454
|
+
const result = await config._data.action(
|
|
3455
|
+
api.org.actions.resendInvitation,
|
|
3456
|
+
{
|
|
3457
|
+
organizationId: orgId,
|
|
3458
|
+
memberId
|
|
3459
|
+
}
|
|
3460
|
+
);
|
|
3461
|
+
return [null, result];
|
|
3462
|
+
} catch (cause) {
|
|
3463
|
+
return [fromConvexError(cause), null];
|
|
2991
3464
|
}
|
|
2992
3465
|
}
|
|
2993
|
-
}
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3466
|
+
},
|
|
3467
|
+
apiKeys: createApiKeysClient(),
|
|
3468
|
+
subAccounts: createOrgSubAccountsClient(config),
|
|
3469
|
+
externalAccounts: createOrgExternalAccountsClient(config),
|
|
3470
|
+
balanceLedger: {
|
|
3471
|
+
list: async (input) => {
|
|
3472
|
+
if (!config._data) {
|
|
3473
|
+
return stub(
|
|
3474
|
+
"organizations.balanceLedger.list"
|
|
3475
|
+
);
|
|
3476
|
+
}
|
|
3477
|
+
try {
|
|
3478
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3479
|
+
const page = await config._data.query(
|
|
3480
|
+
api.balanceLedger.queries.listForOrg,
|
|
3481
|
+
{ orgId, limit: input.limit, cursor: input.cursor }
|
|
3482
|
+
);
|
|
3483
|
+
return [null, page];
|
|
3484
|
+
} catch (cause) {
|
|
3485
|
+
return [fromConvexError(cause), null];
|
|
3486
|
+
}
|
|
3487
|
+
},
|
|
3488
|
+
retrieve: async (input) => {
|
|
3489
|
+
if (!config._data) {
|
|
3490
|
+
return stub(
|
|
3491
|
+
"organizations.balanceLedger.retrieve"
|
|
3492
|
+
);
|
|
3493
|
+
}
|
|
3494
|
+
try {
|
|
3495
|
+
const entry = await config._data.query(
|
|
3496
|
+
api.balanceLedger.queries.retrieve,
|
|
3497
|
+
{ entryId: input.entryId }
|
|
3498
|
+
);
|
|
3499
|
+
if (!entry) {
|
|
3500
|
+
return [
|
|
3501
|
+
new CapxulError({
|
|
3502
|
+
code: "NOT_FOUND",
|
|
3503
|
+
message: `balance_ledger_entry ${input.entryId} not found`
|
|
3504
|
+
}),
|
|
3505
|
+
null
|
|
3506
|
+
];
|
|
3507
|
+
}
|
|
3508
|
+
return [null, entry];
|
|
3509
|
+
} catch (cause) {
|
|
3510
|
+
return [fromConvexError(cause), null];
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
},
|
|
3514
|
+
payments: createOrgPaymentsClient(),
|
|
3515
|
+
transfers: createOrgTransfersClient(),
|
|
3516
|
+
withdrawals: createOrgWithdrawalsClient(config),
|
|
3517
|
+
documents: createOrgDocumentsClient(config),
|
|
3518
|
+
webhookEndpoints: createWebhookEndpointsClient(),
|
|
3519
|
+
webhookEvents: createWebhookEventsClient()
|
|
3520
|
+
};
|
|
3022
3521
|
}
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3522
|
+
|
|
3523
|
+
// src/core/token-transfers.ts
|
|
3524
|
+
var toTokenTransferId = (raw) => {
|
|
3525
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
3526
|
+
throw new Error(
|
|
3527
|
+
`Invalid tokenTransferId: expected non-empty string, got ${String(raw)}`
|
|
3028
3528
|
);
|
|
3029
3529
|
}
|
|
3030
|
-
return
|
|
3530
|
+
return raw;
|
|
3531
|
+
};
|
|
3532
|
+
function brandRow(row) {
|
|
3533
|
+
return {
|
|
3534
|
+
...row,
|
|
3535
|
+
id: toTokenTransferId(row.id)
|
|
3536
|
+
};
|
|
3031
3537
|
}
|
|
3032
|
-
function
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3538
|
+
function createTokenTransfersClient(config = {}) {
|
|
3539
|
+
return {
|
|
3540
|
+
list: async (input) => {
|
|
3541
|
+
if (!config._data) {
|
|
3542
|
+
return stub("tokenTransfers.list");
|
|
3543
|
+
}
|
|
3544
|
+
try {
|
|
3545
|
+
const raw = await config._data.query(
|
|
3546
|
+
api.tokenTransfers.queries.list,
|
|
3547
|
+
{
|
|
3548
|
+
limit: input?.limit,
|
|
3549
|
+
cursor: input?.cursor,
|
|
3550
|
+
direction: input?.direction
|
|
3551
|
+
}
|
|
3552
|
+
);
|
|
3553
|
+
if (!raw) {
|
|
3554
|
+
return [
|
|
3555
|
+
new CapxulError({
|
|
3556
|
+
code: "NOT_AUTHENTICATED",
|
|
3557
|
+
message: "tokenTransfers.list requires an authenticated session."
|
|
3558
|
+
}),
|
|
3559
|
+
null
|
|
3560
|
+
];
|
|
3561
|
+
}
|
|
3562
|
+
return [
|
|
3563
|
+
null,
|
|
3564
|
+
{
|
|
3565
|
+
object: "list",
|
|
3566
|
+
data: raw.items.map(brandRow),
|
|
3567
|
+
page: {
|
|
3568
|
+
hasMore: raw.hasMore,
|
|
3569
|
+
nextCursor: raw.nextCursor
|
|
3570
|
+
},
|
|
3571
|
+
displayCurrency: raw.displayCurrency
|
|
3572
|
+
}
|
|
3573
|
+
];
|
|
3574
|
+
} catch (cause) {
|
|
3575
|
+
return [fromConvexError(cause), null];
|
|
3576
|
+
}
|
|
3577
|
+
},
|
|
3578
|
+
retrieve: async (input) => {
|
|
3579
|
+
if (!config._data) {
|
|
3580
|
+
return stub("tokenTransfers.retrieve");
|
|
3581
|
+
}
|
|
3582
|
+
try {
|
|
3583
|
+
const raw = await config._data.query(
|
|
3584
|
+
api.tokenTransfers.queries.getByTxLogIndex,
|
|
3585
|
+
{
|
|
3586
|
+
txHash: input.txHash,
|
|
3587
|
+
logIndex: input.logIndex,
|
|
3588
|
+
chainId: input.chainId
|
|
3589
|
+
}
|
|
3590
|
+
);
|
|
3591
|
+
if (!raw) {
|
|
3592
|
+
return [
|
|
3593
|
+
new CapxulError({
|
|
3594
|
+
code: "NOT_FOUND",
|
|
3595
|
+
message: `tokenTransfer (txHash=${input.txHash}, logIndex=${input.logIndex}) not found or not visible to caller.`,
|
|
3596
|
+
details: {
|
|
3597
|
+
txHash: input.txHash,
|
|
3598
|
+
logIndex: input.logIndex,
|
|
3599
|
+
chainId: input.chainId
|
|
3600
|
+
}
|
|
3601
|
+
}),
|
|
3602
|
+
null
|
|
3603
|
+
];
|
|
3604
|
+
}
|
|
3605
|
+
return [null, brandRow(raw)];
|
|
3606
|
+
} catch (cause) {
|
|
3607
|
+
return [fromConvexError(cause), null];
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
};
|
|
3038
3611
|
}
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3612
|
+
|
|
3613
|
+
// src/core/virtual-accounts.ts
|
|
3614
|
+
function createVirtualAccountsClient() {
|
|
3615
|
+
return {
|
|
3616
|
+
create: async () => stub("virtualAccounts.create"),
|
|
3617
|
+
retrieve: async () => stub("virtualAccounts.retrieve"),
|
|
3618
|
+
list: async () => stub("virtualAccounts.list"),
|
|
3619
|
+
remove: async () => stub("virtualAccounts.remove")
|
|
3620
|
+
};
|
|
3045
3621
|
}
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3622
|
+
|
|
3623
|
+
// src/core/virtual-cards.ts
|
|
3624
|
+
function createVirtualCardsClient() {
|
|
3625
|
+
return {
|
|
3626
|
+
create: async () => stub("virtualCards.create"),
|
|
3627
|
+
retrieve: async () => stub("virtualCards.retrieve"),
|
|
3628
|
+
list: async () => stub("virtualCards.list"),
|
|
3629
|
+
freeze: async () => stub("virtualCards.freeze"),
|
|
3630
|
+
unfreeze: async () => stub("virtualCards.unfreeze"),
|
|
3631
|
+
cancel: async () => stub("virtualCards.cancel")
|
|
3632
|
+
};
|
|
3049
3633
|
}
|
|
3050
3634
|
function createProvisioningMachine(client) {
|
|
3051
3635
|
return setup({
|
|
@@ -3074,7 +3658,7 @@ function createProvisioningMachine(client) {
|
|
|
3074
3658
|
const provider = context.input?.signerProvider;
|
|
3075
3659
|
if (!provider) return;
|
|
3076
3660
|
track("provisioning_safe_created", {
|
|
3077
|
-
safe_address: provider.
|
|
3661
|
+
safe_address: deriveSafeAddress2(provider.signerAddress)
|
|
3078
3662
|
});
|
|
3079
3663
|
}
|
|
3080
3664
|
}
|
|
@@ -3119,13 +3703,13 @@ function createProvisioningMachine(client) {
|
|
|
3119
3703
|
},
|
|
3120
3704
|
onError: {
|
|
3121
3705
|
target: "error",
|
|
3122
|
-
actions: assign({ error: ({ event }) =>
|
|
3706
|
+
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
3123
3707
|
}
|
|
3124
3708
|
},
|
|
3125
3709
|
after: {
|
|
3126
3710
|
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3127
3711
|
target: "error",
|
|
3128
|
-
actions: assign({ error: () =>
|
|
3712
|
+
actions: assign({ error: () => timeoutError() })
|
|
3129
3713
|
}
|
|
3130
3714
|
}
|
|
3131
3715
|
},
|
|
@@ -3143,7 +3727,7 @@ function createProvisioningMachine(client) {
|
|
|
3143
3727
|
* this payload on its `onDone` transition and branches via guards
|
|
3144
3728
|
* on `event.output.error`.
|
|
3145
3729
|
*/
|
|
3146
|
-
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error:
|
|
3730
|
+
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error: timeoutError() }
|
|
3147
3731
|
});
|
|
3148
3732
|
}
|
|
3149
3733
|
function requireProvisionInput(context) {
|
|
@@ -3155,13 +3739,13 @@ function requireProvisionInput(context) {
|
|
|
3155
3739
|
}
|
|
3156
3740
|
return context.input;
|
|
3157
3741
|
}
|
|
3158
|
-
function
|
|
3742
|
+
function errorFromEvent(event) {
|
|
3159
3743
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3160
3744
|
if (cause instanceof CapxulError) return cause;
|
|
3161
3745
|
if (cause instanceof CapxulError2) return cause;
|
|
3162
3746
|
return Errors.providerError("provisioning", "flow", cause);
|
|
3163
3747
|
}
|
|
3164
|
-
function
|
|
3748
|
+
function timeoutError() {
|
|
3165
3749
|
return Errors.providerError(
|
|
3166
3750
|
"provisioning",
|
|
3167
3751
|
"flow",
|
|
@@ -3254,7 +3838,7 @@ function createOnboardingFlowMachine(client) {
|
|
|
3254
3838
|
error: ({ event }) => extractChildErrorOrFallback(event)
|
|
3255
3839
|
}),
|
|
3256
3840
|
assignChildThrown: assign({
|
|
3257
|
-
error: ({ event }) =>
|
|
3841
|
+
error: ({ event }) => errorFromEvent2(event)
|
|
3258
3842
|
}),
|
|
3259
3843
|
assignAccountFromChild: assign({
|
|
3260
3844
|
account: ({ event }) => extractChildAccountOrNull(event)
|
|
@@ -3416,7 +4000,7 @@ function extractChildAccountOrNull(event) {
|
|
|
3416
4000
|
if (output && "account" in output && output.account) return output.account;
|
|
3417
4001
|
return null;
|
|
3418
4002
|
}
|
|
3419
|
-
function
|
|
4003
|
+
function errorFromEvent2(event) {
|
|
3420
4004
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3421
4005
|
if (cause instanceof CapxulError) return cause;
|
|
3422
4006
|
if (cause instanceof CapxulError2) return cause;
|
|
@@ -3427,7 +4011,7 @@ function errorFromEvent4(event) {
|
|
|
3427
4011
|
function createCapxulClient(config = {}) {
|
|
3428
4012
|
const clientWithoutFlows = {
|
|
3429
4013
|
id: crypto.randomUUID(),
|
|
3430
|
-
auth:
|
|
4014
|
+
auth: new AuthService(config),
|
|
3431
4015
|
me: createMeClient(config),
|
|
3432
4016
|
accounts: createAccountsClient(config),
|
|
3433
4017
|
organizations: createOrganizationsClient(config),
|
|
@@ -3435,8 +4019,8 @@ function createCapxulClient(config = {}) {
|
|
|
3435
4019
|
transfers: createTransfersClient(),
|
|
3436
4020
|
tokenTransfers: createTokenTransfersClient(config),
|
|
3437
4021
|
withdrawals: createWithdrawalsClient(config),
|
|
3438
|
-
documents: createDocumentsClient(),
|
|
3439
|
-
subAccounts: createSubAccountsClient(),
|
|
4022
|
+
documents: createDocumentsClient(config),
|
|
4023
|
+
subAccounts: createSubAccountsClient(config),
|
|
3440
4024
|
virtualAccounts: createVirtualAccountsClient(),
|
|
3441
4025
|
virtualCards: createVirtualCardsClient(),
|
|
3442
4026
|
externalAccounts: createExternalAccountsClient(config),
|
|
@@ -3447,8 +4031,6 @@ function createCapxulClient(config = {}) {
|
|
|
3447
4031
|
};
|
|
3448
4032
|
const client = clientWithoutFlows;
|
|
3449
4033
|
client.flows = {
|
|
3450
|
-
auth: () => createAuthFlowMachine(client),
|
|
3451
|
-
authBootstrap: () => createAuthBootstrapFlowMachine(client),
|
|
3452
4034
|
onboarding: () => createOnboardingFlowMachine(client),
|
|
3453
4035
|
provisioning: () => createProvisioningMachine(client)
|
|
3454
4036
|
};
|