@capxul/sdk 0.1.0-alpha.3 → 0.1.0-alpha.6
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 +51 -0
- package/README.md +1 -1
- package/dist/{client-BI863O0y.d.ts → client-ChfXWMzO.d.ts} +244 -77
- package/dist/{client-CwcnMbGv.d.cts → client-DW_fW9DC.d.cts} +244 -77
- package/dist/client.cjs +982 -118
- package/dist/client.d.cts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/client.js +982 -118
- package/dist/index.cjs +1079 -224
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1079 -225
- package/dist/{types-BE3tVIOI.d.ts → types-CYvLP5pP.d.ts} +22 -3
- package/dist/{types-z4VLz9rS.d.cts → types-X02RbQ2u.d.cts} +22 -3
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/package.json +2 -2
package/dist/client.cjs
CHANGED
|
@@ -69,12 +69,343 @@ function fromConvexError(error) {
|
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// ../observability/src/try-catch.ts
|
|
73
|
+
async function tryCatch(promise) {
|
|
74
|
+
try {
|
|
75
|
+
return [null, await promise];
|
|
76
|
+
} catch (e) {
|
|
77
|
+
return [e instanceof Error ? e : new Error(String(e)), null];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ../observability/src/debug-log.ts
|
|
82
|
+
function isDevelopmentBuild() {
|
|
83
|
+
if (typeof process === "undefined") {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
|
|
87
|
+
}
|
|
88
|
+
function debugLog(line) {
|
|
89
|
+
if (!isDevelopmentBuild()) return;
|
|
90
|
+
if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
|
|
91
|
+
console.info(line);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
|
|
95
|
+
process.stderr.write(`${line}
|
|
96
|
+
`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function formatDebugValue(value) {
|
|
100
|
+
if (value === void 0 || value === "") return "";
|
|
101
|
+
if (typeof value === "string") return value;
|
|
102
|
+
try {
|
|
103
|
+
return JSON.stringify(value);
|
|
104
|
+
} catch {
|
|
105
|
+
return String(value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function track(...args) {
|
|
109
|
+
const [name, props] = args;
|
|
110
|
+
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
111
|
+
}
|
|
112
|
+
function formatDebugValue2(value) {
|
|
113
|
+
if (value === void 0 || value === "") return "";
|
|
114
|
+
if (typeof value === "string") return value;
|
|
115
|
+
try {
|
|
116
|
+
return JSON.stringify(value);
|
|
117
|
+
} catch {
|
|
118
|
+
return String(value);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function identify(userId, traits) {
|
|
122
|
+
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ../platform-kernel/src/ids.ts
|
|
126
|
+
function makePrefixedIdConstructor(prefix, fieldName) {
|
|
127
|
+
const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
|
|
128
|
+
return (raw) => {
|
|
129
|
+
if (typeof raw !== "string" || !re.test(raw)) {
|
|
130
|
+
throw new Error(
|
|
131
|
+
`Invalid ${fieldName}: expected string matching ^${prefix}_[A-Za-z0-9_\\-]+$, got ${String(raw)}`
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
return raw;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
var toOperationId = makePrefixedIdConstructor(
|
|
138
|
+
"op",
|
|
139
|
+
"operationId"
|
|
140
|
+
);
|
|
141
|
+
var toCorrelationId = makePrefixedIdConstructor("ctx", "correlationId");
|
|
142
|
+
var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
|
|
143
|
+
|
|
144
|
+
// src/core/external-accounts.ts
|
|
145
|
+
function brandExternalAccount(raw) {
|
|
146
|
+
return {
|
|
147
|
+
...raw,
|
|
148
|
+
id: toExternalAccountId(raw.id),
|
|
149
|
+
operation: {
|
|
150
|
+
id: toOperationId(raw.operation.id),
|
|
151
|
+
status: raw.operation.status,
|
|
152
|
+
correlationId: toCorrelationId(raw.operation.correlationId)
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function createExternalAccountsClient(config = {}) {
|
|
157
|
+
return {
|
|
158
|
+
retrieve: async (externalAccountId) => {
|
|
159
|
+
if (!config.data) {
|
|
160
|
+
return stub(
|
|
161
|
+
"externalAccounts.retrieve"
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
const [err, raw] = await tryCatch(
|
|
165
|
+
config.data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
166
|
+
externalAccountId
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
if (err) {
|
|
170
|
+
return [
|
|
171
|
+
fromConvexError(err),
|
|
172
|
+
null
|
|
173
|
+
];
|
|
174
|
+
}
|
|
175
|
+
if (!raw) {
|
|
176
|
+
return [
|
|
177
|
+
new CapxulError({
|
|
178
|
+
code: "NOT_FOUND",
|
|
179
|
+
message: `external_account ${externalAccountId} not found`
|
|
180
|
+
}),
|
|
181
|
+
null
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
return [null, brandExternalAccount(raw)];
|
|
185
|
+
},
|
|
186
|
+
remove: async (externalAccountId) => {
|
|
187
|
+
if (!config.data) {
|
|
188
|
+
return stub("externalAccounts.remove");
|
|
189
|
+
}
|
|
190
|
+
const [err] = await tryCatch(
|
|
191
|
+
config.data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
192
|
+
externalAccountId
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
if (err) {
|
|
196
|
+
return [
|
|
197
|
+
fromConvexError(err),
|
|
198
|
+
null
|
|
199
|
+
];
|
|
200
|
+
}
|
|
201
|
+
return [null, void 0];
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
72
206
|
// src/core/accounts.ts
|
|
207
|
+
function createAccountExternalAccountsClient(config) {
|
|
208
|
+
return {
|
|
209
|
+
create: async (input) => {
|
|
210
|
+
if (!config.data) {
|
|
211
|
+
return stub(
|
|
212
|
+
"accounts.externalAccounts.create"
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
const [err, raw] = await tryCatch(
|
|
216
|
+
config.data.mutation(
|
|
217
|
+
api.externalAccounts.mutations.createPersonal,
|
|
218
|
+
{
|
|
219
|
+
kind: input.kind,
|
|
220
|
+
label: input.label,
|
|
221
|
+
address: input.address,
|
|
222
|
+
iban: input.iban,
|
|
223
|
+
bic: input.bic,
|
|
224
|
+
accountHolder: input.accountHolder,
|
|
225
|
+
network: input.network,
|
|
226
|
+
panToken: input.panToken,
|
|
227
|
+
last4: input.last4
|
|
228
|
+
}
|
|
229
|
+
)
|
|
230
|
+
);
|
|
231
|
+
if (err) {
|
|
232
|
+
return [
|
|
233
|
+
fromConvexError(err),
|
|
234
|
+
null
|
|
235
|
+
];
|
|
236
|
+
}
|
|
237
|
+
if (!raw) {
|
|
238
|
+
return [
|
|
239
|
+
new CapxulError({
|
|
240
|
+
code: "NOT_FOUND",
|
|
241
|
+
message: "external_account creation returned no resource"
|
|
242
|
+
}),
|
|
243
|
+
null
|
|
244
|
+
];
|
|
245
|
+
}
|
|
246
|
+
return [
|
|
247
|
+
null,
|
|
248
|
+
brandExternalAccount(
|
|
249
|
+
raw
|
|
250
|
+
)
|
|
251
|
+
];
|
|
252
|
+
},
|
|
253
|
+
list: async (input) => {
|
|
254
|
+
if (!config.data) {
|
|
255
|
+
return stub(
|
|
256
|
+
"accounts.externalAccounts.list"
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
const [err, result] = await tryCatch(
|
|
260
|
+
config.data.query(api.externalAccounts.queries.listPersonal, {
|
|
261
|
+
limit: input.limit,
|
|
262
|
+
cursor: input.cursor
|
|
263
|
+
})
|
|
264
|
+
);
|
|
265
|
+
if (err) {
|
|
266
|
+
return [fromConvexError(err), null];
|
|
267
|
+
}
|
|
268
|
+
const branded = result.data.map(
|
|
269
|
+
(row) => brandExternalAccount(
|
|
270
|
+
row
|
|
271
|
+
)
|
|
272
|
+
);
|
|
273
|
+
return [
|
|
274
|
+
null,
|
|
275
|
+
{
|
|
276
|
+
object: "list",
|
|
277
|
+
data: branded,
|
|
278
|
+
page: result.page
|
|
279
|
+
}
|
|
280
|
+
];
|
|
281
|
+
},
|
|
282
|
+
retrieve: async (externalAccountId) => {
|
|
283
|
+
if (!config.data) {
|
|
284
|
+
return stub(
|
|
285
|
+
"accounts.externalAccounts.retrieve"
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
const [err, raw] = await tryCatch(
|
|
289
|
+
config.data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
290
|
+
externalAccountId
|
|
291
|
+
})
|
|
292
|
+
);
|
|
293
|
+
if (err) {
|
|
294
|
+
return [
|
|
295
|
+
fromConvexError(err),
|
|
296
|
+
null
|
|
297
|
+
];
|
|
298
|
+
}
|
|
299
|
+
if (!raw) {
|
|
300
|
+
return [
|
|
301
|
+
new CapxulError({
|
|
302
|
+
code: "NOT_FOUND",
|
|
303
|
+
message: `external_account ${externalAccountId} not found`
|
|
304
|
+
}),
|
|
305
|
+
null
|
|
306
|
+
];
|
|
307
|
+
}
|
|
308
|
+
return [
|
|
309
|
+
null,
|
|
310
|
+
brandExternalAccount(
|
|
311
|
+
raw
|
|
312
|
+
)
|
|
313
|
+
];
|
|
314
|
+
},
|
|
315
|
+
remove: async (externalAccountId) => {
|
|
316
|
+
if (!config.data) {
|
|
317
|
+
return stub("accounts.externalAccounts.remove");
|
|
318
|
+
}
|
|
319
|
+
const [err] = await tryCatch(
|
|
320
|
+
config.data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
321
|
+
externalAccountId
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
if (err) {
|
|
325
|
+
return [
|
|
326
|
+
fromConvexError(err),
|
|
327
|
+
null
|
|
328
|
+
];
|
|
329
|
+
}
|
|
330
|
+
return [null, void 0];
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
73
334
|
function createAccountsClient(config = {}) {
|
|
74
335
|
return {
|
|
75
|
-
retrieve: async () =>
|
|
336
|
+
retrieve: async (accountId) => {
|
|
337
|
+
if (!config.data) {
|
|
338
|
+
return stub("accounts.retrieve");
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
const account = await config.data.query(
|
|
342
|
+
api.openfort.queries.getMyAccount,
|
|
343
|
+
{}
|
|
344
|
+
);
|
|
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
|
+
},
|
|
76
363
|
lookup: async () => stub("accounts.lookup"),
|
|
77
|
-
update: async () =>
|
|
364
|
+
update: async (input) => {
|
|
365
|
+
if (!config.data) {
|
|
366
|
+
return stub("accounts.update");
|
|
367
|
+
}
|
|
368
|
+
if (input.countryCode !== void 0) {
|
|
369
|
+
return [
|
|
370
|
+
new CapxulError({
|
|
371
|
+
code: "INVALID_INPUT",
|
|
372
|
+
message: "accounts.update does not support countryCode yet \u2014 backend mutation only patches displayName and username.",
|
|
373
|
+
details: { field: "countryCode" }
|
|
374
|
+
}),
|
|
375
|
+
null
|
|
376
|
+
];
|
|
377
|
+
}
|
|
378
|
+
try {
|
|
379
|
+
const current = await config.data.query(
|
|
380
|
+
api.openfort.queries.getMyAccount,
|
|
381
|
+
{}
|
|
382
|
+
);
|
|
383
|
+
if (current.id !== input.accountId) {
|
|
384
|
+
return [
|
|
385
|
+
new CapxulError({
|
|
386
|
+
code: "PERMISSION_DENIED",
|
|
387
|
+
message: "accounts.update currently supports the authenticated caller's own account only.",
|
|
388
|
+
details: {
|
|
389
|
+
requestedAccountId: input.accountId,
|
|
390
|
+
authenticatedAccountId: current.id
|
|
391
|
+
}
|
|
392
|
+
}),
|
|
393
|
+
null
|
|
394
|
+
];
|
|
395
|
+
}
|
|
396
|
+
await config.data.mutation(api.openfort.mutations.updateProfile, {
|
|
397
|
+
displayName: input.name,
|
|
398
|
+
username: input.username
|
|
399
|
+
});
|
|
400
|
+
const updated = await config.data.query(
|
|
401
|
+
api.openfort.queries.getMyAccount,
|
|
402
|
+
{}
|
|
403
|
+
);
|
|
404
|
+
return [null, updated];
|
|
405
|
+
} catch (cause) {
|
|
406
|
+
return [fromConvexError(cause), null];
|
|
407
|
+
}
|
|
408
|
+
},
|
|
78
409
|
provisionPersonal: async (input) => {
|
|
79
410
|
if (!config.data) {
|
|
80
411
|
return stub(
|
|
@@ -154,18 +485,7 @@ function createAccountsClient(config = {}) {
|
|
|
154
485
|
create: async () => stub("accounts.kycProfiles.create"),
|
|
155
486
|
retrieve: async () => stub("accounts.kycProfiles.retrieve")
|
|
156
487
|
},
|
|
157
|
-
externalAccounts:
|
|
158
|
-
create: async () => stub(
|
|
159
|
-
"accounts.externalAccounts.create"
|
|
160
|
-
),
|
|
161
|
-
list: async () => stub(
|
|
162
|
-
"accounts.externalAccounts.list"
|
|
163
|
-
),
|
|
164
|
-
retrieve: async () => stub(
|
|
165
|
-
"accounts.externalAccounts.retrieve"
|
|
166
|
-
),
|
|
167
|
-
remove: async () => stub("accounts.externalAccounts.remove")
|
|
168
|
-
},
|
|
488
|
+
externalAccounts: createAccountExternalAccountsClient(config),
|
|
169
489
|
subAccounts: {
|
|
170
490
|
create: async () => stub("accounts.subAccounts.create"),
|
|
171
491
|
list: async () => stub("accounts.subAccounts.list"),
|
|
@@ -260,7 +580,29 @@ var Errors = {
|
|
|
260
580
|
{ details }
|
|
261
581
|
),
|
|
262
582
|
emailDeliveryFailed: (detail) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`),
|
|
263
|
-
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`)
|
|
583
|
+
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
584
|
+
/**
|
|
585
|
+
* Verification gate. Surfaced when a request hits a verification
|
|
586
|
+
* boundary the actor cannot cross under their current state. Two
|
|
587
|
+
* variants share this code:
|
|
588
|
+
*
|
|
589
|
+
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
590
|
+
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
591
|
+
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
592
|
+
* `details.rail` + `details.currentKind`.
|
|
593
|
+
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
594
|
+
* the required tier. Carries `details.requiredTier`.
|
|
595
|
+
*
|
|
596
|
+
* Code is shared because both expose the same UX shape ("you cannot
|
|
597
|
+
* proceed until verification advances"); the `details.*` keys
|
|
598
|
+
* differentiate the route.
|
|
599
|
+
*/
|
|
600
|
+
verificationRequired: (details) => {
|
|
601
|
+
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
602
|
+
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
603
|
+
details: { ...details }
|
|
604
|
+
});
|
|
605
|
+
}
|
|
264
606
|
};
|
|
265
607
|
|
|
266
608
|
// ../config/src/safe.ts
|
|
@@ -672,14 +1014,6 @@ function createOrgDocumentsClient() {
|
|
|
672
1014
|
};
|
|
673
1015
|
}
|
|
674
1016
|
|
|
675
|
-
// src/core/external-accounts.ts
|
|
676
|
-
function createExternalAccountsClient() {
|
|
677
|
-
return {
|
|
678
|
-
retrieve: async () => stub("externalAccounts.retrieve"),
|
|
679
|
-
remove: async () => stub("externalAccounts.remove")
|
|
680
|
-
};
|
|
681
|
-
}
|
|
682
|
-
|
|
683
1017
|
// src/core/me.ts
|
|
684
1018
|
function createMeClient(config = {}) {
|
|
685
1019
|
return {
|
|
@@ -697,7 +1031,34 @@ function createMeClient(config = {}) {
|
|
|
697
1031
|
return [fromConvexError(cause), null];
|
|
698
1032
|
}
|
|
699
1033
|
},
|
|
700
|
-
update: async () =>
|
|
1034
|
+
update: async (input) => {
|
|
1035
|
+
if (!config.data) {
|
|
1036
|
+
return stub("me.update");
|
|
1037
|
+
}
|
|
1038
|
+
if (input.countryCode !== void 0) {
|
|
1039
|
+
return [
|
|
1040
|
+
new CapxulError({
|
|
1041
|
+
code: "INVALID_INPUT",
|
|
1042
|
+
message: "me.update does not support countryCode yet \u2014 backend mutation only patches displayName and username.",
|
|
1043
|
+
details: { field: "countryCode" }
|
|
1044
|
+
}),
|
|
1045
|
+
null
|
|
1046
|
+
];
|
|
1047
|
+
}
|
|
1048
|
+
try {
|
|
1049
|
+
await config.data.mutation(api.openfort.mutations.updateProfile, {
|
|
1050
|
+
displayName: input.name,
|
|
1051
|
+
username: input.username
|
|
1052
|
+
});
|
|
1053
|
+
const account = await config.data.query(
|
|
1054
|
+
api.openfort.queries.getMyAccount,
|
|
1055
|
+
{}
|
|
1056
|
+
);
|
|
1057
|
+
return [null, account];
|
|
1058
|
+
} catch (cause) {
|
|
1059
|
+
return [fromConvexError(cause), null];
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
701
1062
|
};
|
|
702
1063
|
}
|
|
703
1064
|
|
|
@@ -1100,25 +1461,379 @@ function createOrgTransfersClient() {
|
|
|
1100
1461
|
cancel: async () => stub("organizations.transfers.cancel")
|
|
1101
1462
|
};
|
|
1102
1463
|
}
|
|
1103
|
-
|
|
1104
|
-
// src/core/withdrawals.ts
|
|
1105
|
-
function createWithdrawalsClient() {
|
|
1106
|
-
return {
|
|
1107
|
-
create: async () => stub("withdrawals.create"),
|
|
1108
|
-
retrieve: async () => stub("withdrawals.retrieve"),
|
|
1109
|
-
list: async () => stub("withdrawals.list")
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1112
|
-
function createOrgWithdrawalsClient() {
|
|
1464
|
+
function createWithdrawalsClient(config = {}) {
|
|
1113
1465
|
return {
|
|
1114
|
-
create: async () =>
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1466
|
+
create: async (input) => {
|
|
1467
|
+
if (!config.data) {
|
|
1468
|
+
return stub("withdrawals.create");
|
|
1469
|
+
}
|
|
1470
|
+
const [createErr, createdRaw] = await tryCatch(
|
|
1471
|
+
config.data.mutation(api.withdrawals.mutations.create, {
|
|
1472
|
+
amount: input.amount,
|
|
1473
|
+
destination: {
|
|
1474
|
+
externalAccountId: input.destination.externalAccountId
|
|
1475
|
+
},
|
|
1476
|
+
source: input.source,
|
|
1477
|
+
reference: input.reference,
|
|
1478
|
+
idempotencyKey: input.idempotencyKey
|
|
1479
|
+
})
|
|
1480
|
+
);
|
|
1481
|
+
if (createErr) {
|
|
1482
|
+
return [mapCreateError2(fromConvexError(createErr)), null];
|
|
1483
|
+
}
|
|
1484
|
+
const created = createdRaw;
|
|
1485
|
+
if (!created) {
|
|
1486
|
+
return [
|
|
1487
|
+
new CapxulError({
|
|
1488
|
+
code: "NETWORK_ERROR",
|
|
1489
|
+
message: "withdrawals.create returned no withdrawal resource"
|
|
1490
|
+
}),
|
|
1491
|
+
null
|
|
1492
|
+
];
|
|
1493
|
+
}
|
|
1494
|
+
if (created.status !== "processing" || created.operation.status !== "processing") {
|
|
1495
|
+
return [null, created];
|
|
1496
|
+
}
|
|
1497
|
+
if (!config.signer || !config.signing) {
|
|
1498
|
+
return [null, created];
|
|
1499
|
+
}
|
|
1500
|
+
const [signerErr, currentSigner] = await tryCatch(
|
|
1501
|
+
config.data.query(api.safe.queries.getMySignerAddress, {})
|
|
1502
|
+
);
|
|
1503
|
+
if (signerErr) {
|
|
1504
|
+
return await handleSubmissionFailure(
|
|
1505
|
+
{ data: config.data },
|
|
1506
|
+
created.id,
|
|
1507
|
+
mapCreateError2(fromConvexError(signerErr))
|
|
1508
|
+
);
|
|
1509
|
+
}
|
|
1510
|
+
if (!currentSigner?.address) {
|
|
1511
|
+
return await handleSubmissionFailure(
|
|
1512
|
+
{ data: config.data },
|
|
1513
|
+
created.id,
|
|
1514
|
+
new CapxulError({
|
|
1515
|
+
code: "PERMISSION_DENIED",
|
|
1516
|
+
message: "No signer is registered for the authenticated account.",
|
|
1517
|
+
details: { withdrawalId: created.id }
|
|
1518
|
+
})
|
|
1519
|
+
);
|
|
1520
|
+
}
|
|
1521
|
+
if (viem.getAddress(currentSigner.address) !== viem.getAddress(config.signer.address)) {
|
|
1522
|
+
return await handleSubmissionFailure(
|
|
1523
|
+
{ data: config.data },
|
|
1524
|
+
created.id,
|
|
1525
|
+
new CapxulError({
|
|
1526
|
+
code: "PERMISSION_DENIED",
|
|
1527
|
+
message: "Configured signer does not match the authenticated account signer.",
|
|
1528
|
+
details: {
|
|
1529
|
+
withdrawalId: created.id,
|
|
1530
|
+
expectedSignerAddress: currentSigner.address,
|
|
1531
|
+
actualSignerAddress: config.signer.address
|
|
1532
|
+
}
|
|
1533
|
+
})
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1536
|
+
const [prepErr, submission] = await tryCatch(
|
|
1537
|
+
config.data.query(api.withdrawals.queries.prepareSubmission, {
|
|
1538
|
+
withdrawalId: created.id
|
|
1539
|
+
})
|
|
1540
|
+
);
|
|
1541
|
+
if (prepErr) {
|
|
1542
|
+
return await handleSubmissionFailure(
|
|
1543
|
+
{ data: config.data },
|
|
1544
|
+
created.id,
|
|
1545
|
+
mapCreateError2(fromConvexError(prepErr))
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
const destinationAddress = submission?.destinationAddress;
|
|
1549
|
+
if (!submission || !destinationAddress) {
|
|
1550
|
+
return await handleSubmissionFailure(
|
|
1551
|
+
{ data: config.data },
|
|
1552
|
+
created.id,
|
|
1553
|
+
new CapxulError({
|
|
1554
|
+
code: "NETWORK_ERROR",
|
|
1555
|
+
message: "withdrawals.prepareSubmission returned no destination.",
|
|
1556
|
+
details: { withdrawalId: created.id }
|
|
1557
|
+
})
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
const [transferErr, transferOk] = await tryCatch(
|
|
1561
|
+
transferAsOwner(
|
|
1562
|
+
{
|
|
1563
|
+
signer: config.signer,
|
|
1564
|
+
signing: config.signing
|
|
1565
|
+
},
|
|
1566
|
+
{
|
|
1567
|
+
tokenAddress: resolvePaymentTokenAddress(submission.amount.currency),
|
|
1568
|
+
recipientAddress: destinationAddress,
|
|
1569
|
+
amount: toTokenUnits(submission.amount.value, 6)
|
|
1570
|
+
}
|
|
1571
|
+
)
|
|
1572
|
+
);
|
|
1573
|
+
if (transferErr) {
|
|
1574
|
+
return await handleSubmissionFailure(
|
|
1575
|
+
{ data: config.data },
|
|
1576
|
+
created.id,
|
|
1577
|
+
mapCreateError2(fromConvexError(transferErr))
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1580
|
+
if (!transferOk.success) {
|
|
1581
|
+
return await handleSubmissionFailure(
|
|
1582
|
+
{ data: config.data },
|
|
1583
|
+
created.id,
|
|
1584
|
+
new CapxulError({
|
|
1585
|
+
code: "NETWORK_ERROR",
|
|
1586
|
+
message: "Bundler submission did not succeed.",
|
|
1587
|
+
details: {
|
|
1588
|
+
withdrawalId: created.id,
|
|
1589
|
+
txHash: transferOk.txHash,
|
|
1590
|
+
userOpHash: transferOk.userOpHash
|
|
1591
|
+
}
|
|
1592
|
+
})
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
const [recordErr] = await tryCatch(
|
|
1596
|
+
config.data.mutation(api.withdrawals.mutations.recordSubmitted, {
|
|
1597
|
+
withdrawalId: created.id,
|
|
1598
|
+
txHash: transferOk.txHash,
|
|
1599
|
+
userOpHash: transferOk.userOpHash
|
|
1600
|
+
})
|
|
1601
|
+
);
|
|
1602
|
+
if (recordErr) {
|
|
1603
|
+
return [
|
|
1604
|
+
new CapxulError({
|
|
1605
|
+
code: "NETWORK_ERROR",
|
|
1606
|
+
message: "Withdrawal was submitted on-chain, but backend submission tracking failed.",
|
|
1607
|
+
cause: recordErr,
|
|
1608
|
+
details: {
|
|
1609
|
+
withdrawalId: created.id,
|
|
1610
|
+
txHash: transferOk.txHash,
|
|
1611
|
+
userOpHash: transferOk.userOpHash
|
|
1612
|
+
}
|
|
1613
|
+
}),
|
|
1614
|
+
null
|
|
1615
|
+
];
|
|
1616
|
+
}
|
|
1617
|
+
return [null, created];
|
|
1618
|
+
},
|
|
1619
|
+
retrieve: async (withdrawalId) => {
|
|
1620
|
+
if (!config.data) {
|
|
1621
|
+
return stub("withdrawals.retrieve");
|
|
1622
|
+
}
|
|
1623
|
+
const [err, raw] = await tryCatch(
|
|
1624
|
+
config.data.query(api.withdrawals.queries.retrieve, { withdrawalId })
|
|
1625
|
+
);
|
|
1626
|
+
if (err) {
|
|
1627
|
+
return [fromConvexError(err), null];
|
|
1628
|
+
}
|
|
1629
|
+
const withdrawal = raw;
|
|
1630
|
+
if (!withdrawal) {
|
|
1631
|
+
return [
|
|
1632
|
+
new CapxulError({
|
|
1633
|
+
code: "NOT_FOUND",
|
|
1634
|
+
message: `withdrawal ${withdrawalId} not found`
|
|
1635
|
+
}),
|
|
1636
|
+
null
|
|
1637
|
+
];
|
|
1638
|
+
}
|
|
1639
|
+
return [null, withdrawal];
|
|
1640
|
+
},
|
|
1641
|
+
list: async (input) => {
|
|
1642
|
+
if (!config.data) {
|
|
1643
|
+
return stub("withdrawals.list");
|
|
1644
|
+
}
|
|
1645
|
+
const [err, raw] = await tryCatch(
|
|
1646
|
+
config.data.query(api.withdrawals.queries.list, {
|
|
1647
|
+
limit: input?.limit,
|
|
1648
|
+
cursor: input?.cursor
|
|
1649
|
+
})
|
|
1650
|
+
);
|
|
1651
|
+
if (err) {
|
|
1652
|
+
return [fromConvexError(err), null];
|
|
1653
|
+
}
|
|
1654
|
+
return [null, raw];
|
|
1655
|
+
},
|
|
1656
|
+
recordCompleted: async (input) => {
|
|
1657
|
+
if (!config.data) {
|
|
1658
|
+
return stub(
|
|
1659
|
+
"withdrawals.recordCompleted"
|
|
1660
|
+
);
|
|
1661
|
+
}
|
|
1662
|
+
const [err] = await tryCatch(
|
|
1663
|
+
config.data.mutation(api.withdrawals.mutations.recordCompleted, {
|
|
1664
|
+
withdrawalId: input.withdrawalId,
|
|
1665
|
+
txHash: input.txHash
|
|
1666
|
+
})
|
|
1667
|
+
);
|
|
1668
|
+
if (err) {
|
|
1669
|
+
return [
|
|
1670
|
+
mapRecordCompletedError(fromConvexError(err)),
|
|
1671
|
+
null
|
|
1672
|
+
];
|
|
1673
|
+
}
|
|
1674
|
+
return [null, null];
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
function createOrgWithdrawalsClient(config = {}) {
|
|
1679
|
+
return {
|
|
1680
|
+
/**
|
|
1681
|
+
* Org-scope create (Withdrawals v1 W2, #465).
|
|
1682
|
+
*
|
|
1683
|
+
* D6 — returns the `processing` row only. No `transferAsOwner`
|
|
1684
|
+
* tail, no `recordSubmitted` call. Org Safe + Zodiac submission
|
|
1685
|
+
* orchestration ships in W3+.
|
|
1686
|
+
*/
|
|
1687
|
+
create: async (input) => {
|
|
1688
|
+
if (!config.data) {
|
|
1689
|
+
return stub(
|
|
1690
|
+
"organizations.withdrawals.create"
|
|
1691
|
+
);
|
|
1692
|
+
}
|
|
1693
|
+
const [err, raw] = await tryCatch(
|
|
1694
|
+
config.data.mutation(api.withdrawals.mutations.createOrg, {
|
|
1695
|
+
organizationId: input.organizationId,
|
|
1696
|
+
amount: input.amount,
|
|
1697
|
+
destination: {
|
|
1698
|
+
externalAccountId: input.destination.externalAccountId
|
|
1699
|
+
},
|
|
1700
|
+
source: input.source,
|
|
1701
|
+
reference: input.reference,
|
|
1702
|
+
idempotencyKey: input.idempotencyKey
|
|
1703
|
+
})
|
|
1704
|
+
);
|
|
1705
|
+
if (err) {
|
|
1706
|
+
return [mapCreateError2(fromConvexError(err)), null];
|
|
1707
|
+
}
|
|
1708
|
+
const created = raw;
|
|
1709
|
+
if (!created) {
|
|
1710
|
+
return [
|
|
1711
|
+
new CapxulError({
|
|
1712
|
+
code: "NETWORK_ERROR",
|
|
1713
|
+
message: "organizations.withdrawals.create returned no withdrawal resource"
|
|
1714
|
+
}),
|
|
1715
|
+
null
|
|
1716
|
+
];
|
|
1717
|
+
}
|
|
1718
|
+
return [null, created];
|
|
1719
|
+
},
|
|
1720
|
+
retrieve: async (input) => {
|
|
1721
|
+
if (!config.data) {
|
|
1722
|
+
return stub(
|
|
1723
|
+
"organizations.withdrawals.retrieve"
|
|
1724
|
+
);
|
|
1725
|
+
}
|
|
1726
|
+
const [err, raw] = await tryCatch(
|
|
1727
|
+
config.data.query(api.withdrawals.queries.retrieve, {
|
|
1728
|
+
withdrawalId: input.withdrawalId
|
|
1729
|
+
})
|
|
1730
|
+
);
|
|
1731
|
+
if (err) {
|
|
1732
|
+
return [fromConvexError(err), null];
|
|
1733
|
+
}
|
|
1734
|
+
const withdrawal = raw;
|
|
1735
|
+
if (!withdrawal) {
|
|
1736
|
+
return [
|
|
1737
|
+
new CapxulError({
|
|
1738
|
+
code: "NOT_FOUND",
|
|
1739
|
+
message: `withdrawal ${input.withdrawalId} not found`
|
|
1740
|
+
}),
|
|
1741
|
+
null
|
|
1742
|
+
];
|
|
1743
|
+
}
|
|
1744
|
+
const ownerCheck = withdrawal.owner;
|
|
1745
|
+
if (ownerCheck?.type !== "organization" || ownerCheck.id !== input.organizationId) {
|
|
1746
|
+
return [
|
|
1747
|
+
new CapxulError({
|
|
1748
|
+
code: "NOT_FOUND",
|
|
1749
|
+
message: `withdrawal ${input.withdrawalId} does not belong to organization ${input.organizationId}`
|
|
1750
|
+
}),
|
|
1751
|
+
null
|
|
1752
|
+
];
|
|
1753
|
+
}
|
|
1754
|
+
return [null, withdrawal];
|
|
1755
|
+
},
|
|
1756
|
+
list: async (input) => {
|
|
1757
|
+
if (!config.data) {
|
|
1758
|
+
return stub(
|
|
1759
|
+
"organizations.withdrawals.list"
|
|
1760
|
+
);
|
|
1761
|
+
}
|
|
1762
|
+
const [err, raw] = await tryCatch(
|
|
1763
|
+
config.data.query(api.withdrawals.queries.listOrg, {
|
|
1764
|
+
organizationId: input.organizationId,
|
|
1765
|
+
limit: input.limit,
|
|
1766
|
+
cursor: input.cursor
|
|
1767
|
+
})
|
|
1768
|
+
);
|
|
1769
|
+
if (err) {
|
|
1770
|
+
return [fromConvexError(err), null];
|
|
1771
|
+
}
|
|
1772
|
+
return [null, raw];
|
|
1773
|
+
}
|
|
1774
|
+
};
|
|
1775
|
+
}
|
|
1776
|
+
async function handleSubmissionFailure(config, withdrawalId, error) {
|
|
1777
|
+
await bestEffortMarkFailed2(config, withdrawalId, error);
|
|
1778
|
+
return [error, null];
|
|
1779
|
+
}
|
|
1780
|
+
async function bestEffortMarkFailed2(config, withdrawalId, error) {
|
|
1781
|
+
await tryCatch(
|
|
1782
|
+
config.data.mutation(api.withdrawals.mutations.markFailed, {
|
|
1783
|
+
withdrawalId,
|
|
1784
|
+
errorCode: error.code,
|
|
1785
|
+
errorMessage: error.message
|
|
1786
|
+
})
|
|
1787
|
+
);
|
|
1788
|
+
}
|
|
1789
|
+
function mapCreateError2(error) {
|
|
1790
|
+
switch (error.code) {
|
|
1791
|
+
case "NOT_AUTHENTICATED":
|
|
1792
|
+
case "PERMISSION_DENIED":
|
|
1793
|
+
case "INVALID_INPUT":
|
|
1794
|
+
case "INSUFFICIENT_BALANCE":
|
|
1795
|
+
case "IDEMPOTENCY_CONFLICT":
|
|
1796
|
+
case "KYC_REQUIRED":
|
|
1797
|
+
case "POLICY_DENIED":
|
|
1798
|
+
case "RATE_LIMITED":
|
|
1799
|
+
case "NETWORK_ERROR":
|
|
1800
|
+
case "NOT_FOUND":
|
|
1801
|
+
case "VERIFICATION_REQUIRED":
|
|
1802
|
+
return error;
|
|
1803
|
+
default:
|
|
1804
|
+
return new CapxulError({
|
|
1805
|
+
code: "NETWORK_ERROR",
|
|
1806
|
+
message: error.message,
|
|
1807
|
+
cause: error,
|
|
1808
|
+
details: error.details,
|
|
1809
|
+
operationId: error.operationId,
|
|
1810
|
+
correlationId: error.correlationId,
|
|
1811
|
+
retryable: error.retryable
|
|
1812
|
+
});
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
function mapRecordCompletedError(error) {
|
|
1816
|
+
switch (error.code) {
|
|
1817
|
+
case "NOT_AUTHENTICATED":
|
|
1818
|
+
case "PERMISSION_DENIED":
|
|
1819
|
+
case "INVALID_INPUT":
|
|
1820
|
+
case "NOT_FOUND":
|
|
1821
|
+
case "NETWORK_ERROR":
|
|
1822
|
+
case "INTERNAL_ERROR":
|
|
1823
|
+
return error;
|
|
1824
|
+
default:
|
|
1825
|
+
return new CapxulError({
|
|
1826
|
+
code: "NETWORK_ERROR",
|
|
1827
|
+
message: error.message,
|
|
1828
|
+
cause: error,
|
|
1829
|
+
details: error.details,
|
|
1830
|
+
operationId: error.operationId,
|
|
1831
|
+
correlationId: error.correlationId,
|
|
1832
|
+
retryable: error.retryable
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1122
1837
|
// src/core/webhook-endpoints.ts
|
|
1123
1838
|
function createWebhookEndpointsClient() {
|
|
1124
1839
|
return {
|
|
@@ -1140,6 +1855,136 @@ function createWebhookEventsClient() {
|
|
|
1140
1855
|
}
|
|
1141
1856
|
|
|
1142
1857
|
// src/core/organizations.ts
|
|
1858
|
+
function createOrgExternalAccountsClient(config) {
|
|
1859
|
+
return {
|
|
1860
|
+
create: async (input) => {
|
|
1861
|
+
if (!config.data) {
|
|
1862
|
+
return stub(
|
|
1863
|
+
"organizations.externalAccounts.create"
|
|
1864
|
+
);
|
|
1865
|
+
}
|
|
1866
|
+
const [err, raw] = await tryCatch(
|
|
1867
|
+
config.data.mutation(api.externalAccounts.mutations.createOrg, {
|
|
1868
|
+
organizationId: input.organizationId,
|
|
1869
|
+
kind: input.kind,
|
|
1870
|
+
label: input.label,
|
|
1871
|
+
address: input.address,
|
|
1872
|
+
iban: input.iban,
|
|
1873
|
+
bic: input.bic,
|
|
1874
|
+
accountHolder: input.accountHolder,
|
|
1875
|
+
network: input.network,
|
|
1876
|
+
panToken: input.panToken,
|
|
1877
|
+
last4: input.last4
|
|
1878
|
+
})
|
|
1879
|
+
);
|
|
1880
|
+
if (err) {
|
|
1881
|
+
return [
|
|
1882
|
+
fromConvexError(err),
|
|
1883
|
+
null
|
|
1884
|
+
];
|
|
1885
|
+
}
|
|
1886
|
+
if (!raw) {
|
|
1887
|
+
return [
|
|
1888
|
+
new CapxulError({
|
|
1889
|
+
code: "NOT_FOUND",
|
|
1890
|
+
message: "external_account creation returned no resource"
|
|
1891
|
+
}),
|
|
1892
|
+
null
|
|
1893
|
+
];
|
|
1894
|
+
}
|
|
1895
|
+
return [
|
|
1896
|
+
null,
|
|
1897
|
+
brandExternalAccount(
|
|
1898
|
+
raw
|
|
1899
|
+
)
|
|
1900
|
+
];
|
|
1901
|
+
},
|
|
1902
|
+
list: async (input) => {
|
|
1903
|
+
if (!config.data) {
|
|
1904
|
+
return stub(
|
|
1905
|
+
"organizations.externalAccounts.list"
|
|
1906
|
+
);
|
|
1907
|
+
}
|
|
1908
|
+
const [err, result] = await tryCatch(
|
|
1909
|
+
config.data.query(api.externalAccounts.queries.listOrg, {
|
|
1910
|
+
organizationId: input.organizationId,
|
|
1911
|
+
limit: input.limit,
|
|
1912
|
+
cursor: input.cursor
|
|
1913
|
+
})
|
|
1914
|
+
);
|
|
1915
|
+
if (err) {
|
|
1916
|
+
return [fromConvexError(err), null];
|
|
1917
|
+
}
|
|
1918
|
+
const branded = result.data.map(
|
|
1919
|
+
(row) => brandExternalAccount(
|
|
1920
|
+
row
|
|
1921
|
+
)
|
|
1922
|
+
);
|
|
1923
|
+
return [
|
|
1924
|
+
null,
|
|
1925
|
+
{
|
|
1926
|
+
object: "list",
|
|
1927
|
+
data: branded,
|
|
1928
|
+
page: result.page
|
|
1929
|
+
}
|
|
1930
|
+
];
|
|
1931
|
+
},
|
|
1932
|
+
retrieve: async (input) => {
|
|
1933
|
+
if (!config.data) {
|
|
1934
|
+
return stub(
|
|
1935
|
+
"organizations.externalAccounts.retrieve"
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
const [err, raw] = await tryCatch(
|
|
1939
|
+
config.data.query(api.externalAccounts.queries.retrieveOrg, {
|
|
1940
|
+
organizationId: input.organizationId,
|
|
1941
|
+
externalAccountId: input.externalAccountId
|
|
1942
|
+
})
|
|
1943
|
+
);
|
|
1944
|
+
if (err) {
|
|
1945
|
+
return [
|
|
1946
|
+
fromConvexError(err),
|
|
1947
|
+
null
|
|
1948
|
+
];
|
|
1949
|
+
}
|
|
1950
|
+
if (!raw) {
|
|
1951
|
+
return [
|
|
1952
|
+
new CapxulError({
|
|
1953
|
+
code: "NOT_FOUND",
|
|
1954
|
+
message: `external_account ${input.externalAccountId} not found`
|
|
1955
|
+
}),
|
|
1956
|
+
null
|
|
1957
|
+
];
|
|
1958
|
+
}
|
|
1959
|
+
return [
|
|
1960
|
+
null,
|
|
1961
|
+
brandExternalAccount(
|
|
1962
|
+
raw
|
|
1963
|
+
)
|
|
1964
|
+
];
|
|
1965
|
+
},
|
|
1966
|
+
remove: async (input) => {
|
|
1967
|
+
if (!config.data) {
|
|
1968
|
+
return stub(
|
|
1969
|
+
"organizations.externalAccounts.remove"
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
const [err] = await tryCatch(
|
|
1973
|
+
config.data.mutation(api.externalAccounts.mutations.removeOrg, {
|
|
1974
|
+
organizationId: input.organizationId,
|
|
1975
|
+
externalAccountId: input.externalAccountId
|
|
1976
|
+
})
|
|
1977
|
+
);
|
|
1978
|
+
if (err) {
|
|
1979
|
+
return [
|
|
1980
|
+
fromConvexError(err),
|
|
1981
|
+
null
|
|
1982
|
+
];
|
|
1983
|
+
}
|
|
1984
|
+
return [null, void 0];
|
|
1985
|
+
}
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1143
1988
|
function createOrganizationsClient(config = {}) {
|
|
1144
1989
|
return {
|
|
1145
1990
|
create: async () => stub("organizations.create"),
|
|
@@ -1195,18 +2040,7 @@ function createOrganizationsClient(config = {}) {
|
|
|
1195
2040
|
retrieve: async () => stub("organizations.subAccounts.retrieve"),
|
|
1196
2041
|
remove: async () => stub("organizations.subAccounts.remove")
|
|
1197
2042
|
},
|
|
1198
|
-
externalAccounts:
|
|
1199
|
-
create: async () => stub(
|
|
1200
|
-
"organizations.externalAccounts.create"
|
|
1201
|
-
),
|
|
1202
|
-
list: async () => stub(
|
|
1203
|
-
"organizations.externalAccounts.list"
|
|
1204
|
-
),
|
|
1205
|
-
retrieve: async () => stub(
|
|
1206
|
-
"organizations.externalAccounts.retrieve"
|
|
1207
|
-
),
|
|
1208
|
-
remove: async () => stub("organizations.externalAccounts.remove")
|
|
1209
|
-
},
|
|
2043
|
+
externalAccounts: createOrgExternalAccountsClient(config),
|
|
1210
2044
|
balanceLedger: {
|
|
1211
2045
|
list: async () => stub(
|
|
1212
2046
|
"organizations.balanceLedger.list"
|
|
@@ -1217,7 +2051,7 @@ function createOrganizationsClient(config = {}) {
|
|
|
1217
2051
|
},
|
|
1218
2052
|
payments: createOrgPaymentsClient(),
|
|
1219
2053
|
transfers: createOrgTransfersClient(),
|
|
1220
|
-
withdrawals: createOrgWithdrawalsClient(),
|
|
2054
|
+
withdrawals: createOrgWithdrawalsClient(config),
|
|
1221
2055
|
documents: createOrgDocumentsClient(),
|
|
1222
2056
|
webhookEndpoints: createWebhookEndpointsClient(),
|
|
1223
2057
|
webhookEvents: createWebhookEventsClient()
|
|
@@ -1232,6 +2066,96 @@ function createSubAccountsClient() {
|
|
|
1232
2066
|
};
|
|
1233
2067
|
}
|
|
1234
2068
|
|
|
2069
|
+
// src/core/token-transfers.ts
|
|
2070
|
+
var toTokenTransferId = (raw) => {
|
|
2071
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
2072
|
+
throw new Error(
|
|
2073
|
+
`Invalid tokenTransferId: expected non-empty string, got ${String(raw)}`
|
|
2074
|
+
);
|
|
2075
|
+
}
|
|
2076
|
+
return raw;
|
|
2077
|
+
};
|
|
2078
|
+
function brandRow(row) {
|
|
2079
|
+
return {
|
|
2080
|
+
...row,
|
|
2081
|
+
id: toTokenTransferId(row.id)
|
|
2082
|
+
};
|
|
2083
|
+
}
|
|
2084
|
+
function createTokenTransfersClient(config = {}) {
|
|
2085
|
+
return {
|
|
2086
|
+
list: async (input) => {
|
|
2087
|
+
if (!config.data) {
|
|
2088
|
+
return stub("tokenTransfers.list");
|
|
2089
|
+
}
|
|
2090
|
+
try {
|
|
2091
|
+
const raw = await config.data.query(
|
|
2092
|
+
api.tokenTransfers.queries.list,
|
|
2093
|
+
{
|
|
2094
|
+
limit: input?.limit,
|
|
2095
|
+
cursor: input?.cursor,
|
|
2096
|
+
direction: input?.direction
|
|
2097
|
+
}
|
|
2098
|
+
);
|
|
2099
|
+
if (!raw) {
|
|
2100
|
+
return [
|
|
2101
|
+
new CapxulError({
|
|
2102
|
+
code: "NOT_AUTHENTICATED",
|
|
2103
|
+
message: "tokenTransfers.list requires an authenticated session."
|
|
2104
|
+
}),
|
|
2105
|
+
null
|
|
2106
|
+
];
|
|
2107
|
+
}
|
|
2108
|
+
return [
|
|
2109
|
+
null,
|
|
2110
|
+
{
|
|
2111
|
+
object: "list",
|
|
2112
|
+
data: raw.items.map(brandRow),
|
|
2113
|
+
page: {
|
|
2114
|
+
hasMore: raw.hasMore,
|
|
2115
|
+
nextCursor: raw.nextCursor
|
|
2116
|
+
},
|
|
2117
|
+
displayCurrency: raw.displayCurrency
|
|
2118
|
+
}
|
|
2119
|
+
];
|
|
2120
|
+
} catch (cause) {
|
|
2121
|
+
return [fromConvexError(cause), null];
|
|
2122
|
+
}
|
|
2123
|
+
},
|
|
2124
|
+
retrieve: async (input) => {
|
|
2125
|
+
if (!config.data) {
|
|
2126
|
+
return stub("tokenTransfers.retrieve");
|
|
2127
|
+
}
|
|
2128
|
+
try {
|
|
2129
|
+
const raw = await config.data.query(
|
|
2130
|
+
api.tokenTransfers.queries.getByTxLogIndex,
|
|
2131
|
+
{
|
|
2132
|
+
txHash: input.txHash,
|
|
2133
|
+
logIndex: input.logIndex,
|
|
2134
|
+
chainId: input.chainId
|
|
2135
|
+
}
|
|
2136
|
+
);
|
|
2137
|
+
if (!raw) {
|
|
2138
|
+
return [
|
|
2139
|
+
new CapxulError({
|
|
2140
|
+
code: "NOT_FOUND",
|
|
2141
|
+
message: `tokenTransfer (txHash=${input.txHash}, logIndex=${input.logIndex}) not found or not visible to caller.`,
|
|
2142
|
+
details: {
|
|
2143
|
+
txHash: input.txHash,
|
|
2144
|
+
logIndex: input.logIndex,
|
|
2145
|
+
chainId: input.chainId
|
|
2146
|
+
}
|
|
2147
|
+
}),
|
|
2148
|
+
null
|
|
2149
|
+
];
|
|
2150
|
+
}
|
|
2151
|
+
return [null, brandRow(raw)];
|
|
2152
|
+
} catch (cause) {
|
|
2153
|
+
return [fromConvexError(cause), null];
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
};
|
|
2157
|
+
}
|
|
2158
|
+
|
|
1235
2159
|
// src/core/virtual-accounts.ts
|
|
1236
2160
|
function createVirtualAccountsClient() {
|
|
1237
2161
|
return {
|
|
@@ -1253,50 +2177,6 @@ function createVirtualCardsClient() {
|
|
|
1253
2177
|
cancel: async () => stub("virtualCards.cancel")
|
|
1254
2178
|
};
|
|
1255
2179
|
}
|
|
1256
|
-
|
|
1257
|
-
// ../observability/src/debug-log.ts
|
|
1258
|
-
function isDevelopmentBuild() {
|
|
1259
|
-
if (typeof process === "undefined") {
|
|
1260
|
-
return false;
|
|
1261
|
-
}
|
|
1262
|
-
return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
|
|
1263
|
-
}
|
|
1264
|
-
function debugLog(line) {
|
|
1265
|
-
if (!isDevelopmentBuild()) return;
|
|
1266
|
-
if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
|
|
1267
|
-
console.info(line);
|
|
1268
|
-
return;
|
|
1269
|
-
}
|
|
1270
|
-
if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
|
|
1271
|
-
process.stderr.write(`${line}
|
|
1272
|
-
`);
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
function formatDebugValue(value) {
|
|
1276
|
-
if (value === void 0 || value === "") return "";
|
|
1277
|
-
if (typeof value === "string") return value;
|
|
1278
|
-
try {
|
|
1279
|
-
return JSON.stringify(value);
|
|
1280
|
-
} catch {
|
|
1281
|
-
return String(value);
|
|
1282
|
-
}
|
|
1283
|
-
}
|
|
1284
|
-
function track(...args) {
|
|
1285
|
-
const [name, props] = args;
|
|
1286
|
-
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
1287
|
-
}
|
|
1288
|
-
function formatDebugValue2(value) {
|
|
1289
|
-
if (value === void 0 || value === "") return "";
|
|
1290
|
-
if (typeof value === "string") return value;
|
|
1291
|
-
try {
|
|
1292
|
-
return JSON.stringify(value);
|
|
1293
|
-
} catch {
|
|
1294
|
-
return String(value);
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
function identify(userId, traits) {
|
|
1298
|
-
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
1299
|
-
}
|
|
1300
2180
|
function createAuthFlowMachine(client) {
|
|
1301
2181
|
return xstate.setup({
|
|
1302
2182
|
types: {},
|
|
@@ -1572,23 +2452,6 @@ function emailDomain(email) {
|
|
|
1572
2452
|
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
1573
2453
|
return domain || "unknown";
|
|
1574
2454
|
}
|
|
1575
|
-
|
|
1576
|
-
// ../platform-kernel/src/ids.ts
|
|
1577
|
-
function makePrefixedIdConstructor(prefix, fieldName) {
|
|
1578
|
-
const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
|
|
1579
|
-
return (raw) => {
|
|
1580
|
-
if (typeof raw !== "string" || !re.test(raw)) {
|
|
1581
|
-
throw new Error(
|
|
1582
|
-
`Invalid ${fieldName}: expected string matching ^${prefix}_[A-Za-z0-9_\\-]+$, got ${String(raw)}`
|
|
1583
|
-
);
|
|
1584
|
-
}
|
|
1585
|
-
return raw;
|
|
1586
|
-
};
|
|
1587
|
-
}
|
|
1588
|
-
var toOperationId = makePrefixedIdConstructor(
|
|
1589
|
-
"op",
|
|
1590
|
-
"operationId"
|
|
1591
|
-
);
|
|
1592
2455
|
function createProvisioningMachine(client) {
|
|
1593
2456
|
return xstate.setup({
|
|
1594
2457
|
types: {},
|
|
@@ -1975,12 +2838,13 @@ function createCapxulClient(config = {}) {
|
|
|
1975
2838
|
organizations: createOrganizationsClient(config),
|
|
1976
2839
|
payments: createPaymentsClient(config),
|
|
1977
2840
|
transfers: createTransfersClient(),
|
|
1978
|
-
|
|
2841
|
+
tokenTransfers: createTokenTransfersClient(config),
|
|
2842
|
+
withdrawals: createWithdrawalsClient(config),
|
|
1979
2843
|
documents: createDocumentsClient(),
|
|
1980
2844
|
subAccounts: createSubAccountsClient(),
|
|
1981
2845
|
virtualAccounts: createVirtualAccountsClient(),
|
|
1982
2846
|
virtualCards: createVirtualCardsClient(),
|
|
1983
|
-
externalAccounts: createExternalAccountsClient(),
|
|
2847
|
+
externalAccounts: createExternalAccountsClient(config),
|
|
1984
2848
|
operations: createOperationsClient(config),
|
|
1985
2849
|
webhookEndpoints: createWebhookEndpointsClient(),
|
|
1986
2850
|
webhookEvents: createWebhookEventsClient(),
|