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