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