@capxul/sdk 0.1.0-alpha.8 → 0.2.0-alpha.3
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 +122 -0
- package/README.md +45 -0
- package/dist/{client-DDAVWtzJ.d.cts → client-B_Z3ThFO.d.cts} +231 -42
- package/dist/{client-ByzDfG98.d.ts → client-pMBRFcsz.d.ts} +231 -42
- package/dist/client.cjs +1678 -406
- package/dist/client.d.cts +4 -4
- package/dist/client.d.ts +4 -4
- package/dist/client.js +1678 -406
- 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 +1735 -394
- package/dist/index.d.cts +90 -40
- package/dist/index.d.ts +90 -40
- package/dist/index.js +1733 -396
- 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-hfcOE7Oi.d.cts → types-Brucpq0Z.d.cts} +63 -8
- package/dist/{types-PM4AQRLP.d.ts → types-V_D7qjxY.d.ts} +63 -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 +7 -5
package/dist/client.cjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var server = require('convex/server');
|
|
4
|
-
var viem = require('viem');
|
|
5
4
|
var accounts = require('permissionless/accounts');
|
|
5
|
+
var viem = require('viem');
|
|
6
6
|
var accountAbstraction = require('viem/account-abstraction');
|
|
7
7
|
var chains = require('viem/chains');
|
|
8
|
+
var safeDerive = require('@repo/safe-derive');
|
|
9
|
+
var browser = require('convex/browser');
|
|
8
10
|
var xstate = require('xstate');
|
|
9
11
|
|
|
10
12
|
// src/_generated/api.js
|
|
@@ -122,6 +124,159 @@ function identify(userId, traits) {
|
|
|
122
124
|
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
123
125
|
}
|
|
124
126
|
|
|
127
|
+
// ../config/src/chain.ts
|
|
128
|
+
var CAPXUL_PAYMENTS_ADDRESS = "0xe740ea65521edc9bef0ea75d30b5334711db99f4";
|
|
129
|
+
var TEST_USDC_ADDRESS = "0xf09fcbb6df9f8f918e58f9c8ab15a76ade862b77";
|
|
130
|
+
var CAPXUL_API_BASE_URL = "https://elated-oyster-269.convex.site";
|
|
131
|
+
|
|
132
|
+
// ../config/src/timing.ts
|
|
133
|
+
var FLOW_INVOKE_TIMEOUT_MS = 3e4;
|
|
134
|
+
|
|
135
|
+
// ../config/src/errors.ts
|
|
136
|
+
var CapxulError2 = class extends Error {
|
|
137
|
+
code;
|
|
138
|
+
details;
|
|
139
|
+
correlationId;
|
|
140
|
+
layer;
|
|
141
|
+
constructor(code, message, options) {
|
|
142
|
+
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
143
|
+
this.code = code;
|
|
144
|
+
this.details = options?.details;
|
|
145
|
+
this.correlationId = options?.correlationId;
|
|
146
|
+
this.layer = options?.layer;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
var Errors = {
|
|
150
|
+
notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
|
|
151
|
+
profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
|
|
152
|
+
smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
|
|
153
|
+
envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
|
|
154
|
+
openfortApi: (operation, cause) => new CapxulError2(
|
|
155
|
+
"PROVIDER_ERROR",
|
|
156
|
+
`Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
157
|
+
{ cause, details: { provider: "openfort", operation } }
|
|
158
|
+
),
|
|
159
|
+
shieldApi: (status, detail) => new CapxulError2(
|
|
160
|
+
"PROVIDER_ERROR",
|
|
161
|
+
`Shield API error (${status}): ${detail}`,
|
|
162
|
+
{ details: { provider: "shield", status } }
|
|
163
|
+
),
|
|
164
|
+
providerError: (provider, operation, cause) => (
|
|
165
|
+
// Public `message` is redacted to a fixed shape so provider-side
|
|
166
|
+
// exception text never leaks to the client. The original `cause`
|
|
167
|
+
// is preserved on `Error.cause` for server-side debugging via
|
|
168
|
+
// observability sinks (Sentry, console traces).
|
|
169
|
+
new CapxulError2(
|
|
170
|
+
"PROVIDER_ERROR",
|
|
171
|
+
`Provider error: ${provider} ${operation}`,
|
|
172
|
+
{ cause, details: { provider, operation } }
|
|
173
|
+
)
|
|
174
|
+
),
|
|
175
|
+
invalidInput: (field, reason) => new CapxulError2(
|
|
176
|
+
"INVALID_INPUT",
|
|
177
|
+
`Invalid ${field}: ${reason}`,
|
|
178
|
+
{ details: { field, reason } }
|
|
179
|
+
),
|
|
180
|
+
playerNotFound: (playerId) => new CapxulError2(
|
|
181
|
+
"PLAYER_NOT_FOUND",
|
|
182
|
+
playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
|
|
183
|
+
),
|
|
184
|
+
accountNotFound: (accountId) => new CapxulError2(
|
|
185
|
+
"ACCOUNT_NOT_FOUND",
|
|
186
|
+
accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
|
|
187
|
+
),
|
|
188
|
+
invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
|
|
189
|
+
permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
|
|
190
|
+
notFound: (resource, id) => new CapxulError2(
|
|
191
|
+
"NOT_FOUND",
|
|
192
|
+
id ? `${resource} ${id} not found` : `${resource} not found`
|
|
193
|
+
),
|
|
194
|
+
idempotencyConflict: (details) => new CapxulError2(
|
|
195
|
+
"IDEMPOTENCY_CONFLICT",
|
|
196
|
+
"Idempotency key was already used for a different request",
|
|
197
|
+
{ details }
|
|
198
|
+
),
|
|
199
|
+
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
200
|
+
details
|
|
201
|
+
}),
|
|
202
|
+
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
203
|
+
details: { ...details }
|
|
204
|
+
}),
|
|
205
|
+
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
206
|
+
/**
|
|
207
|
+
* Verification gate. Surfaced when a request hits a verification
|
|
208
|
+
* boundary the actor cannot cross under their current state. Two
|
|
209
|
+
* variants share this code:
|
|
210
|
+
*
|
|
211
|
+
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
212
|
+
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
213
|
+
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
214
|
+
* `details.rail` + `details.currentKind`.
|
|
215
|
+
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
216
|
+
* the required tier. Carries `details.requiredTier`.
|
|
217
|
+
*
|
|
218
|
+
* Code is shared because both expose the same UX shape ("you cannot
|
|
219
|
+
* proceed until verification advances"); the `details.*` keys
|
|
220
|
+
* differentiate the route.
|
|
221
|
+
*/
|
|
222
|
+
verificationRequired: (details) => {
|
|
223
|
+
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
224
|
+
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
225
|
+
details: { ...details }
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// ../config/src/safe.ts
|
|
231
|
+
var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
232
|
+
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
233
|
+
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
234
|
+
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
235
|
+
|
|
236
|
+
// ../config/src/org-roles.ts
|
|
237
|
+
function roleKeyFromLabel(label) {
|
|
238
|
+
const bytes = new TextEncoder().encode(label);
|
|
239
|
+
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
240
|
+
return "0x" + hex.padEnd(64, "0");
|
|
241
|
+
}
|
|
242
|
+
roleKeyFromLabel("OWNER");
|
|
243
|
+
roleKeyFromLabel("FINANCE_MANAGER");
|
|
244
|
+
roleKeyFromLabel("PAYMENTS_OPERATOR");
|
|
245
|
+
async function buildSafeAccount(signer, chain) {
|
|
246
|
+
try {
|
|
247
|
+
const publicClient = viem.createPublicClient({
|
|
248
|
+
chain: chains.baseSepolia,
|
|
249
|
+
transport: viem.http(chain.rpcUrl)
|
|
250
|
+
});
|
|
251
|
+
return await accounts.toSafeSmartAccount({
|
|
252
|
+
client: publicClient,
|
|
253
|
+
entryPoint: { address: accountAbstraction.entryPoint07Address, version: "0.7" },
|
|
254
|
+
version: "1.4.1",
|
|
255
|
+
owners: [signer],
|
|
256
|
+
saltNonce: computeSaltNonce(signer.address),
|
|
257
|
+
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
258
|
+
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
259
|
+
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
260
|
+
safe4337ModuleAddress: SAFE_4337_MODULE,
|
|
261
|
+
safeModules: [],
|
|
262
|
+
setupTransactions: []
|
|
263
|
+
});
|
|
264
|
+
} catch (cause) {
|
|
265
|
+
throw new CapxulError({
|
|
266
|
+
code: "NETWORK_ERROR",
|
|
267
|
+
message: cause instanceof Error ? cause.message : String(cause),
|
|
268
|
+
cause,
|
|
269
|
+
details: { chainId: chain.chainId }
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function computeSaltNonce(ownerAddress) {
|
|
274
|
+
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
275
|
+
}
|
|
276
|
+
function deriveSafeAddress(signerAddress) {
|
|
277
|
+
return safeDerive.deriveSafeAddress(signerAddress, safeDerive.defaultSafeDeriveConfig);
|
|
278
|
+
}
|
|
279
|
+
|
|
125
280
|
// ../platform-kernel/src/ids.ts
|
|
126
281
|
function makePrefixedIdConstructor(prefix, fieldName) {
|
|
127
282
|
const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
|
|
@@ -134,12 +289,24 @@ function makePrefixedIdConstructor(prefix, fieldName) {
|
|
|
134
289
|
return raw;
|
|
135
290
|
};
|
|
136
291
|
}
|
|
292
|
+
var toSafeId = makePrefixedIdConstructor(
|
|
293
|
+
"safe",
|
|
294
|
+
"safeId"
|
|
295
|
+
);
|
|
296
|
+
var toTreasuryId = makePrefixedIdConstructor(
|
|
297
|
+
"try",
|
|
298
|
+
"treasuryId"
|
|
299
|
+
);
|
|
137
300
|
var toOperationId = makePrefixedIdConstructor(
|
|
138
301
|
"op",
|
|
139
302
|
"operationId"
|
|
140
303
|
);
|
|
141
304
|
var toCorrelationId = makePrefixedIdConstructor("ctx", "correlationId");
|
|
142
305
|
var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
|
|
306
|
+
var toSubAccountId = makePrefixedIdConstructor(
|
|
307
|
+
"sub",
|
|
308
|
+
"subAccountId"
|
|
309
|
+
);
|
|
143
310
|
|
|
144
311
|
// src/core/external-accounts.ts
|
|
145
312
|
function brandExternalAccount(raw) {
|
|
@@ -156,13 +323,13 @@ function brandExternalAccount(raw) {
|
|
|
156
323
|
function createExternalAccountsClient(config = {}) {
|
|
157
324
|
return {
|
|
158
325
|
retrieve: async (externalAccountId) => {
|
|
159
|
-
if (!config.
|
|
326
|
+
if (!config._data) {
|
|
160
327
|
return stub(
|
|
161
328
|
"externalAccounts.retrieve"
|
|
162
329
|
);
|
|
163
330
|
}
|
|
164
331
|
const [err, raw] = await tryCatch(
|
|
165
|
-
config.
|
|
332
|
+
config._data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
166
333
|
externalAccountId
|
|
167
334
|
})
|
|
168
335
|
);
|
|
@@ -184,11 +351,11 @@ function createExternalAccountsClient(config = {}) {
|
|
|
184
351
|
return [null, brandExternalAccount(raw)];
|
|
185
352
|
},
|
|
186
353
|
remove: async (externalAccountId) => {
|
|
187
|
-
if (!config.
|
|
354
|
+
if (!config._data) {
|
|
188
355
|
return stub("externalAccounts.remove");
|
|
189
356
|
}
|
|
190
357
|
const [err] = await tryCatch(
|
|
191
|
-
config.
|
|
358
|
+
config._data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
192
359
|
externalAccountId
|
|
193
360
|
})
|
|
194
361
|
);
|
|
@@ -203,17 +370,203 @@ function createExternalAccountsClient(config = {}) {
|
|
|
203
370
|
};
|
|
204
371
|
}
|
|
205
372
|
|
|
373
|
+
// src/core/sub-accounts.ts
|
|
374
|
+
function malformedWireError(reason, raw) {
|
|
375
|
+
return new CapxulError({
|
|
376
|
+
code: "PROVIDER_ERROR",
|
|
377
|
+
message: `convex brandSubAccount failed: ${reason}`,
|
|
378
|
+
details: {
|
|
379
|
+
provider: "convex",
|
|
380
|
+
operation: "brandSubAccount",
|
|
381
|
+
reason,
|
|
382
|
+
// PII discipline (`.claude/rules/posthog.md`): user-authored
|
|
383
|
+
// strings on the wire (`name`, `purpose`) are customer-confidential
|
|
384
|
+
// — sub-account names like "Q3 Acquisition Reserve" or
|
|
385
|
+
// "Vendor ABC payments" must not flow into telemetry. We emit a
|
|
386
|
+
// structural keys-only sample via a strict ALLOWLIST so any future
|
|
387
|
+
// wire-shape addition (e.g. `recipientEmail`, `tags`) is dropped
|
|
388
|
+
// by construction rather than leaked through a denylist gap.
|
|
389
|
+
sample: safeSampleShape(raw)
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
function safeSampleShape(raw) {
|
|
394
|
+
if (raw === null || typeof raw !== "object") {
|
|
395
|
+
return { type: typeof raw };
|
|
396
|
+
}
|
|
397
|
+
const r = raw;
|
|
398
|
+
const balance = r.balance;
|
|
399
|
+
return {
|
|
400
|
+
object: typeof r.object === "string" ? r.object : typeof r.object,
|
|
401
|
+
idPresent: typeof r.id === "string" && r.id.length > 0,
|
|
402
|
+
// First 4 chars only — enough to distinguish "sub_" prefixed IDs
|
|
403
|
+
// from accidental other resource IDs without leaking the full ID.
|
|
404
|
+
idPrefix: typeof r.id === "string" ? r.id.slice(0, 4) : void 0,
|
|
405
|
+
parentKind: r.parent !== null && typeof r.parent === "object" ? r.parent.kind : typeof r.parent,
|
|
406
|
+
status: r.status,
|
|
407
|
+
hasName: typeof r.name === "string",
|
|
408
|
+
hasPurpose: r.purpose !== void 0,
|
|
409
|
+
balanceShape: balance !== null && typeof balance === "object" ? Object.keys(balance).sort() : typeof balance,
|
|
410
|
+
createdAtType: typeof r.createdAt,
|
|
411
|
+
updatedAtType: typeof r.updatedAt
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function isMoneyShape(v) {
|
|
415
|
+
if (typeof v !== "object" || v === null) return false;
|
|
416
|
+
const m = v;
|
|
417
|
+
return typeof m.value === "string" && typeof m.currency === "string";
|
|
418
|
+
}
|
|
419
|
+
function isParentShape(v) {
|
|
420
|
+
if (typeof v !== "object" || v === null) return false;
|
|
421
|
+
const p = v;
|
|
422
|
+
return (p.kind === "account" || p.kind === "organization") && typeof p.id === "string";
|
|
423
|
+
}
|
|
424
|
+
function isFiniteNonNegativeInteger(v) {
|
|
425
|
+
return typeof v === "number" && Number.isFinite(v) && Number.isInteger(v) && v >= 0;
|
|
426
|
+
}
|
|
427
|
+
function validateWireSubAccount(raw) {
|
|
428
|
+
if (typeof raw !== "object" || raw === null) {
|
|
429
|
+
return { ok: false, reason: "not an object" };
|
|
430
|
+
}
|
|
431
|
+
const r = raw;
|
|
432
|
+
if (r.object !== "sub_account") {
|
|
433
|
+
return { ok: false, reason: `object must be "sub_account" (got ${String(r.object)})` };
|
|
434
|
+
}
|
|
435
|
+
if (typeof r.id !== "string" || r.id.length === 0) {
|
|
436
|
+
return { ok: false, reason: "id must be a non-empty string" };
|
|
437
|
+
}
|
|
438
|
+
if (!isParentShape(r.parent)) {
|
|
439
|
+
return { ok: false, reason: "parent must be { kind: 'account' | 'organization', id: string }" };
|
|
440
|
+
}
|
|
441
|
+
if (typeof r.name !== "string") {
|
|
442
|
+
return { ok: false, reason: "name must be a string" };
|
|
443
|
+
}
|
|
444
|
+
if (r.purpose !== void 0 && typeof r.purpose !== "string") {
|
|
445
|
+
return { ok: false, reason: "purpose must be a string when present" };
|
|
446
|
+
}
|
|
447
|
+
if (r.status !== "active" && r.status !== "archived") {
|
|
448
|
+
return { ok: false, reason: `status must be "active" | "archived" (got ${String(r.status)})` };
|
|
449
|
+
}
|
|
450
|
+
if (!isMoneyShape(r.balance)) {
|
|
451
|
+
return { ok: false, reason: "balance must be { value: string, currency: string }" };
|
|
452
|
+
}
|
|
453
|
+
if (!isFiniteNonNegativeInteger(r.createdAt)) {
|
|
454
|
+
return { ok: false, reason: "createdAt must be a finite non-negative integer (epoch ms)" };
|
|
455
|
+
}
|
|
456
|
+
if (r.updatedAt !== void 0 && !isFiniteNonNegativeInteger(r.updatedAt)) {
|
|
457
|
+
return { ok: false, reason: "updatedAt must be a finite non-negative integer when present" };
|
|
458
|
+
}
|
|
459
|
+
return { ok: true, value: r };
|
|
460
|
+
}
|
|
461
|
+
function brandSubAccount(raw) {
|
|
462
|
+
const result = validateWireSubAccount(raw);
|
|
463
|
+
if (!result.ok) {
|
|
464
|
+
throw malformedWireError(result.reason, raw);
|
|
465
|
+
}
|
|
466
|
+
const wire = result.value;
|
|
467
|
+
return {
|
|
468
|
+
object: wire.object,
|
|
469
|
+
id: toSubAccountId(wire.id),
|
|
470
|
+
parent: wire.parent,
|
|
471
|
+
name: wire.name,
|
|
472
|
+
...wire.purpose !== void 0 ? { purpose: wire.purpose } : {},
|
|
473
|
+
status: wire.status,
|
|
474
|
+
balance: wire.balance,
|
|
475
|
+
createdAt: new Date(wire.createdAt).toISOString()
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
function tryBrandSubAccount(raw) {
|
|
479
|
+
try {
|
|
480
|
+
return [null, brandSubAccount(raw)];
|
|
481
|
+
} catch (err) {
|
|
482
|
+
if (err instanceof CapxulError && err.code === "PROVIDER_ERROR") {
|
|
483
|
+
return [err, null];
|
|
484
|
+
}
|
|
485
|
+
return [
|
|
486
|
+
malformedWireError(
|
|
487
|
+
err instanceof Error ? err.message : String(err),
|
|
488
|
+
raw
|
|
489
|
+
),
|
|
490
|
+
null
|
|
491
|
+
];
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function createSubAccountsClient(config = {}) {
|
|
495
|
+
return {
|
|
496
|
+
retrieve: async (subAccountId) => {
|
|
497
|
+
if (!config._data) {
|
|
498
|
+
return stub("subAccounts.retrieve");
|
|
499
|
+
}
|
|
500
|
+
const [err, raw] = await tryCatch(
|
|
501
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
502
|
+
subAccountId
|
|
503
|
+
})
|
|
504
|
+
);
|
|
505
|
+
if (err) {
|
|
506
|
+
return [
|
|
507
|
+
fromConvexError(err),
|
|
508
|
+
null
|
|
509
|
+
];
|
|
510
|
+
}
|
|
511
|
+
if (!raw) {
|
|
512
|
+
return [
|
|
513
|
+
new CapxulError({
|
|
514
|
+
code: "NOT_FOUND",
|
|
515
|
+
message: `sub_account ${subAccountId} not found`
|
|
516
|
+
}),
|
|
517
|
+
null
|
|
518
|
+
];
|
|
519
|
+
}
|
|
520
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
521
|
+
if (brandErr) {
|
|
522
|
+
return [brandErr, null];
|
|
523
|
+
}
|
|
524
|
+
return [null, branded];
|
|
525
|
+
},
|
|
526
|
+
remove: async (subAccountId) => {
|
|
527
|
+
if (!config._data) {
|
|
528
|
+
return stub("subAccounts.remove");
|
|
529
|
+
}
|
|
530
|
+
const [err, raw] = await tryCatch(
|
|
531
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
532
|
+
subAccountId
|
|
533
|
+
})
|
|
534
|
+
);
|
|
535
|
+
if (err) {
|
|
536
|
+
return [
|
|
537
|
+
fromConvexError(err),
|
|
538
|
+
null
|
|
539
|
+
];
|
|
540
|
+
}
|
|
541
|
+
if (!raw) {
|
|
542
|
+
return [
|
|
543
|
+
new CapxulError({
|
|
544
|
+
code: "NOT_FOUND",
|
|
545
|
+
message: `sub_account ${subAccountId} not found`
|
|
546
|
+
}),
|
|
547
|
+
null
|
|
548
|
+
];
|
|
549
|
+
}
|
|
550
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
551
|
+
if (brandErr) {
|
|
552
|
+
return [brandErr, null];
|
|
553
|
+
}
|
|
554
|
+
return [null, branded];
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
|
|
206
559
|
// src/core/accounts.ts
|
|
207
560
|
function createAccountExternalAccountsClient(config) {
|
|
208
561
|
return {
|
|
209
562
|
create: async (input) => {
|
|
210
|
-
if (!config.
|
|
563
|
+
if (!config._data) {
|
|
211
564
|
return stub(
|
|
212
565
|
"accounts.externalAccounts.create"
|
|
213
566
|
);
|
|
214
567
|
}
|
|
215
568
|
const [err, raw] = await tryCatch(
|
|
216
|
-
config.
|
|
569
|
+
config._data.mutation(
|
|
217
570
|
api.externalAccounts.mutations.createPersonal,
|
|
218
571
|
{
|
|
219
572
|
kind: input.kind,
|
|
@@ -251,13 +604,13 @@ function createAccountExternalAccountsClient(config) {
|
|
|
251
604
|
];
|
|
252
605
|
},
|
|
253
606
|
list: async (input) => {
|
|
254
|
-
if (!config.
|
|
607
|
+
if (!config._data) {
|
|
255
608
|
return stub(
|
|
256
609
|
"accounts.externalAccounts.list"
|
|
257
610
|
);
|
|
258
611
|
}
|
|
259
612
|
const [err, result] = await tryCatch(
|
|
260
|
-
config.
|
|
613
|
+
config._data.query(api.externalAccounts.queries.listPersonal, {
|
|
261
614
|
limit: input.limit,
|
|
262
615
|
cursor: input.cursor
|
|
263
616
|
})
|
|
@@ -280,13 +633,13 @@ function createAccountExternalAccountsClient(config) {
|
|
|
280
633
|
];
|
|
281
634
|
},
|
|
282
635
|
retrieve: async (externalAccountId) => {
|
|
283
|
-
if (!config.
|
|
636
|
+
if (!config._data) {
|
|
284
637
|
return stub(
|
|
285
638
|
"accounts.externalAccounts.retrieve"
|
|
286
639
|
);
|
|
287
640
|
}
|
|
288
641
|
const [err, raw] = await tryCatch(
|
|
289
|
-
config.
|
|
642
|
+
config._data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
290
643
|
externalAccountId
|
|
291
644
|
})
|
|
292
645
|
);
|
|
@@ -313,11 +666,11 @@ function createAccountExternalAccountsClient(config) {
|
|
|
313
666
|
];
|
|
314
667
|
},
|
|
315
668
|
remove: async (externalAccountId) => {
|
|
316
|
-
if (!config.
|
|
669
|
+
if (!config._data) {
|
|
317
670
|
return stub("accounts.externalAccounts.remove");
|
|
318
671
|
}
|
|
319
672
|
const [err] = await tryCatch(
|
|
320
|
-
config.
|
|
673
|
+
config._data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
321
674
|
externalAccountId
|
|
322
675
|
})
|
|
323
676
|
);
|
|
@@ -331,41 +684,189 @@ function createAccountExternalAccountsClient(config) {
|
|
|
331
684
|
}
|
|
332
685
|
};
|
|
333
686
|
}
|
|
334
|
-
function
|
|
687
|
+
function createAccountSubAccountsClient(config) {
|
|
335
688
|
return {
|
|
336
|
-
|
|
337
|
-
if (!config.
|
|
338
|
-
return stub(
|
|
339
|
-
|
|
340
|
-
try {
|
|
341
|
-
const account = await config.data.query(
|
|
342
|
-
api.openfort.queries.getMyAccount,
|
|
343
|
-
{}
|
|
689
|
+
create: async (input) => {
|
|
690
|
+
if (!config._data) {
|
|
691
|
+
return stub(
|
|
692
|
+
"accounts.subAccounts.create"
|
|
344
693
|
);
|
|
345
|
-
if (account.id !== accountId) {
|
|
346
|
-
return [
|
|
347
|
-
new CapxulError({
|
|
348
|
-
code: "PERMISSION_DENIED",
|
|
349
|
-
message: "accounts.retrieve currently supports the authenticated caller's own account only.",
|
|
350
|
-
details: {
|
|
351
|
-
requestedAccountId: accountId,
|
|
352
|
-
authenticatedAccountId: account.id
|
|
353
|
-
}
|
|
354
|
-
}),
|
|
355
|
-
null
|
|
356
|
-
];
|
|
357
|
-
}
|
|
358
|
-
return [null, account];
|
|
359
|
-
} catch (cause) {
|
|
360
|
-
return [fromConvexError(cause), null];
|
|
361
|
-
}
|
|
362
|
-
},
|
|
363
|
-
lookup: async () => stub("accounts.lookup"),
|
|
364
|
-
update: async (input) => {
|
|
365
|
-
if (!config.data) {
|
|
366
|
-
return stub("accounts.update");
|
|
367
694
|
}
|
|
368
|
-
|
|
695
|
+
const [err, raw] = await tryCatch(
|
|
696
|
+
config._data.mutation(api.subAccounts.mutations.create, {
|
|
697
|
+
parent: { kind: "account", id: input.accountId },
|
|
698
|
+
name: input.name,
|
|
699
|
+
purpose: input.purpose
|
|
700
|
+
})
|
|
701
|
+
);
|
|
702
|
+
if (err) {
|
|
703
|
+
return [
|
|
704
|
+
fromConvexError(err),
|
|
705
|
+
null
|
|
706
|
+
];
|
|
707
|
+
}
|
|
708
|
+
if (!raw) {
|
|
709
|
+
return [
|
|
710
|
+
new CapxulError({
|
|
711
|
+
code: "NOT_FOUND",
|
|
712
|
+
message: "sub_account creation returned no resource"
|
|
713
|
+
}),
|
|
714
|
+
null
|
|
715
|
+
];
|
|
716
|
+
}
|
|
717
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
718
|
+
if (brandErr) {
|
|
719
|
+
return [
|
|
720
|
+
brandErr,
|
|
721
|
+
null
|
|
722
|
+
];
|
|
723
|
+
}
|
|
724
|
+
return [null, branded];
|
|
725
|
+
},
|
|
726
|
+
list: async (input) => {
|
|
727
|
+
if (!config._data) {
|
|
728
|
+
return stub(
|
|
729
|
+
"accounts.subAccounts.list"
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
const [err, rows] = await tryCatch(
|
|
733
|
+
config._data.query(api.subAccounts.queries.listByAccount, {
|
|
734
|
+
accountId: input.accountId
|
|
735
|
+
})
|
|
736
|
+
);
|
|
737
|
+
if (err) {
|
|
738
|
+
return [
|
|
739
|
+
fromConvexError(err),
|
|
740
|
+
null
|
|
741
|
+
];
|
|
742
|
+
}
|
|
743
|
+
const branded = [];
|
|
744
|
+
for (const row of rows) {
|
|
745
|
+
const [brandErr, value] = tryBrandSubAccount(row);
|
|
746
|
+
if (brandErr) {
|
|
747
|
+
return [
|
|
748
|
+
brandErr,
|
|
749
|
+
null
|
|
750
|
+
];
|
|
751
|
+
}
|
|
752
|
+
branded.push(value);
|
|
753
|
+
}
|
|
754
|
+
return [
|
|
755
|
+
null,
|
|
756
|
+
{
|
|
757
|
+
object: "list",
|
|
758
|
+
data: branded,
|
|
759
|
+
page: { hasMore: false }
|
|
760
|
+
}
|
|
761
|
+
];
|
|
762
|
+
},
|
|
763
|
+
retrieve: async (subAccountId) => {
|
|
764
|
+
if (!config._data) {
|
|
765
|
+
return stub(
|
|
766
|
+
"accounts.subAccounts.retrieve"
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
const [err, raw] = await tryCatch(
|
|
770
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
771
|
+
subAccountId
|
|
772
|
+
})
|
|
773
|
+
);
|
|
774
|
+
if (err) {
|
|
775
|
+
return [
|
|
776
|
+
fromConvexError(err),
|
|
777
|
+
null
|
|
778
|
+
];
|
|
779
|
+
}
|
|
780
|
+
if (!raw) {
|
|
781
|
+
return [
|
|
782
|
+
new CapxulError({
|
|
783
|
+
code: "NOT_FOUND",
|
|
784
|
+
message: `sub_account ${subAccountId} not found`
|
|
785
|
+
}),
|
|
786
|
+
null
|
|
787
|
+
];
|
|
788
|
+
}
|
|
789
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
790
|
+
if (brandErr) {
|
|
791
|
+
return [
|
|
792
|
+
brandErr,
|
|
793
|
+
null
|
|
794
|
+
];
|
|
795
|
+
}
|
|
796
|
+
return [null, branded];
|
|
797
|
+
},
|
|
798
|
+
remove: async (subAccountId) => {
|
|
799
|
+
if (!config._data) {
|
|
800
|
+
return stub(
|
|
801
|
+
"accounts.subAccounts.remove"
|
|
802
|
+
);
|
|
803
|
+
}
|
|
804
|
+
const [err, raw] = await tryCatch(
|
|
805
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
806
|
+
subAccountId
|
|
807
|
+
})
|
|
808
|
+
);
|
|
809
|
+
if (err) {
|
|
810
|
+
return [
|
|
811
|
+
fromConvexError(err),
|
|
812
|
+
null
|
|
813
|
+
];
|
|
814
|
+
}
|
|
815
|
+
if (!raw) {
|
|
816
|
+
return [
|
|
817
|
+
new CapxulError({
|
|
818
|
+
code: "NOT_FOUND",
|
|
819
|
+
message: `sub_account ${subAccountId} not found`
|
|
820
|
+
}),
|
|
821
|
+
null
|
|
822
|
+
];
|
|
823
|
+
}
|
|
824
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
825
|
+
if (brandErr) {
|
|
826
|
+
return [
|
|
827
|
+
brandErr,
|
|
828
|
+
null
|
|
829
|
+
];
|
|
830
|
+
}
|
|
831
|
+
return [null, branded];
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
function createAccountsClient(config = {}) {
|
|
836
|
+
return {
|
|
837
|
+
retrieve: async (accountId) => {
|
|
838
|
+
if (!config._data) {
|
|
839
|
+
return stub("accounts.retrieve");
|
|
840
|
+
}
|
|
841
|
+
try {
|
|
842
|
+
const account = await config._data.query(
|
|
843
|
+
api.openfort.queries.getMyAccount,
|
|
844
|
+
{}
|
|
845
|
+
);
|
|
846
|
+
if (account.id !== accountId) {
|
|
847
|
+
return [
|
|
848
|
+
new CapxulError({
|
|
849
|
+
code: "PERMISSION_DENIED",
|
|
850
|
+
message: "accounts.retrieve currently supports the authenticated caller's own account only.",
|
|
851
|
+
details: {
|
|
852
|
+
requestedAccountId: accountId,
|
|
853
|
+
authenticatedAccountId: account.id
|
|
854
|
+
}
|
|
855
|
+
}),
|
|
856
|
+
null
|
|
857
|
+
];
|
|
858
|
+
}
|
|
859
|
+
return [null, account];
|
|
860
|
+
} catch (cause) {
|
|
861
|
+
return [fromConvexError(cause), null];
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
lookup: async () => stub("accounts.lookup"),
|
|
865
|
+
update: async (input) => {
|
|
866
|
+
if (!config._data) {
|
|
867
|
+
return stub("accounts.update");
|
|
868
|
+
}
|
|
869
|
+
if (input.countryCode !== void 0) {
|
|
369
870
|
return [
|
|
370
871
|
new CapxulError({
|
|
371
872
|
code: "INVALID_INPUT",
|
|
@@ -376,7 +877,7 @@ function createAccountsClient(config = {}) {
|
|
|
376
877
|
];
|
|
377
878
|
}
|
|
378
879
|
try {
|
|
379
|
-
const current = await config.
|
|
880
|
+
const current = await config._data.query(
|
|
380
881
|
api.openfort.queries.getMyAccount,
|
|
381
882
|
{}
|
|
382
883
|
);
|
|
@@ -393,11 +894,11 @@ function createAccountsClient(config = {}) {
|
|
|
393
894
|
null
|
|
394
895
|
];
|
|
395
896
|
}
|
|
396
|
-
await config.
|
|
897
|
+
await config._data.mutation(api.openfort.mutations.updateProfile, {
|
|
397
898
|
displayName: input.name,
|
|
398
899
|
username: input.username
|
|
399
900
|
});
|
|
400
|
-
const updated = await config.
|
|
901
|
+
const updated = await config._data.query(
|
|
401
902
|
api.openfort.queries.getMyAccount,
|
|
402
903
|
{}
|
|
403
904
|
);
|
|
@@ -407,7 +908,7 @@ function createAccountsClient(config = {}) {
|
|
|
407
908
|
}
|
|
408
909
|
},
|
|
409
910
|
provisionPersonal: async (input) => {
|
|
410
|
-
if (!config.
|
|
911
|
+
if (!config._data) {
|
|
411
912
|
return stub(
|
|
412
913
|
"accounts.provisionPersonal"
|
|
413
914
|
);
|
|
@@ -422,17 +923,17 @@ function createAccountsClient(config = {}) {
|
|
|
422
923
|
];
|
|
423
924
|
}
|
|
424
925
|
try {
|
|
425
|
-
await config.
|
|
926
|
+
await config._data.mutation(
|
|
426
927
|
api.safe.mutations.provisionLocalPersonalAccount,
|
|
427
928
|
{
|
|
428
929
|
displayName: input.displayName,
|
|
429
930
|
username: input.username,
|
|
430
931
|
countryCode: input.countryCode,
|
|
431
932
|
eoaAddress: input.signerProvider.signerAddress,
|
|
432
|
-
safeAddress: input.signerProvider.
|
|
933
|
+
safeAddress: deriveSafeAddress(input.signerProvider.signerAddress)
|
|
433
934
|
}
|
|
434
935
|
);
|
|
435
|
-
const account = await config.
|
|
936
|
+
const account = await config._data.query(
|
|
436
937
|
api.openfort.queries.getMyAccount,
|
|
437
938
|
{}
|
|
438
939
|
);
|
|
@@ -455,11 +956,11 @@ function createAccountsClient(config = {}) {
|
|
|
455
956
|
},
|
|
456
957
|
safes: {
|
|
457
958
|
retrieve: async (safeId) => {
|
|
458
|
-
if (!config.
|
|
959
|
+
if (!config._data) {
|
|
459
960
|
return stub("accounts.safes.retrieve");
|
|
460
961
|
}
|
|
461
962
|
try {
|
|
462
|
-
const safe = await config.
|
|
963
|
+
const safe = await config._data.query(
|
|
463
964
|
api.safe.queries.retrieveAccountSafe,
|
|
464
965
|
{ safeId }
|
|
465
966
|
);
|
|
@@ -486,19 +987,50 @@ function createAccountsClient(config = {}) {
|
|
|
486
987
|
retrieve: async () => stub("accounts.kycProfiles.retrieve")
|
|
487
988
|
},
|
|
488
989
|
externalAccounts: createAccountExternalAccountsClient(config),
|
|
489
|
-
subAccounts:
|
|
490
|
-
create: async () => stub("accounts.subAccounts.create"),
|
|
491
|
-
list: async () => stub("accounts.subAccounts.list"),
|
|
492
|
-
retrieve: async () => stub("accounts.subAccounts.retrieve"),
|
|
493
|
-
remove: async () => stub("accounts.subAccounts.remove")
|
|
494
|
-
},
|
|
990
|
+
subAccounts: createAccountSubAccountsClient(config),
|
|
495
991
|
balanceLedger: {
|
|
496
|
-
list: async () =>
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
992
|
+
list: async (input) => {
|
|
993
|
+
if (!config._data) {
|
|
994
|
+
return stub(
|
|
995
|
+
"accounts.balanceLedger.list"
|
|
996
|
+
);
|
|
997
|
+
}
|
|
998
|
+
try {
|
|
999
|
+
const accountId = input.accountId.replace(/^acct_/, "");
|
|
1000
|
+
const page = await config._data.query(
|
|
1001
|
+
api.balanceLedger.queries.listForAccount,
|
|
1002
|
+
{ accountId, limit: input.limit, cursor: input.cursor }
|
|
1003
|
+
);
|
|
1004
|
+
return [null, page];
|
|
1005
|
+
} catch (cause) {
|
|
1006
|
+
return [fromConvexError(cause), null];
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
retrieve: async (entryId) => {
|
|
1010
|
+
if (!config._data) {
|
|
1011
|
+
return stub(
|
|
1012
|
+
"accounts.balanceLedger.retrieve"
|
|
1013
|
+
);
|
|
1014
|
+
}
|
|
1015
|
+
try {
|
|
1016
|
+
const entry = await config._data.query(
|
|
1017
|
+
api.balanceLedger.queries.retrieve,
|
|
1018
|
+
{ entryId }
|
|
1019
|
+
);
|
|
1020
|
+
if (!entry) {
|
|
1021
|
+
return [
|
|
1022
|
+
new CapxulError({
|
|
1023
|
+
code: "NOT_FOUND",
|
|
1024
|
+
message: `balance_ledger_entry ${entryId} not found`
|
|
1025
|
+
}),
|
|
1026
|
+
null
|
|
1027
|
+
];
|
|
1028
|
+
}
|
|
1029
|
+
return [null, entry];
|
|
1030
|
+
} catch (cause) {
|
|
1031
|
+
return [fromConvexError(cause), null];
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
502
1034
|
}
|
|
503
1035
|
};
|
|
504
1036
|
}
|
|
@@ -512,129 +1044,21 @@ function createApiKeysClient() {
|
|
|
512
1044
|
revoke: async () => stub("apiKeys.revoke")
|
|
513
1045
|
};
|
|
514
1046
|
}
|
|
1047
|
+
function createDefaultDataClient(convexUrl, jwt) {
|
|
1048
|
+
const client = new browser.ConvexHttpClient(convexUrl);
|
|
1049
|
+
client.setAuth(jwt);
|
|
1050
|
+
return client;
|
|
1051
|
+
}
|
|
515
1052
|
|
|
516
|
-
//
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
var CapxulError2 = class extends Error {
|
|
526
|
-
code;
|
|
527
|
-
details;
|
|
528
|
-
correlationId;
|
|
529
|
-
layer;
|
|
530
|
-
constructor(code, message, options) {
|
|
531
|
-
super(message, options?.cause ? { cause: options.cause } : void 0);
|
|
532
|
-
this.code = code;
|
|
533
|
-
this.details = options?.details;
|
|
534
|
-
this.correlationId = options?.correlationId;
|
|
535
|
-
this.layer = options?.layer;
|
|
536
|
-
}
|
|
537
|
-
};
|
|
538
|
-
var Errors = {
|
|
539
|
-
notAuthenticated: () => new CapxulError2("NOT_AUTHENTICATED", "Not authenticated"),
|
|
540
|
-
profileNotFound: (authUserId) => new CapxulError2("PROFILE_NOT_FOUND", `Profile not found for user ${authUserId}`),
|
|
541
|
-
smartAccountMissing: (authUserId) => new CapxulError2("SMART_ACCOUNT_MISSING", `Smart account not provisioned for user ${authUserId}`),
|
|
542
|
-
envMissing: (name) => new CapxulError2("ENV_MISSING", `Environment variable ${name} not configured`),
|
|
543
|
-
openfortApi: (operation, cause) => new CapxulError2(
|
|
544
|
-
"PROVIDER_ERROR",
|
|
545
|
-
`Openfort ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
546
|
-
{ cause, details: { provider: "openfort", operation } }
|
|
547
|
-
),
|
|
548
|
-
shieldApi: (status, detail) => new CapxulError2(
|
|
549
|
-
"PROVIDER_ERROR",
|
|
550
|
-
`Shield API error (${status}): ${detail}`,
|
|
551
|
-
{ details: { provider: "shield", status } }
|
|
552
|
-
),
|
|
553
|
-
providerError: (provider, operation, cause) => new CapxulError2(
|
|
554
|
-
"PROVIDER_ERROR",
|
|
555
|
-
`${provider} ${operation} failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
556
|
-
{ cause, details: { provider, operation } }
|
|
557
|
-
),
|
|
558
|
-
invalidInput: (field, reason) => new CapxulError2(
|
|
559
|
-
"INVALID_INPUT",
|
|
560
|
-
`Invalid ${field}: ${reason}`,
|
|
561
|
-
{ details: { field, reason } }
|
|
562
|
-
),
|
|
563
|
-
playerNotFound: (playerId) => new CapxulError2(
|
|
564
|
-
"PLAYER_NOT_FOUND",
|
|
565
|
-
playerId ? `Openfort player ${playerId} not found` : "Openfort player not found"
|
|
566
|
-
),
|
|
567
|
-
accountNotFound: (accountId) => new CapxulError2(
|
|
568
|
-
"ACCOUNT_NOT_FOUND",
|
|
569
|
-
accountId ? `Openfort account ${accountId} not found` : "Openfort smart account not found"
|
|
570
|
-
),
|
|
571
|
-
invalidRecipient: (reason) => new CapxulError2("INVALID_RECIPIENT", reason),
|
|
572
|
-
permissionDenied: (reason = "Permission denied") => new CapxulError2("PERMISSION_DENIED", reason),
|
|
573
|
-
notFound: (resource, id) => new CapxulError2(
|
|
574
|
-
"NOT_FOUND",
|
|
575
|
-
id ? `${resource} ${id} not found` : `${resource} not found`
|
|
576
|
-
),
|
|
577
|
-
idempotencyConflict: (details) => new CapxulError2(
|
|
578
|
-
"IDEMPOTENCY_CONFLICT",
|
|
579
|
-
"Idempotency key was already used for a different request",
|
|
580
|
-
{ details }
|
|
581
|
-
),
|
|
582
|
-
emailDeliveryFailed: (detail, details) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`, {
|
|
583
|
-
details
|
|
584
|
-
}),
|
|
585
|
-
rateLimited: (details) => new CapxulError2("RATE_LIMITED", "Request was rate limited", {
|
|
586
|
-
details: { ...details }
|
|
587
|
-
}),
|
|
588
|
-
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
589
|
-
/**
|
|
590
|
-
* Verification gate. Surfaced when a request hits a verification
|
|
591
|
-
* boundary the actor cannot cross under their current state. Two
|
|
592
|
-
* variants share this code:
|
|
593
|
-
*
|
|
594
|
-
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
595
|
-
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
596
|
-
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
597
|
-
* `details.rail` + `details.currentKind`.
|
|
598
|
-
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
599
|
-
* the required tier. Carries `details.requiredTier`.
|
|
600
|
-
*
|
|
601
|
-
* Code is shared because both expose the same UX shape ("you cannot
|
|
602
|
-
* proceed until verification advances"); the `details.*` keys
|
|
603
|
-
* differentiate the route.
|
|
604
|
-
*/
|
|
605
|
-
verificationRequired: (details) => {
|
|
606
|
-
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
607
|
-
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
608
|
-
details: { ...details }
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
// ../config/src/safe.ts
|
|
614
|
-
var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
615
|
-
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
616
|
-
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
617
|
-
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
618
|
-
|
|
619
|
-
// ../config/src/org-roles.ts
|
|
620
|
-
function roleKeyFromLabel(label) {
|
|
621
|
-
const bytes = new TextEncoder().encode(label);
|
|
622
|
-
const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
623
|
-
return "0x" + hex.padEnd(64, "0");
|
|
624
|
-
}
|
|
625
|
-
roleKeyFromLabel("OWNER");
|
|
626
|
-
roleKeyFromLabel("FINANCE_MANAGER");
|
|
627
|
-
roleKeyFromLabel("TEAM_LEAD");
|
|
628
|
-
|
|
629
|
-
// src/transport.ts
|
|
630
|
-
function makeHttpTransport(config) {
|
|
631
|
-
switch (config.mode) {
|
|
632
|
-
case "build-time-urls":
|
|
633
|
-
return makeBuildTimeUrlsTransport(config);
|
|
634
|
-
case "publishable-key":
|
|
635
|
-
return makePublishableKeyTransport(config);
|
|
636
|
-
default:
|
|
637
|
-
return assertNever(config);
|
|
1053
|
+
// src/transport.ts
|
|
1054
|
+
function makeHttpTransport(config) {
|
|
1055
|
+
switch (config.mode) {
|
|
1056
|
+
case "build-time-urls":
|
|
1057
|
+
return makeBuildTimeUrlsTransport(config);
|
|
1058
|
+
case "publishable-key":
|
|
1059
|
+
return makePublishableKeyTransport(config);
|
|
1060
|
+
default:
|
|
1061
|
+
return assertNever(config);
|
|
638
1062
|
}
|
|
639
1063
|
}
|
|
640
1064
|
function createLifecycle(initial) {
|
|
@@ -955,7 +1379,7 @@ function readNonEmptyString(value) {
|
|
|
955
1379
|
|
|
956
1380
|
// src/core/auth.ts
|
|
957
1381
|
function createAuthClient(config = {}) {
|
|
958
|
-
let dataClient = config.
|
|
1382
|
+
let dataClient = config._data ?? null;
|
|
959
1383
|
const sessionStore = config.auth?.sessionStore ?? createMemorySessionStore();
|
|
960
1384
|
const getTransport = createTransportProvider(config);
|
|
961
1385
|
return {
|
|
@@ -1011,11 +1435,20 @@ function createAuthClient(config = {}) {
|
|
|
1011
1435
|
).toISOString()
|
|
1012
1436
|
};
|
|
1013
1437
|
sessionStore.set(session);
|
|
1014
|
-
if (
|
|
1438
|
+
if (!dataClient) {
|
|
1015
1439
|
try {
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1440
|
+
const convexUrl = transport.convexUrl;
|
|
1441
|
+
if (!convexUrl || !session.convexJwt) {
|
|
1442
|
+
return [
|
|
1443
|
+
new CapxulError({
|
|
1444
|
+
code: "NETWORK_ERROR",
|
|
1445
|
+
message: "Cannot create data client: missing convex URL or JWT."
|
|
1446
|
+
}),
|
|
1447
|
+
null
|
|
1448
|
+
];
|
|
1449
|
+
}
|
|
1450
|
+
dataClient = createDefaultDataClient(convexUrl, session.convexJwt);
|
|
1451
|
+
mutableConfig(config)._data = dataClient;
|
|
1019
1452
|
} catch (cause) {
|
|
1020
1453
|
return [
|
|
1021
1454
|
new CapxulError({
|
|
@@ -1026,14 +1459,89 @@ function createAuthClient(config = {}) {
|
|
|
1026
1459
|
null
|
|
1027
1460
|
];
|
|
1028
1461
|
}
|
|
1462
|
+
} else {
|
|
1463
|
+
const injected = dataClient;
|
|
1464
|
+
if (typeof injected.refreshAuth === "function") {
|
|
1465
|
+
injected.refreshAuth();
|
|
1466
|
+
} else if (typeof injected.setAuth === "function" && session.convexJwt) {
|
|
1467
|
+
injected.setAuth(session.convexJwt);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
transport.markAuthenticated({ dataClient });
|
|
1471
|
+
if (!dataClient) {
|
|
1472
|
+
return [
|
|
1473
|
+
new CapxulError({
|
|
1474
|
+
code: "NOT_AUTHENTICATED",
|
|
1475
|
+
message: "Auth bootstrap requires an authenticated Convex data client."
|
|
1476
|
+
}),
|
|
1477
|
+
null
|
|
1478
|
+
];
|
|
1479
|
+
}
|
|
1480
|
+
try {
|
|
1481
|
+
const resolution = await dataClient.mutation(
|
|
1482
|
+
api.authBootstrap.resolveAfterOtp,
|
|
1483
|
+
{
|
|
1484
|
+
email: session.email,
|
|
1485
|
+
sessionToken: session.token
|
|
1486
|
+
}
|
|
1487
|
+
);
|
|
1488
|
+
if (resolution.kind === "existing_member") {
|
|
1489
|
+
return [null, { ...resolution, session }];
|
|
1490
|
+
}
|
|
1491
|
+
return [null, { ...resolution, session }];
|
|
1492
|
+
} catch (cause) {
|
|
1493
|
+
return [fromConvexError(cause), null];
|
|
1494
|
+
}
|
|
1495
|
+
},
|
|
1496
|
+
completeBootstrap: async (input) => {
|
|
1497
|
+
const session = sessionStore.get();
|
|
1498
|
+
const data = dataClient ?? config._data;
|
|
1499
|
+
if (!session || !data) {
|
|
1500
|
+
return [
|
|
1501
|
+
new CapxulError({
|
|
1502
|
+
code: "INVALID_INPUT",
|
|
1503
|
+
message: "completeBootstrap requires the OTP-verified session that issued the bootstrap token."
|
|
1504
|
+
}),
|
|
1505
|
+
null
|
|
1506
|
+
];
|
|
1507
|
+
}
|
|
1508
|
+
const signerAddress = config.signer?.address;
|
|
1509
|
+
if (!signerAddress) {
|
|
1510
|
+
return [
|
|
1511
|
+
new CapxulError({
|
|
1512
|
+
code: "INVALID_INPUT",
|
|
1513
|
+
message: "completeBootstrap requires a signer to be configured on the client."
|
|
1514
|
+
}),
|
|
1515
|
+
null
|
|
1516
|
+
];
|
|
1517
|
+
}
|
|
1518
|
+
try {
|
|
1519
|
+
const safeAddress = deriveSafeAddress(signerAddress);
|
|
1520
|
+
const result = await data.mutation(api.authBootstrap.completeBootstrap, {
|
|
1521
|
+
bootstrapToken: input.bootstrapToken,
|
|
1522
|
+
sessionToken: session.token,
|
|
1523
|
+
username: input.username,
|
|
1524
|
+
displayName: input.displayName,
|
|
1525
|
+
countryCode: input.countryCode,
|
|
1526
|
+
signerProvider: {
|
|
1527
|
+
kind: "local-private-key",
|
|
1528
|
+
signerAddress,
|
|
1529
|
+
safeAddress
|
|
1530
|
+
}
|
|
1531
|
+
});
|
|
1532
|
+
return [null, { kind: "authenticated", session, ...result }];
|
|
1533
|
+
} catch (cause) {
|
|
1534
|
+
return [
|
|
1535
|
+
fromConvexError(cause),
|
|
1536
|
+
null
|
|
1537
|
+
];
|
|
1029
1538
|
}
|
|
1030
|
-
return [null, session];
|
|
1031
1539
|
},
|
|
1032
1540
|
getSession: async () => [null, sessionStore.get()],
|
|
1033
1541
|
signOut: async () => {
|
|
1034
1542
|
sessionStore.clear();
|
|
1035
1543
|
dataClient = null;
|
|
1036
|
-
mutableConfig(config).
|
|
1544
|
+
mutableConfig(config)._data = void 0;
|
|
1037
1545
|
const transport = getTransport();
|
|
1038
1546
|
transport?.clearAuth();
|
|
1039
1547
|
return [null, void 0];
|
|
@@ -1104,6 +1612,9 @@ async function postBetterAuth(transport, path, body, code, signal) {
|
|
|
1104
1612
|
}
|
|
1105
1613
|
return [null, text ? JSON.parse(text) : void 0];
|
|
1106
1614
|
} catch (cause) {
|
|
1615
|
+
if (cause instanceof CapxulError) {
|
|
1616
|
+
return [cause, null];
|
|
1617
|
+
}
|
|
1107
1618
|
return [
|
|
1108
1619
|
new CapxulError({
|
|
1109
1620
|
code: "NETWORK_ERROR",
|
|
@@ -1142,7 +1653,7 @@ function parseBetterAuthError(text) {
|
|
|
1142
1653
|
}
|
|
1143
1654
|
}
|
|
1144
1655
|
function isCapxulErrorCode2(code) {
|
|
1145
|
-
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";
|
|
1656
|
+
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";
|
|
1146
1657
|
}
|
|
1147
1658
|
async function exchangeConvexToken(transport, config, token, signal) {
|
|
1148
1659
|
const path = config.auth?.convexTokenUrl ?? "/convex/token";
|
|
@@ -1172,6 +1683,9 @@ async function exchangeConvexToken(transport, config, token, signal) {
|
|
|
1172
1683
|
}
|
|
1173
1684
|
return [null, body.token];
|
|
1174
1685
|
} catch (cause) {
|
|
1686
|
+
if (cause instanceof CapxulError) {
|
|
1687
|
+
return [cause, null];
|
|
1688
|
+
}
|
|
1175
1689
|
return [
|
|
1176
1690
|
new CapxulError({
|
|
1177
1691
|
code: "NETWORK_ERROR",
|
|
@@ -1208,11 +1722,11 @@ function createOrgDocumentsClient() {
|
|
|
1208
1722
|
function createMeClient(config = {}) {
|
|
1209
1723
|
return {
|
|
1210
1724
|
get: async () => {
|
|
1211
|
-
if (!config.
|
|
1725
|
+
if (!config._data) {
|
|
1212
1726
|
return stub("me.get");
|
|
1213
1727
|
}
|
|
1214
1728
|
try {
|
|
1215
|
-
const account = await config.
|
|
1729
|
+
const account = await config._data.query(
|
|
1216
1730
|
api.openfort.queries.getMyAccount,
|
|
1217
1731
|
{}
|
|
1218
1732
|
);
|
|
@@ -1222,7 +1736,7 @@ function createMeClient(config = {}) {
|
|
|
1222
1736
|
}
|
|
1223
1737
|
},
|
|
1224
1738
|
update: async (input) => {
|
|
1225
|
-
if (!config.
|
|
1739
|
+
if (!config._data) {
|
|
1226
1740
|
return stub("me.update");
|
|
1227
1741
|
}
|
|
1228
1742
|
if (input.countryCode !== void 0) {
|
|
@@ -1236,11 +1750,11 @@ function createMeClient(config = {}) {
|
|
|
1236
1750
|
];
|
|
1237
1751
|
}
|
|
1238
1752
|
try {
|
|
1239
|
-
await config.
|
|
1753
|
+
await config._data.mutation(api.openfort.mutations.updateProfile, {
|
|
1240
1754
|
displayName: input.name,
|
|
1241
1755
|
username: input.username
|
|
1242
1756
|
});
|
|
1243
|
-
const account = await config.
|
|
1757
|
+
const account = await config._data.query(
|
|
1244
1758
|
api.openfort.queries.getMyAccount,
|
|
1245
1759
|
{}
|
|
1246
1760
|
);
|
|
@@ -1255,11 +1769,11 @@ function createMeClient(config = {}) {
|
|
|
1255
1769
|
// src/core/operations.ts
|
|
1256
1770
|
function createOperationsClient(config = {}) {
|
|
1257
1771
|
const retrieve = async (operationId) => {
|
|
1258
|
-
if (!config.
|
|
1772
|
+
if (!config._data) {
|
|
1259
1773
|
return stub("operations.retrieve");
|
|
1260
1774
|
}
|
|
1261
1775
|
try {
|
|
1262
|
-
const operation = await config.
|
|
1776
|
+
const operation = await config._data.query(api.operations.queries.retrieve, {
|
|
1263
1777
|
operationId
|
|
1264
1778
|
});
|
|
1265
1779
|
if (!operation) {
|
|
@@ -1276,7 +1790,7 @@ function createOperationsClient(config = {}) {
|
|
|
1276
1790
|
return {
|
|
1277
1791
|
retrieve,
|
|
1278
1792
|
wait: async (operationId, input = {}) => {
|
|
1279
|
-
if (!config.
|
|
1793
|
+
if (!config._data) {
|
|
1280
1794
|
return stub("operations.wait");
|
|
1281
1795
|
}
|
|
1282
1796
|
const until = new Set(
|
|
@@ -1311,49 +1825,22 @@ function toTokenUnits(value, decimals = 6) {
|
|
|
1311
1825
|
return viem.parseUnits(value, decimals);
|
|
1312
1826
|
}
|
|
1313
1827
|
|
|
1314
|
-
// src/
|
|
1315
|
-
function
|
|
1828
|
+
// src/core/token-registry.ts
|
|
1829
|
+
function resolvePaymentToken(currency) {
|
|
1316
1830
|
const normalized = currency.trim().toUpperCase();
|
|
1317
1831
|
if (normalized === "USD" || normalized === "USDC") {
|
|
1318
|
-
return
|
|
1832
|
+
return {
|
|
1833
|
+
address: TEST_USDC_ADDRESS.toLowerCase(),
|
|
1834
|
+
decimals: 6,
|
|
1835
|
+
symbol: "USDC"
|
|
1836
|
+
};
|
|
1319
1837
|
}
|
|
1320
1838
|
throw new CapxulError({
|
|
1321
|
-
code: "
|
|
1322
|
-
message: `Currency ${currency} is not
|
|
1839
|
+
code: "NOT_IMPLEMENTED",
|
|
1840
|
+
message: `Currency ${currency} is not yet supported by the token registry.`,
|
|
1323
1841
|
details: { currency: normalized }
|
|
1324
1842
|
});
|
|
1325
1843
|
}
|
|
1326
|
-
async function buildSafeAccount(signer, chain) {
|
|
1327
|
-
try {
|
|
1328
|
-
const publicClient = viem.createPublicClient({
|
|
1329
|
-
chain: chains.baseSepolia,
|
|
1330
|
-
transport: viem.http(chain.rpcUrl)
|
|
1331
|
-
});
|
|
1332
|
-
return await accounts.toSafeSmartAccount({
|
|
1333
|
-
client: publicClient,
|
|
1334
|
-
entryPoint: { address: accountAbstraction.entryPoint07Address, version: "0.7" },
|
|
1335
|
-
version: "1.4.1",
|
|
1336
|
-
owners: [signer],
|
|
1337
|
-
saltNonce: computeSaltNonce(signer.address),
|
|
1338
|
-
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
1339
|
-
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
1340
|
-
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
1341
|
-
safe4337ModuleAddress: SAFE_4337_MODULE,
|
|
1342
|
-
safeModules: [],
|
|
1343
|
-
setupTransactions: []
|
|
1344
|
-
});
|
|
1345
|
-
} catch (cause) {
|
|
1346
|
-
throw new CapxulError({
|
|
1347
|
-
code: "NETWORK_ERROR",
|
|
1348
|
-
message: cause instanceof Error ? cause.message : String(cause),
|
|
1349
|
-
cause,
|
|
1350
|
-
details: { chainId: chain.chainId }
|
|
1351
|
-
});
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
function computeSaltNonce(ownerAddress) {
|
|
1355
|
-
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
1356
|
-
}
|
|
1357
1844
|
function createCapxulBundler(config) {
|
|
1358
1845
|
const paymaster = accountAbstraction.createPaymasterClient({
|
|
1359
1846
|
transport: viem.http(config.rpcUrl)
|
|
@@ -1460,13 +1947,13 @@ async function transferAsOwner(config, params) {
|
|
|
1460
1947
|
function createPaymentsClient(config = {}) {
|
|
1461
1948
|
return {
|
|
1462
1949
|
create: async (input) => {
|
|
1463
|
-
if (!config.
|
|
1950
|
+
if (!config._data || !config.signer || !config.signing) {
|
|
1464
1951
|
return stub("payments.create");
|
|
1465
1952
|
}
|
|
1466
1953
|
let created = null;
|
|
1467
1954
|
let submitted = null;
|
|
1468
1955
|
try {
|
|
1469
|
-
created = await config.
|
|
1956
|
+
created = await config._data.mutation(api.payments.mutations.create, {
|
|
1470
1957
|
to: input.to,
|
|
1471
1958
|
amount: input.amount,
|
|
1472
1959
|
reference: input.reference,
|
|
@@ -1474,15 +1961,21 @@ function createPaymentsClient(config = {}) {
|
|
|
1474
1961
|
source: input.source
|
|
1475
1962
|
});
|
|
1476
1963
|
if (!created) {
|
|
1477
|
-
return [
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1964
|
+
return [
|
|
1965
|
+
new CapxulError({
|
|
1966
|
+
code: "NETWORK_ERROR",
|
|
1967
|
+
message: "payments.create returned no payment resource"
|
|
1968
|
+
}),
|
|
1969
|
+
null
|
|
1970
|
+
];
|
|
1481
1971
|
}
|
|
1482
1972
|
if (created.status !== "processing" || created.operation.status !== "processing") {
|
|
1483
1973
|
return [null, created];
|
|
1484
1974
|
}
|
|
1485
|
-
const currentSigner = await config.
|
|
1975
|
+
const currentSigner = await config._data.query(
|
|
1976
|
+
api.safe.queries.getMySignerAddress,
|
|
1977
|
+
{}
|
|
1978
|
+
);
|
|
1486
1979
|
if (!currentSigner?.address) {
|
|
1487
1980
|
throw new CapxulError({
|
|
1488
1981
|
code: "PERMISSION_DENIED",
|
|
@@ -1501,9 +1994,12 @@ function createPaymentsClient(config = {}) {
|
|
|
1501
1994
|
}
|
|
1502
1995
|
});
|
|
1503
1996
|
}
|
|
1504
|
-
const submission = await config.
|
|
1505
|
-
|
|
1506
|
-
|
|
1997
|
+
const submission = await config._data.query(
|
|
1998
|
+
api.payments.queries.prepareSubmission,
|
|
1999
|
+
{
|
|
2000
|
+
paymentId: created.id
|
|
2001
|
+
}
|
|
2002
|
+
);
|
|
1507
2003
|
if (!submission?.recipientAddress) {
|
|
1508
2004
|
throw new CapxulError({
|
|
1509
2005
|
code: "NETWORK_ERROR",
|
|
@@ -1511,15 +2007,16 @@ function createPaymentsClient(config = {}) {
|
|
|
1511
2007
|
details: { paymentId: created.id }
|
|
1512
2008
|
});
|
|
1513
2009
|
}
|
|
2010
|
+
const token = resolvePaymentToken(submission.amount.currency);
|
|
1514
2011
|
const transfer = await transferAsOwner(
|
|
1515
2012
|
{
|
|
1516
2013
|
signer: config.signer,
|
|
1517
2014
|
signing: config.signing
|
|
1518
2015
|
},
|
|
1519
2016
|
{
|
|
1520
|
-
tokenAddress:
|
|
2017
|
+
tokenAddress: token.address,
|
|
1521
2018
|
recipientAddress: submission.recipientAddress,
|
|
1522
|
-
amount: toTokenUnits(submission.amount.value,
|
|
2019
|
+
amount: toTokenUnits(submission.amount.value, token.decimals)
|
|
1523
2020
|
}
|
|
1524
2021
|
);
|
|
1525
2022
|
if (!transfer.success) {
|
|
@@ -1537,7 +2034,7 @@ function createPaymentsClient(config = {}) {
|
|
|
1537
2034
|
txHash: transfer.txHash,
|
|
1538
2035
|
userOpHash: transfer.userOpHash
|
|
1539
2036
|
};
|
|
1540
|
-
await config.
|
|
2037
|
+
await config._data.mutation(api.payments.mutations.recordSubmitted, {
|
|
1541
2038
|
paymentId: created.id,
|
|
1542
2039
|
txHash: transfer.txHash,
|
|
1543
2040
|
userOpHash: transfer.userOpHash,
|
|
@@ -1547,43 +2044,65 @@ function createPaymentsClient(config = {}) {
|
|
|
1547
2044
|
} catch (cause) {
|
|
1548
2045
|
const error = mapCreateError(fromConvexError(cause));
|
|
1549
2046
|
if (created?.id && created.status === "processing" && !submitted) {
|
|
1550
|
-
await bestEffortMarkFailed({
|
|
2047
|
+
await bestEffortMarkFailed({ _data: config._data }, created.id, error);
|
|
1551
2048
|
}
|
|
1552
2049
|
if (submitted && created?.id) {
|
|
1553
|
-
return [
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
2050
|
+
return [
|
|
2051
|
+
new CapxulError({
|
|
2052
|
+
code: "NETWORK_ERROR",
|
|
2053
|
+
message: "Payment was submitted on-chain, but backend submission tracking failed.",
|
|
2054
|
+
cause,
|
|
2055
|
+
details: {
|
|
2056
|
+
paymentId: created.id,
|
|
2057
|
+
txHash: submitted.txHash,
|
|
2058
|
+
userOpHash: submitted.userOpHash
|
|
2059
|
+
}
|
|
2060
|
+
}),
|
|
2061
|
+
null
|
|
2062
|
+
];
|
|
1563
2063
|
}
|
|
1564
2064
|
return [error, null];
|
|
1565
2065
|
}
|
|
1566
2066
|
},
|
|
1567
2067
|
retrieve: async (paymentId) => {
|
|
1568
|
-
if (!config.
|
|
2068
|
+
if (!config._data) {
|
|
1569
2069
|
return stub("payments.retrieve");
|
|
1570
2070
|
}
|
|
1571
2071
|
try {
|
|
1572
|
-
const payment = await config.
|
|
1573
|
-
|
|
1574
|
-
|
|
2072
|
+
const payment = await config._data.query(
|
|
2073
|
+
api.payments.queries.retrieve,
|
|
2074
|
+
{
|
|
2075
|
+
paymentId
|
|
2076
|
+
}
|
|
2077
|
+
);
|
|
1575
2078
|
if (!payment) {
|
|
1576
|
-
return [
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
2079
|
+
return [
|
|
2080
|
+
new CapxulError({
|
|
2081
|
+
code: "NOT_FOUND",
|
|
2082
|
+
message: `payment ${paymentId} not found`
|
|
2083
|
+
}),
|
|
2084
|
+
null
|
|
2085
|
+
];
|
|
1580
2086
|
}
|
|
1581
2087
|
return [null, payment];
|
|
1582
2088
|
} catch (cause) {
|
|
1583
2089
|
return [fromConvexError(cause), null];
|
|
1584
2090
|
}
|
|
1585
2091
|
},
|
|
1586
|
-
list: async () =>
|
|
2092
|
+
list: async (input) => {
|
|
2093
|
+
if (!config._data) {
|
|
2094
|
+
return stub("payments.list");
|
|
2095
|
+
}
|
|
2096
|
+
try {
|
|
2097
|
+
const page = await config._data.query(api.payments.queries.list, {
|
|
2098
|
+
limit: input?.limit,
|
|
2099
|
+
cursor: input?.cursor
|
|
2100
|
+
});
|
|
2101
|
+
return [null, page];
|
|
2102
|
+
} catch (cause) {
|
|
2103
|
+
return [fromConvexError(cause), null];
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
1587
2106
|
};
|
|
1588
2107
|
}
|
|
1589
2108
|
function createOrgPaymentsClient() {
|
|
@@ -1597,7 +2116,7 @@ function createOrgPaymentsClient() {
|
|
|
1597
2116
|
}
|
|
1598
2117
|
async function bestEffortMarkFailed(config, paymentId, error) {
|
|
1599
2118
|
try {
|
|
1600
|
-
await config.
|
|
2119
|
+
await config._data.mutation(api.payments.mutations.markFailed, {
|
|
1601
2120
|
paymentId,
|
|
1602
2121
|
errorCode: error.code,
|
|
1603
2122
|
errorMessage: error.message,
|
|
@@ -1654,11 +2173,11 @@ function createOrgTransfersClient() {
|
|
|
1654
2173
|
function createWithdrawalsClient(config = {}) {
|
|
1655
2174
|
return {
|
|
1656
2175
|
create: async (input) => {
|
|
1657
|
-
if (!config.
|
|
2176
|
+
if (!config._data) {
|
|
1658
2177
|
return stub("withdrawals.create");
|
|
1659
2178
|
}
|
|
1660
2179
|
const [createErr, createdRaw] = await tryCatch(
|
|
1661
|
-
config.
|
|
2180
|
+
config._data.mutation(api.withdrawals.mutations.create, {
|
|
1662
2181
|
amount: input.amount,
|
|
1663
2182
|
destination: {
|
|
1664
2183
|
externalAccountId: input.destination.externalAccountId
|
|
@@ -1688,18 +2207,18 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1688
2207
|
return [null, created];
|
|
1689
2208
|
}
|
|
1690
2209
|
const [signerErr, currentSigner] = await tryCatch(
|
|
1691
|
-
config.
|
|
2210
|
+
config._data.query(api.safe.queries.getMySignerAddress, {})
|
|
1692
2211
|
);
|
|
1693
2212
|
if (signerErr) {
|
|
1694
2213
|
return await handleSubmissionFailure(
|
|
1695
|
-
{
|
|
2214
|
+
{ _data: config._data },
|
|
1696
2215
|
created.id,
|
|
1697
2216
|
mapCreateError2(fromConvexError(signerErr))
|
|
1698
2217
|
);
|
|
1699
2218
|
}
|
|
1700
2219
|
if (!currentSigner?.address) {
|
|
1701
2220
|
return await handleSubmissionFailure(
|
|
1702
|
-
{
|
|
2221
|
+
{ _data: config._data },
|
|
1703
2222
|
created.id,
|
|
1704
2223
|
new CapxulError({
|
|
1705
2224
|
code: "PERMISSION_DENIED",
|
|
@@ -1710,7 +2229,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1710
2229
|
}
|
|
1711
2230
|
if (viem.getAddress(currentSigner.address) !== viem.getAddress(config.signer.address)) {
|
|
1712
2231
|
return await handleSubmissionFailure(
|
|
1713
|
-
{
|
|
2232
|
+
{ _data: config._data },
|
|
1714
2233
|
created.id,
|
|
1715
2234
|
new CapxulError({
|
|
1716
2235
|
code: "PERMISSION_DENIED",
|
|
@@ -1724,13 +2243,13 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1724
2243
|
);
|
|
1725
2244
|
}
|
|
1726
2245
|
const [prepErr, submission] = await tryCatch(
|
|
1727
|
-
config.
|
|
2246
|
+
config._data.query(api.withdrawals.queries.prepareSubmission, {
|
|
1728
2247
|
withdrawalId: created.id
|
|
1729
2248
|
})
|
|
1730
2249
|
);
|
|
1731
2250
|
if (prepErr) {
|
|
1732
2251
|
return await handleSubmissionFailure(
|
|
1733
|
-
{
|
|
2252
|
+
{ _data: config._data },
|
|
1734
2253
|
created.id,
|
|
1735
2254
|
mapCreateError2(fromConvexError(prepErr))
|
|
1736
2255
|
);
|
|
@@ -1738,7 +2257,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1738
2257
|
const destinationAddress = submission?.destinationAddress;
|
|
1739
2258
|
if (!submission || !destinationAddress) {
|
|
1740
2259
|
return await handleSubmissionFailure(
|
|
1741
|
-
{
|
|
2260
|
+
{ _data: config._data },
|
|
1742
2261
|
created.id,
|
|
1743
2262
|
new CapxulError({
|
|
1744
2263
|
code: "NETWORK_ERROR",
|
|
@@ -1747,6 +2266,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1747
2266
|
})
|
|
1748
2267
|
);
|
|
1749
2268
|
}
|
|
2269
|
+
const token = resolvePaymentToken(submission.amount.currency);
|
|
1750
2270
|
const [transferErr, transferOk] = await tryCatch(
|
|
1751
2271
|
transferAsOwner(
|
|
1752
2272
|
{
|
|
@@ -1754,22 +2274,22 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1754
2274
|
signing: config.signing
|
|
1755
2275
|
},
|
|
1756
2276
|
{
|
|
1757
|
-
tokenAddress:
|
|
2277
|
+
tokenAddress: token.address,
|
|
1758
2278
|
recipientAddress: destinationAddress,
|
|
1759
|
-
amount: toTokenUnits(submission.amount.value,
|
|
2279
|
+
amount: toTokenUnits(submission.amount.value, token.decimals)
|
|
1760
2280
|
}
|
|
1761
2281
|
)
|
|
1762
2282
|
);
|
|
1763
2283
|
if (transferErr) {
|
|
1764
2284
|
return await handleSubmissionFailure(
|
|
1765
|
-
{
|
|
2285
|
+
{ _data: config._data },
|
|
1766
2286
|
created.id,
|
|
1767
2287
|
mapCreateError2(fromConvexError(transferErr))
|
|
1768
2288
|
);
|
|
1769
2289
|
}
|
|
1770
2290
|
if (!transferOk.success) {
|
|
1771
2291
|
return await handleSubmissionFailure(
|
|
1772
|
-
{
|
|
2292
|
+
{ _data: config._data },
|
|
1773
2293
|
created.id,
|
|
1774
2294
|
new CapxulError({
|
|
1775
2295
|
code: "NETWORK_ERROR",
|
|
@@ -1783,7 +2303,7 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1783
2303
|
);
|
|
1784
2304
|
}
|
|
1785
2305
|
const [recordErr] = await tryCatch(
|
|
1786
|
-
config.
|
|
2306
|
+
config._data.mutation(api.withdrawals.mutations.recordSubmitted, {
|
|
1787
2307
|
withdrawalId: created.id,
|
|
1788
2308
|
txHash: transferOk.txHash,
|
|
1789
2309
|
userOpHash: transferOk.userOpHash
|
|
@@ -1807,11 +2327,11 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1807
2327
|
return [null, created];
|
|
1808
2328
|
},
|
|
1809
2329
|
retrieve: async (withdrawalId) => {
|
|
1810
|
-
if (!config.
|
|
2330
|
+
if (!config._data) {
|
|
1811
2331
|
return stub("withdrawals.retrieve");
|
|
1812
2332
|
}
|
|
1813
2333
|
const [err, raw] = await tryCatch(
|
|
1814
|
-
config.
|
|
2334
|
+
config._data.query(api.withdrawals.queries.retrieve, { withdrawalId })
|
|
1815
2335
|
);
|
|
1816
2336
|
if (err) {
|
|
1817
2337
|
return [fromConvexError(err), null];
|
|
@@ -1829,11 +2349,11 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1829
2349
|
return [null, withdrawal];
|
|
1830
2350
|
},
|
|
1831
2351
|
list: async (input) => {
|
|
1832
|
-
if (!config.
|
|
2352
|
+
if (!config._data) {
|
|
1833
2353
|
return stub("withdrawals.list");
|
|
1834
2354
|
}
|
|
1835
2355
|
const [err, raw] = await tryCatch(
|
|
1836
|
-
config.
|
|
2356
|
+
config._data.query(api.withdrawals.queries.list, {
|
|
1837
2357
|
limit: input?.limit,
|
|
1838
2358
|
cursor: input?.cursor
|
|
1839
2359
|
})
|
|
@@ -1844,13 +2364,13 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1844
2364
|
return [null, raw];
|
|
1845
2365
|
},
|
|
1846
2366
|
recordCompleted: async (input) => {
|
|
1847
|
-
if (!config.
|
|
2367
|
+
if (!config._data) {
|
|
1848
2368
|
return stub(
|
|
1849
2369
|
"withdrawals.recordCompleted"
|
|
1850
2370
|
);
|
|
1851
2371
|
}
|
|
1852
2372
|
const [err] = await tryCatch(
|
|
1853
|
-
config.
|
|
2373
|
+
config._data.mutation(api.withdrawals.mutations.recordCompleted, {
|
|
1854
2374
|
withdrawalId: input.withdrawalId,
|
|
1855
2375
|
txHash: input.txHash
|
|
1856
2376
|
})
|
|
@@ -1875,13 +2395,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1875
2395
|
* orchestration ships in W3+.
|
|
1876
2396
|
*/
|
|
1877
2397
|
create: async (input) => {
|
|
1878
|
-
if (!config.
|
|
2398
|
+
if (!config._data) {
|
|
1879
2399
|
return stub(
|
|
1880
2400
|
"organizations.withdrawals.create"
|
|
1881
2401
|
);
|
|
1882
2402
|
}
|
|
1883
2403
|
const [err, raw] = await tryCatch(
|
|
1884
|
-
config.
|
|
2404
|
+
config._data.mutation(api.withdrawals.mutations.createOrg, {
|
|
1885
2405
|
organizationId: input.organizationId,
|
|
1886
2406
|
amount: input.amount,
|
|
1887
2407
|
destination: {
|
|
@@ -1908,13 +2428,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1908
2428
|
return [null, created];
|
|
1909
2429
|
},
|
|
1910
2430
|
retrieve: async (input) => {
|
|
1911
|
-
if (!config.
|
|
2431
|
+
if (!config._data) {
|
|
1912
2432
|
return stub(
|
|
1913
2433
|
"organizations.withdrawals.retrieve"
|
|
1914
2434
|
);
|
|
1915
2435
|
}
|
|
1916
2436
|
const [err, raw] = await tryCatch(
|
|
1917
|
-
config.
|
|
2437
|
+
config._data.query(api.withdrawals.queries.retrieve, {
|
|
1918
2438
|
withdrawalId: input.withdrawalId
|
|
1919
2439
|
})
|
|
1920
2440
|
);
|
|
@@ -1944,13 +2464,13 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1944
2464
|
return [null, withdrawal];
|
|
1945
2465
|
},
|
|
1946
2466
|
list: async (input) => {
|
|
1947
|
-
if (!config.
|
|
2467
|
+
if (!config._data) {
|
|
1948
2468
|
return stub(
|
|
1949
2469
|
"organizations.withdrawals.list"
|
|
1950
2470
|
);
|
|
1951
2471
|
}
|
|
1952
2472
|
const [err, raw] = await tryCatch(
|
|
1953
|
-
config.
|
|
2473
|
+
config._data.query(api.withdrawals.queries.listOrg, {
|
|
1954
2474
|
organizationId: input.organizationId,
|
|
1955
2475
|
limit: input.limit,
|
|
1956
2476
|
cursor: input.cursor
|
|
@@ -1969,7 +2489,7 @@ async function handleSubmissionFailure(config, withdrawalId, error) {
|
|
|
1969
2489
|
}
|
|
1970
2490
|
async function bestEffortMarkFailed2(config, withdrawalId, error) {
|
|
1971
2491
|
await tryCatch(
|
|
1972
|
-
config.
|
|
2492
|
+
config._data.mutation(api.withdrawals.mutations.markFailed, {
|
|
1973
2493
|
withdrawalId,
|
|
1974
2494
|
errorCode: error.code,
|
|
1975
2495
|
errorMessage: error.message
|
|
@@ -2048,13 +2568,13 @@ function createWebhookEventsClient() {
|
|
|
2048
2568
|
function createOrgExternalAccountsClient(config) {
|
|
2049
2569
|
return {
|
|
2050
2570
|
create: async (input) => {
|
|
2051
|
-
if (!config.
|
|
2571
|
+
if (!config._data) {
|
|
2052
2572
|
return stub(
|
|
2053
2573
|
"organizations.externalAccounts.create"
|
|
2054
2574
|
);
|
|
2055
2575
|
}
|
|
2056
2576
|
const [err, raw] = await tryCatch(
|
|
2057
|
-
config.
|
|
2577
|
+
config._data.mutation(api.externalAccounts.mutations.createOrg, {
|
|
2058
2578
|
organizationId: input.organizationId,
|
|
2059
2579
|
kind: input.kind,
|
|
2060
2580
|
label: input.label,
|
|
@@ -2068,10 +2588,7 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2068
2588
|
})
|
|
2069
2589
|
);
|
|
2070
2590
|
if (err) {
|
|
2071
|
-
return [
|
|
2072
|
-
fromConvexError(err),
|
|
2073
|
-
null
|
|
2074
|
-
];
|
|
2591
|
+
return [fromConvexError(err), null];
|
|
2075
2592
|
}
|
|
2076
2593
|
if (!raw) {
|
|
2077
2594
|
return [
|
|
@@ -2082,21 +2599,16 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2082
2599
|
null
|
|
2083
2600
|
];
|
|
2084
2601
|
}
|
|
2085
|
-
return [
|
|
2086
|
-
null,
|
|
2087
|
-
brandExternalAccount(
|
|
2088
|
-
raw
|
|
2089
|
-
)
|
|
2090
|
-
];
|
|
2602
|
+
return [null, brandExternalAccount(raw)];
|
|
2091
2603
|
},
|
|
2092
2604
|
list: async (input) => {
|
|
2093
|
-
if (!config.
|
|
2605
|
+
if (!config._data) {
|
|
2094
2606
|
return stub(
|
|
2095
2607
|
"organizations.externalAccounts.list"
|
|
2096
2608
|
);
|
|
2097
2609
|
}
|
|
2098
2610
|
const [err, result] = await tryCatch(
|
|
2099
|
-
config.
|
|
2611
|
+
config._data.query(api.externalAccounts.queries.listOrg, {
|
|
2100
2612
|
organizationId: input.organizationId,
|
|
2101
2613
|
limit: input.limit,
|
|
2102
2614
|
cursor: input.cursor
|
|
@@ -2106,9 +2618,7 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2106
2618
|
return [fromConvexError(err), null];
|
|
2107
2619
|
}
|
|
2108
2620
|
const branded = result.data.map(
|
|
2109
|
-
(row) => brandExternalAccount(
|
|
2110
|
-
row
|
|
2111
|
-
)
|
|
2621
|
+
(row) => brandExternalAccount(row)
|
|
2112
2622
|
);
|
|
2113
2623
|
return [
|
|
2114
2624
|
null,
|
|
@@ -2120,17 +2630,66 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2120
2630
|
];
|
|
2121
2631
|
},
|
|
2122
2632
|
retrieve: async (input) => {
|
|
2123
|
-
if (!config.
|
|
2633
|
+
if (!config._data) {
|
|
2124
2634
|
return stub(
|
|
2125
2635
|
"organizations.externalAccounts.retrieve"
|
|
2126
2636
|
);
|
|
2127
2637
|
}
|
|
2128
2638
|
const [err, raw] = await tryCatch(
|
|
2129
|
-
config.
|
|
2639
|
+
config._data.query(api.externalAccounts.queries.retrieveOrg, {
|
|
2640
|
+
organizationId: input.organizationId,
|
|
2641
|
+
externalAccountId: input.externalAccountId
|
|
2642
|
+
})
|
|
2643
|
+
);
|
|
2644
|
+
if (err) {
|
|
2645
|
+
return [fromConvexError(err), null];
|
|
2646
|
+
}
|
|
2647
|
+
if (!raw) {
|
|
2648
|
+
return [
|
|
2649
|
+
new CapxulError({
|
|
2650
|
+
code: "NOT_FOUND",
|
|
2651
|
+
message: `external_account ${input.externalAccountId} not found`
|
|
2652
|
+
}),
|
|
2653
|
+
null
|
|
2654
|
+
];
|
|
2655
|
+
}
|
|
2656
|
+
return [null, brandExternalAccount(raw)];
|
|
2657
|
+
},
|
|
2658
|
+
remove: async (input) => {
|
|
2659
|
+
if (!config._data) {
|
|
2660
|
+
return stub("organizations.externalAccounts.remove");
|
|
2661
|
+
}
|
|
2662
|
+
const [err] = await tryCatch(
|
|
2663
|
+
config._data.mutation(api.externalAccounts.mutations.removeOrg, {
|
|
2130
2664
|
organizationId: input.organizationId,
|
|
2131
2665
|
externalAccountId: input.externalAccountId
|
|
2132
2666
|
})
|
|
2133
2667
|
);
|
|
2668
|
+
if (err) {
|
|
2669
|
+
return [fromConvexError(err), null];
|
|
2670
|
+
}
|
|
2671
|
+
return [null, void 0];
|
|
2672
|
+
}
|
|
2673
|
+
};
|
|
2674
|
+
}
|
|
2675
|
+
function createOrgSubAccountsClient(config) {
|
|
2676
|
+
return {
|
|
2677
|
+
create: async (input) => {
|
|
2678
|
+
if (!config._data) {
|
|
2679
|
+
return stub(
|
|
2680
|
+
"organizations.subAccounts.create"
|
|
2681
|
+
);
|
|
2682
|
+
}
|
|
2683
|
+
const [err, raw] = await tryCatch(
|
|
2684
|
+
config._data.mutation(api.subAccounts.mutations.create, {
|
|
2685
|
+
parent: {
|
|
2686
|
+
kind: "organization",
|
|
2687
|
+
id: input.organizationId
|
|
2688
|
+
},
|
|
2689
|
+
name: input.name,
|
|
2690
|
+
purpose: input.purpose
|
|
2691
|
+
})
|
|
2692
|
+
);
|
|
2134
2693
|
if (err) {
|
|
2135
2694
|
return [
|
|
2136
2695
|
fromConvexError(err),
|
|
@@ -2141,28 +2700,95 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2141
2700
|
return [
|
|
2142
2701
|
new CapxulError({
|
|
2143
2702
|
code: "NOT_FOUND",
|
|
2144
|
-
message:
|
|
2703
|
+
message: "sub_account creation returned no resource"
|
|
2145
2704
|
}),
|
|
2146
2705
|
null
|
|
2147
2706
|
];
|
|
2148
2707
|
}
|
|
2708
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
2709
|
+
if (brandErr) {
|
|
2710
|
+
return [brandErr, null];
|
|
2711
|
+
}
|
|
2712
|
+
return [null, branded];
|
|
2713
|
+
},
|
|
2714
|
+
list: async (input) => {
|
|
2715
|
+
if (!config._data) {
|
|
2716
|
+
return stub(
|
|
2717
|
+
"organizations.subAccounts.list"
|
|
2718
|
+
);
|
|
2719
|
+
}
|
|
2720
|
+
const [err, rows] = await tryCatch(
|
|
2721
|
+
config._data.query(api.subAccounts.queries.listByOrganization, {
|
|
2722
|
+
organizationId: input.organizationId
|
|
2723
|
+
})
|
|
2724
|
+
);
|
|
2725
|
+
if (err) {
|
|
2726
|
+
return [
|
|
2727
|
+
fromConvexError(err),
|
|
2728
|
+
null
|
|
2729
|
+
];
|
|
2730
|
+
}
|
|
2731
|
+
const branded = [];
|
|
2732
|
+
for (const row of rows) {
|
|
2733
|
+
const [brandErr, value] = tryBrandSubAccount(row);
|
|
2734
|
+
if (brandErr) {
|
|
2735
|
+
return [brandErr, null];
|
|
2736
|
+
}
|
|
2737
|
+
branded.push(value);
|
|
2738
|
+
}
|
|
2149
2739
|
return [
|
|
2150
2740
|
null,
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2741
|
+
{
|
|
2742
|
+
object: "list",
|
|
2743
|
+
data: branded,
|
|
2744
|
+
page: { hasMore: false }
|
|
2745
|
+
}
|
|
2154
2746
|
];
|
|
2155
2747
|
},
|
|
2748
|
+
retrieve: async (input) => {
|
|
2749
|
+
if (!config._data) {
|
|
2750
|
+
return stub(
|
|
2751
|
+
"organizations.subAccounts.retrieve"
|
|
2752
|
+
);
|
|
2753
|
+
}
|
|
2754
|
+
const [err, raw] = await tryCatch(
|
|
2755
|
+
config._data.query(api.subAccounts.queries.retrieve, {
|
|
2756
|
+
subAccountId: input.subAccountId
|
|
2757
|
+
})
|
|
2758
|
+
);
|
|
2759
|
+
if (err) {
|
|
2760
|
+
return [
|
|
2761
|
+
fromConvexError(err),
|
|
2762
|
+
null
|
|
2763
|
+
];
|
|
2764
|
+
}
|
|
2765
|
+
if (!raw) {
|
|
2766
|
+
return [
|
|
2767
|
+
new CapxulError({
|
|
2768
|
+
code: "NOT_FOUND",
|
|
2769
|
+
message: `sub_account ${input.subAccountId} not found`
|
|
2770
|
+
}),
|
|
2771
|
+
null
|
|
2772
|
+
];
|
|
2773
|
+
}
|
|
2774
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
2775
|
+
if (brandErr) {
|
|
2776
|
+
return [
|
|
2777
|
+
brandErr,
|
|
2778
|
+
null
|
|
2779
|
+
];
|
|
2780
|
+
}
|
|
2781
|
+
return [null, branded];
|
|
2782
|
+
},
|
|
2156
2783
|
remove: async (input) => {
|
|
2157
|
-
if (!config.
|
|
2784
|
+
if (!config._data) {
|
|
2158
2785
|
return stub(
|
|
2159
|
-
"organizations.
|
|
2786
|
+
"organizations.subAccounts.remove"
|
|
2160
2787
|
);
|
|
2161
2788
|
}
|
|
2162
|
-
const [err] = await tryCatch(
|
|
2163
|
-
config.
|
|
2164
|
-
|
|
2165
|
-
externalAccountId: input.externalAccountId
|
|
2789
|
+
const [err, raw] = await tryCatch(
|
|
2790
|
+
config._data.mutation(api.subAccounts.mutations.archive, {
|
|
2791
|
+
subAccountId: input.subAccountId
|
|
2166
2792
|
})
|
|
2167
2793
|
);
|
|
2168
2794
|
if (err) {
|
|
@@ -2171,74 +2797,399 @@ function createOrgExternalAccountsClient(config) {
|
|
|
2171
2797
|
null
|
|
2172
2798
|
];
|
|
2173
2799
|
}
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2800
|
+
if (!raw) {
|
|
2801
|
+
return [
|
|
2802
|
+
new CapxulError({
|
|
2803
|
+
code: "NOT_FOUND",
|
|
2804
|
+
message: `sub_account ${input.subAccountId} not found`
|
|
2805
|
+
}),
|
|
2806
|
+
null
|
|
2807
|
+
];
|
|
2808
|
+
}
|
|
2809
|
+
const [brandErr, branded] = tryBrandSubAccount(raw);
|
|
2810
|
+
if (brandErr) {
|
|
2811
|
+
return [
|
|
2812
|
+
brandErr,
|
|
2813
|
+
null
|
|
2814
|
+
];
|
|
2815
|
+
}
|
|
2816
|
+
return [null, branded];
|
|
2817
|
+
}
|
|
2818
|
+
};
|
|
2819
|
+
}
|
|
2820
|
+
function createOrganizationsClient(config = {}) {
|
|
2821
|
+
return {
|
|
2822
|
+
create: async (input) => {
|
|
2823
|
+
if (!config._data) {
|
|
2824
|
+
return stub("organizations.create");
|
|
2825
|
+
}
|
|
2826
|
+
if (input.country !== void 0) {
|
|
2827
|
+
return [
|
|
2828
|
+
new CapxulError({
|
|
2829
|
+
code: "INVALID_INPUT",
|
|
2830
|
+
message: "organizations.create does not support country yet \u2014 backend mutation only accepts name.",
|
|
2831
|
+
details: { field: "country" }
|
|
2832
|
+
}),
|
|
2833
|
+
null
|
|
2834
|
+
];
|
|
2835
|
+
}
|
|
2836
|
+
try {
|
|
2837
|
+
const orgId = await config._data.mutation(api.org.mutations.create, {
|
|
2838
|
+
name: input.name
|
|
2839
|
+
});
|
|
2840
|
+
const org = await config._data.query(api.org.queries.retrieve, {
|
|
2841
|
+
orgId
|
|
2842
|
+
});
|
|
2843
|
+
if (!org) {
|
|
2844
|
+
return [
|
|
2845
|
+
new CapxulError({
|
|
2846
|
+
code: "NETWORK_ERROR",
|
|
2847
|
+
message: "organization created but could not be retrieved"
|
|
2848
|
+
}),
|
|
2849
|
+
null
|
|
2850
|
+
];
|
|
2851
|
+
}
|
|
2852
|
+
return [null, org];
|
|
2853
|
+
} catch (cause) {
|
|
2854
|
+
return [fromConvexError(cause), null];
|
|
2855
|
+
}
|
|
2856
|
+
},
|
|
2857
|
+
retrieve: async (organizationId) => {
|
|
2858
|
+
if (!config._data) {
|
|
2859
|
+
return stub("organizations.retrieve");
|
|
2860
|
+
}
|
|
2861
|
+
try {
|
|
2862
|
+
const orgId = organizationId.replace(/^org_/, "");
|
|
2863
|
+
const org = await config._data.query(api.org.queries.retrieve, {
|
|
2864
|
+
orgId
|
|
2865
|
+
});
|
|
2866
|
+
if (!org) {
|
|
2867
|
+
return [
|
|
2868
|
+
new CapxulError({
|
|
2869
|
+
code: "NOT_FOUND",
|
|
2870
|
+
message: `organization ${organizationId} not found`
|
|
2871
|
+
}),
|
|
2872
|
+
null
|
|
2873
|
+
];
|
|
2874
|
+
}
|
|
2875
|
+
return [null, org];
|
|
2876
|
+
} catch (cause) {
|
|
2877
|
+
return [fromConvexError(cause), null];
|
|
2878
|
+
}
|
|
2879
|
+
},
|
|
2880
|
+
list: async (input) => {
|
|
2881
|
+
if (!config._data) {
|
|
2882
|
+
return stub("organizations.list");
|
|
2883
|
+
}
|
|
2884
|
+
try {
|
|
2885
|
+
const page = await config._data.query(api.org.queries.list, {
|
|
2886
|
+
limit: input?.limit,
|
|
2887
|
+
cursor: input?.cursor
|
|
2888
|
+
});
|
|
2889
|
+
const result = {
|
|
2890
|
+
object: "list",
|
|
2891
|
+
data: page.data,
|
|
2892
|
+
page: {
|
|
2893
|
+
hasMore: page.hasMore,
|
|
2894
|
+
cursor: page.nextCursor
|
|
2895
|
+
}
|
|
2896
|
+
};
|
|
2897
|
+
return [null, result];
|
|
2898
|
+
} catch (cause) {
|
|
2899
|
+
return [fromConvexError(cause), null];
|
|
2900
|
+
}
|
|
2901
|
+
},
|
|
2902
|
+
update: async (input) => {
|
|
2903
|
+
if (!config._data) {
|
|
2904
|
+
return stub("organizations.update");
|
|
2905
|
+
}
|
|
2906
|
+
try {
|
|
2907
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
2908
|
+
const org = await config._data.mutation(api.org.mutations.update, {
|
|
2909
|
+
orgId,
|
|
2910
|
+
name: input.name
|
|
2911
|
+
});
|
|
2912
|
+
if (!org) {
|
|
2913
|
+
return [
|
|
2914
|
+
new CapxulError({
|
|
2915
|
+
code: "NOT_FOUND",
|
|
2916
|
+
message: `organization ${input.organizationId} not found`
|
|
2917
|
+
}),
|
|
2918
|
+
null
|
|
2919
|
+
];
|
|
2920
|
+
}
|
|
2921
|
+
return [null, org];
|
|
2922
|
+
} catch (cause) {
|
|
2923
|
+
return [fromConvexError(cause), null];
|
|
2924
|
+
}
|
|
2925
|
+
},
|
|
2926
|
+
safes: {
|
|
2927
|
+
retrieve: async (input) => {
|
|
2928
|
+
if (!config._data) {
|
|
2929
|
+
return stub("organizations.safes.retrieve");
|
|
2930
|
+
}
|
|
2931
|
+
try {
|
|
2932
|
+
const safe = await config._data.query(
|
|
2933
|
+
api.safe.queries.retrieveOrganizationSafe,
|
|
2934
|
+
input
|
|
2935
|
+
);
|
|
2936
|
+
if (!safe) {
|
|
2937
|
+
return [
|
|
2938
|
+
new CapxulError({
|
|
2939
|
+
code: "NOT_FOUND",
|
|
2940
|
+
message: `safe ${input.safeId} not found`
|
|
2941
|
+
}),
|
|
2942
|
+
null
|
|
2943
|
+
];
|
|
2944
|
+
}
|
|
2945
|
+
return [null, safe];
|
|
2946
|
+
} catch (cause) {
|
|
2947
|
+
return [
|
|
2948
|
+
fromConvexError(cause),
|
|
2949
|
+
null
|
|
2950
|
+
];
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
2953
|
+
},
|
|
2954
|
+
treasury: {
|
|
2955
|
+
retrieve: async (organizationId) => {
|
|
2956
|
+
if (!config._data) {
|
|
2957
|
+
return stub(
|
|
2958
|
+
"organizations.treasury.retrieve"
|
|
2959
|
+
);
|
|
2960
|
+
}
|
|
2961
|
+
try {
|
|
2962
|
+
const orgId = organizationId.replace(/^org_/, "");
|
|
2963
|
+
const raw = await config._data.query(
|
|
2964
|
+
api.safe.queries.getOrgTreasuryBalance,
|
|
2965
|
+
{ orgId }
|
|
2966
|
+
);
|
|
2967
|
+
if (!raw) {
|
|
2968
|
+
return [
|
|
2969
|
+
new CapxulError({
|
|
2970
|
+
code: "NOT_FOUND",
|
|
2971
|
+
message: `treasury for organization ${organizationId} not found`
|
|
2972
|
+
}),
|
|
2973
|
+
null
|
|
2974
|
+
];
|
|
2975
|
+
}
|
|
2976
|
+
const treasury = {
|
|
2977
|
+
object: "treasury",
|
|
2978
|
+
id: toTreasuryId(`try_${orgId}`),
|
|
2979
|
+
organizationId,
|
|
2980
|
+
status: "active",
|
|
2981
|
+
safeId: toSafeId(
|
|
2982
|
+
`safe_${raw.safeAddress.replace(/^0x/, "").toLowerCase()}`
|
|
2983
|
+
),
|
|
2984
|
+
totalBalance: { value: "0", currency: "USD" },
|
|
2985
|
+
positions: raw.tokens.map((t) => ({
|
|
2986
|
+
symbol: t.symbol,
|
|
2987
|
+
contractAddress: t.tokenAddress,
|
|
2988
|
+
amount: t.balance
|
|
2989
|
+
})),
|
|
2990
|
+
asOf: raw.lastUpdatedAt ? new Date(raw.lastUpdatedAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString()
|
|
2991
|
+
};
|
|
2992
|
+
return [null, treasury];
|
|
2993
|
+
} catch (cause) {
|
|
2994
|
+
return [
|
|
2995
|
+
fromConvexError(cause),
|
|
2996
|
+
null
|
|
2997
|
+
];
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
},
|
|
3001
|
+
members: {
|
|
3002
|
+
list: async (input) => {
|
|
3003
|
+
if (!config._data?.action) {
|
|
3004
|
+
return stub("organizations.members.list");
|
|
3005
|
+
}
|
|
3006
|
+
try {
|
|
3007
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3008
|
+
const page = await config._data.action(api.org.actions.membersList, {
|
|
3009
|
+
organizationId: orgId,
|
|
3010
|
+
status: input.status,
|
|
3011
|
+
limit: input.limit,
|
|
3012
|
+
cursor: input.cursor
|
|
3013
|
+
});
|
|
3014
|
+
return [null, page];
|
|
3015
|
+
} catch (cause) {
|
|
3016
|
+
return [fromConvexError(cause), null];
|
|
3017
|
+
}
|
|
3018
|
+
},
|
|
3019
|
+
retrieve: async (input) => {
|
|
3020
|
+
if (!config._data?.action) {
|
|
3021
|
+
return stub("organizations.members.retrieve");
|
|
3022
|
+
}
|
|
3023
|
+
try {
|
|
3024
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3025
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3026
|
+
const member = await config._data.action(
|
|
3027
|
+
api.org.actions.retrieveMember,
|
|
3028
|
+
{
|
|
3029
|
+
organizationId: orgId,
|
|
3030
|
+
memberId
|
|
3031
|
+
}
|
|
3032
|
+
);
|
|
3033
|
+
return [null, member];
|
|
3034
|
+
} catch (cause) {
|
|
3035
|
+
return [fromConvexError(cause), null];
|
|
3036
|
+
}
|
|
3037
|
+
},
|
|
3038
|
+
invite: async (input) => {
|
|
3039
|
+
if (!config._data?.action) {
|
|
3040
|
+
return stub("organizations.members.invite");
|
|
3041
|
+
}
|
|
3042
|
+
try {
|
|
3043
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3044
|
+
const result = await config._data.action(
|
|
3045
|
+
api.org.actions.inviteMember,
|
|
3046
|
+
{
|
|
3047
|
+
organizationId: orgId,
|
|
3048
|
+
email: input.email,
|
|
3049
|
+
role: input.role
|
|
3050
|
+
}
|
|
3051
|
+
);
|
|
3052
|
+
return [null, result];
|
|
3053
|
+
} catch (cause) {
|
|
3054
|
+
return [fromConvexError(cause), null];
|
|
3055
|
+
}
|
|
3056
|
+
},
|
|
3057
|
+
accept: async (input) => {
|
|
3058
|
+
if (!config._data?.action) {
|
|
3059
|
+
return stub("organizations.members.accept");
|
|
3060
|
+
}
|
|
3061
|
+
try {
|
|
3062
|
+
const member = await config._data.action(
|
|
3063
|
+
api.org.actions.acceptInvitation,
|
|
3064
|
+
{ token: input.token }
|
|
3065
|
+
);
|
|
3066
|
+
return [null, member];
|
|
3067
|
+
} catch (cause) {
|
|
3068
|
+
return [fromConvexError(cause), null];
|
|
3069
|
+
}
|
|
3070
|
+
},
|
|
3071
|
+
updateRole: async (input) => {
|
|
3072
|
+
if (!config._data?.action) {
|
|
3073
|
+
return stub("organizations.members.updateRole");
|
|
3074
|
+
}
|
|
3075
|
+
try {
|
|
3076
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3077
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3078
|
+
const member = await config._data.action(
|
|
3079
|
+
api.org.actions.updateMemberRole,
|
|
3080
|
+
{
|
|
3081
|
+
organizationId: orgId,
|
|
3082
|
+
memberId,
|
|
3083
|
+
role: input.role
|
|
3084
|
+
}
|
|
3085
|
+
);
|
|
3086
|
+
return [null, member];
|
|
3087
|
+
} catch (cause) {
|
|
3088
|
+
return [fromConvexError(cause), null];
|
|
3089
|
+
}
|
|
3090
|
+
},
|
|
3091
|
+
revoke: async (input) => {
|
|
3092
|
+
if (!config._data?.action) {
|
|
3093
|
+
return stub("organizations.members.revoke");
|
|
3094
|
+
}
|
|
3095
|
+
try {
|
|
3096
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3097
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3098
|
+
const member = await config._data.action(
|
|
3099
|
+
api.org.actions.revokeMember,
|
|
3100
|
+
{
|
|
3101
|
+
organizationId: orgId,
|
|
3102
|
+
memberId
|
|
3103
|
+
}
|
|
3104
|
+
);
|
|
3105
|
+
return [null, member];
|
|
3106
|
+
} catch (cause) {
|
|
3107
|
+
return [fromConvexError(cause), null];
|
|
3108
|
+
}
|
|
3109
|
+
},
|
|
3110
|
+
remove: async (input) => {
|
|
3111
|
+
if (!config._data?.action) {
|
|
3112
|
+
return stub("organizations.members.remove");
|
|
3113
|
+
}
|
|
3114
|
+
try {
|
|
3115
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3116
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3117
|
+
await config._data.action(api.org.actions.removeMember, {
|
|
3118
|
+
organizationId: orgId,
|
|
3119
|
+
memberId
|
|
3120
|
+
});
|
|
3121
|
+
return [null, void 0];
|
|
3122
|
+
} catch (cause) {
|
|
3123
|
+
return [fromConvexError(cause), null];
|
|
3124
|
+
}
|
|
3125
|
+
},
|
|
3126
|
+
resend: async (input) => {
|
|
3127
|
+
if (!config._data?.action) {
|
|
3128
|
+
return stub("organizations.members.resend");
|
|
3129
|
+
}
|
|
3130
|
+
try {
|
|
3131
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3132
|
+
const memberId = input.memberId.replace(/^mb_/, "");
|
|
3133
|
+
const result = await config._data.action(
|
|
3134
|
+
api.org.actions.resendInvitation,
|
|
3135
|
+
{
|
|
3136
|
+
organizationId: orgId,
|
|
3137
|
+
memberId
|
|
3138
|
+
}
|
|
3139
|
+
);
|
|
3140
|
+
return [null, result];
|
|
3141
|
+
} catch (cause) {
|
|
3142
|
+
return [fromConvexError(cause), null];
|
|
3143
|
+
}
|
|
3144
|
+
}
|
|
3145
|
+
},
|
|
3146
|
+
apiKeys: createApiKeysClient(),
|
|
3147
|
+
subAccounts: createOrgSubAccountsClient(config),
|
|
3148
|
+
externalAccounts: createOrgExternalAccountsClient(config),
|
|
3149
|
+
balanceLedger: {
|
|
3150
|
+
list: async (input) => {
|
|
3151
|
+
if (!config._data) {
|
|
3152
|
+
return stub(
|
|
3153
|
+
"organizations.balanceLedger.list"
|
|
3154
|
+
);
|
|
3155
|
+
}
|
|
3156
|
+
try {
|
|
3157
|
+
const orgId = input.organizationId.replace(/^org_/, "");
|
|
3158
|
+
const page = await config._data.query(
|
|
3159
|
+
api.balanceLedger.queries.listForOrg,
|
|
3160
|
+
{ orgId, limit: input.limit, cursor: input.cursor }
|
|
3161
|
+
);
|
|
3162
|
+
return [null, page];
|
|
3163
|
+
} catch (cause) {
|
|
3164
|
+
return [fromConvexError(cause), null];
|
|
3165
|
+
}
|
|
3166
|
+
},
|
|
2185
3167
|
retrieve: async (input) => {
|
|
2186
|
-
if (!config.
|
|
2187
|
-
return stub(
|
|
3168
|
+
if (!config._data) {
|
|
3169
|
+
return stub(
|
|
3170
|
+
"organizations.balanceLedger.retrieve"
|
|
3171
|
+
);
|
|
2188
3172
|
}
|
|
2189
3173
|
try {
|
|
2190
|
-
const
|
|
2191
|
-
api.
|
|
2192
|
-
input
|
|
3174
|
+
const entry = await config._data.query(
|
|
3175
|
+
api.balanceLedger.queries.retrieve,
|
|
3176
|
+
{ entryId: input.entryId }
|
|
2193
3177
|
);
|
|
2194
|
-
if (!
|
|
3178
|
+
if (!entry) {
|
|
2195
3179
|
return [
|
|
2196
3180
|
new CapxulError({
|
|
2197
3181
|
code: "NOT_FOUND",
|
|
2198
|
-
message: `
|
|
3182
|
+
message: `balance_ledger_entry ${input.entryId} not found`
|
|
2199
3183
|
}),
|
|
2200
3184
|
null
|
|
2201
3185
|
];
|
|
2202
3186
|
}
|
|
2203
|
-
return [null,
|
|
3187
|
+
return [null, entry];
|
|
2204
3188
|
} catch (cause) {
|
|
2205
|
-
return [
|
|
2206
|
-
fromConvexError(cause),
|
|
2207
|
-
null
|
|
2208
|
-
];
|
|
3189
|
+
return [fromConvexError(cause), null];
|
|
2209
3190
|
}
|
|
2210
3191
|
}
|
|
2211
3192
|
},
|
|
2212
|
-
treasury: {
|
|
2213
|
-
retrieve: async () => stub("organizations.treasury.retrieve")
|
|
2214
|
-
},
|
|
2215
|
-
members: {
|
|
2216
|
-
list: async () => stub("organizations.members.list"),
|
|
2217
|
-
retrieve: async () => stub("organizations.members.retrieve"),
|
|
2218
|
-
invite: async () => stub("organizations.members.invite"),
|
|
2219
|
-
updateRole: async () => stub("organizations.members.updateRole"),
|
|
2220
|
-
remove: async () => stub("organizations.members.remove")
|
|
2221
|
-
},
|
|
2222
|
-
apiKeys: createApiKeysClient(),
|
|
2223
|
-
kybProfile: {
|
|
2224
|
-
start: async () => stub("organizations.kybProfile.start"),
|
|
2225
|
-
retrieve: async () => stub("organizations.kybProfile.retrieve")
|
|
2226
|
-
},
|
|
2227
|
-
subAccounts: {
|
|
2228
|
-
create: async () => stub("organizations.subAccounts.create"),
|
|
2229
|
-
list: async () => stub("organizations.subAccounts.list"),
|
|
2230
|
-
retrieve: async () => stub("organizations.subAccounts.retrieve"),
|
|
2231
|
-
remove: async () => stub("organizations.subAccounts.remove")
|
|
2232
|
-
},
|
|
2233
|
-
externalAccounts: createOrgExternalAccountsClient(config),
|
|
2234
|
-
balanceLedger: {
|
|
2235
|
-
list: async () => stub(
|
|
2236
|
-
"organizations.balanceLedger.list"
|
|
2237
|
-
),
|
|
2238
|
-
retrieve: async () => stub(
|
|
2239
|
-
"organizations.balanceLedger.retrieve"
|
|
2240
|
-
)
|
|
2241
|
-
},
|
|
2242
3193
|
payments: createOrgPaymentsClient(),
|
|
2243
3194
|
transfers: createOrgTransfersClient(),
|
|
2244
3195
|
withdrawals: createOrgWithdrawalsClient(config),
|
|
@@ -2248,14 +3199,6 @@ function createOrganizationsClient(config = {}) {
|
|
|
2248
3199
|
};
|
|
2249
3200
|
}
|
|
2250
3201
|
|
|
2251
|
-
// src/core/sub-accounts.ts
|
|
2252
|
-
function createSubAccountsClient() {
|
|
2253
|
-
return {
|
|
2254
|
-
retrieve: async () => stub("subAccounts.retrieve"),
|
|
2255
|
-
remove: async () => stub("subAccounts.remove")
|
|
2256
|
-
};
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
3202
|
// src/core/token-transfers.ts
|
|
2260
3203
|
var toTokenTransferId = (raw) => {
|
|
2261
3204
|
if (typeof raw !== "string" || raw.length === 0) {
|
|
@@ -2274,11 +3217,11 @@ function brandRow(row) {
|
|
|
2274
3217
|
function createTokenTransfersClient(config = {}) {
|
|
2275
3218
|
return {
|
|
2276
3219
|
list: async (input) => {
|
|
2277
|
-
if (!config.
|
|
3220
|
+
if (!config._data) {
|
|
2278
3221
|
return stub("tokenTransfers.list");
|
|
2279
3222
|
}
|
|
2280
3223
|
try {
|
|
2281
|
-
const raw = await config.
|
|
3224
|
+
const raw = await config._data.query(
|
|
2282
3225
|
api.tokenTransfers.queries.list,
|
|
2283
3226
|
{
|
|
2284
3227
|
limit: input?.limit,
|
|
@@ -2312,11 +3255,11 @@ function createTokenTransfersClient(config = {}) {
|
|
|
2312
3255
|
}
|
|
2313
3256
|
},
|
|
2314
3257
|
retrieve: async (input) => {
|
|
2315
|
-
if (!config.
|
|
3258
|
+
if (!config._data) {
|
|
2316
3259
|
return stub("tokenTransfers.retrieve");
|
|
2317
3260
|
}
|
|
2318
3261
|
try {
|
|
2319
|
-
const raw = await config.
|
|
3262
|
+
const raw = await config._data.query(
|
|
2320
3263
|
api.tokenTransfers.queries.getByTxLogIndex,
|
|
2321
3264
|
{
|
|
2322
3265
|
txHash: input.txHash,
|
|
@@ -2386,7 +3329,7 @@ function createAuthFlowMachine(client) {
|
|
|
2386
3329
|
}),
|
|
2387
3330
|
verifyOtp: xstate.fromPromise(
|
|
2388
3331
|
async ({ input, signal }) => {
|
|
2389
|
-
const [error,
|
|
3332
|
+
const [error, result] = await client.auth.verifyOtp(
|
|
2390
3333
|
{
|
|
2391
3334
|
email: input.email,
|
|
2392
3335
|
otp: input.code
|
|
@@ -2394,7 +3337,14 @@ function createAuthFlowMachine(client) {
|
|
|
2394
3337
|
{ signal }
|
|
2395
3338
|
);
|
|
2396
3339
|
if (error) throw error;
|
|
2397
|
-
|
|
3340
|
+
if (result.kind === "bootstrap_required") {
|
|
3341
|
+
throw new CapxulError({
|
|
3342
|
+
code: "ACTION_REQUIRED",
|
|
3343
|
+
message: "OTP verified but auth bootstrap is required. Use createAuthBootstrapFlowMachine for product sign-up.",
|
|
3344
|
+
details: { reason: result.reason }
|
|
3345
|
+
});
|
|
3346
|
+
}
|
|
3347
|
+
return result.session;
|
|
2398
3348
|
}
|
|
2399
3349
|
),
|
|
2400
3350
|
signOut: xstate.fromPromise(async () => {
|
|
@@ -2642,6 +3592,327 @@ function emailDomain(email) {
|
|
|
2642
3592
|
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
2643
3593
|
return domain || "unknown";
|
|
2644
3594
|
}
|
|
3595
|
+
var initialContext = {
|
|
3596
|
+
email: null,
|
|
3597
|
+
code: null,
|
|
3598
|
+
username: null,
|
|
3599
|
+
bootstrapToken: null,
|
|
3600
|
+
bootstrapReason: null,
|
|
3601
|
+
session: null,
|
|
3602
|
+
account: null,
|
|
3603
|
+
safe: null,
|
|
3604
|
+
error: null
|
|
3605
|
+
};
|
|
3606
|
+
function createAuthBootstrapFlowMachine(client) {
|
|
3607
|
+
return xstate.setup({
|
|
3608
|
+
types: {},
|
|
3609
|
+
actors: {
|
|
3610
|
+
sendOtp: xstate.fromPromise(async ({ input, signal }) => {
|
|
3611
|
+
const [error] = await client.auth.sendOtp(
|
|
3612
|
+
{ email: input.email },
|
|
3613
|
+
{ signal }
|
|
3614
|
+
);
|
|
3615
|
+
if (error) throw error;
|
|
3616
|
+
}),
|
|
3617
|
+
verifyOtp: xstate.fromPromise(
|
|
3618
|
+
async ({ input, signal }) => {
|
|
3619
|
+
const [error, result] = await client.auth.verifyOtp(
|
|
3620
|
+
{ email: input.email, otp: input.code },
|
|
3621
|
+
{ signal }
|
|
3622
|
+
);
|
|
3623
|
+
if (error) throw error;
|
|
3624
|
+
return result;
|
|
3625
|
+
}
|
|
3626
|
+
),
|
|
3627
|
+
completeBootstrap: xstate.fromPromise(async ({ input }) => {
|
|
3628
|
+
const [error, result] = await client.auth.completeBootstrap(input);
|
|
3629
|
+
if (error) throw error;
|
|
3630
|
+
return result;
|
|
3631
|
+
}),
|
|
3632
|
+
signOut: xstate.fromPromise(async () => {
|
|
3633
|
+
const [error] = await client.auth.signOut();
|
|
3634
|
+
if (error) throw error;
|
|
3635
|
+
})
|
|
3636
|
+
},
|
|
3637
|
+
actions: {
|
|
3638
|
+
trackOtpRequested: ({ context }) => {
|
|
3639
|
+
if (!context.email) return;
|
|
3640
|
+
track("auth_otp_requested", {
|
|
3641
|
+
email_domain: emailDomain2(context.email)
|
|
3642
|
+
});
|
|
3643
|
+
},
|
|
3644
|
+
trackFailed: ({ event }) => {
|
|
3645
|
+
track("auth_failed", {
|
|
3646
|
+
auth_type: "email_otp",
|
|
3647
|
+
reason: errorFromEvent2(event).code
|
|
3648
|
+
});
|
|
3649
|
+
},
|
|
3650
|
+
trackTimeoutFailed: () => {
|
|
3651
|
+
track("auth_failed", {
|
|
3652
|
+
auth_type: "email_otp",
|
|
3653
|
+
reason: "timeout"
|
|
3654
|
+
});
|
|
3655
|
+
},
|
|
3656
|
+
trackVerified: () => {
|
|
3657
|
+
track("auth_verified", { auth_type: "email_otp" });
|
|
3658
|
+
},
|
|
3659
|
+
trackBootstrapRequired: ({ context }) => {
|
|
3660
|
+
track("auth_verified", {
|
|
3661
|
+
auth_type: "email_otp",
|
|
3662
|
+
auth_mode: context.bootstrapReason ?? "bootstrap_required"
|
|
3663
|
+
});
|
|
3664
|
+
},
|
|
3665
|
+
identifyAndTrack: ({ context }) => {
|
|
3666
|
+
if (!context.session) return;
|
|
3667
|
+
identify(context.session.authUserId, {
|
|
3668
|
+
email_domain: emailDomain2(context.session.email)
|
|
3669
|
+
});
|
|
3670
|
+
track("auth_identified", {
|
|
3671
|
+
email_domain: emailDomain2(context.session.email)
|
|
3672
|
+
});
|
|
3673
|
+
},
|
|
3674
|
+
trackSignedOut: () => {
|
|
3675
|
+
track("auth_signed_out");
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
}).createMachine({
|
|
3679
|
+
id: "authBootstrap",
|
|
3680
|
+
initial: "email",
|
|
3681
|
+
context: initialContext,
|
|
3682
|
+
states: {
|
|
3683
|
+
email: {
|
|
3684
|
+
on: {
|
|
3685
|
+
ENTER_EMAIL: {
|
|
3686
|
+
actions: xstate.assign({
|
|
3687
|
+
email: ({ event }) => event.email,
|
|
3688
|
+
error: () => null
|
|
3689
|
+
})
|
|
3690
|
+
},
|
|
3691
|
+
REQUEST_OTP: { target: "sending_otp" }
|
|
3692
|
+
}
|
|
3693
|
+
},
|
|
3694
|
+
sending_otp: {
|
|
3695
|
+
invoke: {
|
|
3696
|
+
src: "sendOtp",
|
|
3697
|
+
input: ({ context }) => ({ email: requireEmail2(context) }),
|
|
3698
|
+
onDone: { target: "otp_requested", actions: "trackOtpRequested" },
|
|
3699
|
+
onError: {
|
|
3700
|
+
target: "otp_requested",
|
|
3701
|
+
actions: [
|
|
3702
|
+
xstate.assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3703
|
+
"trackFailed"
|
|
3704
|
+
]
|
|
3705
|
+
}
|
|
3706
|
+
},
|
|
3707
|
+
after: {
|
|
3708
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3709
|
+
target: "otp_requested",
|
|
3710
|
+
actions: [
|
|
3711
|
+
xstate.assign({ error: () => timeoutError2("sending_otp") }),
|
|
3712
|
+
"trackTimeoutFailed"
|
|
3713
|
+
]
|
|
3714
|
+
}
|
|
3715
|
+
}
|
|
3716
|
+
},
|
|
3717
|
+
otp_requested: {
|
|
3718
|
+
on: {
|
|
3719
|
+
ENTER_OTP: {
|
|
3720
|
+
actions: xstate.assign({
|
|
3721
|
+
code: ({ event }) => event.code,
|
|
3722
|
+
error: () => null
|
|
3723
|
+
})
|
|
3724
|
+
},
|
|
3725
|
+
VERIFY_OTP: { target: "verifying_otp" },
|
|
3726
|
+
BACK: { target: "email" },
|
|
3727
|
+
RESET: { target: "email", actions: xstate.assign(() => initialContext) }
|
|
3728
|
+
}
|
|
3729
|
+
},
|
|
3730
|
+
verifying_otp: {
|
|
3731
|
+
invoke: {
|
|
3732
|
+
src: "verifyOtp",
|
|
3733
|
+
input: ({ context }) => ({
|
|
3734
|
+
email: requireEmail2(context),
|
|
3735
|
+
code: requireCode(context)
|
|
3736
|
+
}),
|
|
3737
|
+
onDone: [
|
|
3738
|
+
{
|
|
3739
|
+
guard: ({ event }) => event.output.kind === "existing_member",
|
|
3740
|
+
target: "authenticated",
|
|
3741
|
+
actions: [
|
|
3742
|
+
xstate.assign({
|
|
3743
|
+
session: ({ event }) => event.output.session,
|
|
3744
|
+
account: ({ event }) => event.output.kind === "existing_member" ? event.output.account : null,
|
|
3745
|
+
username: ({ event }) => event.output.kind === "existing_member" ? event.output.username : null,
|
|
3746
|
+
safe: ({ event }) => event.output.kind === "existing_member" ? event.output.safe : null,
|
|
3747
|
+
email: () => null,
|
|
3748
|
+
error: () => null
|
|
3749
|
+
}),
|
|
3750
|
+
"trackVerified",
|
|
3751
|
+
"identifyAndTrack"
|
|
3752
|
+
]
|
|
3753
|
+
},
|
|
3754
|
+
{
|
|
3755
|
+
target: "bootstrap_required",
|
|
3756
|
+
actions: [
|
|
3757
|
+
xstate.assign({
|
|
3758
|
+
session: ({ event }) => event.output.session,
|
|
3759
|
+
bootstrapToken: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.bootstrapToken : null,
|
|
3760
|
+
bootstrapReason: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.reason : null,
|
|
3761
|
+
username: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.username ?? null : null,
|
|
3762
|
+
email: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.email : null,
|
|
3763
|
+
error: () => null
|
|
3764
|
+
}),
|
|
3765
|
+
"trackVerified",
|
|
3766
|
+
"trackBootstrapRequired"
|
|
3767
|
+
]
|
|
3768
|
+
}
|
|
3769
|
+
],
|
|
3770
|
+
onError: {
|
|
3771
|
+
target: "otp_requested",
|
|
3772
|
+
actions: [
|
|
3773
|
+
xstate.assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3774
|
+
"trackFailed"
|
|
3775
|
+
]
|
|
3776
|
+
}
|
|
3777
|
+
},
|
|
3778
|
+
after: {
|
|
3779
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3780
|
+
target: "otp_requested",
|
|
3781
|
+
actions: [
|
|
3782
|
+
xstate.assign({ error: () => timeoutError2("verifying_otp") }),
|
|
3783
|
+
"trackTimeoutFailed"
|
|
3784
|
+
]
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
},
|
|
3788
|
+
bootstrap_required: {
|
|
3789
|
+
on: {
|
|
3790
|
+
ENTER_USERNAME: {
|
|
3791
|
+
actions: xstate.assign({
|
|
3792
|
+
username: ({ event }) => event.username,
|
|
3793
|
+
error: () => null
|
|
3794
|
+
})
|
|
3795
|
+
},
|
|
3796
|
+
COMPLETE_BOOTSTRAP: { target: "completing_bootstrap" },
|
|
3797
|
+
BACK: { target: "otp_requested" },
|
|
3798
|
+
RESET: { target: "email", actions: xstate.assign(() => initialContext) }
|
|
3799
|
+
}
|
|
3800
|
+
},
|
|
3801
|
+
completing_bootstrap: {
|
|
3802
|
+
invoke: {
|
|
3803
|
+
src: "completeBootstrap",
|
|
3804
|
+
input: ({ context }) => ({
|
|
3805
|
+
bootstrapToken: requireBootstrapToken(context),
|
|
3806
|
+
username: requireUsername(context)
|
|
3807
|
+
}),
|
|
3808
|
+
onDone: {
|
|
3809
|
+
target: "authenticated",
|
|
3810
|
+
actions: [
|
|
3811
|
+
xstate.assign({
|
|
3812
|
+
session: ({ event }) => event.output.session,
|
|
3813
|
+
account: ({ event }) => event.output.account,
|
|
3814
|
+
username: ({ event }) => event.output.username,
|
|
3815
|
+
safe: ({ event }) => event.output.safe,
|
|
3816
|
+
bootstrapToken: () => null,
|
|
3817
|
+
bootstrapReason: () => null,
|
|
3818
|
+
email: () => null,
|
|
3819
|
+
error: () => null
|
|
3820
|
+
}),
|
|
3821
|
+
"identifyAndTrack"
|
|
3822
|
+
]
|
|
3823
|
+
},
|
|
3824
|
+
onError: {
|
|
3825
|
+
target: "bootstrap_required",
|
|
3826
|
+
actions: [
|
|
3827
|
+
xstate.assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3828
|
+
"trackFailed"
|
|
3829
|
+
]
|
|
3830
|
+
}
|
|
3831
|
+
},
|
|
3832
|
+
after: {
|
|
3833
|
+
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3834
|
+
target: "bootstrap_required",
|
|
3835
|
+
actions: [
|
|
3836
|
+
xstate.assign({ error: () => timeoutError2("completing_bootstrap") }),
|
|
3837
|
+
"trackTimeoutFailed"
|
|
3838
|
+
]
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
},
|
|
3842
|
+
authenticated: {
|
|
3843
|
+
on: {
|
|
3844
|
+
SIGN_OUT: { target: "signing_out" }
|
|
3845
|
+
}
|
|
3846
|
+
},
|
|
3847
|
+
signing_out: {
|
|
3848
|
+
invoke: {
|
|
3849
|
+
src: "signOut",
|
|
3850
|
+
onDone: {
|
|
3851
|
+
target: "email",
|
|
3852
|
+
actions: [
|
|
3853
|
+
xstate.assign(() => initialContext),
|
|
3854
|
+
"trackSignedOut"
|
|
3855
|
+
]
|
|
3856
|
+
},
|
|
3857
|
+
onError: {
|
|
3858
|
+
target: "error",
|
|
3859
|
+
actions: xstate.assign({ error: ({ event }) => errorFromEvent2(event) })
|
|
3860
|
+
}
|
|
3861
|
+
}
|
|
3862
|
+
},
|
|
3863
|
+
error: {
|
|
3864
|
+
on: {
|
|
3865
|
+
RESET: { target: "email", actions: xstate.assign(() => initialContext) }
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
});
|
|
3870
|
+
}
|
|
3871
|
+
function requireEmail2(context) {
|
|
3872
|
+
if (!context.email) {
|
|
3873
|
+
throw Errors.invalidInput("email", "Auth bootstrap requires an email.");
|
|
3874
|
+
}
|
|
3875
|
+
return context.email;
|
|
3876
|
+
}
|
|
3877
|
+
function requireCode(context) {
|
|
3878
|
+
if (!context.code) {
|
|
3879
|
+
throw Errors.invalidInput("code", "Auth bootstrap requires an OTP code.");
|
|
3880
|
+
}
|
|
3881
|
+
return context.code;
|
|
3882
|
+
}
|
|
3883
|
+
function requireBootstrapToken(context) {
|
|
3884
|
+
if (!context.bootstrapToken) {
|
|
3885
|
+
throw Errors.invalidInput(
|
|
3886
|
+
"bootstrapToken",
|
|
3887
|
+
"Auth bootstrap requires a continuation token."
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
return context.bootstrapToken;
|
|
3891
|
+
}
|
|
3892
|
+
function requireUsername(context) {
|
|
3893
|
+
if (!context.username) {
|
|
3894
|
+
throw Errors.invalidInput("username", "Auth bootstrap requires a username.");
|
|
3895
|
+
}
|
|
3896
|
+
return context.username;
|
|
3897
|
+
}
|
|
3898
|
+
function errorFromEvent2(event) {
|
|
3899
|
+
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3900
|
+
if (cause instanceof CapxulError || cause instanceof CapxulError2) {
|
|
3901
|
+
return cause;
|
|
3902
|
+
}
|
|
3903
|
+
return Errors.providerError("auth", "bootstrap", cause);
|
|
3904
|
+
}
|
|
3905
|
+
function timeoutError2(state) {
|
|
3906
|
+
return Errors.providerError(
|
|
3907
|
+
"auth",
|
|
3908
|
+
"bootstrap",
|
|
3909
|
+
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
3910
|
+
);
|
|
3911
|
+
}
|
|
3912
|
+
function emailDomain2(email) {
|
|
3913
|
+
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
3914
|
+
return domain || "unknown";
|
|
3915
|
+
}
|
|
2645
3916
|
function createProvisioningMachine(client) {
|
|
2646
3917
|
return xstate.setup({
|
|
2647
3918
|
types: {},
|
|
@@ -2669,7 +3940,7 @@ function createProvisioningMachine(client) {
|
|
|
2669
3940
|
const provider = context.input?.signerProvider;
|
|
2670
3941
|
if (!provider) return;
|
|
2671
3942
|
track("provisioning_safe_created", {
|
|
2672
|
-
safe_address: provider.
|
|
3943
|
+
safe_address: deriveSafeAddress(provider.signerAddress)
|
|
2673
3944
|
});
|
|
2674
3945
|
}
|
|
2675
3946
|
}
|
|
@@ -2714,13 +3985,13 @@ function createProvisioningMachine(client) {
|
|
|
2714
3985
|
},
|
|
2715
3986
|
onError: {
|
|
2716
3987
|
target: "error",
|
|
2717
|
-
actions: xstate.assign({ error: ({ event }) =>
|
|
3988
|
+
actions: xstate.assign({ error: ({ event }) => errorFromEvent3(event) })
|
|
2718
3989
|
}
|
|
2719
3990
|
},
|
|
2720
3991
|
after: {
|
|
2721
3992
|
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
2722
3993
|
target: "error",
|
|
2723
|
-
actions: xstate.assign({ error: () =>
|
|
3994
|
+
actions: xstate.assign({ error: () => timeoutError3() })
|
|
2724
3995
|
}
|
|
2725
3996
|
}
|
|
2726
3997
|
},
|
|
@@ -2738,7 +4009,7 @@ function createProvisioningMachine(client) {
|
|
|
2738
4009
|
* this payload on its `onDone` transition and branches via guards
|
|
2739
4010
|
* on `event.output.error`.
|
|
2740
4011
|
*/
|
|
2741
|
-
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error:
|
|
4012
|
+
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error: timeoutError3() }
|
|
2742
4013
|
});
|
|
2743
4014
|
}
|
|
2744
4015
|
function requireProvisionInput(context) {
|
|
@@ -2750,13 +4021,13 @@ function requireProvisionInput(context) {
|
|
|
2750
4021
|
}
|
|
2751
4022
|
return context.input;
|
|
2752
4023
|
}
|
|
2753
|
-
function
|
|
4024
|
+
function errorFromEvent3(event) {
|
|
2754
4025
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
2755
4026
|
if (cause instanceof CapxulError) return cause;
|
|
2756
4027
|
if (cause instanceof CapxulError2) return cause;
|
|
2757
4028
|
return Errors.providerError("provisioning", "flow", cause);
|
|
2758
4029
|
}
|
|
2759
|
-
function
|
|
4030
|
+
function timeoutError3() {
|
|
2760
4031
|
return Errors.providerError(
|
|
2761
4032
|
"provisioning",
|
|
2762
4033
|
"flow",
|
|
@@ -2849,7 +4120,7 @@ function createOnboardingFlowMachine(client) {
|
|
|
2849
4120
|
error: ({ event }) => extractChildErrorOrFallback(event)
|
|
2850
4121
|
}),
|
|
2851
4122
|
assignChildThrown: xstate.assign({
|
|
2852
|
-
error: ({ event }) =>
|
|
4123
|
+
error: ({ event }) => errorFromEvent4(event)
|
|
2853
4124
|
}),
|
|
2854
4125
|
assignAccountFromChild: xstate.assign({
|
|
2855
4126
|
account: ({ event }) => extractChildAccountOrNull(event)
|
|
@@ -3011,7 +4282,7 @@ function extractChildAccountOrNull(event) {
|
|
|
3011
4282
|
if (output && "account" in output && output.account) return output.account;
|
|
3012
4283
|
return null;
|
|
3013
4284
|
}
|
|
3014
|
-
function
|
|
4285
|
+
function errorFromEvent4(event) {
|
|
3015
4286
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3016
4287
|
if (cause instanceof CapxulError) return cause;
|
|
3017
4288
|
if (cause instanceof CapxulError2) return cause;
|
|
@@ -3031,7 +4302,7 @@ function createCapxulClient(config = {}) {
|
|
|
3031
4302
|
tokenTransfers: createTokenTransfersClient(config),
|
|
3032
4303
|
withdrawals: createWithdrawalsClient(config),
|
|
3033
4304
|
documents: createDocumentsClient(),
|
|
3034
|
-
subAccounts: createSubAccountsClient(),
|
|
4305
|
+
subAccounts: createSubAccountsClient(config),
|
|
3035
4306
|
virtualAccounts: createVirtualAccountsClient(),
|
|
3036
4307
|
virtualCards: createVirtualCardsClient(),
|
|
3037
4308
|
externalAccounts: createExternalAccountsClient(config),
|
|
@@ -3043,6 +4314,7 @@ function createCapxulClient(config = {}) {
|
|
|
3043
4314
|
const client = clientWithoutFlows;
|
|
3044
4315
|
client.flows = {
|
|
3045
4316
|
auth: () => createAuthFlowMachine(client),
|
|
4317
|
+
authBootstrap: () => createAuthBootstrapFlowMachine(client),
|
|
3046
4318
|
onboarding: () => createOnboardingFlowMachine(client),
|
|
3047
4319
|
provisioning: () => createProvisioningMachine(client)
|
|
3048
4320
|
};
|