@capxul/sdk 0.1.0-alpha.4 → 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 +28 -0
- package/README.md +1 -1
- package/dist/{client-CcCtq5XO.d.ts → client-ChfXWMzO.d.ts} +66 -26
- package/dist/{client-CXRKtbfn.d.cts → client-DW_fW9DC.d.cts} +66 -26
- package/dist/client.cjs +678 -276
- package/dist/client.d.cts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/client.js +678 -276
- package/dist/index.cjs +781 -389
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +781 -389
- package/dist/{types-75UokagF.d.ts → types-CYvLP5pP.d.ts} +13 -2
- package/dist/{types-DVWojoy4.d.cts → types-X02RbQ2u.d.cts} +13 -2
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -68,7 +68,366 @@ function fromConvexError(error) {
|
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// ../observability/src/try-catch.ts
|
|
72
|
+
async function tryCatch(promise) {
|
|
73
|
+
try {
|
|
74
|
+
return [null, await promise];
|
|
75
|
+
} catch (e) {
|
|
76
|
+
return [e instanceof Error ? e : new Error(String(e)), null];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ../observability/src/debug-log.ts
|
|
81
|
+
function isDevelopmentBuild() {
|
|
82
|
+
if (typeof process === "undefined") {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
|
|
86
|
+
}
|
|
87
|
+
function debugLog(line) {
|
|
88
|
+
if (!isDevelopmentBuild()) return;
|
|
89
|
+
if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
|
|
90
|
+
console.info(line);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
|
|
94
|
+
process.stderr.write(`${line}
|
|
95
|
+
`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function formatDebugValue(value) {
|
|
99
|
+
if (value === void 0 || value === "") return "";
|
|
100
|
+
if (typeof value === "string") return value;
|
|
101
|
+
try {
|
|
102
|
+
return JSON.stringify(value);
|
|
103
|
+
} catch {
|
|
104
|
+
return String(value);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function track(...args) {
|
|
108
|
+
const [name, props] = args;
|
|
109
|
+
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
110
|
+
}
|
|
111
|
+
function formatDebugValue2(value) {
|
|
112
|
+
if (value === void 0 || value === "") return "";
|
|
113
|
+
if (typeof value === "string") return value;
|
|
114
|
+
try {
|
|
115
|
+
return JSON.stringify(value);
|
|
116
|
+
} catch {
|
|
117
|
+
return String(value);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function identify(userId, traits) {
|
|
121
|
+
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ../platform-kernel/src/ids.ts
|
|
125
|
+
function makePrefixedIdConstructor(prefix, fieldName) {
|
|
126
|
+
const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
|
|
127
|
+
return (raw) => {
|
|
128
|
+
if (typeof raw !== "string" || !re.test(raw)) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`Invalid ${fieldName}: expected string matching ^${prefix}_[A-Za-z0-9_\\-]+$, got ${String(raw)}`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return raw;
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
var toAccountId = makePrefixedIdConstructor(
|
|
137
|
+
"acct",
|
|
138
|
+
"accountId"
|
|
139
|
+
);
|
|
140
|
+
var toOrganizationId = makePrefixedIdConstructor("org", "organizationId");
|
|
141
|
+
var toMemberId = makePrefixedIdConstructor(
|
|
142
|
+
"mem",
|
|
143
|
+
"memberId"
|
|
144
|
+
);
|
|
145
|
+
var toSafeId = makePrefixedIdConstructor(
|
|
146
|
+
"safe",
|
|
147
|
+
"safeId"
|
|
148
|
+
);
|
|
149
|
+
var toTreasuryId = makePrefixedIdConstructor(
|
|
150
|
+
"try",
|
|
151
|
+
"treasuryId"
|
|
152
|
+
);
|
|
153
|
+
var toApiKeyId = makePrefixedIdConstructor(
|
|
154
|
+
"ak",
|
|
155
|
+
"apiKeyId"
|
|
156
|
+
);
|
|
157
|
+
var toOperationId = makePrefixedIdConstructor(
|
|
158
|
+
"op",
|
|
159
|
+
"operationId"
|
|
160
|
+
);
|
|
161
|
+
var toCorrelationId = makePrefixedIdConstructor("ctx", "correlationId");
|
|
162
|
+
var toKycProfileId = makePrefixedIdConstructor(
|
|
163
|
+
"kyc",
|
|
164
|
+
"kycProfileId"
|
|
165
|
+
);
|
|
166
|
+
var toKybProfileId = makePrefixedIdConstructor(
|
|
167
|
+
"kyb",
|
|
168
|
+
"kybProfileId"
|
|
169
|
+
);
|
|
170
|
+
var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
|
|
171
|
+
var toPaymentId = makePrefixedIdConstructor(
|
|
172
|
+
"pay",
|
|
173
|
+
"paymentId"
|
|
174
|
+
);
|
|
175
|
+
var toWithdrawalId = makePrefixedIdConstructor(
|
|
176
|
+
"wd",
|
|
177
|
+
"withdrawalId"
|
|
178
|
+
);
|
|
179
|
+
var toWebhookEndpointId = makePrefixedIdConstructor("we", "webhookEndpointId");
|
|
180
|
+
var toWebhookEventId = makePrefixedIdConstructor("evt", "webhookEventId");
|
|
181
|
+
var toSubAccountId = makePrefixedIdConstructor(
|
|
182
|
+
"sub",
|
|
183
|
+
"subAccountId"
|
|
184
|
+
);
|
|
185
|
+
var toVirtualAccountId = makePrefixedIdConstructor("va", "virtualAccountId");
|
|
186
|
+
var toVirtualCardId = makePrefixedIdConstructor(
|
|
187
|
+
"vc",
|
|
188
|
+
"virtualCardId"
|
|
189
|
+
);
|
|
190
|
+
var toTransferId = makePrefixedIdConstructor(
|
|
191
|
+
"txfr",
|
|
192
|
+
"transferId"
|
|
193
|
+
);
|
|
194
|
+
var toDocumentId = makePrefixedIdConstructor(
|
|
195
|
+
"doc",
|
|
196
|
+
"documentId"
|
|
197
|
+
);
|
|
198
|
+
var toBalanceLedgerEntryId = makePrefixedIdConstructor("bal", "balanceLedgerEntryId");
|
|
199
|
+
|
|
200
|
+
// ../platform-kernel/src/value-objects.ts
|
|
201
|
+
var PHONE_NUMBER_RE = /^\+[1-9]\d{1,14}$/;
|
|
202
|
+
function toPhoneNumber(raw) {
|
|
203
|
+
if (typeof raw !== "string" || !PHONE_NUMBER_RE.test(raw)) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`Invalid phoneNumber: expected E.164 string matching ^\\+[1-9]\\d{1,14}$, got ${String(raw)}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
return raw;
|
|
209
|
+
}
|
|
210
|
+
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
211
|
+
function toEmail(raw) {
|
|
212
|
+
if (typeof raw !== "string") {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`Invalid email: expected string, got ${String(raw)}`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
const lowered = raw.trim().toLowerCase();
|
|
218
|
+
if (!EMAIL_RE.test(lowered)) {
|
|
219
|
+
throw new Error(
|
|
220
|
+
`Invalid email: expected local@domain.tld, got ${String(raw)}`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
return lowered;
|
|
224
|
+
}
|
|
225
|
+
var USERNAME_RE = /^[a-z][a-z0-9_-]{2,29}$/;
|
|
226
|
+
function toUsername(raw) {
|
|
227
|
+
if (typeof raw !== "string") {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Invalid username: expected string, got ${String(raw)}`
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
const lowered = raw.toLowerCase();
|
|
233
|
+
if (!USERNAME_RE.test(lowered)) {
|
|
234
|
+
throw new Error(
|
|
235
|
+
`Invalid username: expected 3-30 chars, letter-first, [a-z0-9_-], got ${String(raw)}`
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
return lowered;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// src/core/external-accounts.ts
|
|
242
|
+
function brandExternalAccount(raw) {
|
|
243
|
+
return {
|
|
244
|
+
...raw,
|
|
245
|
+
id: toExternalAccountId(raw.id),
|
|
246
|
+
operation: {
|
|
247
|
+
id: toOperationId(raw.operation.id),
|
|
248
|
+
status: raw.operation.status,
|
|
249
|
+
correlationId: toCorrelationId(raw.operation.correlationId)
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function createExternalAccountsClient(config = {}) {
|
|
254
|
+
return {
|
|
255
|
+
retrieve: async (externalAccountId) => {
|
|
256
|
+
if (!config.data) {
|
|
257
|
+
return stub(
|
|
258
|
+
"externalAccounts.retrieve"
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const [err, raw] = await tryCatch(
|
|
262
|
+
config.data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
263
|
+
externalAccountId
|
|
264
|
+
})
|
|
265
|
+
);
|
|
266
|
+
if (err) {
|
|
267
|
+
return [
|
|
268
|
+
fromConvexError(err),
|
|
269
|
+
null
|
|
270
|
+
];
|
|
271
|
+
}
|
|
272
|
+
if (!raw) {
|
|
273
|
+
return [
|
|
274
|
+
new CapxulError({
|
|
275
|
+
code: "NOT_FOUND",
|
|
276
|
+
message: `external_account ${externalAccountId} not found`
|
|
277
|
+
}),
|
|
278
|
+
null
|
|
279
|
+
];
|
|
280
|
+
}
|
|
281
|
+
return [null, brandExternalAccount(raw)];
|
|
282
|
+
},
|
|
283
|
+
remove: async (externalAccountId) => {
|
|
284
|
+
if (!config.data) {
|
|
285
|
+
return stub("externalAccounts.remove");
|
|
286
|
+
}
|
|
287
|
+
const [err] = await tryCatch(
|
|
288
|
+
config.data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
289
|
+
externalAccountId
|
|
290
|
+
})
|
|
291
|
+
);
|
|
292
|
+
if (err) {
|
|
293
|
+
return [
|
|
294
|
+
fromConvexError(err),
|
|
295
|
+
null
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
return [null, void 0];
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
71
303
|
// src/core/accounts.ts
|
|
304
|
+
function createAccountExternalAccountsClient(config) {
|
|
305
|
+
return {
|
|
306
|
+
create: async (input) => {
|
|
307
|
+
if (!config.data) {
|
|
308
|
+
return stub(
|
|
309
|
+
"accounts.externalAccounts.create"
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
const [err, raw] = await tryCatch(
|
|
313
|
+
config.data.mutation(
|
|
314
|
+
api.externalAccounts.mutations.createPersonal,
|
|
315
|
+
{
|
|
316
|
+
kind: input.kind,
|
|
317
|
+
label: input.label,
|
|
318
|
+
address: input.address,
|
|
319
|
+
iban: input.iban,
|
|
320
|
+
bic: input.bic,
|
|
321
|
+
accountHolder: input.accountHolder,
|
|
322
|
+
network: input.network,
|
|
323
|
+
panToken: input.panToken,
|
|
324
|
+
last4: input.last4
|
|
325
|
+
}
|
|
326
|
+
)
|
|
327
|
+
);
|
|
328
|
+
if (err) {
|
|
329
|
+
return [
|
|
330
|
+
fromConvexError(err),
|
|
331
|
+
null
|
|
332
|
+
];
|
|
333
|
+
}
|
|
334
|
+
if (!raw) {
|
|
335
|
+
return [
|
|
336
|
+
new CapxulError({
|
|
337
|
+
code: "NOT_FOUND",
|
|
338
|
+
message: "external_account creation returned no resource"
|
|
339
|
+
}),
|
|
340
|
+
null
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
return [
|
|
344
|
+
null,
|
|
345
|
+
brandExternalAccount(
|
|
346
|
+
raw
|
|
347
|
+
)
|
|
348
|
+
];
|
|
349
|
+
},
|
|
350
|
+
list: async (input) => {
|
|
351
|
+
if (!config.data) {
|
|
352
|
+
return stub(
|
|
353
|
+
"accounts.externalAccounts.list"
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
const [err, result] = await tryCatch(
|
|
357
|
+
config.data.query(api.externalAccounts.queries.listPersonal, {
|
|
358
|
+
limit: input.limit,
|
|
359
|
+
cursor: input.cursor
|
|
360
|
+
})
|
|
361
|
+
);
|
|
362
|
+
if (err) {
|
|
363
|
+
return [fromConvexError(err), null];
|
|
364
|
+
}
|
|
365
|
+
const branded = result.data.map(
|
|
366
|
+
(row) => brandExternalAccount(
|
|
367
|
+
row
|
|
368
|
+
)
|
|
369
|
+
);
|
|
370
|
+
return [
|
|
371
|
+
null,
|
|
372
|
+
{
|
|
373
|
+
object: "list",
|
|
374
|
+
data: branded,
|
|
375
|
+
page: result.page
|
|
376
|
+
}
|
|
377
|
+
];
|
|
378
|
+
},
|
|
379
|
+
retrieve: async (externalAccountId) => {
|
|
380
|
+
if (!config.data) {
|
|
381
|
+
return stub(
|
|
382
|
+
"accounts.externalAccounts.retrieve"
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
const [err, raw] = await tryCatch(
|
|
386
|
+
config.data.query(api.externalAccounts.queries.retrievePersonal, {
|
|
387
|
+
externalAccountId
|
|
388
|
+
})
|
|
389
|
+
);
|
|
390
|
+
if (err) {
|
|
391
|
+
return [
|
|
392
|
+
fromConvexError(err),
|
|
393
|
+
null
|
|
394
|
+
];
|
|
395
|
+
}
|
|
396
|
+
if (!raw) {
|
|
397
|
+
return [
|
|
398
|
+
new CapxulError({
|
|
399
|
+
code: "NOT_FOUND",
|
|
400
|
+
message: `external_account ${externalAccountId} not found`
|
|
401
|
+
}),
|
|
402
|
+
null
|
|
403
|
+
];
|
|
404
|
+
}
|
|
405
|
+
return [
|
|
406
|
+
null,
|
|
407
|
+
brandExternalAccount(
|
|
408
|
+
raw
|
|
409
|
+
)
|
|
410
|
+
];
|
|
411
|
+
},
|
|
412
|
+
remove: async (externalAccountId) => {
|
|
413
|
+
if (!config.data) {
|
|
414
|
+
return stub("accounts.externalAccounts.remove");
|
|
415
|
+
}
|
|
416
|
+
const [err] = await tryCatch(
|
|
417
|
+
config.data.mutation(api.externalAccounts.mutations.removePersonal, {
|
|
418
|
+
externalAccountId
|
|
419
|
+
})
|
|
420
|
+
);
|
|
421
|
+
if (err) {
|
|
422
|
+
return [
|
|
423
|
+
fromConvexError(err),
|
|
424
|
+
null
|
|
425
|
+
];
|
|
426
|
+
}
|
|
427
|
+
return [null, void 0];
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
}
|
|
72
431
|
function createAccountsClient(config = {}) {
|
|
73
432
|
return {
|
|
74
433
|
retrieve: async (accountId) => {
|
|
@@ -223,18 +582,7 @@ function createAccountsClient(config = {}) {
|
|
|
223
582
|
create: async () => stub("accounts.kycProfiles.create"),
|
|
224
583
|
retrieve: async () => stub("accounts.kycProfiles.retrieve")
|
|
225
584
|
},
|
|
226
|
-
externalAccounts:
|
|
227
|
-
create: async () => stub(
|
|
228
|
-
"accounts.externalAccounts.create"
|
|
229
|
-
),
|
|
230
|
-
list: async () => stub(
|
|
231
|
-
"accounts.externalAccounts.list"
|
|
232
|
-
),
|
|
233
|
-
retrieve: async () => stub(
|
|
234
|
-
"accounts.externalAccounts.retrieve"
|
|
235
|
-
),
|
|
236
|
-
remove: async () => stub("accounts.externalAccounts.remove")
|
|
237
|
-
},
|
|
585
|
+
externalAccounts: createAccountExternalAccountsClient(config),
|
|
238
586
|
subAccounts: {
|
|
239
587
|
create: async () => stub("accounts.subAccounts.create"),
|
|
240
588
|
list: async () => stub("accounts.subAccounts.list"),
|
|
@@ -330,7 +678,29 @@ var Errors = {
|
|
|
330
678
|
{ details }
|
|
331
679
|
),
|
|
332
680
|
emailDeliveryFailed: (detail) => new CapxulError2("EMAIL_DELIVERY_FAILED", `Failed to send email: ${detail}`),
|
|
333
|
-
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`)
|
|
681
|
+
internalError: (reason) => new CapxulError2("INTERNAL_ERROR", `Internal error: ${reason}`),
|
|
682
|
+
/**
|
|
683
|
+
* Verification gate. Surfaced when a request hits a verification
|
|
684
|
+
* boundary the actor cannot cross under their current state. Two
|
|
685
|
+
* variants share this code:
|
|
686
|
+
*
|
|
687
|
+
* - Rail gate (Withdrawals v1 W2, #465): the resolved
|
|
688
|
+
* `external_account.kind` routes to a withdrawal rail (e.g.
|
|
689
|
+
* `fiat_offramp`, `card_payout`) that is not yet supported. Carries
|
|
690
|
+
* `details.rail` + `details.currentKind`.
|
|
691
|
+
* - KYC tier gate (legacy / future): the actor's KYC tier is below
|
|
692
|
+
* the required tier. Carries `details.requiredTier`.
|
|
693
|
+
*
|
|
694
|
+
* Code is shared because both expose the same UX shape ("you cannot
|
|
695
|
+
* proceed until verification advances"); the `details.*` keys
|
|
696
|
+
* differentiate the route.
|
|
697
|
+
*/
|
|
698
|
+
verificationRequired: (details) => {
|
|
699
|
+
const message = "rail" in details ? `Withdrawal rail "${details.rail}" (kind=${details.currentKind}) is not yet supported.` : `Verification tier ${details.requiredTier} is required.`;
|
|
700
|
+
return new CapxulError2("VERIFICATION_REQUIRED", message, {
|
|
701
|
+
details: { ...details }
|
|
702
|
+
});
|
|
703
|
+
}
|
|
334
704
|
};
|
|
335
705
|
|
|
336
706
|
// ../config/src/safe.ts
|
|
@@ -742,14 +1112,6 @@ function createOrgDocumentsClient() {
|
|
|
742
1112
|
};
|
|
743
1113
|
}
|
|
744
1114
|
|
|
745
|
-
// src/core/external-accounts.ts
|
|
746
|
-
function createExternalAccountsClient() {
|
|
747
|
-
return {
|
|
748
|
-
retrieve: async () => stub("externalAccounts.retrieve"),
|
|
749
|
-
remove: async () => stub("externalAccounts.remove")
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
|
|
753
1115
|
// src/core/me.ts
|
|
754
1116
|
function createMeClient(config = {}) {
|
|
755
1117
|
return {
|
|
@@ -1197,67 +1559,68 @@ function createOrgTransfersClient() {
|
|
|
1197
1559
|
cancel: async () => stub("organizations.transfers.cancel")
|
|
1198
1560
|
};
|
|
1199
1561
|
}
|
|
1200
|
-
var EVM_ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
1201
1562
|
function createWithdrawalsClient(config = {}) {
|
|
1202
1563
|
return {
|
|
1203
1564
|
create: async (input) => {
|
|
1204
1565
|
if (!config.data) {
|
|
1205
1566
|
return stub("withdrawals.create");
|
|
1206
1567
|
}
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
details: { field: "destination.externalAccountId" }
|
|
1246
|
-
});
|
|
1247
|
-
}
|
|
1248
|
-
const currentSigner = await config.data.query(
|
|
1249
|
-
api.safe.queries.getMySignerAddress,
|
|
1250
|
-
{}
|
|
1568
|
+
const [createErr, createdRaw] = await tryCatch(
|
|
1569
|
+
config.data.mutation(api.withdrawals.mutations.create, {
|
|
1570
|
+
amount: input.amount,
|
|
1571
|
+
destination: {
|
|
1572
|
+
externalAccountId: input.destination.externalAccountId
|
|
1573
|
+
},
|
|
1574
|
+
source: input.source,
|
|
1575
|
+
reference: input.reference,
|
|
1576
|
+
idempotencyKey: input.idempotencyKey
|
|
1577
|
+
})
|
|
1578
|
+
);
|
|
1579
|
+
if (createErr) {
|
|
1580
|
+
return [mapCreateError2(fromConvexError(createErr)), null];
|
|
1581
|
+
}
|
|
1582
|
+
const created = createdRaw;
|
|
1583
|
+
if (!created) {
|
|
1584
|
+
return [
|
|
1585
|
+
new CapxulError({
|
|
1586
|
+
code: "NETWORK_ERROR",
|
|
1587
|
+
message: "withdrawals.create returned no withdrawal resource"
|
|
1588
|
+
}),
|
|
1589
|
+
null
|
|
1590
|
+
];
|
|
1591
|
+
}
|
|
1592
|
+
if (created.status !== "processing" || created.operation.status !== "processing") {
|
|
1593
|
+
return [null, created];
|
|
1594
|
+
}
|
|
1595
|
+
if (!config.signer || !config.signing) {
|
|
1596
|
+
return [null, created];
|
|
1597
|
+
}
|
|
1598
|
+
const [signerErr, currentSigner] = await tryCatch(
|
|
1599
|
+
config.data.query(api.safe.queries.getMySignerAddress, {})
|
|
1600
|
+
);
|
|
1601
|
+
if (signerErr) {
|
|
1602
|
+
return await handleSubmissionFailure(
|
|
1603
|
+
{ data: config.data },
|
|
1604
|
+
created.id,
|
|
1605
|
+
mapCreateError2(fromConvexError(signerErr))
|
|
1251
1606
|
);
|
|
1252
|
-
|
|
1253
|
-
|
|
1607
|
+
}
|
|
1608
|
+
if (!currentSigner?.address) {
|
|
1609
|
+
return await handleSubmissionFailure(
|
|
1610
|
+
{ data: config.data },
|
|
1611
|
+
created.id,
|
|
1612
|
+
new CapxulError({
|
|
1254
1613
|
code: "PERMISSION_DENIED",
|
|
1255
1614
|
message: "No signer is registered for the authenticated account.",
|
|
1256
1615
|
details: { withdrawalId: created.id }
|
|
1257
|
-
})
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1616
|
+
})
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
if (getAddress(currentSigner.address) !== getAddress(config.signer.address)) {
|
|
1620
|
+
return await handleSubmissionFailure(
|
|
1621
|
+
{ data: config.data },
|
|
1622
|
+
created.id,
|
|
1623
|
+
new CapxulError({
|
|
1261
1624
|
code: "PERMISSION_DENIED",
|
|
1262
1625
|
message: "Configured signer does not match the authenticated account signer.",
|
|
1263
1626
|
details: {
|
|
@@ -1265,170 +1628,228 @@ function createWithdrawalsClient(config = {}) {
|
|
|
1265
1628
|
expectedSignerAddress: currentSigner.address,
|
|
1266
1629
|
actualSignerAddress: config.signer.address
|
|
1267
1630
|
}
|
|
1268
|
-
})
|
|
1269
|
-
}
|
|
1270
|
-
const submission = await config.data.query(
|
|
1271
|
-
api.withdrawals.queries.prepareSubmission,
|
|
1272
|
-
{ withdrawalId: created.id }
|
|
1631
|
+
})
|
|
1273
1632
|
);
|
|
1274
|
-
|
|
1275
|
-
|
|
1633
|
+
}
|
|
1634
|
+
const [prepErr, submission] = await tryCatch(
|
|
1635
|
+
config.data.query(api.withdrawals.queries.prepareSubmission, {
|
|
1636
|
+
withdrawalId: created.id
|
|
1637
|
+
})
|
|
1638
|
+
);
|
|
1639
|
+
if (prepErr) {
|
|
1640
|
+
return await handleSubmissionFailure(
|
|
1641
|
+
{ data: config.data },
|
|
1642
|
+
created.id,
|
|
1643
|
+
mapCreateError2(fromConvexError(prepErr))
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
const destinationAddress = submission?.destinationAddress;
|
|
1647
|
+
if (!submission || !destinationAddress) {
|
|
1648
|
+
return await handleSubmissionFailure(
|
|
1649
|
+
{ data: config.data },
|
|
1650
|
+
created.id,
|
|
1651
|
+
new CapxulError({
|
|
1276
1652
|
code: "NETWORK_ERROR",
|
|
1277
1653
|
message: "withdrawals.prepareSubmission returned no destination.",
|
|
1278
1654
|
details: { withdrawalId: created.id }
|
|
1279
|
-
})
|
|
1280
|
-
|
|
1281
|
-
|
|
1655
|
+
})
|
|
1656
|
+
);
|
|
1657
|
+
}
|
|
1658
|
+
const [transferErr, transferOk] = await tryCatch(
|
|
1659
|
+
transferAsOwner(
|
|
1282
1660
|
{
|
|
1283
1661
|
signer: config.signer,
|
|
1284
1662
|
signing: config.signing
|
|
1285
1663
|
},
|
|
1286
1664
|
{
|
|
1287
1665
|
tokenAddress: resolvePaymentTokenAddress(submission.amount.currency),
|
|
1288
|
-
recipientAddress:
|
|
1666
|
+
recipientAddress: destinationAddress,
|
|
1289
1667
|
amount: toTokenUnits(submission.amount.value, 6)
|
|
1290
1668
|
}
|
|
1669
|
+
)
|
|
1670
|
+
);
|
|
1671
|
+
if (transferErr) {
|
|
1672
|
+
return await handleSubmissionFailure(
|
|
1673
|
+
{ data: config.data },
|
|
1674
|
+
created.id,
|
|
1675
|
+
mapCreateError2(fromConvexError(transferErr))
|
|
1291
1676
|
);
|
|
1292
|
-
|
|
1293
|
-
|
|
1677
|
+
}
|
|
1678
|
+
if (!transferOk.success) {
|
|
1679
|
+
return await handleSubmissionFailure(
|
|
1680
|
+
{ data: config.data },
|
|
1681
|
+
created.id,
|
|
1682
|
+
new CapxulError({
|
|
1294
1683
|
code: "NETWORK_ERROR",
|
|
1295
1684
|
message: "Bundler submission did not succeed.",
|
|
1296
1685
|
details: {
|
|
1297
1686
|
withdrawalId: created.id,
|
|
1298
|
-
txHash:
|
|
1299
|
-
userOpHash:
|
|
1687
|
+
txHash: transferOk.txHash,
|
|
1688
|
+
userOpHash: transferOk.userOpHash
|
|
1300
1689
|
}
|
|
1301
|
-
})
|
|
1302
|
-
}
|
|
1303
|
-
submitted = {
|
|
1304
|
-
txHash: transfer.txHash,
|
|
1305
|
-
userOpHash: transfer.userOpHash
|
|
1306
|
-
};
|
|
1307
|
-
await config.data.mutation(
|
|
1308
|
-
api.withdrawals.mutations.recordSubmitted,
|
|
1309
|
-
{
|
|
1310
|
-
withdrawalId: created.id,
|
|
1311
|
-
txHash: transfer.txHash,
|
|
1312
|
-
userOpHash: transfer.userOpHash
|
|
1313
|
-
}
|
|
1690
|
+
})
|
|
1314
1691
|
);
|
|
1315
|
-
return [null, created];
|
|
1316
|
-
} catch (cause) {
|
|
1317
|
-
const error = mapCreateError2(fromConvexError(cause));
|
|
1318
|
-
if (created?.id && created.status === "processing" && !submitted) {
|
|
1319
|
-
await bestEffortMarkFailed2({ data: config.data }, created.id, error);
|
|
1320
|
-
}
|
|
1321
|
-
if (submitted && created?.id) {
|
|
1322
|
-
return [
|
|
1323
|
-
new CapxulError({
|
|
1324
|
-
code: "NETWORK_ERROR",
|
|
1325
|
-
message: "Withdrawal was submitted on-chain, but backend submission tracking failed.",
|
|
1326
|
-
cause,
|
|
1327
|
-
details: {
|
|
1328
|
-
withdrawalId: created.id,
|
|
1329
|
-
txHash: submitted.txHash,
|
|
1330
|
-
userOpHash: submitted.userOpHash
|
|
1331
|
-
}
|
|
1332
|
-
}),
|
|
1333
|
-
null
|
|
1334
|
-
];
|
|
1335
|
-
}
|
|
1336
|
-
return [error, null];
|
|
1337
1692
|
}
|
|
1693
|
+
const [recordErr] = await tryCatch(
|
|
1694
|
+
config.data.mutation(api.withdrawals.mutations.recordSubmitted, {
|
|
1695
|
+
withdrawalId: created.id,
|
|
1696
|
+
txHash: transferOk.txHash,
|
|
1697
|
+
userOpHash: transferOk.userOpHash
|
|
1698
|
+
})
|
|
1699
|
+
);
|
|
1700
|
+
if (recordErr) {
|
|
1701
|
+
return [
|
|
1702
|
+
new CapxulError({
|
|
1703
|
+
code: "NETWORK_ERROR",
|
|
1704
|
+
message: "Withdrawal was submitted on-chain, but backend submission tracking failed.",
|
|
1705
|
+
cause: recordErr,
|
|
1706
|
+
details: {
|
|
1707
|
+
withdrawalId: created.id,
|
|
1708
|
+
txHash: transferOk.txHash,
|
|
1709
|
+
userOpHash: transferOk.userOpHash
|
|
1710
|
+
}
|
|
1711
|
+
}),
|
|
1712
|
+
null
|
|
1713
|
+
];
|
|
1714
|
+
}
|
|
1715
|
+
return [null, created];
|
|
1338
1716
|
},
|
|
1339
1717
|
retrieve: async (withdrawalId) => {
|
|
1340
1718
|
if (!config.data) {
|
|
1341
1719
|
return stub("withdrawals.retrieve");
|
|
1342
1720
|
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
);
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
code: "NOT_FOUND",
|
|
1352
|
-
message: `withdrawal ${withdrawalId} not found`
|
|
1353
|
-
}),
|
|
1354
|
-
null
|
|
1355
|
-
];
|
|
1356
|
-
}
|
|
1357
|
-
return [null, withdrawal];
|
|
1358
|
-
} catch (cause) {
|
|
1721
|
+
const [err, raw] = await tryCatch(
|
|
1722
|
+
config.data.query(api.withdrawals.queries.retrieve, { withdrawalId })
|
|
1723
|
+
);
|
|
1724
|
+
if (err) {
|
|
1725
|
+
return [fromConvexError(err), null];
|
|
1726
|
+
}
|
|
1727
|
+
const withdrawal = raw;
|
|
1728
|
+
if (!withdrawal) {
|
|
1359
1729
|
return [
|
|
1360
|
-
|
|
1730
|
+
new CapxulError({
|
|
1731
|
+
code: "NOT_FOUND",
|
|
1732
|
+
message: `withdrawal ${withdrawalId} not found`
|
|
1733
|
+
}),
|
|
1361
1734
|
null
|
|
1362
1735
|
];
|
|
1363
1736
|
}
|
|
1737
|
+
return [null, withdrawal];
|
|
1364
1738
|
},
|
|
1365
1739
|
list: async (input) => {
|
|
1366
1740
|
if (!config.data) {
|
|
1367
1741
|
return stub("withdrawals.list");
|
|
1368
1742
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1743
|
+
const [err, raw] = await tryCatch(
|
|
1744
|
+
config.data.query(api.withdrawals.queries.list, {
|
|
1745
|
+
limit: input?.limit,
|
|
1746
|
+
cursor: input?.cursor
|
|
1747
|
+
})
|
|
1748
|
+
);
|
|
1749
|
+
if (err) {
|
|
1750
|
+
return [fromConvexError(err), null];
|
|
1751
|
+
}
|
|
1752
|
+
return [null, raw];
|
|
1753
|
+
},
|
|
1754
|
+
recordCompleted: async (input) => {
|
|
1755
|
+
if (!config.data) {
|
|
1756
|
+
return stub(
|
|
1757
|
+
"withdrawals.recordCompleted"
|
|
1376
1758
|
);
|
|
1377
|
-
|
|
1378
|
-
|
|
1759
|
+
}
|
|
1760
|
+
const [err] = await tryCatch(
|
|
1761
|
+
config.data.mutation(api.withdrawals.mutations.recordCompleted, {
|
|
1762
|
+
withdrawalId: input.withdrawalId,
|
|
1763
|
+
txHash: input.txHash
|
|
1764
|
+
})
|
|
1765
|
+
);
|
|
1766
|
+
if (err) {
|
|
1379
1767
|
return [
|
|
1380
|
-
fromConvexError(
|
|
1768
|
+
mapRecordCompletedError(fromConvexError(err)),
|
|
1381
1769
|
null
|
|
1382
1770
|
];
|
|
1383
1771
|
}
|
|
1772
|
+
return [null, null];
|
|
1384
1773
|
}
|
|
1385
1774
|
};
|
|
1386
1775
|
}
|
|
1387
1776
|
function createOrgWithdrawalsClient(config = {}) {
|
|
1388
1777
|
return {
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1778
|
+
/**
|
|
1779
|
+
* Org-scope create (Withdrawals v1 W2, #465).
|
|
1780
|
+
*
|
|
1781
|
+
* D6 — returns the `processing` row only. No `transferAsOwner`
|
|
1782
|
+
* tail, no `recordSubmitted` call. Org Safe + Zodiac submission
|
|
1783
|
+
* orchestration ships in W3+.
|
|
1784
|
+
*/
|
|
1785
|
+
create: async (input) => {
|
|
1786
|
+
if (!config.data) {
|
|
1787
|
+
return stub(
|
|
1788
|
+
"organizations.withdrawals.create"
|
|
1789
|
+
);
|
|
1790
|
+
}
|
|
1791
|
+
const [err, raw] = await tryCatch(
|
|
1792
|
+
config.data.mutation(api.withdrawals.mutations.createOrg, {
|
|
1793
|
+
organizationId: input.organizationId,
|
|
1794
|
+
amount: input.amount,
|
|
1795
|
+
destination: {
|
|
1796
|
+
externalAccountId: input.destination.externalAccountId
|
|
1797
|
+
},
|
|
1798
|
+
source: input.source,
|
|
1799
|
+
reference: input.reference,
|
|
1800
|
+
idempotencyKey: input.idempotencyKey
|
|
1801
|
+
})
|
|
1802
|
+
);
|
|
1803
|
+
if (err) {
|
|
1804
|
+
return [mapCreateError2(fromConvexError(err)), null];
|
|
1805
|
+
}
|
|
1806
|
+
const created = raw;
|
|
1807
|
+
if (!created) {
|
|
1808
|
+
return [
|
|
1809
|
+
new CapxulError({
|
|
1810
|
+
code: "NETWORK_ERROR",
|
|
1811
|
+
message: "organizations.withdrawals.create returned no withdrawal resource"
|
|
1812
|
+
}),
|
|
1813
|
+
null
|
|
1814
|
+
];
|
|
1815
|
+
}
|
|
1816
|
+
return [null, created];
|
|
1817
|
+
},
|
|
1395
1818
|
retrieve: async (input) => {
|
|
1396
1819
|
if (!config.data) {
|
|
1397
1820
|
return stub(
|
|
1398
1821
|
"organizations.withdrawals.retrieve"
|
|
1399
1822
|
);
|
|
1400
1823
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
}),
|
|
1412
|
-
null
|
|
1413
|
-
];
|
|
1414
|
-
}
|
|
1415
|
-
const ownerCheck = withdrawal.owner;
|
|
1416
|
-
if (ownerCheck?.type !== "organization" || ownerCheck.id !== input.organizationId) {
|
|
1417
|
-
return [
|
|
1418
|
-
new CapxulError({
|
|
1419
|
-
code: "NOT_FOUND",
|
|
1420
|
-
message: `withdrawal ${input.withdrawalId} does not belong to organization ${input.organizationId}`
|
|
1421
|
-
}),
|
|
1422
|
-
null
|
|
1423
|
-
];
|
|
1424
|
-
}
|
|
1425
|
-
return [null, withdrawal];
|
|
1426
|
-
} catch (cause) {
|
|
1824
|
+
const [err, raw] = await tryCatch(
|
|
1825
|
+
config.data.query(api.withdrawals.queries.retrieve, {
|
|
1826
|
+
withdrawalId: input.withdrawalId
|
|
1827
|
+
})
|
|
1828
|
+
);
|
|
1829
|
+
if (err) {
|
|
1830
|
+
return [fromConvexError(err), null];
|
|
1831
|
+
}
|
|
1832
|
+
const withdrawal = raw;
|
|
1833
|
+
if (!withdrawal) {
|
|
1427
1834
|
return [
|
|
1428
|
-
|
|
1835
|
+
new CapxulError({
|
|
1836
|
+
code: "NOT_FOUND",
|
|
1837
|
+
message: `withdrawal ${input.withdrawalId} not found`
|
|
1838
|
+
}),
|
|
1839
|
+
null
|
|
1840
|
+
];
|
|
1841
|
+
}
|
|
1842
|
+
const ownerCheck = withdrawal.owner;
|
|
1843
|
+
if (ownerCheck?.type !== "organization" || ownerCheck.id !== input.organizationId) {
|
|
1844
|
+
return [
|
|
1845
|
+
new CapxulError({
|
|
1846
|
+
code: "NOT_FOUND",
|
|
1847
|
+
message: `withdrawal ${input.withdrawalId} does not belong to organization ${input.organizationId}`
|
|
1848
|
+
}),
|
|
1429
1849
|
null
|
|
1430
1850
|
];
|
|
1431
1851
|
}
|
|
1852
|
+
return [null, withdrawal];
|
|
1432
1853
|
},
|
|
1433
1854
|
list: async (input) => {
|
|
1434
1855
|
if (!config.data) {
|
|
@@ -1436,46 +1857,67 @@ function createOrgWithdrawalsClient(config = {}) {
|
|
|
1436
1857
|
"organizations.withdrawals.list"
|
|
1437
1858
|
);
|
|
1438
1859
|
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
);
|
|
1448
|
-
return [null, result];
|
|
1449
|
-
} catch (cause) {
|
|
1450
|
-
return [
|
|
1451
|
-
fromConvexError(cause),
|
|
1452
|
-
null
|
|
1453
|
-
];
|
|
1860
|
+
const [err, raw] = await tryCatch(
|
|
1861
|
+
config.data.query(api.withdrawals.queries.listOrg, {
|
|
1862
|
+
organizationId: input.organizationId,
|
|
1863
|
+
limit: input.limit,
|
|
1864
|
+
cursor: input.cursor
|
|
1865
|
+
})
|
|
1866
|
+
);
|
|
1867
|
+
if (err) {
|
|
1868
|
+
return [fromConvexError(err), null];
|
|
1454
1869
|
}
|
|
1870
|
+
return [null, raw];
|
|
1455
1871
|
}
|
|
1456
1872
|
};
|
|
1457
1873
|
}
|
|
1874
|
+
async function handleSubmissionFailure(config, withdrawalId, error) {
|
|
1875
|
+
await bestEffortMarkFailed2(config, withdrawalId, error);
|
|
1876
|
+
return [error, null];
|
|
1877
|
+
}
|
|
1458
1878
|
async function bestEffortMarkFailed2(config, withdrawalId, error) {
|
|
1459
|
-
|
|
1460
|
-
|
|
1879
|
+
await tryCatch(
|
|
1880
|
+
config.data.mutation(api.withdrawals.mutations.markFailed, {
|
|
1461
1881
|
withdrawalId,
|
|
1462
1882
|
errorCode: error.code,
|
|
1463
1883
|
errorMessage: error.message
|
|
1464
|
-
})
|
|
1465
|
-
|
|
1884
|
+
})
|
|
1885
|
+
);
|
|
1886
|
+
}
|
|
1887
|
+
function mapCreateError2(error) {
|
|
1888
|
+
switch (error.code) {
|
|
1889
|
+
case "NOT_AUTHENTICATED":
|
|
1890
|
+
case "PERMISSION_DENIED":
|
|
1891
|
+
case "INVALID_INPUT":
|
|
1892
|
+
case "INSUFFICIENT_BALANCE":
|
|
1893
|
+
case "IDEMPOTENCY_CONFLICT":
|
|
1894
|
+
case "KYC_REQUIRED":
|
|
1895
|
+
case "POLICY_DENIED":
|
|
1896
|
+
case "RATE_LIMITED":
|
|
1897
|
+
case "NETWORK_ERROR":
|
|
1898
|
+
case "NOT_FOUND":
|
|
1899
|
+
case "VERIFICATION_REQUIRED":
|
|
1900
|
+
return error;
|
|
1901
|
+
default:
|
|
1902
|
+
return new CapxulError({
|
|
1903
|
+
code: "NETWORK_ERROR",
|
|
1904
|
+
message: error.message,
|
|
1905
|
+
cause: error,
|
|
1906
|
+
details: error.details,
|
|
1907
|
+
operationId: error.operationId,
|
|
1908
|
+
correlationId: error.correlationId,
|
|
1909
|
+
retryable: error.retryable
|
|
1910
|
+
});
|
|
1466
1911
|
}
|
|
1467
1912
|
}
|
|
1468
|
-
function
|
|
1913
|
+
function mapRecordCompletedError(error) {
|
|
1469
1914
|
switch (error.code) {
|
|
1470
1915
|
case "NOT_AUTHENTICATED":
|
|
1471
1916
|
case "PERMISSION_DENIED":
|
|
1472
1917
|
case "INVALID_INPUT":
|
|
1473
|
-
case "
|
|
1474
|
-
case "IDEMPOTENCY_CONFLICT":
|
|
1475
|
-
case "KYC_REQUIRED":
|
|
1476
|
-
case "POLICY_DENIED":
|
|
1477
|
-
case "RATE_LIMITED":
|
|
1918
|
+
case "NOT_FOUND":
|
|
1478
1919
|
case "NETWORK_ERROR":
|
|
1920
|
+
case "INTERNAL_ERROR":
|
|
1479
1921
|
return error;
|
|
1480
1922
|
default:
|
|
1481
1923
|
return new CapxulError({
|
|
@@ -1511,6 +1953,136 @@ function createWebhookEventsClient() {
|
|
|
1511
1953
|
}
|
|
1512
1954
|
|
|
1513
1955
|
// src/core/organizations.ts
|
|
1956
|
+
function createOrgExternalAccountsClient(config) {
|
|
1957
|
+
return {
|
|
1958
|
+
create: async (input) => {
|
|
1959
|
+
if (!config.data) {
|
|
1960
|
+
return stub(
|
|
1961
|
+
"organizations.externalAccounts.create"
|
|
1962
|
+
);
|
|
1963
|
+
}
|
|
1964
|
+
const [err, raw] = await tryCatch(
|
|
1965
|
+
config.data.mutation(api.externalAccounts.mutations.createOrg, {
|
|
1966
|
+
organizationId: input.organizationId,
|
|
1967
|
+
kind: input.kind,
|
|
1968
|
+
label: input.label,
|
|
1969
|
+
address: input.address,
|
|
1970
|
+
iban: input.iban,
|
|
1971
|
+
bic: input.bic,
|
|
1972
|
+
accountHolder: input.accountHolder,
|
|
1973
|
+
network: input.network,
|
|
1974
|
+
panToken: input.panToken,
|
|
1975
|
+
last4: input.last4
|
|
1976
|
+
})
|
|
1977
|
+
);
|
|
1978
|
+
if (err) {
|
|
1979
|
+
return [
|
|
1980
|
+
fromConvexError(err),
|
|
1981
|
+
null
|
|
1982
|
+
];
|
|
1983
|
+
}
|
|
1984
|
+
if (!raw) {
|
|
1985
|
+
return [
|
|
1986
|
+
new CapxulError({
|
|
1987
|
+
code: "NOT_FOUND",
|
|
1988
|
+
message: "external_account creation returned no resource"
|
|
1989
|
+
}),
|
|
1990
|
+
null
|
|
1991
|
+
];
|
|
1992
|
+
}
|
|
1993
|
+
return [
|
|
1994
|
+
null,
|
|
1995
|
+
brandExternalAccount(
|
|
1996
|
+
raw
|
|
1997
|
+
)
|
|
1998
|
+
];
|
|
1999
|
+
},
|
|
2000
|
+
list: async (input) => {
|
|
2001
|
+
if (!config.data) {
|
|
2002
|
+
return stub(
|
|
2003
|
+
"organizations.externalAccounts.list"
|
|
2004
|
+
);
|
|
2005
|
+
}
|
|
2006
|
+
const [err, result] = await tryCatch(
|
|
2007
|
+
config.data.query(api.externalAccounts.queries.listOrg, {
|
|
2008
|
+
organizationId: input.organizationId,
|
|
2009
|
+
limit: input.limit,
|
|
2010
|
+
cursor: input.cursor
|
|
2011
|
+
})
|
|
2012
|
+
);
|
|
2013
|
+
if (err) {
|
|
2014
|
+
return [fromConvexError(err), null];
|
|
2015
|
+
}
|
|
2016
|
+
const branded = result.data.map(
|
|
2017
|
+
(row) => brandExternalAccount(
|
|
2018
|
+
row
|
|
2019
|
+
)
|
|
2020
|
+
);
|
|
2021
|
+
return [
|
|
2022
|
+
null,
|
|
2023
|
+
{
|
|
2024
|
+
object: "list",
|
|
2025
|
+
data: branded,
|
|
2026
|
+
page: result.page
|
|
2027
|
+
}
|
|
2028
|
+
];
|
|
2029
|
+
},
|
|
2030
|
+
retrieve: async (input) => {
|
|
2031
|
+
if (!config.data) {
|
|
2032
|
+
return stub(
|
|
2033
|
+
"organizations.externalAccounts.retrieve"
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
const [err, raw] = await tryCatch(
|
|
2037
|
+
config.data.query(api.externalAccounts.queries.retrieveOrg, {
|
|
2038
|
+
organizationId: input.organizationId,
|
|
2039
|
+
externalAccountId: input.externalAccountId
|
|
2040
|
+
})
|
|
2041
|
+
);
|
|
2042
|
+
if (err) {
|
|
2043
|
+
return [
|
|
2044
|
+
fromConvexError(err),
|
|
2045
|
+
null
|
|
2046
|
+
];
|
|
2047
|
+
}
|
|
2048
|
+
if (!raw) {
|
|
2049
|
+
return [
|
|
2050
|
+
new CapxulError({
|
|
2051
|
+
code: "NOT_FOUND",
|
|
2052
|
+
message: `external_account ${input.externalAccountId} not found`
|
|
2053
|
+
}),
|
|
2054
|
+
null
|
|
2055
|
+
];
|
|
2056
|
+
}
|
|
2057
|
+
return [
|
|
2058
|
+
null,
|
|
2059
|
+
brandExternalAccount(
|
|
2060
|
+
raw
|
|
2061
|
+
)
|
|
2062
|
+
];
|
|
2063
|
+
},
|
|
2064
|
+
remove: async (input) => {
|
|
2065
|
+
if (!config.data) {
|
|
2066
|
+
return stub(
|
|
2067
|
+
"organizations.externalAccounts.remove"
|
|
2068
|
+
);
|
|
2069
|
+
}
|
|
2070
|
+
const [err] = await tryCatch(
|
|
2071
|
+
config.data.mutation(api.externalAccounts.mutations.removeOrg, {
|
|
2072
|
+
organizationId: input.organizationId,
|
|
2073
|
+
externalAccountId: input.externalAccountId
|
|
2074
|
+
})
|
|
2075
|
+
);
|
|
2076
|
+
if (err) {
|
|
2077
|
+
return [
|
|
2078
|
+
fromConvexError(err),
|
|
2079
|
+
null
|
|
2080
|
+
];
|
|
2081
|
+
}
|
|
2082
|
+
return [null, void 0];
|
|
2083
|
+
}
|
|
2084
|
+
};
|
|
2085
|
+
}
|
|
1514
2086
|
function createOrganizationsClient(config = {}) {
|
|
1515
2087
|
return {
|
|
1516
2088
|
create: async () => stub("organizations.create"),
|
|
@@ -1566,18 +2138,7 @@ function createOrganizationsClient(config = {}) {
|
|
|
1566
2138
|
retrieve: async () => stub("organizations.subAccounts.retrieve"),
|
|
1567
2139
|
remove: async () => stub("organizations.subAccounts.remove")
|
|
1568
2140
|
},
|
|
1569
|
-
externalAccounts:
|
|
1570
|
-
create: async () => stub(
|
|
1571
|
-
"organizations.externalAccounts.create"
|
|
1572
|
-
),
|
|
1573
|
-
list: async () => stub(
|
|
1574
|
-
"organizations.externalAccounts.list"
|
|
1575
|
-
),
|
|
1576
|
-
retrieve: async () => stub(
|
|
1577
|
-
"organizations.externalAccounts.retrieve"
|
|
1578
|
-
),
|
|
1579
|
-
remove: async () => stub("organizations.externalAccounts.remove")
|
|
1580
|
-
},
|
|
2141
|
+
externalAccounts: createOrgExternalAccountsClient(config),
|
|
1581
2142
|
balanceLedger: {
|
|
1582
2143
|
list: async () => stub(
|
|
1583
2144
|
"organizations.balanceLedger.list"
|
|
@@ -1714,59 +2275,6 @@ function createVirtualCardsClient() {
|
|
|
1714
2275
|
cancel: async () => stub("virtualCards.cancel")
|
|
1715
2276
|
};
|
|
1716
2277
|
}
|
|
1717
|
-
|
|
1718
|
-
// ../observability/src/try-catch.ts
|
|
1719
|
-
async function tryCatch(promise) {
|
|
1720
|
-
try {
|
|
1721
|
-
return [null, await promise];
|
|
1722
|
-
} catch (e) {
|
|
1723
|
-
return [e instanceof Error ? e : new Error(String(e)), null];
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1726
|
-
|
|
1727
|
-
// ../observability/src/debug-log.ts
|
|
1728
|
-
function isDevelopmentBuild() {
|
|
1729
|
-
if (typeof process === "undefined") {
|
|
1730
|
-
return false;
|
|
1731
|
-
}
|
|
1732
|
-
return process.env?.NODE_ENV === "development" || process.env?.NODE_ENV === "test";
|
|
1733
|
-
}
|
|
1734
|
-
function debugLog(line) {
|
|
1735
|
-
if (!isDevelopmentBuild()) return;
|
|
1736
|
-
if (typeof globalThis !== "undefined" && "window" in globalThis && typeof console?.info === "function") {
|
|
1737
|
-
console.info(line);
|
|
1738
|
-
return;
|
|
1739
|
-
}
|
|
1740
|
-
if (typeof process !== "undefined" && typeof process.stderr?.write === "function") {
|
|
1741
|
-
process.stderr.write(`${line}
|
|
1742
|
-
`);
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
function formatDebugValue(value) {
|
|
1746
|
-
if (value === void 0 || value === "") return "";
|
|
1747
|
-
if (typeof value === "string") return value;
|
|
1748
|
-
try {
|
|
1749
|
-
return JSON.stringify(value);
|
|
1750
|
-
} catch {
|
|
1751
|
-
return String(value);
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
function track(...args) {
|
|
1755
|
-
const [name, props] = args;
|
|
1756
|
-
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
1757
|
-
}
|
|
1758
|
-
function formatDebugValue2(value) {
|
|
1759
|
-
if (value === void 0 || value === "") return "";
|
|
1760
|
-
if (typeof value === "string") return value;
|
|
1761
|
-
try {
|
|
1762
|
-
return JSON.stringify(value);
|
|
1763
|
-
} catch {
|
|
1764
|
-
return String(value);
|
|
1765
|
-
}
|
|
1766
|
-
}
|
|
1767
|
-
function identify(userId, traits) {
|
|
1768
|
-
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
1769
|
-
}
|
|
1770
2278
|
function createAuthFlowMachine(client) {
|
|
1771
2279
|
return setup({
|
|
1772
2280
|
types: {},
|
|
@@ -2042,122 +2550,6 @@ function emailDomain(email) {
|
|
|
2042
2550
|
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
2043
2551
|
return domain || "unknown";
|
|
2044
2552
|
}
|
|
2045
|
-
|
|
2046
|
-
// ../platform-kernel/src/ids.ts
|
|
2047
|
-
function makePrefixedIdConstructor(prefix, fieldName) {
|
|
2048
|
-
const re = new RegExp(`^${prefix}_[A-Za-z0-9_\\-]+$`);
|
|
2049
|
-
return (raw) => {
|
|
2050
|
-
if (typeof raw !== "string" || !re.test(raw)) {
|
|
2051
|
-
throw new Error(
|
|
2052
|
-
`Invalid ${fieldName}: expected string matching ^${prefix}_[A-Za-z0-9_\\-]+$, got ${String(raw)}`
|
|
2053
|
-
);
|
|
2054
|
-
}
|
|
2055
|
-
return raw;
|
|
2056
|
-
};
|
|
2057
|
-
}
|
|
2058
|
-
var toAccountId = makePrefixedIdConstructor(
|
|
2059
|
-
"acct",
|
|
2060
|
-
"accountId"
|
|
2061
|
-
);
|
|
2062
|
-
var toOrganizationId = makePrefixedIdConstructor("org", "organizationId");
|
|
2063
|
-
var toMemberId = makePrefixedIdConstructor(
|
|
2064
|
-
"mem",
|
|
2065
|
-
"memberId"
|
|
2066
|
-
);
|
|
2067
|
-
var toSafeId = makePrefixedIdConstructor(
|
|
2068
|
-
"safe",
|
|
2069
|
-
"safeId"
|
|
2070
|
-
);
|
|
2071
|
-
var toTreasuryId = makePrefixedIdConstructor(
|
|
2072
|
-
"try",
|
|
2073
|
-
"treasuryId"
|
|
2074
|
-
);
|
|
2075
|
-
var toApiKeyId = makePrefixedIdConstructor(
|
|
2076
|
-
"ak",
|
|
2077
|
-
"apiKeyId"
|
|
2078
|
-
);
|
|
2079
|
-
var toOperationId = makePrefixedIdConstructor(
|
|
2080
|
-
"op",
|
|
2081
|
-
"operationId"
|
|
2082
|
-
);
|
|
2083
|
-
var toKycProfileId = makePrefixedIdConstructor(
|
|
2084
|
-
"kyc",
|
|
2085
|
-
"kycProfileId"
|
|
2086
|
-
);
|
|
2087
|
-
var toKybProfileId = makePrefixedIdConstructor(
|
|
2088
|
-
"kyb",
|
|
2089
|
-
"kybProfileId"
|
|
2090
|
-
);
|
|
2091
|
-
var toExternalAccountId = makePrefixedIdConstructor("ext", "externalAccountId");
|
|
2092
|
-
var toPaymentId = makePrefixedIdConstructor(
|
|
2093
|
-
"pay",
|
|
2094
|
-
"paymentId"
|
|
2095
|
-
);
|
|
2096
|
-
var toWithdrawalId = makePrefixedIdConstructor(
|
|
2097
|
-
"wd",
|
|
2098
|
-
"withdrawalId"
|
|
2099
|
-
);
|
|
2100
|
-
var toWebhookEndpointId = makePrefixedIdConstructor("we", "webhookEndpointId");
|
|
2101
|
-
var toWebhookEventId = makePrefixedIdConstructor("evt", "webhookEventId");
|
|
2102
|
-
var toSubAccountId = makePrefixedIdConstructor(
|
|
2103
|
-
"sub",
|
|
2104
|
-
"subAccountId"
|
|
2105
|
-
);
|
|
2106
|
-
var toVirtualAccountId = makePrefixedIdConstructor("va", "virtualAccountId");
|
|
2107
|
-
var toVirtualCardId = makePrefixedIdConstructor(
|
|
2108
|
-
"vc",
|
|
2109
|
-
"virtualCardId"
|
|
2110
|
-
);
|
|
2111
|
-
var toTransferId = makePrefixedIdConstructor(
|
|
2112
|
-
"txfr",
|
|
2113
|
-
"transferId"
|
|
2114
|
-
);
|
|
2115
|
-
var toDocumentId = makePrefixedIdConstructor(
|
|
2116
|
-
"doc",
|
|
2117
|
-
"documentId"
|
|
2118
|
-
);
|
|
2119
|
-
var toBalanceLedgerEntryId = makePrefixedIdConstructor("bal", "balanceLedgerEntryId");
|
|
2120
|
-
|
|
2121
|
-
// ../platform-kernel/src/value-objects.ts
|
|
2122
|
-
var PHONE_NUMBER_RE = /^\+[1-9]\d{1,14}$/;
|
|
2123
|
-
function toPhoneNumber(raw) {
|
|
2124
|
-
if (typeof raw !== "string" || !PHONE_NUMBER_RE.test(raw)) {
|
|
2125
|
-
throw new Error(
|
|
2126
|
-
`Invalid phoneNumber: expected E.164 string matching ^\\+[1-9]\\d{1,14}$, got ${String(raw)}`
|
|
2127
|
-
);
|
|
2128
|
-
}
|
|
2129
|
-
return raw;
|
|
2130
|
-
}
|
|
2131
|
-
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
2132
|
-
function toEmail(raw) {
|
|
2133
|
-
if (typeof raw !== "string") {
|
|
2134
|
-
throw new Error(
|
|
2135
|
-
`Invalid email: expected string, got ${String(raw)}`
|
|
2136
|
-
);
|
|
2137
|
-
}
|
|
2138
|
-
const lowered = raw.trim().toLowerCase();
|
|
2139
|
-
if (!EMAIL_RE.test(lowered)) {
|
|
2140
|
-
throw new Error(
|
|
2141
|
-
`Invalid email: expected local@domain.tld, got ${String(raw)}`
|
|
2142
|
-
);
|
|
2143
|
-
}
|
|
2144
|
-
return lowered;
|
|
2145
|
-
}
|
|
2146
|
-
var USERNAME_RE = /^[a-z][a-z0-9_-]{2,29}$/;
|
|
2147
|
-
function toUsername(raw) {
|
|
2148
|
-
if (typeof raw !== "string") {
|
|
2149
|
-
throw new Error(
|
|
2150
|
-
`Invalid username: expected string, got ${String(raw)}`
|
|
2151
|
-
);
|
|
2152
|
-
}
|
|
2153
|
-
const lowered = raw.toLowerCase();
|
|
2154
|
-
if (!USERNAME_RE.test(lowered)) {
|
|
2155
|
-
throw new Error(
|
|
2156
|
-
`Invalid username: expected 3-30 chars, letter-first, [a-z0-9_-], got ${String(raw)}`
|
|
2157
|
-
);
|
|
2158
|
-
}
|
|
2159
|
-
return lowered;
|
|
2160
|
-
}
|
|
2161
2553
|
function createProvisioningMachine(client) {
|
|
2162
2554
|
return setup({
|
|
2163
2555
|
types: {},
|
|
@@ -2550,7 +2942,7 @@ function createCapxulClient(config = {}) {
|
|
|
2550
2942
|
subAccounts: createSubAccountsClient(),
|
|
2551
2943
|
virtualAccounts: createVirtualAccountsClient(),
|
|
2552
2944
|
virtualCards: createVirtualCardsClient(),
|
|
2553
|
-
externalAccounts: createExternalAccountsClient(),
|
|
2945
|
+
externalAccounts: createExternalAccountsClient(config),
|
|
2554
2946
|
operations: createOperationsClient(config),
|
|
2555
2947
|
webhookEndpoints: createWebhookEndpointsClient(),
|
|
2556
2948
|
webhookEvents: createWebhookEventsClient(),
|