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