@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/index.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$1 = 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
|
var accounts = require('viem/accounts');
|
|
10
11
|
|
|
@@ -110,17 +111,271 @@ function track(...args) {
|
|
|
110
111
|
const [name, props] = args;
|
|
111
112
|
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
112
113
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
|
|
115
|
+
// ../config/src/chain.ts
|
|
116
|
+
var CAPXUL_PAYMENTS_ADDRESS = "0xe740ea65521edc9bef0ea75d30b5334711db99f4";
|
|
117
|
+
var TEST_USDC_ADDRESS = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
|
|
118
|
+
var CAPXUL_API_BASE_URL = "https://elated-oyster-269.convex.site";
|
|
119
|
+
|
|
120
|
+
// ../config/src/timing.ts
|
|
121
|
+
var FLOW_INVOKE_TIMEOUT_MS = 3e4;
|
|
122
|
+
var WEBHOOK_FRESHNESS_WINDOW_MS = 5 * 60 * 1e3;
|
|
123
|
+
|
|
124
|
+
// ../config/src/errors.ts
|
|
125
|
+
var CapxulError2 = class extends Error {
|
|
126
|
+
code;
|
|
127
|
+
details;
|
|
128
|
+
correlationId;
|
|
129
|
+
layer;
|
|
130
|
+
constructor(code, message, options) {
|
|
131
|
+
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
132
|
+
this.code = code;
|
|
133
|
+
this.details = options?.details;
|
|
134
|
+
this.correlationId = options?.correlationId;
|
|
135
|
+
this.layer = options?.layer;
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
var Errors = {
|
|
139
|
+
notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
|
|
140
|
+
profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
|
|
141
|
+
smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
|
|
142
|
+
envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
|
|
143
|
+
openfortApi: (operation, cause) => new CapxulError2(
|
|
144
|
+
"PROVIDER_ERROR",
|
|
145
|
+
`Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
146
|
+
{ cause, details: { provider: "openfort", operation } }
|
|
147
|
+
),
|
|
148
|
+
shieldApi: (status, detail) => new CapxulError2(
|
|
149
|
+
"PROVIDER_ERROR",
|
|
150
|
+
`Shield API error (${status}): ${detail}`,
|
|
151
|
+
{ details: { provider: "shield", status } }
|
|
152
|
+
),
|
|
153
|
+
providerError: (provider, operation, cause) => (
|
|
154
|
+
// Public `message` is redacted to a fixed shape so provider-side
|
|
155
|
+
// exception text never leaks to the client. The original `cause`
|
|
156
|
+
// is preserved on `Error.cause` for server-side debugging via
|
|
157
|
+
// observability sinks (Sentry, console traces).
|
|
158
|
+
new CapxulError2(
|
|
159
|
+
"PROVIDER_ERROR",
|
|
160
|
+
`Provider error: ${provider} ${operation}`,
|
|
161
|
+
{ cause, details: { provider, operation } }
|
|
162
|
+
)
|
|
163
|
+
),
|
|
164
|
+
invalidInput: (field, reason) => new CapxulError2(
|
|
165
|
+
"INVALID_INPUT",
|
|
166
|
+
`Invalid ${field}: ${reason}`,
|
|
167
|
+
{ details: { field, reason } }
|
|
168
|
+
),
|
|
169
|
+
playerNotFound: (playerId) => new CapxulError2(
|
|
170
|
+
"PLAYER_NOT_FOUND",
|
|
171
|
+
playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
|
|
172
|
+
),
|
|
173
|
+
accountNotFound: (accountId) => new CapxulError2(
|
|
174
|
+
"ACCOUNT_NOT_FOUND",
|
|
175
|
+
accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
|
|
176
|
+
),
|
|
177
|
+
invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
|
|
178
|
+
permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
|
|
179
|
+
notFound: (resource, id) => new CapxulError2(
|
|
180
|
+
"NOT_FOUND",
|
|
181
|
+
id ? `${resource} ${id} not found` : `${resource} not found`
|
|
182
|
+
),
|
|
183
|
+
idempotencyConflict: (details) => new CapxulError2(
|
|
184
|
+
"IDEMPOTENCY_CONFLICT",
|
|
185
|
+
"Idempotency key was already used for a different request",
|
|
186
|
+
{ details }
|
|
187
|
+
),
|
|
188
|
+
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
189
|
+
details
|
|
190
|
+
}),
|
|
191
|
+
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
192
|
+
details: { ...details }
|
|
193
|
+
}),
|
|
194
|
+
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
195
|
+
/**
|
|
196
|
+
* Verification gate. Surfaced when a request hits a verification
|
|
197
|
+
* boundary the actor cannot cross under their current state. Two
|
|
198
|
+
* variants share this code:
|
|
199
|
+
*
|
|
200
|
+
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
201
|
+
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
202
|
+
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
203
|
+
* `details.rail` + `details.currentKind`.
|
|
204
|
+
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
205
|
+
* the required tier. Carries `details.requiredTier`.
|
|
206
|
+
*
|
|
207
|
+
* Code is shared because both expose the same UX shape ("you cannot
|
|
208
|
+
* proceed until verification advances"); the `details.*` keys
|
|
209
|
+
* differentiate the route.
|
|
210
|
+
*/
|
|
211
|
+
verificationRequired: (details) => {
|
|
212
|
+
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
213
|
+
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
214
|
+
details: { ...details }
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// ../config/src/safe.ts
|
|
220
|
+
var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
221
|
+
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
222
|
+
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
223
|
+
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
224
|
+
var MULTI_SEND = "0x38869bf66a61cf6bdb996a6ae40d5853fd43b526";
|
|
225
|
+
|
|
226
|
+
// ../config/src/org-roles.ts
|
|
227
|
+
function roleKeyFromLabel(label) {
|
|
228
|
+
const bytes = new TextEncoder().encode(label);
|
|
229
|
+
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
230
|
+
return "0x" + hex.padEnd(64, "0");
|
|
231
|
+
}
|
|
232
|
+
roleKeyFromLabel("OWNER");
|
|
233
|
+
roleKeyFromLabel("FINANCE_MANAGER");
|
|
234
|
+
roleKeyFromLabel("PAYMENTS_OPERATOR");
|
|
235
|
+
var defaultSafeDeriveConfig = {
|
|
236
|
+
safeProxyFactory: SAFE_PROXY_FACTORY,
|
|
237
|
+
safeL2Singleton: SAFE_L2_SINGLETON,
|
|
238
|
+
safeModuleSetup: SAFE_MODULE_SETUP,
|
|
239
|
+
safe4337Module: SAFE_4337_MODULE,
|
|
240
|
+
multiSend: MULTI_SEND
|
|
241
|
+
};
|
|
242
|
+
var SAFE_PROXY_CREATION_CODE = "0x608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564";
|
|
243
|
+
var enableModulesAbi = [
|
|
244
|
+
{
|
|
245
|
+
type: "function",
|
|
246
|
+
name: "enableModules",
|
|
247
|
+
inputs: [{ type: "address[]", name: "modules" }],
|
|
248
|
+
outputs: [],
|
|
249
|
+
stateMutability: "nonpayable"
|
|
250
|
+
}
|
|
251
|
+
];
|
|
252
|
+
var multiSendAbi = [
|
|
253
|
+
{
|
|
254
|
+
type: "function",
|
|
255
|
+
name: "multiSend",
|
|
256
|
+
inputs: [{ type: "bytes", name: "transactions" }],
|
|
257
|
+
outputs: [],
|
|
258
|
+
stateMutability: "payable"
|
|
259
|
+
}
|
|
260
|
+
];
|
|
261
|
+
var setupAbi = [
|
|
262
|
+
{
|
|
263
|
+
type: "function",
|
|
264
|
+
name: "setup",
|
|
265
|
+
inputs: [
|
|
266
|
+
{ type: "address[]", name: "owners" },
|
|
267
|
+
{ type: "uint256", name: "threshold" },
|
|
268
|
+
{ type: "address", name: "to" },
|
|
269
|
+
{ type: "bytes", name: "data" },
|
|
270
|
+
{ type: "address", name: "fallbackHandler" },
|
|
271
|
+
{ type: "address", name: "paymentToken" },
|
|
272
|
+
{ type: "uint256", name: "payment" },
|
|
273
|
+
{ type: "address", name: "paymentReceiver" }
|
|
274
|
+
],
|
|
275
|
+
outputs: [],
|
|
276
|
+
stateMutability: "nonpayable"
|
|
277
|
+
}
|
|
278
|
+
];
|
|
279
|
+
function encodeInternalTransaction(tx) {
|
|
280
|
+
const encoded = viem.encodePacked(
|
|
281
|
+
["uint8", "address", "uint256", "uint256", "bytes"],
|
|
282
|
+
[
|
|
283
|
+
tx.operation,
|
|
284
|
+
tx.to,
|
|
285
|
+
tx.value,
|
|
286
|
+
BigInt(tx.data.slice(2).length / 2),
|
|
287
|
+
tx.data
|
|
288
|
+
]
|
|
289
|
+
);
|
|
290
|
+
return encoded.slice(2);
|
|
291
|
+
}
|
|
292
|
+
function computeSaltNonce(ownerAddress) {
|
|
293
|
+
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
294
|
+
}
|
|
295
|
+
function deriveSafeAddress(signerAddress, config = defaultSafeDeriveConfig) {
|
|
296
|
+
const saltNonce = computeSaltNonce(signerAddress);
|
|
297
|
+
const enableModulesData = viem.encodeFunctionData({
|
|
298
|
+
abi: enableModulesAbi,
|
|
299
|
+
functionName: "enableModules",
|
|
300
|
+
args: [[config.safe4337Module]]
|
|
301
|
+
});
|
|
302
|
+
const innerTx = encodeInternalTransaction({
|
|
303
|
+
operation: 1,
|
|
304
|
+
to: config.safeModuleSetup,
|
|
305
|
+
value: 0n,
|
|
306
|
+
data: enableModulesData
|
|
307
|
+
});
|
|
308
|
+
const multiSendCallData = viem.encodeFunctionData({
|
|
309
|
+
abi: multiSendAbi,
|
|
310
|
+
functionName: "multiSend",
|
|
311
|
+
args: [`0x${innerTx}`]
|
|
312
|
+
});
|
|
313
|
+
const initializer = viem.encodeFunctionData({
|
|
314
|
+
abi: setupAbi,
|
|
315
|
+
functionName: "setup",
|
|
316
|
+
args: [
|
|
317
|
+
[signerAddress],
|
|
318
|
+
1n,
|
|
319
|
+
config.multiSend,
|
|
320
|
+
multiSendCallData,
|
|
321
|
+
config.safe4337Module,
|
|
322
|
+
"0x0000000000000000000000000000000000000000",
|
|
323
|
+
0n,
|
|
324
|
+
"0x0000000000000000000000000000000000000000"
|
|
325
|
+
]
|
|
326
|
+
});
|
|
327
|
+
const deploymentCode = viem.encodePacked(
|
|
328
|
+
["bytes", "uint256"],
|
|
329
|
+
[SAFE_PROXY_CREATION_CODE, BigInt(config.safeL2Singleton)]
|
|
330
|
+
);
|
|
331
|
+
const salt = viem.keccak256(
|
|
332
|
+
viem.encodePacked(
|
|
333
|
+
["bytes32", "uint256"],
|
|
334
|
+
[viem.keccak256(viem.encodePacked(["bytes"], [initializer])), saltNonce]
|
|
335
|
+
)
|
|
336
|
+
);
|
|
337
|
+
return viem.getContractAddress({
|
|
338
|
+
from: config.safeProxyFactory,
|
|
339
|
+
salt,
|
|
340
|
+
bytecode: deploymentCode,
|
|
341
|
+
opcode: "CREATE2"
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// src/internal/safe/account.ts
|
|
346
|
+
async function buildSafeAccount(signer, chain) {
|
|
116
347
|
try {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
348
|
+
const publicClient = viem.createPublicClient({
|
|
349
|
+
chain: chains.baseSepolia,
|
|
350
|
+
transport: viem.http(chain.rpcUrl)
|
|
351
|
+
});
|
|
352
|
+
return await accounts$1.toSafeSmartAccount({
|
|
353
|
+
client: publicClient,
|
|
354
|
+
entryPoint: { address: accountAbstraction.entryPoint07Address, version: "0.7" },
|
|
355
|
+
version: "1.4.1",
|
|
356
|
+
owners: [signer],
|
|
357
|
+
saltNonce: computeSaltNonce2(signer.address),
|
|
358
|
+
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
359
|
+
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
360
|
+
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
361
|
+
safe4337ModuleAddress: SAFE_4337_MODULE,
|
|
362
|
+
safeModules: [],
|
|
363
|
+
setupTransactions: []
|
|
364
|
+
});
|
|
365
|
+
} catch (cause) {
|
|
366
|
+
throw new CapxulError({
|
|
367
|
+
code: "NETWORK_ERROR",
|
|
368
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
369
|
+
cause,
|
|
370
|
+
details: { chainId: chain.chainId }
|
|
371
|
+
});
|
|
120
372
|
}
|
|
121
373
|
}
|
|
122
|
-
function
|
|
123
|
-
|
|
374
|
+
function computeSaltNonce2(ownerAddress) {
|
|
375
|
+
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
376
|
+
}
|
|
377
|
+
function deriveSafeAddress2(signerAddress) {
|
|
378
|
+
return deriveSafeAddress(signerAddress, defaultSafeDeriveConfig);
|
|
124
379
|
}
|
|
125
380
|
|
|
126
381
|
// ../platform-kernel/src/ids.ts
|
|
@@ -141,7 +396,7 @@ var toAccountId = makePrefixedIdConstructor(
|
|
|
141
396
|
);
|
|
142
397
|
var toOrganizationId = makePrefixedIdConstructor("org", "organizationId");
|
|
143
398
|
var toMemberId = makePrefixedIdConstructor(
|
|
144
|
-
"
|
|
399
|
+
"mb",
|
|
145
400
|
"memberId"
|
|
146
401
|
);
|
|
147
402
|
var toSafeId = makePrefixedIdConstructor(
|
|
@@ -255,13 +510,13 @@ function brandExternalAccount(raw) {
|
|
|
255
510
|
function createExternalAccountsClient(config = {}) {
|
|
256
511
|
return {
|
|
257
512
|
retrieve: async (externalAccountId) => {
|
|
258
|
-
if (!config.
|
|
513
|
+
if (!config._data) {
|
|
259
514
|
return stub(
|
|
260
515
|
"externalAccounts.retrieve"
|
|
261
516
|
);
|
|
262
517
|
}
|
|
263
518
|
const [err, raw] = await tryCatch(
|
|
264
|
-
config.
|
|
519
|
+
config._data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
265
520
|
externalAccountId
|
|
266
521
|
})
|
|
267
522
|
);
|
|
@@ -283,11 +538,11 @@ function createExternalAccountsClient(config = {}) {
|
|
|
283
538
|
return [null, brandExternalAccount(raw)];
|
|
284
539
|
},
|
|
285
540
|
remove: async (externalAccountId) => {
|
|
286
|
-
if (!config.
|
|
541
|
+
if (!config._data) {
|
|
287
542
|
return stub("externalAccounts.remove");
|
|
288
543
|
}
|
|
289
544
|
const [err] = await tryCatch(
|
|
290
|
-
config.
|
|
545
|
+
config._data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
291
546
|
externalAccountId
|
|
292
547
|
})
|
|
293
548
|
);
|
|
@@ -302,17 +557,203 @@ function createExternalAccountsClient(config = {}) {
|
|
|
302
557
|
};
|
|
303
558
|
}
|
|
304
559
|
|
|
560
|
+
// src/core/sub-accounts.ts
|
|
561
|
+
function malformedWireError(reason, raw) {
|
|
562
|
+
return new CapxulError({
|
|
563
|
+
code: "PROVIDER_ERROR",
|
|
564
|
+
message: `convex brandSubAccount failed: ${reason}`,
|
|
565
|
+
details: {
|
|
566
|
+
provider: "convex",
|
|
567
|
+
operation: "brandSubAccount",
|
|
568
|
+
reason,
|
|
569
|
+
// PII discipline (`.claude/rules/posthog.md`): user-authored
|
|
570
|
+
// strings on the wire (`name`, `purpose`) are customer-confidential
|
|
571
|
+
// — sub-account names like "Q3 Acquisition Reserve" or
|
|
572
|
+
// "Vendor ABC payments" must not flow into telemetry. We emit a
|
|
573
|
+
// structural keys-only sample via a strict ALLOWLIST so any future
|
|
574
|
+
// wire-shape addition (e.g. `recipientEmail`, `tags`) is dropped
|
|
575
|
+
// by construction rather than leaked through a denylist gap.
|
|
576
|
+
sample: safeSampleShape(raw)
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
function safeSampleShape(raw) {
|
|
581
|
+
if (raw === null || typeof raw !== "object") {
|
|
582
|
+
return { type: typeof raw };
|
|
583
|
+
}
|
|
584
|
+
const r = raw;
|
|
585
|
+
const balance = r.balance;
|
|
586
|
+
return {
|
|
587
|
+
object: typeof r.object === "string" ? r.object : typeof r.object,
|
|
588
|
+
idPresent: typeof r.id === "string" && r.id.length > 0,
|
|
589
|
+
// First 4 chars only — enough to distinguish "sub_" prefixed IDs
|
|
590
|
+
// from accidental other resource IDs without leaking the full ID.
|
|
591
|
+
idPrefix: typeof r.id === "string" ? r.id.slice(0, 4) : void 0,
|
|
592
|
+
parentKind: r.parent !== null && typeof r.parent === "object" ? r.parent.kind : typeof r.parent,
|
|
593
|
+
status: r.status,
|
|
594
|
+
hasName: typeof r.name === "string",
|
|
595
|
+
hasPurpose: r.purpose !== void 0,
|
|
596
|
+
balanceShape: balance !== null && typeof balance === "object" ? Object.keys(balance).sort() : typeof balance,
|
|
597
|
+
createdAtType: typeof r.createdAt,
|
|
598
|
+
updatedAtType: typeof r.updatedAt
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
function isMoneyShape(v) {
|
|
602
|
+
if (typeof v !== "object" || v === null) return false;
|
|
603
|
+
const m = v;
|
|
604
|
+
return typeof m.value === "string" && typeof m.currency === "string";
|
|
605
|
+
}
|
|
606
|
+
function isParentShape(v) {
|
|
607
|
+
if (typeof v !== "object" || v === null) return false;
|
|
608
|
+
const p = v;
|
|
609
|
+
return (p.kind === "account" || p.kind === "organization") && typeof p.id === "string";
|
|
610
|
+
}
|
|
611
|
+
function isFiniteNonNegativeInteger(v) {
|
|
612
|
+
return typeof v === "number" && Number.isFinite(v) && Number.isInteger(v) && v >= 0;
|
|
613
|
+
}
|
|
614
|
+
function validateWireSubAccount(raw) {
|
|
615
|
+
if (typeof raw !== "object" || raw === null) {
|
|
616
|
+
return { ok: false, reason: "not an object" };
|
|
617
|
+
}
|
|
618
|
+
const r = raw;
|
|
619
|
+
if (r.object !== "sub_account") {
|
|
620
|
+
return { ok: false, reason: `object must be "sub_account" (got ${String(r.object)})` };
|
|
621
|
+
}
|
|
622
|
+
if (typeof r.id !== "string" || r.id.length === 0) {
|
|
623
|
+
return { ok: false, reason: "id must be a non-empty string" };
|
|
624
|
+
}
|
|
625
|
+
if (!isParentShape(r.parent)) {
|
|
626
|
+
return { ok: false, reason: "parent must be { kind: 'account' | 'organization', id: string }" };
|
|
627
|
+
}
|
|
628
|
+
if (typeof r.name !== "string") {
|
|
629
|
+
return { ok: false, reason: "name must be a string" };
|
|
630
|
+
}
|
|
631
|
+
if (r.purpose !== void 0 && typeof r.purpose !== "string") {
|
|
632
|
+
return { ok: false, reason: "purpose must be a string when present" };
|
|
633
|
+
}
|
|
634
|
+
if (r.status !== "active" && r.status !== "archived") {
|
|
635
|
+
return { ok: false, reason: `status must be "active" | "archived" (got ${String(r.status)})` };
|
|
636
|
+
}
|
|
637
|
+
if (!isMoneyShape(r.balance)) {
|
|
638
|
+
return { ok: false, reason: "balance must be { value: string, currency: string }" };
|
|
639
|
+
}
|
|
640
|
+
if (!isFiniteNonNegativeInteger(r.createdAt)) {
|
|
641
|
+
return { ok: false, reason: "createdAt must be a finite non-negative integer (epoch ms)" };
|
|
642
|
+
}
|
|
643
|
+
if (r.updatedAt !== void 0 && !isFiniteNonNegativeInteger(r.updatedAt)) {
|
|
644
|
+
return { ok: false, reason: "updatedAt must be a finite non-negative integer when present" };
|
|
645
|
+
}
|
|
646
|
+
return { ok: true, value: r };
|
|
647
|
+
}
|
|
648
|
+
function brandSubAccount(raw) {
|
|
649
|
+
const result = validateWireSubAccount(raw);
|
|
650
|
+
if (!result.ok) {
|
|
651
|
+
throw malformedWireError(result.reason, raw);
|
|
652
|
+
}
|
|
653
|
+
const wire = result.value;
|
|
654
|
+
return {
|
|
655
|
+
object: wire.object,
|
|
656
|
+
id: toSubAccountId(wire.id),
|
|
657
|
+
parent: wire.parent,
|
|
658
|
+
name: wire.name,
|
|
659
|
+
...wire.purpose !== void 0 ? { purpose: wire.purpose } : {},
|
|
660
|
+
status: wire.status,
|
|
661
|
+
balance: wire.balance,
|
|
662
|
+
createdAt: new Date(wire.createdAt).toISOString()
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
function tryBrandSubAccount(raw) {
|
|
666
|
+
try {
|
|
667
|
+
return [null, brandSubAccount(raw)];
|
|
668
|
+
} catch (err) {
|
|
669
|
+
if (err instanceof CapxulError && err.code === "PROVIDER_ERROR") {
|
|
670
|
+
return [err, null];
|
|
671
|
+
}
|
|
672
|
+
return [
|
|
673
|
+
malformedWireError(
|
|
674
|
+
err instanceof Error ? err.message : String(err),
|
|
675
|
+
raw
|
|
676
|
+
),
|
|
677
|
+
null
|
|
678
|
+
];
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
function createSubAccountsClient(config = {}) {
|
|
682
|
+
return {
|
|
683
|
+
retrieve: async (subAccountId) => {
|
|
684
|
+
if (!config._data) {
|
|
685
|
+
return stub("subAccounts.retrieve");
|
|
686
|
+
}
|
|
687
|
+
const [err, raw] = await tryCatch(
|
|
688
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
689
|
+
subAccountId
|
|
690
|
+
})
|
|
691
|
+
);
|
|
692
|
+
if (err) {
|
|
693
|
+
return [
|
|
694
|
+
fromConvexError(err),
|
|
695
|
+
null
|
|
696
|
+
];
|
|
697
|
+
}
|
|
698
|
+
if (!raw) {
|
|
699
|
+
return [
|
|
700
|
+
new CapxulError({
|
|
701
|
+
code: "NOT_FOUND",
|
|
702
|
+
message: `sub_account ${subAccountId} not found`
|
|
703
|
+
}),
|
|
704
|
+
null
|
|
705
|
+
];
|
|
706
|
+
}
|
|
707
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
708
|
+
if (brandErr) {
|
|
709
|
+
return [brandErr, null];
|
|
710
|
+
}
|
|
711
|
+
return [null, branded];
|
|
712
|
+
},
|
|
713
|
+
remove: async (subAccountId) => {
|
|
714
|
+
if (!config._data) {
|
|
715
|
+
return stub("subAccounts.remove");
|
|
716
|
+
}
|
|
717
|
+
const [err, raw] = await tryCatch(
|
|
718
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
719
|
+
subAccountId
|
|
720
|
+
})
|
|
721
|
+
);
|
|
722
|
+
if (err) {
|
|
723
|
+
return [
|
|
724
|
+
fromConvexError(err),
|
|
725
|
+
null
|
|
726
|
+
];
|
|
727
|
+
}
|
|
728
|
+
if (!raw) {
|
|
729
|
+
return [
|
|
730
|
+
new CapxulError({
|
|
731
|
+
code: "NOT_FOUND",
|
|
732
|
+
message: `sub_account ${subAccountId} not found`
|
|
733
|
+
}),
|
|
734
|
+
null
|
|
735
|
+
];
|
|
736
|
+
}
|
|
737
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
738
|
+
if (brandErr) {
|
|
739
|
+
return [brandErr, null];
|
|
740
|
+
}
|
|
741
|
+
return [null, branded];
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
|
|
305
746
|
// src/core/accounts.ts
|
|
306
747
|
function createAccountExternalAccountsClient(config) {
|
|
307
748
|
return {
|
|
308
749
|
create: async (input) => {
|
|
309
|
-
if (!config.
|
|
750
|
+
if (!config._data) {
|
|
310
751
|
return stub(
|
|
311
752
|
"accounts.externalAccounts.create"
|
|
312
753
|
);
|
|
313
754
|
}
|
|
314
755
|
const [err, raw] = await tryCatch(
|
|
315
|
-
config.
|
|
756
|
+
config._data.mutation(
|
|
316
757
|
api.externalAccounts.mutations.createPersonal,
|
|
317
758
|
{
|
|
318
759
|
kind: input.kind,
|
|
@@ -350,13 +791,13 @@ function createAccountExternalAccountsClient(config) {
|
|
|
350
791
|
];
|
|
351
792
|
},
|
|
352
793
|
list: async (input) => {
|
|
353
|
-
if (!config.
|
|
794
|
+
if (!config._data) {
|
|
354
795
|
return stub(
|
|
355
796
|
"accounts.externalAccounts.list"
|
|
356
797
|
);
|
|
357
798
|
}
|
|
358
799
|
const [err, result] = await tryCatch(
|
|
359
|
-
config.
|
|
800
|
+
config._data.query(api.externalAccounts.queries.listPersonal, {
|
|
360
801
|
limit: input.limit,
|
|
361
802
|
cursor: input.cursor
|
|
362
803
|
})
|
|
@@ -379,13 +820,13 @@ function createAccountExternalAccountsClient(config) {
|
|
|
379
820
|
];
|
|
380
821
|
},
|
|
381
822
|
retrieve: async (externalAccountId) => {
|
|
382
|
-
if (!config.
|
|
823
|
+
if (!config._data) {
|
|
383
824
|
return stub(
|
|
384
825
|
"accounts.externalAccounts.retrieve"
|
|
385
826
|
);
|
|
386
827
|
}
|
|
387
828
|
const [err, raw] = await tryCatch(
|
|
388
|
-
config.
|
|
829
|
+
config._data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
389
830
|
externalAccountId
|
|
390
831
|
})
|
|
391
832
|
);
|
|
@@ -412,11 +853,11 @@ function createAccountExternalAccountsClient(config) {
|
|
|
412
853
|
];
|
|
413
854
|
},
|
|
414
855
|
remove: async (externalAccountId) => {
|
|
415
|
-
if (!config.
|
|
856
|
+
if (!config._data) {
|
|
416
857
|
return stub("accounts.externalAccounts.remove");
|
|
417
858
|
}
|
|
418
859
|
const [err] = await tryCatch(
|
|
419
|
-
config.
|
|
860
|
+
config._data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
420
861
|
externalAccountId
|
|
421
862
|
})
|
|
422
863
|
);
|
|
@@ -430,14 +871,162 @@ function createAccountExternalAccountsClient(config) {
|
|
|
430
871
|
}
|
|
431
872
|
};
|
|
432
873
|
}
|
|
433
|
-
function
|
|
874
|
+
function createAccountSubAccountsClient(config) {
|
|
434
875
|
return {
|
|
435
|
-
|
|
436
|
-
if (!config.
|
|
876
|
+
create: async (input) => {
|
|
877
|
+
if (!config._data) {
|
|
878
|
+
return stub(
|
|
879
|
+
"accounts.subAccounts.create"
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
const [err, raw] = await tryCatch(
|
|
883
|
+
config._data.mutation(api.subAccounts.mutations.create, {
|
|
884
|
+
parent: { kind: "account", id: input.accountId },
|
|
885
|
+
name: input.name,
|
|
886
|
+
purpose: input.purpose
|
|
887
|
+
})
|
|
888
|
+
);
|
|
889
|
+
if (err) {
|
|
890
|
+
return [
|
|
891
|
+
fromConvexError(err),
|
|
892
|
+
null
|
|
893
|
+
];
|
|
894
|
+
}
|
|
895
|
+
if (!raw) {
|
|
896
|
+
return [
|
|
897
|
+
new CapxulError({
|
|
898
|
+
code: "NOT_FOUND",
|
|
899
|
+
message: "sub_account creation returned no resource"
|
|
900
|
+
}),
|
|
901
|
+
null
|
|
902
|
+
];
|
|
903
|
+
}
|
|
904
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
905
|
+
if (brandErr) {
|
|
906
|
+
return [
|
|
907
|
+
brandErr,
|
|
908
|
+
null
|
|
909
|
+
];
|
|
910
|
+
}
|
|
911
|
+
return [null, branded];
|
|
912
|
+
},
|
|
913
|
+
list: async (input) => {
|
|
914
|
+
if (!config._data) {
|
|
915
|
+
return stub(
|
|
916
|
+
"accounts.subAccounts.list"
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
const [err, rows] = await tryCatch(
|
|
920
|
+
config._data.query(api.subAccounts.queries.listByAccount, {
|
|
921
|
+
accountId: input.accountId
|
|
922
|
+
})
|
|
923
|
+
);
|
|
924
|
+
if (err) {
|
|
925
|
+
return [
|
|
926
|
+
fromConvexError(err),
|
|
927
|
+
null
|
|
928
|
+
];
|
|
929
|
+
}
|
|
930
|
+
const branded = [];
|
|
931
|
+
for (const row of rows) {
|
|
932
|
+
const [brandErr, value] = tryBrandSubAccount(row);
|
|
933
|
+
if (brandErr) {
|
|
934
|
+
return [
|
|
935
|
+
brandErr,
|
|
936
|
+
null
|
|
937
|
+
];
|
|
938
|
+
}
|
|
939
|
+
branded.push(value);
|
|
940
|
+
}
|
|
941
|
+
return [
|
|
942
|
+
null,
|
|
943
|
+
{
|
|
944
|
+
object: "list",
|
|
945
|
+
data: branded,
|
|
946
|
+
page: { hasMore: false }
|
|
947
|
+
}
|
|
948
|
+
];
|
|
949
|
+
},
|
|
950
|
+
retrieve: async (subAccountId) => {
|
|
951
|
+
if (!config._data) {
|
|
952
|
+
return stub(
|
|
953
|
+
"accounts.subAccounts.retrieve"
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
const [err, raw] = await tryCatch(
|
|
957
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
958
|
+
subAccountId
|
|
959
|
+
})
|
|
960
|
+
);
|
|
961
|
+
if (err) {
|
|
962
|
+
return [
|
|
963
|
+
fromConvexError(err),
|
|
964
|
+
null
|
|
965
|
+
];
|
|
966
|
+
}
|
|
967
|
+
if (!raw) {
|
|
968
|
+
return [
|
|
969
|
+
new CapxulError({
|
|
970
|
+
code: "NOT_FOUND",
|
|
971
|
+
message: `sub_account ${subAccountId} not found`
|
|
972
|
+
}),
|
|
973
|
+
null
|
|
974
|
+
];
|
|
975
|
+
}
|
|
976
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
977
|
+
if (brandErr) {
|
|
978
|
+
return [
|
|
979
|
+
brandErr,
|
|
980
|
+
null
|
|
981
|
+
];
|
|
982
|
+
}
|
|
983
|
+
return [null, branded];
|
|
984
|
+
},
|
|
985
|
+
remove: async (subAccountId) => {
|
|
986
|
+
if (!config._data) {
|
|
987
|
+
return stub(
|
|
988
|
+
"accounts.subAccounts.remove"
|
|
989
|
+
);
|
|
990
|
+
}
|
|
991
|
+
const [err, raw] = await tryCatch(
|
|
992
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
993
|
+
subAccountId
|
|
994
|
+
})
|
|
995
|
+
);
|
|
996
|
+
if (err) {
|
|
997
|
+
return [
|
|
998
|
+
fromConvexError(err),
|
|
999
|
+
null
|
|
1000
|
+
];
|
|
1001
|
+
}
|
|
1002
|
+
if (!raw) {
|
|
1003
|
+
return [
|
|
1004
|
+
new CapxulError({
|
|
1005
|
+
code: "NOT_FOUND",
|
|
1006
|
+
message: `sub_account ${subAccountId} not found`
|
|
1007
|
+
}),
|
|
1008
|
+
null
|
|
1009
|
+
];
|
|
1010
|
+
}
|
|
1011
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
1012
|
+
if (brandErr) {
|
|
1013
|
+
return [
|
|
1014
|
+
brandErr,
|
|
1015
|
+
null
|
|
1016
|
+
];
|
|
1017
|
+
}
|
|
1018
|
+
return [null, branded];
|
|
1019
|
+
}
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
function createAccountsClient(config = {}) {
|
|
1023
|
+
return {
|
|
1024
|
+
retrieve: async (accountId) => {
|
|
1025
|
+
if (!config._data) {
|
|
437
1026
|
return stub("accounts.retrieve");
|
|
438
1027
|
}
|
|
439
1028
|
try {
|
|
440
|
-
const account = await config.
|
|
1029
|
+
const account = await config._data.query(
|
|
441
1030
|
api.openfort.queries.getMyAccount,
|
|
442
1031
|
{}
|
|
443
1032
|
);
|
|
@@ -461,7 +1050,7 @@ function createAccountsClient(config = {}) {
|
|
|
461
1050
|
},
|
|
462
1051
|
lookup: async () => stub("accounts.lookup"),
|
|
463
1052
|
update: async (input) => {
|
|
464
|
-
if (!config.
|
|
1053
|
+
if (!config._data) {
|
|
465
1054
|
return stub("accounts.update");
|
|
466
1055
|
}
|
|
467
1056
|
if (input.countryCode !== void 0) {
|
|
@@ -475,7 +1064,7 @@ function createAccountsClient(config = {}) {
|
|
|
475
1064
|
];
|
|
476
1065
|
}
|
|
477
1066
|
try {
|
|
478
|
-
const current = await config.
|
|
1067
|
+
const current = await config._data.query(
|
|
479
1068
|
api.openfort.queries.getMyAccount,
|
|
480
1069
|
{}
|
|
481
1070
|
);
|
|
@@ -492,11 +1081,11 @@ function createAccountsClient(config = {}) {
|
|
|
492
1081
|
null
|
|
493
1082
|
];
|
|
494
1083
|
}
|
|
495
|
-
await config.
|
|
1084
|
+
await config._data.mutation(api.openfort.mutations.updateProfile, {
|
|
496
1085
|
displayName: input.name,
|
|
497
1086
|
username: input.username
|
|
498
1087
|
});
|
|
499
|
-
const updated = await config.
|
|
1088
|
+
const updated = await config._data.query(
|
|
500
1089
|
api.openfort.queries.getMyAccount,
|
|
501
1090
|
{}
|
|
502
1091
|
);
|
|
@@ -506,7 +1095,7 @@ function createAccountsClient(config = {}) {
|
|
|
506
1095
|
}
|
|
507
1096
|
},
|
|
508
1097
|
provisionPersonal: async (input) => {
|
|
509
|
-
if (!config.
|
|
1098
|
+
if (!config._data) {
|
|
510
1099
|
return stub(
|
|
511
1100
|
"accounts.provisionPersonal"
|
|
512
1101
|
);
|
|
@@ -521,17 +1110,17 @@ function createAccountsClient(config = {}) {
|
|
|
521
1110
|
];
|
|
522
1111
|
}
|
|
523
1112
|
try {
|
|
524
|
-
await config.
|
|
1113
|
+
await config._data.mutation(
|
|
525
1114
|
api.safe.mutations.provisionLocalPersonalAccount,
|
|
526
1115
|
{
|
|
527
1116
|
displayName: input.displayName,
|
|
528
1117
|
username: input.username,
|
|
529
1118
|
countryCode: input.countryCode,
|
|
530
1119
|
eoaAddress: input.signerProvider.signerAddress,
|
|
531
|
-
safeAddress: input.signerProvider.
|
|
1120
|
+
safeAddress: deriveSafeAddress2(input.signerProvider.signerAddress)
|
|
532
1121
|
}
|
|
533
1122
|
);
|
|
534
|
-
const account = await config.
|
|
1123
|
+
const account = await config._data.query(
|
|
535
1124
|
api.openfort.queries.getMyAccount,
|
|
536
1125
|
{}
|
|
537
1126
|
);
|
|
@@ -554,11 +1143,11 @@ function createAccountsClient(config = {}) {
|
|
|
554
1143
|
},
|
|
555
1144
|
safes: {
|
|
556
1145
|
retrieve: async (safeId) => {
|
|
557
|
-
if (!config.
|
|
1146
|
+
if (!config._data) {
|
|
558
1147
|
return stub("accounts.safes.retrieve");
|
|
559
1148
|
}
|
|
560
1149
|
try {
|
|
561
|
-
const safe = await config.
|
|
1150
|
+
const safe = await config._data.query(
|
|
562
1151
|
api.safe.queries.retrieveAccountSafe,
|
|
563
1152
|
{ safeId }
|
|
564
1153
|
);
|
|
@@ -585,19 +1174,50 @@ function createAccountsClient(config = {}) {
|
|
|
585
1174
|
retrieve: async () => stub("accounts.kycProfiles.retrieve")
|
|
586
1175
|
},
|
|
587
1176
|
externalAccounts: createAccountExternalAccountsClient(config),
|
|
588
|
-
subAccounts:
|
|
589
|
-
create: async () => stub("accounts.subAccounts.create"),
|
|
590
|
-
list: async () => stub("accounts.subAccounts.list"),
|
|
591
|
-
retrieve: async () => stub("accounts.subAccounts.retrieve"),
|
|
592
|
-
remove: async () => stub("accounts.subAccounts.remove")
|
|
593
|
-
},
|
|
1177
|
+
subAccounts: createAccountSubAccountsClient(config),
|
|
594
1178
|
balanceLedger: {
|
|
595
|
-
list: async () =>
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
1179
|
+
list: async (input) => {
|
|
1180
|
+
if (!config._data) {
|
|
1181
|
+
return stub(
|
|
1182
|
+
"accounts.balanceLedger.list"
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
try {
|
|
1186
|
+
const accountId = input.accountId.replace(/^acct_/, "");
|
|
1187
|
+
const page = await config._data.query(
|
|
1188
|
+
api.balanceLedger.queries.listForAccount,
|
|
1189
|
+
{ accountId, limit: input.limit, cursor: input.cursor }
|
|
1190
|
+
);
|
|
1191
|
+
return [null, page];
|
|
1192
|
+
} catch (cause) {
|
|
1193
|
+
return [fromConvexError(cause), null];
|
|
1194
|
+
}
|
|
1195
|
+
},
|
|
1196
|
+
retrieve: async (entryId) => {
|
|
1197
|
+
if (!config._data) {
|
|
1198
|
+
return stub(
|
|
1199
|
+
"accounts.balanceLedger.retrieve"
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
1202
|
+
try {
|
|
1203
|
+
const entry = await config._data.query(
|
|
1204
|
+
api.balanceLedger.queries.retrieve,
|
|
1205
|
+
{ entryId }
|
|
1206
|
+
);
|
|
1207
|
+
if (!entry) {
|
|
1208
|
+
return [
|
|
1209
|
+
new CapxulError({
|
|
1210
|
+
code: "NOT_FOUND",
|
|
1211
|
+
message: `balance_ledger_entry ${entryId} not found`
|
|
1212
|
+
}),
|
|
1213
|
+
null
|
|
1214
|
+
];
|
|
1215
|
+
}
|
|
1216
|
+
return [null, entry];
|
|
1217
|
+
} catch (cause) {
|
|
1218
|
+
return [fromConvexError(cause), null];
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
601
1221
|
}
|
|
602
1222
|
};
|
|
603
1223
|
}
|
|
@@ -611,120 +1231,11 @@ function createApiKeysClient() {
|
|
|
611
1231
|
revoke: async () => stub("apiKeys.revoke")
|
|
612
1232
|
};
|
|
613
1233
|
}
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
var CAPXUL_API_BASE_URL = "https://elated-oyster-269.convex.site";
|
|
619
|
-
|
|
620
|
-
// ../config/src/timing.ts
|
|
621
|
-
var FLOW_INVOKE_TIMEOUT_MS = 3e4;
|
|
622
|
-
var WEBHOOK_FRESHNESS_WINDOW_MS = 5 * 60 * 1e3;
|
|
623
|
-
|
|
624
|
-
// ../config/src/errors.ts
|
|
625
|
-
var CapxulError2 = class extends Error {
|
|
626
|
-
code;
|
|
627
|
-
details;
|
|
628
|
-
correlationId;
|
|
629
|
-
layer;
|
|
630
|
-
constructor(code, message, options) {
|
|
631
|
-
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
632
|
-
this.code = code;
|
|
633
|
-
this.details = options?.details;
|
|
634
|
-
this.correlationId = options?.correlationId;
|
|
635
|
-
this.layer = options?.layer;
|
|
636
|
-
}
|
|
637
|
-
};
|
|
638
|
-
var Errors = {
|
|
639
|
-
notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
|
|
640
|
-
profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
|
|
641
|
-
smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
|
|
642
|
-
envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
|
|
643
|
-
openfortApi: (operation, cause) => new CapxulError2(
|
|
644
|
-
"PROVIDER_ERROR",
|
|
645
|
-
`Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
646
|
-
{ cause, details: { provider: "openfort", operation } }
|
|
647
|
-
),
|
|
648
|
-
shieldApi: (status, detail) => new CapxulError2(
|
|
649
|
-
"PROVIDER_ERROR",
|
|
650
|
-
`Shield API error (${status}): ${detail}`,
|
|
651
|
-
{ details: { provider: "shield", status } }
|
|
652
|
-
),
|
|
653
|
-
providerError: (provider, operation, cause) => new CapxulError2(
|
|
654
|
-
"PROVIDER_ERROR",
|
|
655
|
-
`${provider} ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
656
|
-
{ cause, details: { provider, operation } }
|
|
657
|
-
),
|
|
658
|
-
invalidInput: (field, reason) => new CapxulError2(
|
|
659
|
-
"INVALID_INPUT",
|
|
660
|
-
`Invalid ${field}: ${reason}`,
|
|
661
|
-
{ details: { field, reason } }
|
|
662
|
-
),
|
|
663
|
-
playerNotFound: (playerId) => new CapxulError2(
|
|
664
|
-
"PLAYER_NOT_FOUND",
|
|
665
|
-
playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
|
|
666
|
-
),
|
|
667
|
-
accountNotFound: (accountId) => new CapxulError2(
|
|
668
|
-
"ACCOUNT_NOT_FOUND",
|
|
669
|
-
accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
|
|
670
|
-
),
|
|
671
|
-
invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
|
|
672
|
-
permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
|
|
673
|
-
notFound: (resource, id) => new CapxulError2(
|
|
674
|
-
"NOT_FOUND",
|
|
675
|
-
id ? `${resource} ${id} not found` : `${resource} not found`
|
|
676
|
-
),
|
|
677
|
-
idempotencyConflict: (details) => new CapxulError2(
|
|
678
|
-
"IDEMPOTENCY_CONFLICT",
|
|
679
|
-
"Idempotency key was already used for a different request",
|
|
680
|
-
{ details }
|
|
681
|
-
),
|
|
682
|
-
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
683
|
-
details
|
|
684
|
-
}),
|
|
685
|
-
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
686
|
-
details: { ...details }
|
|
687
|
-
}),
|
|
688
|
-
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
689
|
-
/**
|
|
690
|
-
* Verification gate. Surfaced when a request hits a verification
|
|
691
|
-
* boundary the actor cannot cross under their current state. Two
|
|
692
|
-
* variants share this code:
|
|
693
|
-
*
|
|
694
|
-
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
695
|
-
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
696
|
-
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
697
|
-
* `details.rail` + `details.currentKind`.
|
|
698
|
-
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
699
|
-
* the required tier. Carries `details.requiredTier`.
|
|
700
|
-
*
|
|
701
|
-
* Code is shared because both expose the same UX shape ("you cannot
|
|
702
|
-
* proceed until verification advances"); the `details.*` keys
|
|
703
|
-
* differentiate the route.
|
|
704
|
-
*/
|
|
705
|
-
verificationRequired: (details) => {
|
|
706
|
-
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
707
|
-
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
708
|
-
details: { ...details }
|
|
709
|
-
});
|
|
710
|
-
}
|
|
711
|
-
};
|
|
712
|
-
|
|
713
|
-
// ../config/src/safe.ts
|
|
714
|
-
var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
715
|
-
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
716
|
-
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
717
|
-
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
718
|
-
|
|
719
|
-
// ../config/src/org-roles.ts
|
|
720
|
-
function roleKeyFromLabel(label) {
|
|
721
|
-
const bytes = new TextEncoder().encode(label);
|
|
722
|
-
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
723
|
-
return "0x" + hex.padEnd(64, "0");
|
|
1234
|
+
function createDefaultDataClient(convexUrl, jwt) {
|
|
1235
|
+
const client = new browser.ConvexHttpClient(convexUrl);
|
|
1236
|
+
client.setAuth(jwt);
|
|
1237
|
+
return client;
|
|
724
1238
|
}
|
|
725
|
-
roleKeyFromLabel("OWNER");
|
|
726
|
-
roleKeyFromLabel("FINANCE_MANAGER");
|
|
727
|
-
roleKeyFromLabel("TEAM_LEAD");
|
|
728
1239
|
|
|
729
1240
|
// src/transport.ts
|
|
730
1241
|
function makeHttpTransport(config) {
|
|
@@ -1055,7 +1566,7 @@ function readNonEmptyString(value) {
|
|
|
1055
1566
|
|
|
1056
1567
|
// src/core/auth.ts
|
|
1057
1568
|
function createAuthClient(config = {}) {
|
|
1058
|
-
let dataClient = config.
|
|
1569
|
+
let dataClient = config._data ?? null;
|
|
1059
1570
|
const sessionStore = config.auth?.sessionStore ?? createMemorySessionStore();
|
|
1060
1571
|
const getTransport = createTransportProvider(config);
|
|
1061
1572
|
return {
|
|
@@ -1111,11 +1622,20 @@ function createAuthClient(config = {}) {
|
|
|
1111
1622
|
).toISOString()
|
|
1112
1623
|
};
|
|
1113
1624
|
sessionStore.set(session);
|
|
1114
|
-
if (
|
|
1625
|
+
if (!dataClient) {
|
|
1115
1626
|
try {
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1627
|
+
const convexUrl = transport.convexUrl;
|
|
1628
|
+
if (!convexUrl || !session.convexJwt) {
|
|
1629
|
+
return [
|
|
1630
|
+
new CapxulError({
|
|
1631
|
+
code: "NETWORK_ERROR",
|
|
1632
|
+
message: "Cannot create data client: missing convex URL or JWT."
|
|
1633
|
+
}),
|
|
1634
|
+
null
|
|
1635
|
+
];
|
|
1636
|
+
}
|
|
1637
|
+
dataClient = createDefaultDataClient(convexUrl, session.convexJwt);
|
|
1638
|
+
mutableConfig(config)._data = dataClient;
|
|
1119
1639
|
} catch (cause) {
|
|
1120
1640
|
return [
|
|
1121
1641
|
new CapxulError({
|
|
@@ -1126,7 +1646,15 @@ function createAuthClient(config = {}) {
|
|
|
1126
1646
|
null
|
|
1127
1647
|
];
|
|
1128
1648
|
}
|
|
1649
|
+
} else {
|
|
1650
|
+
const injected = dataClient;
|
|
1651
|
+
if (typeof injected.refreshAuth === "function") {
|
|
1652
|
+
injected.refreshAuth();
|
|
1653
|
+
} else if (typeof injected.setAuth === "function" && session.convexJwt) {
|
|
1654
|
+
injected.setAuth(session.convexJwt);
|
|
1655
|
+
}
|
|
1129
1656
|
}
|
|
1657
|
+
transport.markAuthenticated({ dataClient });
|
|
1130
1658
|
if (!dataClient) {
|
|
1131
1659
|
return [
|
|
1132
1660
|
new CapxulError({
|
|
@@ -1154,7 +1682,7 @@ function createAuthClient(config = {}) {
|
|
|
1154
1682
|
},
|
|
1155
1683
|
completeBootstrap: async (input) => {
|
|
1156
1684
|
const session = sessionStore.get();
|
|
1157
|
-
const data = dataClient ?? config.
|
|
1685
|
+
const data = dataClient ?? config._data;
|
|
1158
1686
|
if (!session || !data) {
|
|
1159
1687
|
return [
|
|
1160
1688
|
new CapxulError({
|
|
@@ -1164,23 +1692,38 @@ function createAuthClient(config = {}) {
|
|
|
1164
1692
|
null
|
|
1165
1693
|
];
|
|
1166
1694
|
}
|
|
1167
|
-
|
|
1695
|
+
const signerAddress = config.signer?.address;
|
|
1696
|
+
if (!signerAddress) {
|
|
1168
1697
|
return [
|
|
1169
1698
|
new CapxulError({
|
|
1170
1699
|
code: "INVALID_INPUT",
|
|
1171
|
-
message: "completeBootstrap
|
|
1700
|
+
message: "completeBootstrap requires a signer to be configured on the client."
|
|
1172
1701
|
}),
|
|
1173
1702
|
null
|
|
1174
1703
|
];
|
|
1175
1704
|
}
|
|
1176
1705
|
try {
|
|
1177
|
-
const
|
|
1706
|
+
const safeAddress = deriveSafeAddress2(signerAddress);
|
|
1707
|
+
if (!data.action) {
|
|
1708
|
+
return [
|
|
1709
|
+
new CapxulError({
|
|
1710
|
+
code: "INVALID_INPUT",
|
|
1711
|
+
message: "completeBootstrap requires a data client that can execute Convex actions."
|
|
1712
|
+
}),
|
|
1713
|
+
null
|
|
1714
|
+
];
|
|
1715
|
+
}
|
|
1716
|
+
const result = await data.action(api.authBootstrap.completeBootstrap, {
|
|
1178
1717
|
bootstrapToken: input.bootstrapToken,
|
|
1179
1718
|
sessionToken: session.token,
|
|
1180
1719
|
username: input.username,
|
|
1181
1720
|
displayName: input.displayName,
|
|
1182
1721
|
countryCode: input.countryCode,
|
|
1183
|
-
signerProvider:
|
|
1722
|
+
signerProvider: {
|
|
1723
|
+
kind: "local-private-key",
|
|
1724
|
+
signerAddress,
|
|
1725
|
+
safeAddress
|
|
1726
|
+
}
|
|
1184
1727
|
});
|
|
1185
1728
|
return [null, { kind: "authenticated", session, ...result }];
|
|
1186
1729
|
} catch (cause) {
|
|
@@ -1194,7 +1737,7 @@ function createAuthClient(config = {}) {
|
|
|
1194
1737
|
signOut: async () => {
|
|
1195
1738
|
sessionStore.clear();
|
|
1196
1739
|
dataClient = null;
|
|
1197
|
-
mutableConfig(config).
|
|
1740
|
+
mutableConfig(config)._data = void 0;
|
|
1198
1741
|
const transport = getTransport();
|
|
1199
1742
|
transport?.clearAuth();
|
|
1200
1743
|
return [null, void 0];
|
|
@@ -1265,6 +1808,9 @@ async function postBetterAuth(transport, path, body, code, signal) {
|
|
|
1265
1808
|
}
|
|
1266
1809
|
return [null, text ? JSON.parse(text) : void 0];
|
|
1267
1810
|
} catch (cause) {
|
|
1811
|
+
if (cause instanceof CapxulError) {
|
|
1812
|
+
return [cause, null];
|
|
1813
|
+
}
|
|
1268
1814
|
return [
|
|
1269
1815
|
new CapxulError({
|
|
1270
1816
|
code: "NETWORK_ERROR",
|
|
@@ -1303,7 +1849,7 @@ function parseBetterAuthError(text) {
|
|
|
1303
1849
|
}
|
|
1304
1850
|
}
|
|
1305
1851
|
function isCapxulErrorCode2(code) {
|
|
1306
|
-
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";
|
|
1852
|
+
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";
|
|
1307
1853
|
}
|
|
1308
1854
|
async function exchangeConvexToken(transport, config, token, signal) {
|
|
1309
1855
|
const path = config.auth?.convexTokenUrl ?? "/convex/token";
|
|
@@ -1333,6 +1879,9 @@ async function exchangeConvexToken(transport, config, token, signal) {
|
|
|
1333
1879
|
}
|
|
1334
1880
|
return [null, body.token];
|
|
1335
1881
|
} catch (cause) {
|
|
1882
|
+
if (cause instanceof CapxulError) {
|
|
1883
|
+
return [cause, null];
|
|
1884
|
+
}
|
|
1336
1885
|
return [
|
|
1337
1886
|
new CapxulError({
|
|
1338
1887
|
code: "NETWORK_ERROR",
|
|
@@ -1347,16 +1896,227 @@ function mutableConfig(config) {
|
|
|
1347
1896
|
return config;
|
|
1348
1897
|
}
|
|
1349
1898
|
|
|
1899
|
+
// src/core/auth-service.ts
|
|
1900
|
+
var AuthService = class {
|
|
1901
|
+
authClient;
|
|
1902
|
+
sessionStore;
|
|
1903
|
+
config;
|
|
1904
|
+
constructor(config = {}) {
|
|
1905
|
+
this.config = config;
|
|
1906
|
+
this.sessionStore = config.auth?.sessionStore ?? createMemorySessionStore2();
|
|
1907
|
+
this.authClient = createAuthClient({
|
|
1908
|
+
...config,
|
|
1909
|
+
auth: { ...config.auth, sessionStore: this.sessionStore }
|
|
1910
|
+
});
|
|
1911
|
+
}
|
|
1912
|
+
async sendOtp(email, options) {
|
|
1913
|
+
const [err] = await this.authClient.sendOtp({ email }, options);
|
|
1914
|
+
if (err) throw err;
|
|
1915
|
+
}
|
|
1916
|
+
async verifyOtp(email, otp, options) {
|
|
1917
|
+
const [err, result] = await this.authClient.verifyOtp(
|
|
1918
|
+
{ email, otp },
|
|
1919
|
+
options
|
|
1920
|
+
);
|
|
1921
|
+
if (err) throw err;
|
|
1922
|
+
return result;
|
|
1923
|
+
}
|
|
1924
|
+
async completeBootstrap(params, signer) {
|
|
1925
|
+
if (signer) {
|
|
1926
|
+
const tempClient = createAuthClient({
|
|
1927
|
+
...this.config,
|
|
1928
|
+
signer,
|
|
1929
|
+
auth: { ...this.config.auth, sessionStore: this.sessionStore }
|
|
1930
|
+
});
|
|
1931
|
+
const [err2, result2] = await tempClient.completeBootstrap(params);
|
|
1932
|
+
if (err2) throw err2;
|
|
1933
|
+
return result2;
|
|
1934
|
+
}
|
|
1935
|
+
const [err, result] = await this.authClient.completeBootstrap(params);
|
|
1936
|
+
if (err) throw err;
|
|
1937
|
+
return result;
|
|
1938
|
+
}
|
|
1939
|
+
/**
|
|
1940
|
+
* Clears the persisted session and, when a transport was pre-injected,
|
|
1941
|
+
* drops the cached auth header.
|
|
1942
|
+
*
|
|
1943
|
+
* **Transport safety note:** `clearAuth()` is only invoked when
|
|
1944
|
+
* `config._transport` was supplied at construction (e.g. by the React
|
|
1945
|
+
* provider). If `AuthService` is instantiated directly in a Node/CLI
|
|
1946
|
+
* context without an injected transport, the transport-side auth cache
|
|
1947
|
+
* is the caller's responsibility.
|
|
1948
|
+
*/
|
|
1949
|
+
async signOut() {
|
|
1950
|
+
if (!this.config._transport) {
|
|
1951
|
+
const [err] = await this.authClient.signOut();
|
|
1952
|
+
if (err) throw err;
|
|
1953
|
+
mutableConfig2(this.config)._data = void 0;
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
this.sessionStore.clear();
|
|
1957
|
+
this.config._transport.clearAuth();
|
|
1958
|
+
}
|
|
1959
|
+
async getSession() {
|
|
1960
|
+
const [err, session] = await this.authClient.getSession();
|
|
1961
|
+
if (err) throw err;
|
|
1962
|
+
return session;
|
|
1963
|
+
}
|
|
1964
|
+
};
|
|
1965
|
+
function mutableConfig2(config) {
|
|
1966
|
+
return config;
|
|
1967
|
+
}
|
|
1968
|
+
function createMemorySessionStore2() {
|
|
1969
|
+
let current = null;
|
|
1970
|
+
return {
|
|
1971
|
+
get: () => current,
|
|
1972
|
+
set: (session) => {
|
|
1973
|
+
current = session;
|
|
1974
|
+
},
|
|
1975
|
+
clear: () => {
|
|
1976
|
+
current = null;
|
|
1977
|
+
}
|
|
1978
|
+
};
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1350
1981
|
// src/core/documents.ts
|
|
1351
|
-
function
|
|
1982
|
+
function requireInvoiceHash(row) {
|
|
1983
|
+
if (!row.invoiceHash) {
|
|
1984
|
+
throw new CapxulError({
|
|
1985
|
+
code: "INVALID_INPUT",
|
|
1986
|
+
message: `invoice document ${row.documentId ?? row._id} is missing its canonical invoiceHash`
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
return row.invoiceHash;
|
|
1990
|
+
}
|
|
1991
|
+
function mapInvoiceRow(row) {
|
|
1992
|
+
const status = row.status === "cancelled" ? "canceled" : row.status === "pending" ? "open" : row.status === "overdue" ? "expired" : row.status;
|
|
1993
|
+
return {
|
|
1994
|
+
object: "document",
|
|
1995
|
+
id: row.documentId ?? row._id,
|
|
1996
|
+
type: "invoice",
|
|
1997
|
+
owner: {
|
|
1998
|
+
kind: row.scope === "org" ? "organization" : "account",
|
|
1999
|
+
id: row.orgId ?? row.payeeEmail ?? row.payeeLabel
|
|
2000
|
+
},
|
|
2001
|
+
recipient: { email: row.payerEmail },
|
|
2002
|
+
amount: {
|
|
2003
|
+
value: row.amount,
|
|
2004
|
+
currency: row.currency
|
|
2005
|
+
},
|
|
2006
|
+
reference: row.note,
|
|
2007
|
+
lineItems: row.items,
|
|
2008
|
+
invoiceHash: requireInvoiceHash(row),
|
|
2009
|
+
dueAt: row.dueDate,
|
|
2010
|
+
status,
|
|
2011
|
+
createdAt: new Date(row.createdAt).toISOString()
|
|
2012
|
+
};
|
|
2013
|
+
}
|
|
2014
|
+
function mapDocumentError(cause) {
|
|
2015
|
+
return fromConvexError(cause);
|
|
2016
|
+
}
|
|
2017
|
+
function createDocumentsClient(config = {}) {
|
|
1352
2018
|
return {
|
|
1353
|
-
create: async () =>
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
2019
|
+
create: async (input) => {
|
|
2020
|
+
if (!config._data) return stub("documents.create");
|
|
2021
|
+
if (input.type !== "invoice") {
|
|
2022
|
+
return [
|
|
2023
|
+
new CapxulError({
|
|
2024
|
+
code: "INVALID_INPUT",
|
|
2025
|
+
message: "documents.create currently supports personal invoice documents only."
|
|
2026
|
+
}),
|
|
2027
|
+
null
|
|
2028
|
+
];
|
|
2029
|
+
}
|
|
2030
|
+
if (!("email" in input.recipient)) {
|
|
2031
|
+
return [
|
|
2032
|
+
new CapxulError({
|
|
2033
|
+
code: "INVALID_INPUT",
|
|
2034
|
+
message: "personal invoice documents currently require an email recipient."
|
|
2035
|
+
}),
|
|
2036
|
+
null
|
|
2037
|
+
];
|
|
2038
|
+
}
|
|
2039
|
+
try {
|
|
2040
|
+
const created = await config._data.mutation(
|
|
2041
|
+
api.paymentRecords.mutations.createInvoice,
|
|
2042
|
+
{
|
|
2043
|
+
scope: "personal",
|
|
2044
|
+
payerEmail: input.recipient.email,
|
|
2045
|
+
amount: input.amount.value,
|
|
2046
|
+
currency: input.amount.currency,
|
|
2047
|
+
dueDate: input.dueAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
2048
|
+
note: input.reference,
|
|
2049
|
+
items: input.lineItems
|
|
2050
|
+
}
|
|
2051
|
+
);
|
|
2052
|
+
const row = await config._data.query(
|
|
2053
|
+
api.paymentRecords.queries.getInvoiceByDocumentId,
|
|
2054
|
+
{ documentId: created.documentId }
|
|
2055
|
+
);
|
|
2056
|
+
if (!row) throw new Error("created invoice was not readable");
|
|
2057
|
+
return [null, mapInvoiceRow(row)];
|
|
2058
|
+
} catch (cause) {
|
|
2059
|
+
return [mapDocumentError(cause), null];
|
|
2060
|
+
}
|
|
2061
|
+
},
|
|
2062
|
+
retrieve: async (documentId) => {
|
|
2063
|
+
if (!config._data)
|
|
2064
|
+
return stub("documents.retrieve");
|
|
2065
|
+
try {
|
|
2066
|
+
const row = await config._data.query(
|
|
2067
|
+
api.paymentRecords.queries.getInvoiceByDocumentId,
|
|
2068
|
+
{ documentId }
|
|
2069
|
+
);
|
|
2070
|
+
if (!row) {
|
|
2071
|
+
return [
|
|
2072
|
+
new CapxulError({
|
|
2073
|
+
code: "NOT_FOUND",
|
|
2074
|
+
message: `document ${documentId} not found`
|
|
2075
|
+
}),
|
|
2076
|
+
null
|
|
2077
|
+
];
|
|
2078
|
+
}
|
|
2079
|
+
return [null, mapInvoiceRow(row)];
|
|
2080
|
+
} catch (cause) {
|
|
2081
|
+
return [mapDocumentError(cause), null];
|
|
2082
|
+
}
|
|
2083
|
+
},
|
|
2084
|
+
list: async (input = {}) => {
|
|
2085
|
+
if (!config._data)
|
|
2086
|
+
return stub("documents.list");
|
|
2087
|
+
try {
|
|
2088
|
+
if (input.type && input.type !== "invoice") {
|
|
2089
|
+
return [null, { object: "list", data: [], page: { hasMore: false } }];
|
|
2090
|
+
}
|
|
2091
|
+
const rows = await config._data.query(
|
|
2092
|
+
api.paymentRecords.queries.listMyInvoices,
|
|
2093
|
+
{
|
|
2094
|
+
limit: input.limit,
|
|
2095
|
+
cursor: input.cursor
|
|
2096
|
+
}
|
|
2097
|
+
);
|
|
2098
|
+
const page = rows;
|
|
2099
|
+
const data = page.data.map((row) => mapInvoiceRow(row));
|
|
2100
|
+
return [null, { object: "list", data, page: page.page }];
|
|
2101
|
+
} catch (cause) {
|
|
2102
|
+
return [mapDocumentError(cause), null];
|
|
2103
|
+
}
|
|
2104
|
+
},
|
|
2105
|
+
cancel: async (documentId) => {
|
|
2106
|
+
if (!config._data) return stub("documents.cancel");
|
|
2107
|
+
try {
|
|
2108
|
+
const row = await config._data.mutation(
|
|
2109
|
+
api.paymentRecords.mutations.cancelInvoice,
|
|
2110
|
+
{ documentId }
|
|
2111
|
+
);
|
|
2112
|
+
return [null, mapInvoiceRow(row)];
|
|
2113
|
+
} catch (cause) {
|
|
2114
|
+
return [mapDocumentError(cause), null];
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
1357
2117
|
};
|
|
1358
2118
|
}
|
|
1359
|
-
function createOrgDocumentsClient() {
|
|
2119
|
+
function createOrgDocumentsClient(_config = {}) {
|
|
1360
2120
|
return {
|
|
1361
2121
|
create: async () => stub("organizations.documents.create"),
|
|
1362
2122
|
retrieve: async () => stub("organizations.documents.retrieve"),
|
|
@@ -1369,11 +2129,11 @@ function createOrgDocumentsClient() {
|
|
|
1369
2129
|
function createMeClient(config = {}) {
|
|
1370
2130
|
return {
|
|
1371
2131
|
get: async () => {
|
|
1372
|
-
if (!config.
|
|
2132
|
+
if (!config._data) {
|
|
1373
2133
|
return stub("me.get");
|
|
1374
2134
|
}
|
|
1375
2135
|
try {
|
|
1376
|
-
const account = await config.
|
|
2136
|
+
const account = await config._data.query(
|
|
1377
2137
|
api.openfort.queries.getMyAccount,
|
|
1378
2138
|
{}
|
|
1379
2139
|
);
|
|
@@ -1383,7 +2143,7 @@ function createMeClient(config = {}) {
|
|
|
1383
2143
|
}
|
|
1384
2144
|
},
|
|
1385
2145
|
update: async (input) => {
|
|
1386
|
-
if (!config.
|
|
2146
|
+
if (!config._data) {
|
|
1387
2147
|
return stub("me.update");
|
|
1388
2148
|
}
|
|
1389
2149
|
if (input.countryCode !== void 0) {
|
|
@@ -1397,11 +2157,11 @@ function createMeClient(config = {}) {
|
|
|
1397
2157
|
];
|
|
1398
2158
|
}
|
|
1399
2159
|
try {
|
|
1400
|
-
await config.
|
|
2160
|
+
await config._data.mutation(api.openfort.mutations.updateProfile, {
|
|
1401
2161
|
displayName: input.name,
|
|
1402
2162
|
username: input.username
|
|
1403
2163
|
});
|
|
1404
|
-
const account = await config.
|
|
2164
|
+
const account = await config._data.query(
|
|
1405
2165
|
api.openfort.queries.getMyAccount,
|
|
1406
2166
|
{}
|
|
1407
2167
|
);
|
|
@@ -1416,11 +2176,11 @@ function createMeClient(config = {}) {
|
|
|
1416
2176
|
// src/core/operations.ts
|
|
1417
2177
|
function createOperationsClient(config = {}) {
|
|
1418
2178
|
const retrieve = async (operationId) => {
|
|
1419
|
-
if (!config.
|
|
2179
|
+
if (!config._data) {
|
|
1420
2180
|
return stub("operations.retrieve");
|
|
1421
2181
|
}
|
|
1422
2182
|
try {
|
|
1423
|
-
const operation = await config.
|
|
2183
|
+
const operation = await config._data.query(api.operations.queries.retrieve, {
|
|
1424
2184
|
operationId
|
|
1425
2185
|
});
|
|
1426
2186
|
if (!operation) {
|
|
@@ -1437,7 +2197,7 @@ function createOperationsClient(config = {}) {
|
|
|
1437
2197
|
return {
|
|
1438
2198
|
retrieve,
|
|
1439
2199
|
wait: async (operationId, input = {}) => {
|
|
1440
|
-
if (!config.
|
|
2200
|
+
if (!config._data) {
|
|
1441
2201
|
return stub("operations.wait");
|
|
1442
2202
|
}
|
|
1443
2203
|
const until = new Set(
|
|
@@ -1472,49 +2232,22 @@ function toTokenUnits(value, decimals = 6) {
|
|
|
1472
2232
|
return viem.parseUnits(value, decimals);
|
|
1473
2233
|
}
|
|
1474
2234
|
|
|
1475
|
-
// src/
|
|
1476
|
-
function
|
|
2235
|
+
// src/core/token-registry.ts
|
|
2236
|
+
function resolvePaymentToken(currency) {
|
|
1477
2237
|
const normalized = currency.trim().toUpperCase();
|
|
1478
2238
|
if (normalized === "USD" || normalized === "USDC") {
|
|
1479
|
-
return
|
|
2239
|
+
return {
|
|
2240
|
+
address: TEST_USDC_ADDRESS.toLowerCase(),
|
|
2241
|
+
decimals: 6,
|
|
2242
|
+
symbol: "USDC"
|
|
2243
|
+
};
|
|
1480
2244
|
}
|
|
1481
2245
|
throw new CapxulError({
|
|
1482
|
-
code: "
|
|
1483
|
-
message: `Currency ${currency} is not
|
|
2246
|
+
code: "NOT_IMPLEMENTED",
|
|
2247
|
+
message: `Currency ${currency} is not yet supported by the token registry.`,
|
|
1484
2248
|
details: { currency: normalized }
|
|
1485
2249
|
});
|
|
1486
2250
|
}
|
|
1487
|
-
async function buildSafeAccount(signer, chain) {
|
|
1488
|
-
try {
|
|
1489
|
-
const publicClient = viem.createPublicClient({
|
|
1490
|
-
chain: chains.baseSepolia,
|
|
1491
|
-
transport: viem.http(chain.rpcUrl)
|
|
1492
|
-
});
|
|
1493
|
-
return await accounts$1.toSafeSmartAccount({
|
|
1494
|
-
client: publicClient,
|
|
1495
|
-
entryPoint: { address: accountAbstraction.entryPoint07Address, version: "0.7" },
|
|
1496
|
-
version: "1.4.1",
|
|
1497
|
-
owners: [signer],
|
|
1498
|
-
saltNonce: computeSaltNonce(signer.address),
|
|
1499
|
-
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
1500
|
-
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
1501
|
-
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
1502
|
-
safe4337ModuleAddress: SAFE_4337_MODULE,
|
|
1503
|
-
safeModules: [],
|
|
1504
|
-
setupTransactions: []
|
|
1505
|
-
});
|
|
1506
|
-
} catch (cause) {
|
|
1507
|
-
throw new CapxulError({
|
|
1508
|
-
code: "NETWORK_ERROR",
|
|
1509
|
-
message: cause instanceof Error ? cause.message : String(cause),
|
|
1510
|
-
cause,
|
|
1511
|
-
details: { chainId: chain.chainId }
|
|
1512
|
-
});
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
function computeSaltNonce(ownerAddress) {
|
|
1516
|
-
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
1517
|
-
}
|
|
1518
2251
|
function createCapxulBundler(config) {
|
|
1519
2252
|
const paymaster = accountAbstraction.createPaymasterClient({
|
|
1520
2253
|
transport: viem.http(config.rpcUrl)
|
|
@@ -1621,13 +2354,13 @@ async function transferAsOwner(config, params) {
|
|
|
1621
2354
|
function createPaymentsClient(config = {}) {
|
|
1622
2355
|
return {
|
|
1623
2356
|
create: async (input) => {
|
|
1624
|
-
if (!config.
|
|
2357
|
+
if (!config._data || !config.signer || !config.signing) {
|
|
1625
2358
|
return stub("payments.create");
|
|
1626
2359
|
}
|
|
1627
2360
|
let created = null;
|
|
1628
2361
|
let submitted = null;
|
|
1629
2362
|
try {
|
|
1630
|
-
created = await config.
|
|
2363
|
+
created = await config._data.mutation(api.payments.mutations.create, {
|
|
1631
2364
|
to: input.to,
|
|
1632
2365
|
amount: input.amount,
|
|
1633
2366
|
reference: input.reference,
|
|
@@ -1635,15 +2368,21 @@ function createPaymentsClient(config = {}) {
|
|
|
1635
2368
|
source: input.source
|
|
1636
2369
|
});
|
|
1637
2370
|
if (!created) {
|
|
1638
|
-
return [
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
2371
|
+
return [
|
|
2372
|
+
new CapxulError({
|
|
2373
|
+
code: "NETWORK_ERROR",
|
|
2374
|
+
message: "payments.create returned no payment resource"
|
|
2375
|
+
}),
|
|
2376
|
+
null
|
|
2377
|
+
];
|
|
1642
2378
|
}
|
|
1643
2379
|
if (created.status !== "processing" || created.operation.status !== "processing") {
|
|
1644
2380
|
return [null, created];
|
|
1645
2381
|
}
|
|
1646
|
-
const currentSigner = await config.
|
|
2382
|
+
const currentSigner = await config._data.query(
|
|
2383
|
+
api.safe.queries.getMySignerAddress,
|
|
2384
|
+
{}
|
|
2385
|
+
);
|
|
1647
2386
|
if (!currentSigner?.address) {
|
|
1648
2387
|
throw new CapxulError({
|
|
1649
2388
|
code: "PERMISSION_DENIED",
|
|
@@ -1662,9 +2401,12 @@ function createPaymentsClient(config = {}) {
|
|
|
1662
2401
|
}
|
|
1663
2402
|
});
|
|
1664
2403
|
}
|
|
1665
|
-
const submission = await config.
|
|
1666
|
-
|
|
1667
|
-
|
|
2404
|
+
const submission = await config._data.query(
|
|
2405
|
+
api.payments.queries.prepareSubmission,
|
|
2406
|
+
{
|
|
2407
|
+
paymentId: created.id
|
|
2408
|
+
}
|
|
2409
|
+
);
|
|
1668
2410
|
if (!submission?.recipientAddress) {
|
|
1669
2411
|
throw new CapxulError({
|
|
1670
2412
|
code: "NETWORK_ERROR",
|
|
@@ -1672,15 +2414,16 @@ function createPaymentsClient(config = {}) {
|
|
|
1672
2414
|
details: { paymentId: created.id }
|
|
1673
2415
|
});
|
|
1674
2416
|
}
|
|
2417
|
+
const token = resolvePaymentToken(submission.amount.currency);
|
|
1675
2418
|
const transfer = await transferAsOwner(
|
|
1676
2419
|
{
|
|
1677
2420
|
signer: config.signer,
|
|
1678
2421
|
signing: config.signing
|
|
1679
2422
|
},
|
|
1680
2423
|
{
|
|
1681
|
-
tokenAddress:
|
|
2424
|
+
tokenAddress: token.address,
|
|
1682
2425
|
recipientAddress: submission.recipientAddress,
|
|
1683
|
-
amount: toTokenUnits(submission.amount.value,
|
|
2426
|
+
amount: toTokenUnits(submission.amount.value, token.decimals)
|
|
1684
2427
|
}
|
|
1685
2428
|
);
|
|
1686
2429
|
if (!transfer.success) {
|
|
@@ -1698,7 +2441,7 @@ function createPaymentsClient(config = {}) {
|
|
|
1698
2441
|
txHash: transfer.txHash,
|
|
1699
2442
|
userOpHash: transfer.userOpHash
|
|
1700
2443
|
};
|
|
1701
|
-
await config.
|
|
2444
|
+
await config._data.mutation(api.payments.mutations.recordSubmitted, {
|
|
1702
2445
|
paymentId: created.id,
|
|
1703
2446
|
txHash: transfer.txHash,
|
|
1704
2447
|
userOpHash: transfer.userOpHash,
|
|
@@ -1708,43 +2451,65 @@ function createPaymentsClient(config = {}) {
|
|
|
1708
2451
|
} catch (cause) {
|
|
1709
2452
|
const error = mapCreateError(fromConvexError(cause));
|
|
1710
2453
|
if (created?.id && created.status === "processing" && !submitted) {
|
|
1711
|
-
await bestEffortMarkFailed({
|
|
2454
|
+
await bestEffortMarkFailed({ _data: config._data }, created.id, error);
|
|
1712
2455
|
}
|
|
1713
2456
|
if (submitted && created?.id) {
|
|
1714
|
-
return [
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
2457
|
+
return [
|
|
2458
|
+
new CapxulError({
|
|
2459
|
+
code: "NETWORK_ERROR",
|
|
2460
|
+
message: "Payment was submitted on-chain, but backend submission tracking failed.",
|
|
2461
|
+
cause,
|
|
2462
|
+
details: {
|
|
2463
|
+
paymentId: created.id,
|
|
2464
|
+
txHash: submitted.txHash,
|
|
2465
|
+
userOpHash: submitted.userOpHash
|
|
2466
|
+
}
|
|
2467
|
+
}),
|
|
2468
|
+
null
|
|
2469
|
+
];
|
|
1724
2470
|
}
|
|
1725
2471
|
return [error, null];
|
|
1726
2472
|
}
|
|
1727
2473
|
},
|
|
1728
2474
|
retrieve: async (paymentId) => {
|
|
1729
|
-
if (!config.
|
|
2475
|
+
if (!config._data) {
|
|
1730
2476
|
return stub("payments.retrieve");
|
|
1731
2477
|
}
|
|
1732
2478
|
try {
|
|
1733
|
-
const payment = await config.
|
|
1734
|
-
|
|
1735
|
-
|
|
2479
|
+
const payment = await config._data.query(
|
|
2480
|
+
api.payments.queries.retrieve,
|
|
2481
|
+
{
|
|
2482
|
+
paymentId
|
|
2483
|
+
}
|
|
2484
|
+
);
|
|
1736
2485
|
if (!payment) {
|
|
1737
|
-
return [
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
2486
|
+
return [
|
|
2487
|
+
new CapxulError({
|
|
2488
|
+
code: "NOT_FOUND",
|
|
2489
|
+
message: `payment ${paymentId} not found`
|
|
2490
|
+
}),
|
|
2491
|
+
null
|
|
2492
|
+
];
|
|
1741
2493
|
}
|
|
1742
2494
|
return [null, payment];
|
|
1743
2495
|
} catch (cause) {
|
|
1744
2496
|
return [fromConvexError(cause), null];
|
|
1745
2497
|
}
|
|
1746
2498
|
},
|
|
1747
|
-
list: async () =>
|
|
2499
|
+
list: async (input) => {
|
|
2500
|
+
if (!config._data) {
|
|
2501
|
+
return stub("payments.list");
|
|
2502
|
+
}
|
|
2503
|
+
try {
|
|
2504
|
+
const page = await config._data.query(api.payments.queries.list, {
|
|
2505
|
+
limit: input?.limit,
|
|
2506
|
+
cursor: input?.cursor
|
|
2507
|
+
});
|
|
2508
|
+
return [null, page];
|
|
2509
|
+
} catch (cause) {
|
|
2510
|
+
return [fromConvexError(cause), null];
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
1748
2513
|
};
|
|
1749
2514
|
}
|
|
1750
2515
|
function createOrgPaymentsClient() {
|
|
@@ -1758,7 +2523,7 @@ function createOrgPaymentsClient() {
|
|
|
1758
2523
|
}
|
|
1759
2524
|
async function bestEffortMarkFailed(config, paymentId, error) {
|
|
1760
2525
|
try {
|
|
1761
|
-
await config.
|
|
2526
|
+
await config._data.mutation(api.payments.mutations.markFailed, {
|
|
1762
2527
|
paymentId,
|
|
1763
2528
|
errorCode: error.code,
|
|
1764
2529
|
errorMessage: error.message,
|
|
@@ -1815,11 +2580,11 @@ function createOrgTransfersClient() {
|
|
|
1815
2580
|
function createWithdrawalsClient(config = {}) {
|
|
1816
2581
|
return {
|
|
1817
2582
|
create: async (input) => {
|
|
1818
|
-
if (!config.
|
|
2583
|
+
if (!config._data) {
|
|
1819
2584
|
return stub("withdrawals.create");
|
|
1820
2585
|
}
|
|
1821
2586
|
const [createErr, createdRaw] = await tryCatch(
|
|
1822
|
-
config.
|
|
2587
|
+
config._data.mutation(api.withdrawals.mutations.create, {
|
|
1823
2588
|
amount: input.amount,
|
|
1824
2589
|
destination: {
|
|
1825
2590
|
externalAccountId: input.destination.externalAccountId
|
|
@@ -1849,18 +2614,18 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1849
2614
|
return [null, created];
|
|
1850
2615
|
}
|
|
1851
2616
|
const [signerErr, currentSigner] = await tryCatch(
|
|
1852
|
-
config.
|
|
2617
|
+
config._data.query(api.safe.queries.getMySignerAddress, {})
|
|
1853
2618
|
);
|
|
1854
2619
|
if (signerErr) {
|
|
1855
2620
|
return await handleSubmissionFailure(
|
|
1856
|
-
{
|
|
2621
|
+
{ _data: config._data },
|
|
1857
2622
|
created.id,
|
|
1858
2623
|
mapCreateError2(fromConvexError(signerErr))
|
|
1859
2624
|
);
|
|
1860
2625
|
}
|
|
1861
2626
|
if (!currentSigner?.address) {
|
|
1862
2627
|
return await handleSubmissionFailure(
|
|
1863
|
-
{
|
|
2628
|
+
{ _data: config._data },
|
|
1864
2629
|
created.id,
|
|
1865
2630
|
new CapxulError({
|
|
1866
2631
|
code: "PERMISSION_DENIED",
|
|
@@ -1871,7 +2636,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1871
2636
|
}
|
|
1872
2637
|
if (viem.getAddress(currentSigner.address) !== viem.getAddress(config.signer.address)) {
|
|
1873
2638
|
return await handleSubmissionFailure(
|
|
1874
|
-
{
|
|
2639
|
+
{ _data: config._data },
|
|
1875
2640
|
created.id,
|
|
1876
2641
|
new CapxulError({
|
|
1877
2642
|
code: "PERMISSION_DENIED",
|
|
@@ -1885,13 +2650,13 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1885
2650
|
);
|
|
1886
2651
|
}
|
|
1887
2652
|
const [prepErr, submission] = await tryCatch(
|
|
1888
|
-
config.
|
|
2653
|
+
config._data.query(api.withdrawals.queries.prepareSubmission, {
|
|
1889
2654
|
withdrawalId: created.id
|
|
1890
2655
|
})
|
|
1891
2656
|
);
|
|
1892
2657
|
if (prepErr) {
|
|
1893
2658
|
return await handleSubmissionFailure(
|
|
1894
|
-
{
|
|
2659
|
+
{ _data: config._data },
|
|
1895
2660
|
created.id,
|
|
1896
2661
|
mapCreateError2(fromConvexError(prepErr))
|
|
1897
2662
|
);
|
|
@@ -1899,7 +2664,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1899
2664
|
const destinationAddress = submission?.destinationAddress;
|
|
1900
2665
|
if (!submission || !destinationAddress) {
|
|
1901
2666
|
return await handleSubmissionFailure(
|
|
1902
|
-
{
|
|
2667
|
+
{ _data: config._data },
|
|
1903
2668
|
created.id,
|
|
1904
2669
|
new CapxulError({
|
|
1905
2670
|
code: "NETWORK_ERROR",
|
|
@@ -1908,6 +2673,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1908
2673
|
})
|
|
1909
2674
|
);
|
|
1910
2675
|
}
|
|
2676
|
+
const token = resolvePaymentToken(submission.amount.currency);
|
|
1911
2677
|
const [transferErr, transferOk] = await tryCatch(
|
|
1912
2678
|
transferAsOwner(
|
|
1913
2679
|
{
|
|
@@ -1915,22 +2681,22 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1915
2681
|
signing: config.signing
|
|
1916
2682
|
},
|
|
1917
2683
|
{
|
|
1918
|
-
tokenAddress:
|
|
2684
|
+
tokenAddress: token.address,
|
|
1919
2685
|
recipientAddress: destinationAddress,
|
|
1920
|
-
amount: toTokenUnits(submission.amount.value,
|
|
2686
|
+
amount: toTokenUnits(submission.amount.value, token.decimals)
|
|
1921
2687
|
}
|
|
1922
2688
|
)
|
|
1923
2689
|
);
|
|
1924
2690
|
if (transferErr) {
|
|
1925
2691
|
return await handleSubmissionFailure(
|
|
1926
|
-
{
|
|
2692
|
+
{ _data: config._data },
|
|
1927
2693
|
created.id,
|
|
1928
2694
|
mapCreateError2(fromConvexError(transferErr))
|
|
1929
2695
|
);
|
|
1930
2696
|
}
|
|
1931
2697
|
if (!transferOk.success) {
|
|
1932
2698
|
return await handleSubmissionFailure(
|
|
1933
|
-
{
|
|
2699
|
+
{ _data: config._data },
|
|
1934
2700
|
created.id,
|
|
1935
2701
|
new CapxulError({
|
|
1936
2702
|
code: "NETWORK_ERROR",
|
|
@@ -1944,7 +2710,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1944
2710
|
);
|
|
1945
2711
|
}
|
|
1946
2712
|
const [recordErr] = await tryCatch(
|
|
1947
|
-
config.
|
|
2713
|
+
config._data.mutation(api.withdrawals.mutations.recordSubmitted, {
|
|
1948
2714
|
withdrawalId: created.id,
|
|
1949
2715
|
txHash: transferOk.txHash,
|
|
1950
2716
|
userOpHash: transferOk.userOpHash
|
|
@@ -1968,11 +2734,11 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1968
2734
|
return [null, created];
|
|
1969
2735
|
},
|
|
1970
2736
|
retrieve: async (withdrawalId) => {
|
|
1971
|
-
if (!config.
|
|
2737
|
+
if (!config._data) {
|
|
1972
2738
|
return stub("withdrawals.retrieve");
|
|
1973
2739
|
}
|
|
1974
2740
|
const [err, raw] = await tryCatch(
|
|
1975
|
-
config.
|
|
2741
|
+
config._data.query(api.withdrawals.queries.retrieve, { withdrawalId })
|
|
1976
2742
|
);
|
|
1977
2743
|
if (err) {
|
|
1978
2744
|
return [fromConvexError(err), null];
|
|
@@ -1990,11 +2756,11 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1990
2756
|
return [null, withdrawal];
|
|
1991
2757
|
},
|
|
1992
2758
|
list: async (input) => {
|
|
1993
|
-
if (!config.
|
|
2759
|
+
if (!config._data) {
|
|
1994
2760
|
return stub("withdrawals.list");
|
|
1995
2761
|
}
|
|
1996
2762
|
const [err, raw] = await tryCatch(
|
|
1997
|
-
config.
|
|
2763
|
+
config._data.query(api.withdrawals.queries.list, {
|
|
1998
2764
|
limit: input?.limit,
|
|
1999
2765
|
cursor: input?.cursor
|
|
2000
2766
|
})
|
|
@@ -2005,13 +2771,13 @@ function createWithdrawalsClient(config = {}) {
|
|
|
2005
2771
|
return [null, raw];
|
|
2006
2772
|
},
|
|
2007
2773
|
recordCompleted: async (input) => {
|
|
2008
|
-
if (!config.
|
|
2774
|
+
if (!config._data) {
|
|
2009
2775
|
return stub(
|
|
2010
2776
|
"withdrawals.recordCompleted"
|
|
2011
2777
|
);
|
|
2012
2778
|
}
|
|
2013
2779
|
const [err] = await tryCatch(
|
|
2014
|
-
config.
|
|
2780
|
+
config._data.mutation(api.withdrawals.mutations.recordCompleted, {
|
|
2015
2781
|
withdrawalId: input.withdrawalId,
|
|
2016
2782
|
txHash: input.txHash
|
|
2017
2783
|
})
|
|
@@ -2036,13 +2802,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
2036
2802
|
* orchestration ships in W3+.
|
|
2037
2803
|
*/
|
|
2038
2804
|
create: async (input) => {
|
|
2039
|
-
if (!config.
|
|
2805
|
+
if (!config._data) {
|
|
2040
2806
|
return stub(
|
|
2041
2807
|
"organizations.withdrawals.create"
|
|
2042
2808
|
);
|
|
2043
2809
|
}
|
|
2044
2810
|
const [err, raw] = await tryCatch(
|
|
2045
|
-
config.
|
|
2811
|
+
config._data.mutation(api.withdrawals.mutations.createOrg, {
|
|
2046
2812
|
organizationId: input.organizationId,
|
|
2047
2813
|
amount: input.amount,
|
|
2048
2814
|
destination: {
|
|
@@ -2069,13 +2835,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
2069
2835
|
return [null, created];
|
|
2070
2836
|
},
|
|
2071
2837
|
retrieve: async (input) => {
|
|
2072
|
-
if (!config.
|
|
2838
|
+
if (!config._data) {
|
|
2073
2839
|
return stub(
|
|
2074
2840
|
"organizations.withdrawals.retrieve"
|
|
2075
2841
|
);
|
|
2076
2842
|
}
|
|
2077
2843
|
const [err, raw] = await tryCatch(
|
|
2078
|
-
config.
|
|
2844
|
+
config._data.query(api.withdrawals.queries.retrieve, {
|
|
2079
2845
|
withdrawalId: input.withdrawalId
|
|
2080
2846
|
})
|
|
2081
2847
|
);
|
|
@@ -2105,13 +2871,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
2105
2871
|
return [null, withdrawal];
|
|
2106
2872
|
},
|
|
2107
2873
|
list: async (input) => {
|
|
2108
|
-
if (!config.
|
|
2874
|
+
if (!config._data) {
|
|
2109
2875
|
return stub(
|
|
2110
2876
|
"organizations.withdrawals.list"
|
|
2111
2877
|
);
|
|
2112
2878
|
}
|
|
2113
2879
|
const [err, raw] = await tryCatch(
|
|
2114
|
-
config.
|
|
2880
|
+
config._data.query(api.withdrawals.queries.listOrg, {
|
|
2115
2881
|
organizationId: input.organizationId,
|
|
2116
2882
|
limit: input.limit,
|
|
2117
2883
|
cursor: input.cursor
|
|
@@ -2130,7 +2896,7 @@ async function handleSubmissionFailure(config, withdrawalId, error) {
|
|
|
2130
2896
|
}
|
|
2131
2897
|
async function bestEffortMarkFailed2(config, withdrawalId, error) {
|
|
2132
2898
|
await tryCatch(
|
|
2133
|
-
config.
|
|
2899
|
+
config._data.mutation(api.withdrawals.mutations.markFailed, {
|
|
2134
2900
|
withdrawalId,
|
|
2135
2901
|
errorCode: error.code,
|
|
2136
2902
|
errorMessage: error.message
|
|
@@ -2209,13 +2975,13 @@ function createWebhookEventsClient() {
|
|
|
2209
2975
|
function createOrgExternalAccountsClient(config) {
|
|
2210
2976
|
return {
|
|
2211
2977
|
create: async (input) => {
|
|
2212
|
-
if (!config.
|
|
2978
|
+
if (!config._data) {
|
|
2213
2979
|
return stub(
|
|
2214
2980
|
"organizations.externalAccounts.create"
|
|
2215
2981
|
);
|
|
2216
2982
|
}
|
|
2217
2983
|
const [err, raw] = await tryCatch(
|
|
2218
|
-
config.
|
|
2984
|
+
config._data.mutation(api.externalAccounts.mutations.createOrg, {
|
|
2219
2985
|
organizationId: input.organizationId,
|
|
2220
2986
|
kind: input.kind,
|
|
2221
2987
|
label: input.label,
|
|
@@ -2229,10 +2995,7 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2229
2995
|
})
|
|
2230
2996
|
);
|
|
2231
2997
|
if (err) {
|
|
2232
|
-
return [
|
|
2233
|
-
fromConvexError(err),
|
|
2234
|
-
null
|
|
2235
|
-
];
|
|
2998
|
+
return [fromConvexError(err), null];
|
|
2236
2999
|
}
|
|
2237
3000
|
if (!raw) {
|
|
2238
3001
|
return [
|
|
@@ -2243,21 +3006,16 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2243
3006
|
null
|
|
2244
3007
|
];
|
|
2245
3008
|
}
|
|
2246
|
-
return [
|
|
2247
|
-
null,
|
|
2248
|
-
brandExternalAccount(
|
|
2249
|
-
raw
|
|
2250
|
-
)
|
|
2251
|
-
];
|
|
3009
|
+
return [null, brandExternalAccount(raw)];
|
|
2252
3010
|
},
|
|
2253
3011
|
list: async (input) => {
|
|
2254
|
-
if (!config.
|
|
3012
|
+
if (!config._data) {
|
|
2255
3013
|
return stub(
|
|
2256
3014
|
"organizations.externalAccounts.list"
|
|
2257
3015
|
);
|
|
2258
3016
|
}
|
|
2259
3017
|
const [err, result] = await tryCatch(
|
|
2260
|
-
config.
|
|
3018
|
+
config._data.query(api.externalAccounts.queries.listOrg, {
|
|
2261
3019
|
organizationId: input.organizationId,
|
|
2262
3020
|
limit: input.limit,
|
|
2263
3021
|
cursor: input.cursor
|
|
@@ -2267,9 +3025,7 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2267
3025
|
return [fromConvexError(err), null];
|
|
2268
3026
|
}
|
|
2269
3027
|
const branded = result.data.map(
|
|
2270
|
-
(row) => brandExternalAccount(
|
|
2271
|
-
row
|
|
2272
|
-
)
|
|
3028
|
+
(row) => brandExternalAccount(row)
|
|
2273
3029
|
);
|
|
2274
3030
|
return [
|
|
2275
3031
|
null,
|
|
@@ -2281,17 +3037,66 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2281
3037
|
];
|
|
2282
3038
|
},
|
|
2283
3039
|
retrieve: async (input) => {
|
|
2284
|
-
if (!config.
|
|
3040
|
+
if (!config._data) {
|
|
2285
3041
|
return stub(
|
|
2286
3042
|
"organizations.externalAccounts.retrieve"
|
|
2287
3043
|
);
|
|
2288
3044
|
}
|
|
2289
3045
|
const [err, raw] = await tryCatch(
|
|
2290
|
-
config.
|
|
3046
|
+
config._data.query(api.externalAccounts.queries.retrieveOrg, {
|
|
3047
|
+
organizationId: input.organizationId,
|
|
3048
|
+
externalAccountId: input.externalAccountId
|
|
3049
|
+
})
|
|
3050
|
+
);
|
|
3051
|
+
if (err) {
|
|
3052
|
+
return [fromConvexError(err), null];
|
|
3053
|
+
}
|
|
3054
|
+
if (!raw) {
|
|
3055
|
+
return [
|
|
3056
|
+
new CapxulError({
|
|
3057
|
+
code: "NOT_FOUND",
|
|
3058
|
+
message: `external_account ${input.externalAccountId} not found`
|
|
3059
|
+
}),
|
|
3060
|
+
null
|
|
3061
|
+
];
|
|
3062
|
+
}
|
|
3063
|
+
return [null, brandExternalAccount(raw)];
|
|
3064
|
+
},
|
|
3065
|
+
remove: async (input) => {
|
|
3066
|
+
if (!config._data) {
|
|
3067
|
+
return stub("organizations.externalAccounts.remove");
|
|
3068
|
+
}
|
|
3069
|
+
const [err] = await tryCatch(
|
|
3070
|
+
config._data.mutation(api.externalAccounts.mutations.removeOrg, {
|
|
2291
3071
|
organizationId: input.organizationId,
|
|
2292
3072
|
externalAccountId: input.externalAccountId
|
|
2293
3073
|
})
|
|
2294
3074
|
);
|
|
3075
|
+
if (err) {
|
|
3076
|
+
return [fromConvexError(err), null];
|
|
3077
|
+
}
|
|
3078
|
+
return [null, void 0];
|
|
3079
|
+
}
|
|
3080
|
+
};
|
|
3081
|
+
}
|
|
3082
|
+
function createOrgSubAccountsClient(config) {
|
|
3083
|
+
return {
|
|
3084
|
+
create: async (input) => {
|
|
3085
|
+
if (!config._data) {
|
|
3086
|
+
return stub(
|
|
3087
|
+
"organizations.subAccounts.create"
|
|
3088
|
+
);
|
|
3089
|
+
}
|
|
3090
|
+
const [err, raw] = await tryCatch(
|
|
3091
|
+
config._data.mutation(api.subAccounts.mutations.create, {
|
|
3092
|
+
parent: {
|
|
3093
|
+
kind: "organization",
|
|
3094
|
+
id: input.organizationId
|
|
3095
|
+
},
|
|
3096
|
+
name: input.name,
|
|
3097
|
+
purpose: input.purpose
|
|
3098
|
+
})
|
|
3099
|
+
);
|
|
2295
3100
|
if (err) {
|
|
2296
3101
|
return [
|
|
2297
3102
|
fromConvexError(err),
|
|
@@ -2302,28 +3107,60 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2302
3107
|
return [
|
|
2303
3108
|
new CapxulError({
|
|
2304
3109
|
code: "NOT_FOUND",
|
|
2305
|
-
message:
|
|
3110
|
+
message: "sub_account creation returned no resource"
|
|
2306
3111
|
}),
|
|
2307
3112
|
null
|
|
2308
3113
|
];
|
|
2309
3114
|
}
|
|
3115
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
3116
|
+
if (brandErr) {
|
|
3117
|
+
return [brandErr, null];
|
|
3118
|
+
}
|
|
3119
|
+
return [null, branded];
|
|
3120
|
+
},
|
|
3121
|
+
list: async (input) => {
|
|
3122
|
+
if (!config._data) {
|
|
3123
|
+
return stub(
|
|
3124
|
+
"organizations.subAccounts.list"
|
|
3125
|
+
);
|
|
3126
|
+
}
|
|
3127
|
+
const [err, rows] = await tryCatch(
|
|
3128
|
+
config._data.query(api.subAccounts.queries.listByOrganization, {
|
|
3129
|
+
organizationId: input.organizationId
|
|
3130
|
+
})
|
|
3131
|
+
);
|
|
3132
|
+
if (err) {
|
|
3133
|
+
return [
|
|
3134
|
+
fromConvexError(err),
|
|
3135
|
+
null
|
|
3136
|
+
];
|
|
3137
|
+
}
|
|
3138
|
+
const branded = [];
|
|
3139
|
+
for (const row of rows) {
|
|
3140
|
+
const [brandErr, value] = tryBrandSubAccount(row);
|
|
3141
|
+
if (brandErr) {
|
|
3142
|
+
return [brandErr, null];
|
|
3143
|
+
}
|
|
3144
|
+
branded.push(value);
|
|
3145
|
+
}
|
|
2310
3146
|
return [
|
|
2311
3147
|
null,
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
3148
|
+
{
|
|
3149
|
+
object: "list",
|
|
3150
|
+
data: branded,
|
|
3151
|
+
page: { hasMore: false }
|
|
3152
|
+
}
|
|
2315
3153
|
];
|
|
2316
3154
|
},
|
|
2317
|
-
|
|
2318
|
-
if (!config.
|
|
3155
|
+
retrieve: async (input) => {
|
|
3156
|
+
if (!config._data) {
|
|
2319
3157
|
return stub(
|
|
2320
|
-
"organizations.
|
|
3158
|
+
"organizations.subAccounts.retrieve"
|
|
2321
3159
|
);
|
|
2322
3160
|
}
|
|
2323
|
-
const [err] = await tryCatch(
|
|
2324
|
-
config.
|
|
2325
|
-
|
|
2326
|
-
externalAccountId: input.externalAccountId
|
|
3161
|
+
const [err, raw] = await tryCatch(
|
|
3162
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
3163
|
+
subAccountId: input.subAccountId
|
|
2327
3164
|
})
|
|
2328
3165
|
);
|
|
2329
3166
|
if (err) {
|
|
@@ -2332,822 +3169,557 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2332
3169
|
null
|
|
2333
3170
|
];
|
|
2334
3171
|
}
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
list: async () => stub("organizations.list"),
|
|
2344
|
-
update: async () => stub("organizations.update"),
|
|
2345
|
-
safes: {
|
|
2346
|
-
retrieve: async (input) => {
|
|
2347
|
-
if (!config.data) {
|
|
2348
|
-
return stub("organizations.safes.retrieve");
|
|
2349
|
-
}
|
|
2350
|
-
try {
|
|
2351
|
-
const safe = await config.data.query(
|
|
2352
|
-
api.safe.queries.retrieveOrganizationSafe,
|
|
2353
|
-
input
|
|
2354
|
-
);
|
|
2355
|
-
if (!safe) {
|
|
2356
|
-
return [
|
|
2357
|
-
new CapxulError({
|
|
2358
|
-
code: "NOT_FOUND",
|
|
2359
|
-
message: `safe ${input.safeId} not found`
|
|
2360
|
-
}),
|
|
2361
|
-
null
|
|
2362
|
-
];
|
|
2363
|
-
}
|
|
2364
|
-
return [null, safe];
|
|
2365
|
-
} catch (cause) {
|
|
2366
|
-
return [
|
|
2367
|
-
fromConvexError(cause),
|
|
2368
|
-
null
|
|
2369
|
-
];
|
|
2370
|
-
}
|
|
3172
|
+
if (!raw) {
|
|
3173
|
+
return [
|
|
3174
|
+
new CapxulError({
|
|
3175
|
+
code: "NOT_FOUND",
|
|
3176
|
+
message: `sub_account ${input.subAccountId} not found`
|
|
3177
|
+
}),
|
|
3178
|
+
null
|
|
3179
|
+
];
|
|
2371
3180
|
}
|
|
3181
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
3182
|
+
if (brandErr) {
|
|
3183
|
+
return [
|
|
3184
|
+
brandErr,
|
|
3185
|
+
null
|
|
3186
|
+
];
|
|
3187
|
+
}
|
|
3188
|
+
return [null, branded];
|
|
2372
3189
|
},
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
webhookEvents: createWebhookEventsClient()
|
|
2409
|
-
};
|
|
2410
|
-
}
|
|
2411
|
-
|
|
2412
|
-
// src/core/sub-accounts.ts
|
|
2413
|
-
function createSubAccountsClient() {
|
|
2414
|
-
return {
|
|
2415
|
-
retrieve: async () => stub("subAccounts.retrieve"),
|
|
2416
|
-
remove: async () => stub("subAccounts.remove")
|
|
2417
|
-
};
|
|
2418
|
-
}
|
|
2419
|
-
|
|
2420
|
-
// src/core/token-transfers.ts
|
|
2421
|
-
var toTokenTransferId = (raw) => {
|
|
2422
|
-
if (typeof raw !== "string" || raw.length === 0) {
|
|
2423
|
-
throw new Error(
|
|
2424
|
-
`Invalid tokenTransferId: expected non-empty string, got ${String(raw)}`
|
|
2425
|
-
);
|
|
2426
|
-
}
|
|
2427
|
-
return raw;
|
|
2428
|
-
};
|
|
2429
|
-
function brandRow(row) {
|
|
2430
|
-
return {
|
|
2431
|
-
...row,
|
|
2432
|
-
id: toTokenTransferId(row.id)
|
|
3190
|
+
remove: async (input) => {
|
|
3191
|
+
if (!config._data) {
|
|
3192
|
+
return stub(
|
|
3193
|
+
"organizations.subAccounts.remove"
|
|
3194
|
+
);
|
|
3195
|
+
}
|
|
3196
|
+
const [err, raw] = await tryCatch(
|
|
3197
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
3198
|
+
subAccountId: input.subAccountId
|
|
3199
|
+
})
|
|
3200
|
+
);
|
|
3201
|
+
if (err) {
|
|
3202
|
+
return [
|
|
3203
|
+
fromConvexError(err),
|
|
3204
|
+
null
|
|
3205
|
+
];
|
|
3206
|
+
}
|
|
3207
|
+
if (!raw) {
|
|
3208
|
+
return [
|
|
3209
|
+
new CapxulError({
|
|
3210
|
+
code: "NOT_FOUND",
|
|
3211
|
+
message: `sub_account ${input.subAccountId} not found`
|
|
3212
|
+
}),
|
|
3213
|
+
null
|
|
3214
|
+
];
|
|
3215
|
+
}
|
|
3216
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
3217
|
+
if (brandErr) {
|
|
3218
|
+
return [
|
|
3219
|
+
brandErr,
|
|
3220
|
+
null
|
|
3221
|
+
];
|
|
3222
|
+
}
|
|
3223
|
+
return [null, branded];
|
|
3224
|
+
}
|
|
2433
3225
|
};
|
|
2434
3226
|
}
|
|
2435
|
-
function
|
|
3227
|
+
function createOrganizationsClient(config = {}) {
|
|
2436
3228
|
return {
|
|
2437
|
-
|
|
2438
|
-
if (!config.
|
|
2439
|
-
return stub("
|
|
3229
|
+
create: async (input) => {
|
|
3230
|
+
if (!config._data) {
|
|
3231
|
+
return stub("organizations.create");
|
|
3232
|
+
}
|
|
3233
|
+
if (input.country !== void 0) {
|
|
3234
|
+
return [
|
|
3235
|
+
new CapxulError({
|
|
3236
|
+
code: "INVALID_INPUT",
|
|
3237
|
+
message: "organizations.create does not support country yet \u2014 backend mutation only accepts name.",
|
|
3238
|
+
details: { field: "country" }
|
|
3239
|
+
}),
|
|
3240
|
+
null
|
|
3241
|
+
];
|
|
2440
3242
|
}
|
|
2441
3243
|
try {
|
|
2442
|
-
const
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
);
|
|
2450
|
-
if (!raw) {
|
|
3244
|
+
const orgId = await config._data.mutation(api.org.mutations.create, {
|
|
3245
|
+
name: input.name
|
|
3246
|
+
});
|
|
3247
|
+
const org = await config._data.query(api.org.queries.retrieve, {
|
|
3248
|
+
orgId
|
|
3249
|
+
});
|
|
3250
|
+
if (!org) {
|
|
2451
3251
|
return [
|
|
2452
3252
|
new CapxulError({
|
|
2453
|
-
code: "
|
|
2454
|
-
message: "
|
|
3253
|
+
code: "NETWORK_ERROR",
|
|
3254
|
+
message: "organization created but could not be retrieved"
|
|
2455
3255
|
}),
|
|
2456
3256
|
null
|
|
2457
3257
|
];
|
|
2458
3258
|
}
|
|
2459
|
-
return [
|
|
2460
|
-
null,
|
|
2461
|
-
{
|
|
2462
|
-
object: "list",
|
|
2463
|
-
data: raw.items.map(brandRow),
|
|
2464
|
-
page: {
|
|
2465
|
-
hasMore: raw.hasMore,
|
|
2466
|
-
nextCursor: raw.nextCursor
|
|
2467
|
-
},
|
|
2468
|
-
displayCurrency: raw.displayCurrency
|
|
2469
|
-
}
|
|
2470
|
-
];
|
|
3259
|
+
return [null, org];
|
|
2471
3260
|
} catch (cause) {
|
|
2472
3261
|
return [fromConvexError(cause), null];
|
|
2473
3262
|
}
|
|
2474
3263
|
},
|
|
2475
|
-
retrieve: async (
|
|
2476
|
-
if (!config.
|
|
2477
|
-
return stub("
|
|
3264
|
+
retrieve: async (organizationId) => {
|
|
3265
|
+
if (!config._data) {
|
|
3266
|
+
return stub("organizations.retrieve");
|
|
2478
3267
|
}
|
|
2479
3268
|
try {
|
|
2480
|
-
const
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
chainId: input.chainId
|
|
2486
|
-
}
|
|
2487
|
-
);
|
|
2488
|
-
if (!raw) {
|
|
3269
|
+
const orgId = organizationId.replace(/^org_/, "");
|
|
3270
|
+
const org = await config._data.query(api.org.queries.retrieve, {
|
|
3271
|
+
orgId
|
|
3272
|
+
});
|
|
3273
|
+
if (!org) {
|
|
2489
3274
|
return [
|
|
2490
3275
|
new CapxulError({
|
|
2491
3276
|
code: "NOT_FOUND",
|
|
2492
|
-
message: `
|
|
2493
|
-
details: {
|
|
2494
|
-
txHash: input.txHash,
|
|
2495
|
-
logIndex: input.logIndex,
|
|
2496
|
-
chainId: input.chainId
|
|
2497
|
-
}
|
|
3277
|
+
message: `organization ${organizationId} not found`
|
|
2498
3278
|
}),
|
|
2499
3279
|
null
|
|
2500
3280
|
];
|
|
2501
3281
|
}
|
|
2502
|
-
return [null,
|
|
3282
|
+
return [null, org];
|
|
2503
3283
|
} catch (cause) {
|
|
2504
3284
|
return [fromConvexError(cause), null];
|
|
2505
3285
|
}
|
|
2506
|
-
}
|
|
2507
|
-
};
|
|
2508
|
-
}
|
|
2509
|
-
|
|
2510
|
-
// src/core/virtual-accounts.ts
|
|
2511
|
-
function createVirtualAccountsClient() {
|
|
2512
|
-
return {
|
|
2513
|
-
create: async () => stub("virtualAccounts.create"),
|
|
2514
|
-
retrieve: async () => stub("virtualAccounts.retrieve"),
|
|
2515
|
-
list: async () => stub("virtualAccounts.list"),
|
|
2516
|
-
remove: async () => stub("virtualAccounts.remove")
|
|
2517
|
-
};
|
|
2518
|
-
}
|
|
2519
|
-
|
|
2520
|
-
// src/core/virtual-cards.ts
|
|
2521
|
-
function createVirtualCardsClient() {
|
|
2522
|
-
return {
|
|
2523
|
-
create: async () => stub("virtualCards.create"),
|
|
2524
|
-
retrieve: async () => stub("virtualCards.retrieve"),
|
|
2525
|
-
list: async () => stub("virtualCards.list"),
|
|
2526
|
-
freeze: async () => stub("virtualCards.freeze"),
|
|
2527
|
-
unfreeze: async () => stub("virtualCards.unfreeze"),
|
|
2528
|
-
cancel: async () => stub("virtualCards.cancel")
|
|
2529
|
-
};
|
|
2530
|
-
}
|
|
2531
|
-
function createAuthFlowMachine(client) {
|
|
2532
|
-
return xstate.setup({
|
|
2533
|
-
types: {},
|
|
2534
|
-
actors: {
|
|
2535
|
-
// XState v5's `fromPromise` injects an `AbortSignal` that aborts
|
|
2536
|
-
// when the actor is stopped (parent transition fires, machine is
|
|
2537
|
-
// disposed, etc.). Plumbing it through `client.auth.sendOtp` /
|
|
2538
|
-
// `client.auth.verifyOtp` makes the in-flight HTTP request
|
|
2539
|
-
// cancellable: stale responses can't race a state machine
|
|
2540
|
-
// that's already moved on. See PR #406 S5.
|
|
2541
|
-
sendOtp: xstate.fromPromise(async ({ input, signal }) => {
|
|
2542
|
-
const [error] = await client.auth.sendOtp(
|
|
2543
|
-
{ email: input.email },
|
|
2544
|
-
{ signal }
|
|
2545
|
-
);
|
|
2546
|
-
if (error) throw error;
|
|
2547
|
-
}),
|
|
2548
|
-
verifyOtp: xstate.fromPromise(
|
|
2549
|
-
async ({ input, signal }) => {
|
|
2550
|
-
const [error, result] = await client.auth.verifyOtp(
|
|
2551
|
-
{
|
|
2552
|
-
email: input.email,
|
|
2553
|
-
otp: input.code
|
|
2554
|
-
},
|
|
2555
|
-
{ signal }
|
|
2556
|
-
);
|
|
2557
|
-
if (error) throw error;
|
|
2558
|
-
if (result.kind === "bootstrap_required") {
|
|
2559
|
-
throw new CapxulError({
|
|
2560
|
-
code: "ACTION_REQUIRED",
|
|
2561
|
-
message: "OTP verified but auth bootstrap is required. Use createAuthBootstrapFlowMachine for product sign-up.",
|
|
2562
|
-
details: { reason: result.reason }
|
|
2563
|
-
});
|
|
2564
|
-
}
|
|
2565
|
-
return result.session;
|
|
2566
|
-
}
|
|
2567
|
-
),
|
|
2568
|
-
signOut: xstate.fromPromise(async () => {
|
|
2569
|
-
const [error] = await client.auth.signOut();
|
|
2570
|
-
if (error) throw error;
|
|
2571
|
-
})
|
|
2572
3286
|
},
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
track("auth_otp_requested", {
|
|
2577
|
-
email_domain: emailDomain(context.email)
|
|
2578
|
-
});
|
|
2579
|
-
},
|
|
2580
|
-
trackOtpFailed: ({ event }) => {
|
|
2581
|
-
const error = errorFromEvent(event);
|
|
2582
|
-
track("auth_failed", {
|
|
2583
|
-
auth_type: "email_otp",
|
|
2584
|
-
reason: error.code
|
|
2585
|
-
});
|
|
2586
|
-
},
|
|
2587
|
-
trackTimeoutFailed: () => {
|
|
2588
|
-
track("auth_failed", {
|
|
2589
|
-
auth_type: "email_otp",
|
|
2590
|
-
reason: "timeout"
|
|
2591
|
-
});
|
|
2592
|
-
},
|
|
2593
|
-
trackVerified: () => {
|
|
2594
|
-
track("auth_verified", { auth_type: "email_otp" });
|
|
2595
|
-
},
|
|
2596
|
-
identifyAndTrack: ({ context }) => {
|
|
2597
|
-
if (!context.session) return;
|
|
2598
|
-
identify(context.session.authUserId, {
|
|
2599
|
-
email_domain: emailDomain(context.session.email)
|
|
2600
|
-
});
|
|
2601
|
-
track("auth_identified", {
|
|
2602
|
-
email_domain: emailDomain(context.session.email)
|
|
2603
|
-
});
|
|
2604
|
-
},
|
|
2605
|
-
trackSignedOut: () => {
|
|
2606
|
-
track("auth_signed_out");
|
|
3287
|
+
list: async (input) => {
|
|
3288
|
+
if (!config._data) {
|
|
3289
|
+
return stub("organizations.list");
|
|
2607
3290
|
}
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
email: ({ event }) => event.email,
|
|
2620
|
-
error: () => null
|
|
2621
|
-
})
|
|
2622
|
-
}
|
|
2623
|
-
}
|
|
2624
|
-
},
|
|
2625
|
-
sending_otp: {
|
|
2626
|
-
invoke: {
|
|
2627
|
-
src: "sendOtp",
|
|
2628
|
-
input: ({ context }) => ({ email: requireEmail(context) }),
|
|
2629
|
-
onDone: {
|
|
2630
|
-
target: "otp_requested",
|
|
2631
|
-
actions: ["trackOtpRequested"]
|
|
2632
|
-
},
|
|
2633
|
-
onError: {
|
|
2634
|
-
target: "error",
|
|
2635
|
-
actions: [
|
|
2636
|
-
xstate.assign({ error: ({ event }) => errorFromEvent(event) }),
|
|
2637
|
-
"trackOtpFailed"
|
|
2638
|
-
]
|
|
2639
|
-
}
|
|
2640
|
-
},
|
|
2641
|
-
after: {
|
|
2642
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2643
|
-
target: "error",
|
|
2644
|
-
actions: [
|
|
2645
|
-
xstate.assign({
|
|
2646
|
-
error: () => timeoutError("sending_otp")
|
|
2647
|
-
}),
|
|
2648
|
-
"trackTimeoutFailed"
|
|
2649
|
-
]
|
|
3291
|
+
try {
|
|
3292
|
+
const page = await config._data.query(api.org.queries.list, {
|
|
3293
|
+
limit: input?.limit,
|
|
3294
|
+
cursor: input?.cursor
|
|
3295
|
+
});
|
|
3296
|
+
const result = {
|
|
3297
|
+
object: "list",
|
|
3298
|
+
data: page.data,
|
|
3299
|
+
page: {
|
|
3300
|
+
hasMore: page.hasMore,
|
|
3301
|
+
cursor: page.nextCursor
|
|
2650
3302
|
}
|
|
3303
|
+
};
|
|
3304
|
+
return [null, result];
|
|
3305
|
+
} catch (cause) {
|
|
3306
|
+
return [fromConvexError(cause), null];
|
|
3307
|
+
}
|
|
3308
|
+
},
|
|
3309
|
+
update: async (input) => {
|
|
3310
|
+
if (!config._data) {
|
|
3311
|
+
return stub("organizations.update");
|
|
3312
|
+
}
|
|
3313
|
+
try {
|
|
3314
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3315
|
+
const org = await config._data.mutation(api.org.mutations.update, {
|
|
3316
|
+
orgId,
|
|
3317
|
+
name: input.name
|
|
3318
|
+
});
|
|
3319
|
+
if (!org) {
|
|
3320
|
+
return [
|
|
3321
|
+
new CapxulError({
|
|
3322
|
+
code: "NOT_FOUND",
|
|
3323
|
+
message: `organization ${input.organizationId} not found`
|
|
3324
|
+
}),
|
|
3325
|
+
null
|
|
3326
|
+
];
|
|
2651
3327
|
}
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
3328
|
+
return [null, org];
|
|
3329
|
+
} catch (cause) {
|
|
3330
|
+
return [fromConvexError(cause), null];
|
|
3331
|
+
}
|
|
3332
|
+
},
|
|
3333
|
+
safes: {
|
|
3334
|
+
retrieve: async (input) => {
|
|
3335
|
+
if (!config._data) {
|
|
3336
|
+
return stub("organizations.safes.retrieve");
|
|
2660
3337
|
}
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
actions: [
|
|
2672
|
-
// Scrub the duplicate `context.email` (input value
|
|
2673
|
-
// captured during sendOtp) since the verified
|
|
2674
|
-
// `session.email` is now the canonical source
|
|
2675
|
-
// post-authentication. The session's email is
|
|
2676
|
-
// intentionally retained — it's the auth result, not
|
|
2677
|
-
// lingering input. See PR #406 S2.
|
|
2678
|
-
xstate.assign({
|
|
2679
|
-
session: ({ event }) => event.output,
|
|
2680
|
-
email: () => null
|
|
2681
|
-
}),
|
|
2682
|
-
"trackVerified",
|
|
2683
|
-
"identifyAndTrack"
|
|
2684
|
-
]
|
|
2685
|
-
},
|
|
2686
|
-
onError: {
|
|
2687
|
-
target: "error",
|
|
2688
|
-
actions: [
|
|
2689
|
-
xstate.assign({ error: ({ event }) => errorFromEvent(event) }),
|
|
2690
|
-
"trackOtpFailed"
|
|
2691
|
-
]
|
|
2692
|
-
}
|
|
2693
|
-
},
|
|
2694
|
-
after: {
|
|
2695
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2696
|
-
target: "error",
|
|
2697
|
-
actions: [
|
|
2698
|
-
xstate.assign({
|
|
2699
|
-
error: () => timeoutError("verifying")
|
|
3338
|
+
try {
|
|
3339
|
+
const safe = await config._data.query(
|
|
3340
|
+
api.safe.queries.retrieveOrganizationSafe,
|
|
3341
|
+
input
|
|
3342
|
+
);
|
|
3343
|
+
if (!safe) {
|
|
3344
|
+
return [
|
|
3345
|
+
new CapxulError({
|
|
3346
|
+
code: "NOT_FOUND",
|
|
3347
|
+
message: `safe ${input.safeId} not found`
|
|
2700
3348
|
}),
|
|
2701
|
-
|
|
2702
|
-
]
|
|
3349
|
+
null
|
|
3350
|
+
];
|
|
2703
3351
|
}
|
|
3352
|
+
return [null, safe];
|
|
3353
|
+
} catch (cause) {
|
|
3354
|
+
return [
|
|
3355
|
+
fromConvexError(cause),
|
|
3356
|
+
null
|
|
3357
|
+
];
|
|
2704
3358
|
}
|
|
2705
|
-
}
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
3359
|
+
}
|
|
3360
|
+
},
|
|
3361
|
+
treasury: {
|
|
3362
|
+
retrieve: async (organizationId) => {
|
|
3363
|
+
if (!config._data) {
|
|
3364
|
+
return stub(
|
|
3365
|
+
"organizations.treasury.retrieve"
|
|
3366
|
+
);
|
|
2709
3367
|
}
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
3368
|
+
try {
|
|
3369
|
+
const orgId = organizationId.replace(/^org_/, "");
|
|
3370
|
+
const raw = await config._data.query(
|
|
3371
|
+
api.safe.queries.getOrgTreasuryBalance,
|
|
3372
|
+
{ orgId }
|
|
3373
|
+
);
|
|
3374
|
+
if (!raw) {
|
|
3375
|
+
return [
|
|
3376
|
+
new CapxulError({
|
|
3377
|
+
code: "NOT_FOUND",
|
|
3378
|
+
message: `treasury for organization ${organizationId} not found`
|
|
2721
3379
|
}),
|
|
2722
|
-
|
|
2723
|
-
]
|
|
2724
|
-
},
|
|
2725
|
-
onError: {
|
|
2726
|
-
target: "error",
|
|
2727
|
-
actions: xstate.assign({ error: ({ event }) => errorFromEvent(event) })
|
|
2728
|
-
}
|
|
2729
|
-
}
|
|
2730
|
-
},
|
|
2731
|
-
error: {
|
|
2732
|
-
on: {
|
|
2733
|
-
RESET: {
|
|
2734
|
-
target: "idle",
|
|
2735
|
-
actions: xstate.assign({ error: () => null })
|
|
3380
|
+
null
|
|
3381
|
+
];
|
|
2736
3382
|
}
|
|
3383
|
+
const treasury = {
|
|
3384
|
+
object: "treasury",
|
|
3385
|
+
id: toTreasuryId(`try_${orgId}`),
|
|
3386
|
+
organizationId,
|
|
3387
|
+
status: "active",
|
|
3388
|
+
safeId: toSafeId(
|
|
3389
|
+
`safe_${raw.safeAddress.replace(/^0x/, "").toLowerCase()}`
|
|
3390
|
+
),
|
|
3391
|
+
totalBalance: { value: "0", currency: "USD" },
|
|
3392
|
+
positions: raw.tokens.map((t) => ({
|
|
3393
|
+
symbol: t.symbol,
|
|
3394
|
+
contractAddress: t.tokenAddress,
|
|
3395
|
+
amount: t.balance
|
|
3396
|
+
})),
|
|
3397
|
+
asOf: raw.lastUpdatedAt ? new Date(raw.lastUpdatedAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
3398
|
+
};
|
|
3399
|
+
return [null, treasury];
|
|
3400
|
+
} catch (cause) {
|
|
3401
|
+
return [
|
|
3402
|
+
fromConvexError(cause),
|
|
3403
|
+
null
|
|
3404
|
+
];
|
|
2737
3405
|
}
|
|
2738
3406
|
}
|
|
2739
|
-
}
|
|
2740
|
-
});
|
|
2741
|
-
}
|
|
2742
|
-
function requireEmail(context) {
|
|
2743
|
-
if (!context.email) {
|
|
2744
|
-
throw Errors.invalidInput(
|
|
2745
|
-
"email",
|
|
2746
|
-
"Auth flow advanced without an email captured in context."
|
|
2747
|
-
);
|
|
2748
|
-
}
|
|
2749
|
-
return context.email;
|
|
2750
|
-
}
|
|
2751
|
-
function requireCodeFromEvent(event) {
|
|
2752
|
-
if (event.type !== "VERIFY") {
|
|
2753
|
-
throw Errors.invalidInput(
|
|
2754
|
-
"code",
|
|
2755
|
-
`Auth flow's verifying state requires a VERIFY event, got ${event.type}.`
|
|
2756
|
-
);
|
|
2757
|
-
}
|
|
2758
|
-
return event.code;
|
|
2759
|
-
}
|
|
2760
|
-
function errorFromEvent(event) {
|
|
2761
|
-
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
2762
|
-
if (cause instanceof CapxulError) {
|
|
2763
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
2764
|
-
return new CapxulError({
|
|
2765
|
-
code: cause.code,
|
|
2766
|
-
message: redactEmail(cause.message),
|
|
2767
|
-
cause,
|
|
2768
|
-
details: cause.details,
|
|
2769
|
-
operationId: cause.operationId,
|
|
2770
|
-
correlationId: cause.correlationId,
|
|
2771
|
-
retryable: cause.retryable
|
|
2772
|
-
});
|
|
2773
|
-
}
|
|
2774
|
-
if (cause instanceof CapxulError2) {
|
|
2775
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
2776
|
-
return new CapxulError2(cause.code, redactEmail(cause.message), {
|
|
2777
|
-
cause,
|
|
2778
|
-
details: cause.details,
|
|
2779
|
-
correlationId: cause.correlationId,
|
|
2780
|
-
layer: cause.layer
|
|
2781
|
-
});
|
|
2782
|
-
}
|
|
2783
|
-
return Errors.providerError("auth", "flow", redactCauseEmail(cause));
|
|
2784
|
-
}
|
|
2785
|
-
var EMAIL_MATCH_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
|
|
2786
|
-
var EMAIL_REDACT_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
|
|
2787
|
-
function redactEmail(message) {
|
|
2788
|
-
return message.replace(EMAIL_REDACT_PATTERN, "<redacted>");
|
|
2789
|
-
}
|
|
2790
|
-
function redactCauseEmail(cause) {
|
|
2791
|
-
if (cause instanceof Error) {
|
|
2792
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
2793
|
-
const redacted = new Error(redactEmail(cause.message));
|
|
2794
|
-
redacted.cause = cause;
|
|
2795
|
-
return redacted;
|
|
2796
|
-
}
|
|
2797
|
-
if (typeof cause === "string") {
|
|
2798
|
-
return redactEmail(cause);
|
|
2799
|
-
}
|
|
2800
|
-
return cause;
|
|
2801
|
-
}
|
|
2802
|
-
function timeoutError(state) {
|
|
2803
|
-
return Errors.providerError(
|
|
2804
|
-
"auth",
|
|
2805
|
-
"flow",
|
|
2806
|
-
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
2807
|
-
);
|
|
2808
|
-
}
|
|
2809
|
-
function emailDomain(email) {
|
|
2810
|
-
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
2811
|
-
return domain || "unknown";
|
|
2812
|
-
}
|
|
2813
|
-
var initialContext = {
|
|
2814
|
-
email: null,
|
|
2815
|
-
code: null,
|
|
2816
|
-
username: null,
|
|
2817
|
-
signerProvider: null,
|
|
2818
|
-
bootstrapToken: null,
|
|
2819
|
-
bootstrapReason: null,
|
|
2820
|
-
session: null,
|
|
2821
|
-
account: null,
|
|
2822
|
-
safe: null,
|
|
2823
|
-
error: null
|
|
2824
|
-
};
|
|
2825
|
-
function createAuthBootstrapFlowMachine(client) {
|
|
2826
|
-
return xstate.setup({
|
|
2827
|
-
types: {},
|
|
2828
|
-
actors: {
|
|
2829
|
-
sendOtp: xstate.fromPromise(async ({ input, signal }) => {
|
|
2830
|
-
const [error] = await client.auth.sendOtp(
|
|
2831
|
-
{ email: input.email },
|
|
2832
|
-
{ signal }
|
|
2833
|
-
);
|
|
2834
|
-
if (error) throw error;
|
|
2835
|
-
}),
|
|
2836
|
-
verifyOtp: xstate.fromPromise(
|
|
2837
|
-
async ({ input, signal }) => {
|
|
2838
|
-
const [error, result] = await client.auth.verifyOtp(
|
|
2839
|
-
{ email: input.email, otp: input.code },
|
|
2840
|
-
{ signal }
|
|
2841
|
-
);
|
|
2842
|
-
if (error) throw error;
|
|
2843
|
-
return result;
|
|
2844
|
-
}
|
|
2845
|
-
),
|
|
2846
|
-
completeBootstrap: xstate.fromPromise(async ({ input }) => {
|
|
2847
|
-
const [error, result] = await client.auth.completeBootstrap(input);
|
|
2848
|
-
if (error) throw error;
|
|
2849
|
-
return result;
|
|
2850
|
-
}),
|
|
2851
|
-
signOut: xstate.fromPromise(async () => {
|
|
2852
|
-
const [error] = await client.auth.signOut();
|
|
2853
|
-
if (error) throw error;
|
|
2854
|
-
})
|
|
2855
3407
|
},
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
if (!
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
});
|
|
2874
|
-
},
|
|
2875
|
-
trackVerified: () => {
|
|
2876
|
-
track("auth_verified", { auth_type: "email_otp" });
|
|
2877
|
-
},
|
|
2878
|
-
trackBootstrapRequired: ({ context }) => {
|
|
2879
|
-
track("auth_verified", {
|
|
2880
|
-
auth_type: "email_otp",
|
|
2881
|
-
auth_mode: context.bootstrapReason ?? "bootstrap_required"
|
|
2882
|
-
});
|
|
2883
|
-
},
|
|
2884
|
-
identifyAndTrack: ({ context }) => {
|
|
2885
|
-
if (!context.session) return;
|
|
2886
|
-
identify(context.session.authUserId, {
|
|
2887
|
-
email_domain: emailDomain2(context.session.email)
|
|
2888
|
-
});
|
|
2889
|
-
track("auth_identified", {
|
|
2890
|
-
email_domain: emailDomain2(context.session.email)
|
|
2891
|
-
});
|
|
3408
|
+
members: {
|
|
3409
|
+
list: async (input) => {
|
|
3410
|
+
if (!config._data?.action) {
|
|
3411
|
+
return stub("organizations.members.list");
|
|
3412
|
+
}
|
|
3413
|
+
try {
|
|
3414
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3415
|
+
const page = await config._data.action(api.org.actions.membersList, {
|
|
3416
|
+
organizationId: orgId,
|
|
3417
|
+
status: input.status,
|
|
3418
|
+
limit: input.limit,
|
|
3419
|
+
cursor: input.cursor
|
|
3420
|
+
});
|
|
3421
|
+
return [null, page];
|
|
3422
|
+
} catch (cause) {
|
|
3423
|
+
return [fromConvexError(cause), null];
|
|
3424
|
+
}
|
|
2892
3425
|
},
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
REQUEST_OTP: { target: "sending_otp" }
|
|
3426
|
+
retrieve: async (input) => {
|
|
3427
|
+
if (!config._data?.action) {
|
|
3428
|
+
return stub("organizations.members.retrieve");
|
|
3429
|
+
}
|
|
3430
|
+
try {
|
|
3431
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3432
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3433
|
+
const member = await config._data.action(
|
|
3434
|
+
api.org.actions.retrieveMember,
|
|
3435
|
+
{
|
|
3436
|
+
organizationId: orgId,
|
|
3437
|
+
memberId
|
|
3438
|
+
}
|
|
3439
|
+
);
|
|
3440
|
+
return [null, member];
|
|
3441
|
+
} catch (cause) {
|
|
3442
|
+
return [fromConvexError(cause), null];
|
|
2911
3443
|
}
|
|
2912
3444
|
},
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
]
|
|
2933
|
-
}
|
|
3445
|
+
invite: async (input) => {
|
|
3446
|
+
if (!config._data?.action) {
|
|
3447
|
+
return stub(
|
|
3448
|
+
"organizations.members.invite"
|
|
3449
|
+
);
|
|
3450
|
+
}
|
|
3451
|
+
try {
|
|
3452
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3453
|
+
const result = await config._data.action(
|
|
3454
|
+
api.org.actions.inviteMember,
|
|
3455
|
+
{
|
|
3456
|
+
organizationId: orgId,
|
|
3457
|
+
email: input.email,
|
|
3458
|
+
role: input.role
|
|
3459
|
+
}
|
|
3460
|
+
);
|
|
3461
|
+
return [null, result];
|
|
3462
|
+
} catch (cause) {
|
|
3463
|
+
return [fromConvexError(cause), null];
|
|
2934
3464
|
}
|
|
2935
3465
|
},
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
3466
|
+
accept: async (input) => {
|
|
3467
|
+
if (!config._data?.action) {
|
|
3468
|
+
return stub("organizations.members.accept");
|
|
3469
|
+
}
|
|
3470
|
+
try {
|
|
3471
|
+
const member = await config._data.action(
|
|
3472
|
+
api.org.actions.acceptInvitation,
|
|
3473
|
+
{ token: input.token }
|
|
3474
|
+
);
|
|
3475
|
+
return [null, member];
|
|
3476
|
+
} catch (cause) {
|
|
3477
|
+
return [fromConvexError(cause), null];
|
|
2947
3478
|
}
|
|
2948
3479
|
},
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
guard: ({ event }) => event.output.kind === "existing_member",
|
|
2959
|
-
target: "authenticated",
|
|
2960
|
-
actions: [
|
|
2961
|
-
xstate.assign({
|
|
2962
|
-
session: ({ event }) => event.output.session,
|
|
2963
|
-
account: ({ event }) => event.output.kind === "existing_member" ? event.output.account : null,
|
|
2964
|
-
username: ({ event }) => event.output.kind === "existing_member" ? event.output.username : null,
|
|
2965
|
-
safe: ({ event }) => event.output.kind === "existing_member" ? event.output.safe : null,
|
|
2966
|
-
email: () => null,
|
|
2967
|
-
error: () => null
|
|
2968
|
-
}),
|
|
2969
|
-
"trackVerified",
|
|
2970
|
-
"identifyAndTrack"
|
|
2971
|
-
]
|
|
2972
|
-
},
|
|
3480
|
+
updateRole: async (input) => {
|
|
3481
|
+
if (!config._data?.action) {
|
|
3482
|
+
return stub("organizations.members.updateRole");
|
|
3483
|
+
}
|
|
3484
|
+
try {
|
|
3485
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3486
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3487
|
+
const member = await config._data.action(
|
|
3488
|
+
api.org.actions.updateMemberRole,
|
|
2973
3489
|
{
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
session: ({ event }) => event.output.session,
|
|
2978
|
-
bootstrapToken: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.bootstrapToken : null,
|
|
2979
|
-
bootstrapReason: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.reason : null,
|
|
2980
|
-
username: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.username ?? null : null,
|
|
2981
|
-
email: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.email : null,
|
|
2982
|
-
error: () => null
|
|
2983
|
-
}),
|
|
2984
|
-
"trackVerified",
|
|
2985
|
-
"trackBootstrapRequired"
|
|
2986
|
-
]
|
|
3490
|
+
organizationId: orgId,
|
|
3491
|
+
memberId,
|
|
3492
|
+
role: input.role
|
|
2987
3493
|
}
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
xstate.assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
2993
|
-
"trackFailed"
|
|
2994
|
-
]
|
|
2995
|
-
}
|
|
2996
|
-
},
|
|
2997
|
-
after: {
|
|
2998
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2999
|
-
target: "otp_requested",
|
|
3000
|
-
actions: [
|
|
3001
|
-
xstate.assign({ error: () => timeoutError2("verifying_otp") }),
|
|
3002
|
-
"trackTimeoutFailed"
|
|
3003
|
-
]
|
|
3004
|
-
}
|
|
3494
|
+
);
|
|
3495
|
+
return [null, member];
|
|
3496
|
+
} catch (cause) {
|
|
3497
|
+
return [fromConvexError(cause), null];
|
|
3005
3498
|
}
|
|
3006
3499
|
},
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
actions: xstate.assign({
|
|
3011
|
-
username: ({ event }) => event.username,
|
|
3012
|
-
error: () => null
|
|
3013
|
-
})
|
|
3014
|
-
},
|
|
3015
|
-
ENTER_SIGNER_PROVIDER: {
|
|
3016
|
-
actions: xstate.assign({
|
|
3017
|
-
signerProvider: ({ event }) => event.signerProvider,
|
|
3018
|
-
error: () => null
|
|
3019
|
-
})
|
|
3020
|
-
},
|
|
3021
|
-
COMPLETE_BOOTSTRAP: { target: "completing_bootstrap" },
|
|
3022
|
-
BACK: { target: "otp_requested" },
|
|
3023
|
-
RESET: { target: "email", actions: xstate.assign(() => initialContext) }
|
|
3500
|
+
revoke: async (input) => {
|
|
3501
|
+
if (!config._data?.action) {
|
|
3502
|
+
return stub("organizations.members.revoke");
|
|
3024
3503
|
}
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
session: ({ event }) => event.output.session,
|
|
3039
|
-
account: ({ event }) => event.output.account,
|
|
3040
|
-
username: ({ event }) => event.output.username,
|
|
3041
|
-
safe: ({ event }) => event.output.safe,
|
|
3042
|
-
bootstrapToken: () => null,
|
|
3043
|
-
bootstrapReason: () => null,
|
|
3044
|
-
signerProvider: () => null,
|
|
3045
|
-
email: () => null,
|
|
3046
|
-
error: () => null
|
|
3047
|
-
}),
|
|
3048
|
-
"identifyAndTrack"
|
|
3049
|
-
]
|
|
3050
|
-
},
|
|
3051
|
-
onError: {
|
|
3052
|
-
target: "bootstrap_required",
|
|
3053
|
-
actions: [
|
|
3054
|
-
xstate.assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3055
|
-
"trackFailed"
|
|
3056
|
-
]
|
|
3057
|
-
}
|
|
3058
|
-
},
|
|
3059
|
-
after: {
|
|
3060
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3061
|
-
target: "bootstrap_required",
|
|
3062
|
-
actions: [
|
|
3063
|
-
xstate.assign({ error: () => timeoutError2("completing_bootstrap") }),
|
|
3064
|
-
"trackTimeoutFailed"
|
|
3065
|
-
]
|
|
3066
|
-
}
|
|
3504
|
+
try {
|
|
3505
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3506
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3507
|
+
const member = await config._data.action(
|
|
3508
|
+
api.org.actions.revokeMember,
|
|
3509
|
+
{
|
|
3510
|
+
organizationId: orgId,
|
|
3511
|
+
memberId
|
|
3512
|
+
}
|
|
3513
|
+
);
|
|
3514
|
+
return [null, member];
|
|
3515
|
+
} catch (cause) {
|
|
3516
|
+
return [fromConvexError(cause), null];
|
|
3067
3517
|
}
|
|
3068
3518
|
},
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3519
|
+
remove: async (input) => {
|
|
3520
|
+
if (!config._data?.action) {
|
|
3521
|
+
return stub("organizations.members.remove");
|
|
3522
|
+
}
|
|
3523
|
+
try {
|
|
3524
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3525
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3526
|
+
await config._data.action(api.org.actions.removeMember, {
|
|
3527
|
+
organizationId: orgId,
|
|
3528
|
+
memberId
|
|
3529
|
+
});
|
|
3530
|
+
return [null, void 0];
|
|
3531
|
+
} catch (cause) {
|
|
3532
|
+
return [fromConvexError(cause), null];
|
|
3072
3533
|
}
|
|
3073
3534
|
},
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3535
|
+
resend: async (input) => {
|
|
3536
|
+
if (!config._data?.action) {
|
|
3537
|
+
return stub(
|
|
3538
|
+
"organizations.members.resend"
|
|
3539
|
+
);
|
|
3540
|
+
}
|
|
3541
|
+
try {
|
|
3542
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3543
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3544
|
+
const result = await config._data.action(
|
|
3545
|
+
api.org.actions.resendInvitation,
|
|
3546
|
+
{
|
|
3547
|
+
organizationId: orgId,
|
|
3548
|
+
memberId
|
|
3549
|
+
}
|
|
3550
|
+
);
|
|
3551
|
+
return [null, result];
|
|
3552
|
+
} catch (cause) {
|
|
3553
|
+
return [fromConvexError(cause), null];
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
},
|
|
3557
|
+
apiKeys: createApiKeysClient(),
|
|
3558
|
+
subAccounts: createOrgSubAccountsClient(config),
|
|
3559
|
+
externalAccounts: createOrgExternalAccountsClient(config),
|
|
3560
|
+
balanceLedger: {
|
|
3561
|
+
list: async (input) => {
|
|
3562
|
+
if (!config._data) {
|
|
3563
|
+
return stub(
|
|
3564
|
+
"organizations.balanceLedger.list"
|
|
3565
|
+
);
|
|
3566
|
+
}
|
|
3567
|
+
try {
|
|
3568
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3569
|
+
const page = await config._data.query(
|
|
3570
|
+
api.balanceLedger.queries.listForOrg,
|
|
3571
|
+
{ orgId, limit: input.limit, cursor: input.cursor }
|
|
3572
|
+
);
|
|
3573
|
+
return [null, page];
|
|
3574
|
+
} catch (cause) {
|
|
3575
|
+
return [fromConvexError(cause), null];
|
|
3088
3576
|
}
|
|
3089
3577
|
},
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3578
|
+
retrieve: async (input) => {
|
|
3579
|
+
if (!config._data) {
|
|
3580
|
+
return stub(
|
|
3581
|
+
"organizations.balanceLedger.retrieve"
|
|
3582
|
+
);
|
|
3583
|
+
}
|
|
3584
|
+
try {
|
|
3585
|
+
const entry = await config._data.query(
|
|
3586
|
+
api.balanceLedger.queries.retrieve,
|
|
3587
|
+
{ entryId: input.entryId }
|
|
3588
|
+
);
|
|
3589
|
+
if (!entry) {
|
|
3590
|
+
return [
|
|
3591
|
+
new CapxulError({
|
|
3592
|
+
code: "NOT_FOUND",
|
|
3593
|
+
message: `balance_ledger_entry ${input.entryId} not found`
|
|
3594
|
+
}),
|
|
3595
|
+
null
|
|
3596
|
+
];
|
|
3597
|
+
}
|
|
3598
|
+
return [null, entry];
|
|
3599
|
+
} catch (cause) {
|
|
3600
|
+
return [fromConvexError(cause), null];
|
|
3093
3601
|
}
|
|
3094
3602
|
}
|
|
3095
|
-
}
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
}
|
|
3104
|
-
function requireCode(context) {
|
|
3105
|
-
if (!context.code) {
|
|
3106
|
-
throw Errors.invalidInput("code", "Auth bootstrap requires an OTP code.");
|
|
3107
|
-
}
|
|
3108
|
-
return context.code;
|
|
3109
|
-
}
|
|
3110
|
-
function requireBootstrapToken(context) {
|
|
3111
|
-
if (!context.bootstrapToken) {
|
|
3112
|
-
throw Errors.invalidInput(
|
|
3113
|
-
"bootstrapToken",
|
|
3114
|
-
"Auth bootstrap requires a continuation token."
|
|
3115
|
-
);
|
|
3116
|
-
}
|
|
3117
|
-
return context.bootstrapToken;
|
|
3118
|
-
}
|
|
3119
|
-
function requireUsername(context) {
|
|
3120
|
-
if (!context.username) {
|
|
3121
|
-
throw Errors.invalidInput("username", "Auth bootstrap requires a username.");
|
|
3122
|
-
}
|
|
3123
|
-
return context.username;
|
|
3603
|
+
},
|
|
3604
|
+
payments: createOrgPaymentsClient(),
|
|
3605
|
+
transfers: createOrgTransfersClient(),
|
|
3606
|
+
withdrawals: createOrgWithdrawalsClient(config),
|
|
3607
|
+
documents: createOrgDocumentsClient(config),
|
|
3608
|
+
webhookEndpoints: createWebhookEndpointsClient(),
|
|
3609
|
+
webhookEvents: createWebhookEventsClient()
|
|
3610
|
+
};
|
|
3124
3611
|
}
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3612
|
+
|
|
3613
|
+
// src/core/token-transfers.ts
|
|
3614
|
+
var toTokenTransferId = (raw) => {
|
|
3615
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
3616
|
+
throw new Error(
|
|
3617
|
+
`Invalid tokenTransferId: expected non-empty string, got ${String(raw)}`
|
|
3130
3618
|
);
|
|
3131
3619
|
}
|
|
3132
|
-
return
|
|
3620
|
+
return raw;
|
|
3621
|
+
};
|
|
3622
|
+
function brandRow(row) {
|
|
3623
|
+
return {
|
|
3624
|
+
...row,
|
|
3625
|
+
id: toTokenTransferId(row.id)
|
|
3626
|
+
};
|
|
3133
3627
|
}
|
|
3134
|
-
function
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3628
|
+
function createTokenTransfersClient(config = {}) {
|
|
3629
|
+
return {
|
|
3630
|
+
list: async (input) => {
|
|
3631
|
+
if (!config._data) {
|
|
3632
|
+
return stub("tokenTransfers.list");
|
|
3633
|
+
}
|
|
3634
|
+
try {
|
|
3635
|
+
const raw = await config._data.query(
|
|
3636
|
+
api.tokenTransfers.queries.list,
|
|
3637
|
+
{
|
|
3638
|
+
limit: input?.limit,
|
|
3639
|
+
cursor: input?.cursor,
|
|
3640
|
+
direction: input?.direction
|
|
3641
|
+
}
|
|
3642
|
+
);
|
|
3643
|
+
if (!raw) {
|
|
3644
|
+
return [
|
|
3645
|
+
new CapxulError({
|
|
3646
|
+
code: "NOT_AUTHENTICATED",
|
|
3647
|
+
message: "tokenTransfers.list requires an authenticated session."
|
|
3648
|
+
}),
|
|
3649
|
+
null
|
|
3650
|
+
];
|
|
3651
|
+
}
|
|
3652
|
+
return [
|
|
3653
|
+
null,
|
|
3654
|
+
{
|
|
3655
|
+
object: "list",
|
|
3656
|
+
data: raw.items.map(brandRow),
|
|
3657
|
+
page: {
|
|
3658
|
+
hasMore: raw.hasMore,
|
|
3659
|
+
nextCursor: raw.nextCursor
|
|
3660
|
+
},
|
|
3661
|
+
displayCurrency: raw.displayCurrency
|
|
3662
|
+
}
|
|
3663
|
+
];
|
|
3664
|
+
} catch (cause) {
|
|
3665
|
+
return [fromConvexError(cause), null];
|
|
3666
|
+
}
|
|
3667
|
+
},
|
|
3668
|
+
retrieve: async (input) => {
|
|
3669
|
+
if (!config._data) {
|
|
3670
|
+
return stub("tokenTransfers.retrieve");
|
|
3671
|
+
}
|
|
3672
|
+
try {
|
|
3673
|
+
const raw = await config._data.query(
|
|
3674
|
+
api.tokenTransfers.queries.getByTxLogIndex,
|
|
3675
|
+
{
|
|
3676
|
+
txHash: input.txHash,
|
|
3677
|
+
logIndex: input.logIndex,
|
|
3678
|
+
chainId: input.chainId
|
|
3679
|
+
}
|
|
3680
|
+
);
|
|
3681
|
+
if (!raw) {
|
|
3682
|
+
return [
|
|
3683
|
+
new CapxulError({
|
|
3684
|
+
code: "NOT_FOUND",
|
|
3685
|
+
message: `tokenTransfer (txHash=${input.txHash}, logIndex=${input.logIndex}) not found or not visible to caller.`,
|
|
3686
|
+
details: {
|
|
3687
|
+
txHash: input.txHash,
|
|
3688
|
+
logIndex: input.logIndex,
|
|
3689
|
+
chainId: input.chainId
|
|
3690
|
+
}
|
|
3691
|
+
}),
|
|
3692
|
+
null
|
|
3693
|
+
];
|
|
3694
|
+
}
|
|
3695
|
+
return [null, brandRow(raw)];
|
|
3696
|
+
} catch (cause) {
|
|
3697
|
+
return [fromConvexError(cause), null];
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
};
|
|
3140
3701
|
}
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3702
|
+
|
|
3703
|
+
// src/core/virtual-accounts.ts
|
|
3704
|
+
function createVirtualAccountsClient() {
|
|
3705
|
+
return {
|
|
3706
|
+
create: async () => stub("virtualAccounts.create"),
|
|
3707
|
+
retrieve: async () => stub("virtualAccounts.retrieve"),
|
|
3708
|
+
list: async () => stub("virtualAccounts.list"),
|
|
3709
|
+
remove: async () => stub("virtualAccounts.remove")
|
|
3710
|
+
};
|
|
3147
3711
|
}
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3712
|
+
|
|
3713
|
+
// src/core/virtual-cards.ts
|
|
3714
|
+
function createVirtualCardsClient() {
|
|
3715
|
+
return {
|
|
3716
|
+
create: async () => stub("virtualCards.create"),
|
|
3717
|
+
retrieve: async () => stub("virtualCards.retrieve"),
|
|
3718
|
+
list: async () => stub("virtualCards.list"),
|
|
3719
|
+
freeze: async () => stub("virtualCards.freeze"),
|
|
3720
|
+
unfreeze: async () => stub("virtualCards.unfreeze"),
|
|
3721
|
+
cancel: async () => stub("virtualCards.cancel")
|
|
3722
|
+
};
|
|
3151
3723
|
}
|
|
3152
3724
|
function createProvisioningMachine(client) {
|
|
3153
3725
|
return xstate.setup({
|
|
@@ -3176,7 +3748,7 @@ function createProvisioningMachine(client) {
|
|
|
3176
3748
|
const provider = context.input?.signerProvider;
|
|
3177
3749
|
if (!provider) return;
|
|
3178
3750
|
track("provisioning_safe_created", {
|
|
3179
|
-
safe_address: provider.
|
|
3751
|
+
safe_address: deriveSafeAddress2(provider.signerAddress)
|
|
3180
3752
|
});
|
|
3181
3753
|
}
|
|
3182
3754
|
}
|
|
@@ -3221,13 +3793,13 @@ function createProvisioningMachine(client) {
|
|
|
3221
3793
|
},
|
|
3222
3794
|
onError: {
|
|
3223
3795
|
target: "error",
|
|
3224
|
-
actions: xstate.assign({ error: ({ event }) =>
|
|
3796
|
+
actions: xstate.assign({ error: ({ event }) => errorFromEvent(event) })
|
|
3225
3797
|
}
|
|
3226
3798
|
},
|
|
3227
3799
|
after: {
|
|
3228
3800
|
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3229
3801
|
target: "error",
|
|
3230
|
-
actions: xstate.assign({ error: () =>
|
|
3802
|
+
actions: xstate.assign({ error: () => timeoutError() })
|
|
3231
3803
|
}
|
|
3232
3804
|
}
|
|
3233
3805
|
},
|
|
@@ -3245,7 +3817,7 @@ function createProvisioningMachine(client) {
|
|
|
3245
3817
|
* this payload on its `onDone` transition and branches via guards
|
|
3246
3818
|
* on `event.output.error`.
|
|
3247
3819
|
*/
|
|
3248
|
-
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error:
|
|
3820
|
+
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error: timeoutError() }
|
|
3249
3821
|
});
|
|
3250
3822
|
}
|
|
3251
3823
|
function requireProvisionInput(context) {
|
|
@@ -3257,13 +3829,13 @@ function requireProvisionInput(context) {
|
|
|
3257
3829
|
}
|
|
3258
3830
|
return context.input;
|
|
3259
3831
|
}
|
|
3260
|
-
function
|
|
3832
|
+
function errorFromEvent(event) {
|
|
3261
3833
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3262
3834
|
if (cause instanceof CapxulError) return cause;
|
|
3263
3835
|
if (cause instanceof CapxulError2) return cause;
|
|
3264
3836
|
return Errors.providerError("provisioning", "flow", cause);
|
|
3265
3837
|
}
|
|
3266
|
-
function
|
|
3838
|
+
function timeoutError() {
|
|
3267
3839
|
return Errors.providerError(
|
|
3268
3840
|
"provisioning",
|
|
3269
3841
|
"flow",
|
|
@@ -3356,7 +3928,7 @@ function createOnboardingFlowMachine(client) {
|
|
|
3356
3928
|
error: ({ event }) => extractChildErrorOrFallback(event)
|
|
3357
3929
|
}),
|
|
3358
3930
|
assignChildThrown: xstate.assign({
|
|
3359
|
-
error: ({ event }) =>
|
|
3931
|
+
error: ({ event }) => errorFromEvent2(event)
|
|
3360
3932
|
}),
|
|
3361
3933
|
assignAccountFromChild: xstate.assign({
|
|
3362
3934
|
account: ({ event }) => extractChildAccountOrNull(event)
|
|
@@ -3518,7 +4090,7 @@ function extractChildAccountOrNull(event) {
|
|
|
3518
4090
|
if (output && "account" in output && output.account) return output.account;
|
|
3519
4091
|
return null;
|
|
3520
4092
|
}
|
|
3521
|
-
function
|
|
4093
|
+
function errorFromEvent2(event) {
|
|
3522
4094
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3523
4095
|
if (cause instanceof CapxulError) return cause;
|
|
3524
4096
|
if (cause instanceof CapxulError2) return cause;
|
|
@@ -3529,7 +4101,7 @@ function errorFromEvent4(event) {
|
|
|
3529
4101
|
function createCapxulClient(config = {}) {
|
|
3530
4102
|
const clientWithoutFlows = {
|
|
3531
4103
|
id: crypto.randomUUID(),
|
|
3532
|
-
auth:
|
|
4104
|
+
auth: new AuthService(config),
|
|
3533
4105
|
me: createMeClient(config),
|
|
3534
4106
|
accounts: createAccountsClient(config),
|
|
3535
4107
|
organizations: createOrganizationsClient(config),
|
|
@@ -3537,8 +4109,8 @@ function createCapxulClient(config = {}) {
|
|
|
3537
4109
|
transfers: createTransfersClient(),
|
|
3538
4110
|
tokenTransfers: createTokenTransfersClient(config),
|
|
3539
4111
|
withdrawals: createWithdrawalsClient(config),
|
|
3540
|
-
documents: createDocumentsClient(),
|
|
3541
|
-
subAccounts: createSubAccountsClient(),
|
|
4112
|
+
documents: createDocumentsClient(config),
|
|
4113
|
+
subAccounts: createSubAccountsClient(config),
|
|
3542
4114
|
virtualAccounts: createVirtualAccountsClient(),
|
|
3543
4115
|
virtualCards: createVirtualCardsClient(),
|
|
3544
4116
|
externalAccounts: createExternalAccountsClient(config),
|
|
@@ -3549,8 +4121,6 @@ function createCapxulClient(config = {}) {
|
|
|
3549
4121
|
};
|
|
3550
4122
|
const client = clientWithoutFlows;
|
|
3551
4123
|
client.flows = {
|
|
3552
|
-
auth: () => createAuthFlowMachine(client),
|
|
3553
|
-
authBootstrap: () => createAuthBootstrapFlowMachine(client),
|
|
3554
4124
|
onboarding: () => createOnboardingFlowMachine(client),
|
|
3555
4125
|
provisioning: () => createProvisioningMachine(client)
|
|
3556
4126
|
};
|
|
@@ -3654,10 +4224,18 @@ function isWebhookEvent(value) {
|
|
|
3654
4224
|
const candidate = value;
|
|
3655
4225
|
return typeof candidate.id === "string" && typeof candidate.type === "string" && typeof candidate.createdAt === "string" && (candidate.operationId === void 0 || typeof candidate.operationId === "string") && (candidate.correlationId === void 0 || typeof candidate.correlationId === "string") && !!candidate.data && typeof candidate.data === "object" && !Array.isArray(candidate.data);
|
|
3656
4226
|
}
|
|
4227
|
+
var SignerProvisioner = class {
|
|
4228
|
+
provision() {
|
|
4229
|
+
const privateKey = accounts.generatePrivateKey();
|
|
4230
|
+
const signer = accounts.privateKeyToAccount(privateKey);
|
|
4231
|
+
const safeAddress = deriveSafeAddress2(signer.address);
|
|
4232
|
+
return { signer, safeAddress };
|
|
4233
|
+
}
|
|
4234
|
+
};
|
|
3657
4235
|
|
|
4236
|
+
exports.AuthService = AuthService;
|
|
3658
4237
|
exports.CapxulError = CapxulError;
|
|
3659
|
-
exports.
|
|
3660
|
-
exports.createAuthFlowMachine = createAuthFlowMachine;
|
|
4238
|
+
exports.SignerProvisioner = SignerProvisioner;
|
|
3661
4239
|
exports.createCapxulClient = createCapxulClient;
|
|
3662
4240
|
exports.createLocalSigner = createLocalSigner;
|
|
3663
4241
|
exports.createOnboardingFlowMachine = createOnboardingFlowMachine;
|
|
@@ -3666,6 +4244,7 @@ exports.makeHttpTransport = makeHttpTransport;
|
|
|
3666
4244
|
exports.matchAction = matchAction;
|
|
3667
4245
|
exports.matchError = matchError;
|
|
3668
4246
|
exports.matchStatus = matchStatus;
|
|
4247
|
+
exports.resolvePaymentToken = resolvePaymentToken;
|
|
3669
4248
|
exports.toAccountId = toAccountId;
|
|
3670
4249
|
exports.toApiKeyId = toApiKeyId;
|
|
3671
4250
|
exports.toBalanceLedgerEntryId = toBalanceLedgerEntryId;
|