@capxul/sdk 0.2.0-alpha.3 → 0.2.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.md +64 -22
- package/dist/{client-pMBRFcsz.d.ts → client-CbUeJoM9.d.ts} +41 -190
- package/dist/{client-B_Z3ThFO.d.cts → client-UEm2oZbZ.d.cts} +41 -190
- package/dist/client.cjs +362 -644
- package/dist/client.d.cts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/client.js +363 -645
- package/dist/index.cjs +363 -716
- package/dist/index.d.cts +32 -142
- package/dist/index.d.ts +32 -142
- package/dist/index.js +365 -716
- package/dist/{types-V_D7qjxY.d.ts → types-BD4VAQb5.d.ts} +14 -0
- package/dist/{types-Brucpq0Z.d.cts → types-HlwCIjgQ.d.cts} +14 -0
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/package.json +2 -3
package/dist/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { componentsGeneric, anyApi } from 'convex/server';
|
|
2
2
|
import { toSafeSmartAccount } from 'permissionless/accounts';
|
|
3
|
-
import { getAddress, parseUnits, createPublicClient, http
|
|
3
|
+
import { getAddress, encodeFunctionData, encodePacked, keccak256, getContractAddress, parseUnits, createPublicClient, http } from 'viem';
|
|
4
4
|
import { entryPoint07Address, createPaymasterClient, createBundlerClient } from 'viem/account-abstraction';
|
|
5
5
|
import { baseSepolia } from 'viem/chains';
|
|
6
|
-
import { deriveSafeAddress as deriveSafeAddress$1, defaultSafeDeriveConfig } from '@repo/safe-derive';
|
|
7
6
|
import { ConvexHttpClient } from 'convex/browser';
|
|
8
7
|
import { setup, fromPromise, assign } from 'xstate';
|
|
9
8
|
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
|
|
@@ -110,18 +109,6 @@ function track(...args) {
|
|
|
110
109
|
const [name, props] = args;
|
|
111
110
|
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
112
111
|
}
|
|
113
|
-
function formatDebugValue2(value) {
|
|
114
|
-
if (value === void 0 || value === "") return "";
|
|
115
|
-
if (typeof value === "string") return value;
|
|
116
|
-
try {
|
|
117
|
-
return JSON.stringify(value);
|
|
118
|
-
} catch {
|
|
119
|
-
return String(value);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function identify(userId, traits) {
|
|
123
|
-
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
124
|
-
}
|
|
125
112
|
|
|
126
113
|
// ../config/src/chain.ts
|
|
127
114
|
var CAPXUL_PAYMENTS_ADDRESS = "0xe740ea65521edc9bef0ea75d30b5334711db99f4";
|
|
@@ -232,6 +219,7 @@ var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
|
232
219
|
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
233
220
|
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
234
221
|
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
222
|
+
var MULTI_SEND = "0x38869bf66a61cf6bdb996a6ae40d5853fd43b526";
|
|
235
223
|
|
|
236
224
|
// ../config/src/org-roles.ts
|
|
237
225
|
function roleKeyFromLabel(label) {
|
|
@@ -242,6 +230,117 @@ function roleKeyFromLabel(label) {
|
|
|
242
230
|
roleKeyFromLabel("OWNER");
|
|
243
231
|
roleKeyFromLabel("FINANCE_MANAGER");
|
|
244
232
|
roleKeyFromLabel("PAYMENTS_OPERATOR");
|
|
233
|
+
var defaultSafeDeriveConfig = {
|
|
234
|
+
safeProxyFactory: SAFE_PROXY_FACTORY,
|
|
235
|
+
safeL2Singleton: SAFE_L2_SINGLETON,
|
|
236
|
+
safeModuleSetup: SAFE_MODULE_SETUP,
|
|
237
|
+
safe4337Module: SAFE_4337_MODULE,
|
|
238
|
+
multiSend: MULTI_SEND
|
|
239
|
+
};
|
|
240
|
+
var SAFE_PROXY_CREATION_CODE = "0x608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564";
|
|
241
|
+
var enableModulesAbi = [
|
|
242
|
+
{
|
|
243
|
+
type: "function",
|
|
244
|
+
name: "enableModules",
|
|
245
|
+
inputs: [{ type: "address[]", name: "modules" }],
|
|
246
|
+
outputs: [],
|
|
247
|
+
stateMutability: "nonpayable"
|
|
248
|
+
}
|
|
249
|
+
];
|
|
250
|
+
var multiSendAbi = [
|
|
251
|
+
{
|
|
252
|
+
type: "function",
|
|
253
|
+
name: "multiSend",
|
|
254
|
+
inputs: [{ type: "bytes", name: "transactions" }],
|
|
255
|
+
outputs: [],
|
|
256
|
+
stateMutability: "payable"
|
|
257
|
+
}
|
|
258
|
+
];
|
|
259
|
+
var setupAbi = [
|
|
260
|
+
{
|
|
261
|
+
type: "function",
|
|
262
|
+
name: "setup",
|
|
263
|
+
inputs: [
|
|
264
|
+
{ type: "address[]", name: "owners" },
|
|
265
|
+
{ type: "uint256", name: "threshold" },
|
|
266
|
+
{ type: "address", name: "to" },
|
|
267
|
+
{ type: "bytes", name: "data" },
|
|
268
|
+
{ type: "address", name: "fallbackHandler" },
|
|
269
|
+
{ type: "address", name: "paymentToken" },
|
|
270
|
+
{ type: "uint256", name: "payment" },
|
|
271
|
+
{ type: "address", name: "paymentReceiver" }
|
|
272
|
+
],
|
|
273
|
+
outputs: [],
|
|
274
|
+
stateMutability: "nonpayable"
|
|
275
|
+
}
|
|
276
|
+
];
|
|
277
|
+
function encodeInternalTransaction(tx) {
|
|
278
|
+
const encoded = encodePacked(
|
|
279
|
+
["uint8", "address", "uint256", "uint256", "bytes"],
|
|
280
|
+
[
|
|
281
|
+
tx.operation,
|
|
282
|
+
tx.to,
|
|
283
|
+
tx.value,
|
|
284
|
+
BigInt(tx.data.slice(2).length / 2),
|
|
285
|
+
tx.data
|
|
286
|
+
]
|
|
287
|
+
);
|
|
288
|
+
return encoded.slice(2);
|
|
289
|
+
}
|
|
290
|
+
function computeSaltNonce(ownerAddress) {
|
|
291
|
+
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
292
|
+
}
|
|
293
|
+
function deriveSafeAddress(signerAddress, config = defaultSafeDeriveConfig) {
|
|
294
|
+
const saltNonce = computeSaltNonce(signerAddress);
|
|
295
|
+
const enableModulesData = encodeFunctionData({
|
|
296
|
+
abi: enableModulesAbi,
|
|
297
|
+
functionName: "enableModules",
|
|
298
|
+
args: [[config.safe4337Module]]
|
|
299
|
+
});
|
|
300
|
+
const innerTx = encodeInternalTransaction({
|
|
301
|
+
operation: 1,
|
|
302
|
+
to: config.safeModuleSetup,
|
|
303
|
+
value: 0n,
|
|
304
|
+
data: enableModulesData
|
|
305
|
+
});
|
|
306
|
+
const multiSendCallData = encodeFunctionData({
|
|
307
|
+
abi: multiSendAbi,
|
|
308
|
+
functionName: "multiSend",
|
|
309
|
+
args: [`0x${innerTx}`]
|
|
310
|
+
});
|
|
311
|
+
const initializer = encodeFunctionData({
|
|
312
|
+
abi: setupAbi,
|
|
313
|
+
functionName: "setup",
|
|
314
|
+
args: [
|
|
315
|
+
[signerAddress],
|
|
316
|
+
1n,
|
|
317
|
+
config.multiSend,
|
|
318
|
+
multiSendCallData,
|
|
319
|
+
config.safe4337Module,
|
|
320
|
+
"0x0000000000000000000000000000000000000000",
|
|
321
|
+
0n,
|
|
322
|
+
"0x0000000000000000000000000000000000000000"
|
|
323
|
+
]
|
|
324
|
+
});
|
|
325
|
+
const deploymentCode = encodePacked(
|
|
326
|
+
["bytes", "uint256"],
|
|
327
|
+
[SAFE_PROXY_CREATION_CODE, BigInt(config.safeL2Singleton)]
|
|
328
|
+
);
|
|
329
|
+
const salt = keccak256(
|
|
330
|
+
encodePacked(
|
|
331
|
+
["bytes32", "uint256"],
|
|
332
|
+
[keccak256(encodePacked(["bytes"], [initializer])), saltNonce]
|
|
333
|
+
)
|
|
334
|
+
);
|
|
335
|
+
return getContractAddress({
|
|
336
|
+
from: config.safeProxyFactory,
|
|
337
|
+
salt,
|
|
338
|
+
bytecode: deploymentCode,
|
|
339
|
+
opcode: "CREATE2"
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/internal/safe/account.ts
|
|
245
344
|
async function buildSafeAccount(signer, chain) {
|
|
246
345
|
try {
|
|
247
346
|
const publicClient = createPublicClient({
|
|
@@ -253,7 +352,7 @@ async function buildSafeAccount(signer, chain) {
|
|
|
253
352
|
entryPoint: { address: entryPoint07Address, version: "0.7" },
|
|
254
353
|
version: "1.4.1",
|
|
255
354
|
owners: [signer],
|
|
256
|
-
saltNonce:
|
|
355
|
+
saltNonce: computeSaltNonce2(signer.address),
|
|
257
356
|
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
258
357
|
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
259
358
|
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
@@ -270,11 +369,11 @@ async function buildSafeAccount(signer, chain) {
|
|
|
270
369
|
});
|
|
271
370
|
}
|
|
272
371
|
}
|
|
273
|
-
function
|
|
372
|
+
function computeSaltNonce2(ownerAddress) {
|
|
274
373
|
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
275
374
|
}
|
|
276
|
-
function
|
|
277
|
-
return deriveSafeAddress
|
|
375
|
+
function deriveSafeAddress2(signerAddress) {
|
|
376
|
+
return deriveSafeAddress(signerAddress, defaultSafeDeriveConfig);
|
|
278
377
|
}
|
|
279
378
|
|
|
280
379
|
// ../platform-kernel/src/ids.ts
|
|
@@ -1016,7 +1115,7 @@ function createAccountsClient(config = {}) {
|
|
|
1016
1115
|
username: input.username,
|
|
1017
1116
|
countryCode: input.countryCode,
|
|
1018
1117
|
eoaAddress: input.signerProvider.signerAddress,
|
|
1019
|
-
safeAddress:
|
|
1118
|
+
safeAddress: deriveSafeAddress2(input.signerProvider.signerAddress)
|
|
1020
1119
|
}
|
|
1021
1120
|
);
|
|
1022
1121
|
const account = await config._data.query(
|
|
@@ -1602,8 +1701,17 @@ function createAuthClient(config = {}) {
|
|
|
1602
1701
|
];
|
|
1603
1702
|
}
|
|
1604
1703
|
try {
|
|
1605
|
-
const safeAddress =
|
|
1606
|
-
|
|
1704
|
+
const safeAddress = deriveSafeAddress2(signerAddress);
|
|
1705
|
+
if (!data.action) {
|
|
1706
|
+
return [
|
|
1707
|
+
new CapxulError({
|
|
1708
|
+
code: "INVALID_INPUT",
|
|
1709
|
+
message: "completeBootstrap requires a data client that can execute Convex actions."
|
|
1710
|
+
}),
|
|
1711
|
+
null
|
|
1712
|
+
];
|
|
1713
|
+
}
|
|
1714
|
+
const result = await data.action(api.authBootstrap.completeBootstrap, {
|
|
1607
1715
|
bootstrapToken: input.bootstrapToken,
|
|
1608
1716
|
sessionToken: session.token,
|
|
1609
1717
|
username: input.username,
|
|
@@ -1786,16 +1894,227 @@ function mutableConfig(config) {
|
|
|
1786
1894
|
return config;
|
|
1787
1895
|
}
|
|
1788
1896
|
|
|
1897
|
+
// src/core/auth-service.ts
|
|
1898
|
+
var AuthService = class {
|
|
1899
|
+
authClient;
|
|
1900
|
+
sessionStore;
|
|
1901
|
+
config;
|
|
1902
|
+
constructor(config = {}) {
|
|
1903
|
+
this.config = config;
|
|
1904
|
+
this.sessionStore = config.auth?.sessionStore ?? createMemorySessionStore2();
|
|
1905
|
+
this.authClient = createAuthClient({
|
|
1906
|
+
...config,
|
|
1907
|
+
auth: { ...config.auth, sessionStore: this.sessionStore }
|
|
1908
|
+
});
|
|
1909
|
+
}
|
|
1910
|
+
async sendOtp(email, options) {
|
|
1911
|
+
const [err] = await this.authClient.sendOtp({ email }, options);
|
|
1912
|
+
if (err) throw err;
|
|
1913
|
+
}
|
|
1914
|
+
async verifyOtp(email, otp, options) {
|
|
1915
|
+
const [err, result] = await this.authClient.verifyOtp(
|
|
1916
|
+
{ email, otp },
|
|
1917
|
+
options
|
|
1918
|
+
);
|
|
1919
|
+
if (err) throw err;
|
|
1920
|
+
return result;
|
|
1921
|
+
}
|
|
1922
|
+
async completeBootstrap(params, signer) {
|
|
1923
|
+
if (signer) {
|
|
1924
|
+
const tempClient = createAuthClient({
|
|
1925
|
+
...this.config,
|
|
1926
|
+
signer,
|
|
1927
|
+
auth: { ...this.config.auth, sessionStore: this.sessionStore }
|
|
1928
|
+
});
|
|
1929
|
+
const [err2, result2] = await tempClient.completeBootstrap(params);
|
|
1930
|
+
if (err2) throw err2;
|
|
1931
|
+
return result2;
|
|
1932
|
+
}
|
|
1933
|
+
const [err, result] = await this.authClient.completeBootstrap(params);
|
|
1934
|
+
if (err) throw err;
|
|
1935
|
+
return result;
|
|
1936
|
+
}
|
|
1937
|
+
/**
|
|
1938
|
+
* Clears the persisted session and, when a transport was pre-injected,
|
|
1939
|
+
* drops the cached auth header.
|
|
1940
|
+
*
|
|
1941
|
+
* **Transport safety note:** `clearAuth()` is only invoked when
|
|
1942
|
+
* `config._transport` was supplied at construction (e.g. by the React
|
|
1943
|
+
* provider). If `AuthService` is instantiated directly in a Node/CLI
|
|
1944
|
+
* context without an injected transport, the transport-side auth cache
|
|
1945
|
+
* is the caller's responsibility.
|
|
1946
|
+
*/
|
|
1947
|
+
async signOut() {
|
|
1948
|
+
if (!this.config._transport) {
|
|
1949
|
+
const [err] = await this.authClient.signOut();
|
|
1950
|
+
if (err) throw err;
|
|
1951
|
+
mutableConfig2(this.config)._data = void 0;
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
this.sessionStore.clear();
|
|
1955
|
+
this.config._transport.clearAuth();
|
|
1956
|
+
}
|
|
1957
|
+
async getSession() {
|
|
1958
|
+
const [err, session] = await this.authClient.getSession();
|
|
1959
|
+
if (err) throw err;
|
|
1960
|
+
return session;
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
function mutableConfig2(config) {
|
|
1964
|
+
return config;
|
|
1965
|
+
}
|
|
1966
|
+
function createMemorySessionStore2() {
|
|
1967
|
+
let current = null;
|
|
1968
|
+
return {
|
|
1969
|
+
get: () => current,
|
|
1970
|
+
set: (session) => {
|
|
1971
|
+
current = session;
|
|
1972
|
+
},
|
|
1973
|
+
clear: () => {
|
|
1974
|
+
current = null;
|
|
1975
|
+
}
|
|
1976
|
+
};
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1789
1979
|
// src/core/documents.ts
|
|
1790
|
-
function
|
|
1980
|
+
function requireInvoiceHash(row) {
|
|
1981
|
+
if (!row.invoiceHash) {
|
|
1982
|
+
throw new CapxulError({
|
|
1983
|
+
code: "INVALID_INPUT",
|
|
1984
|
+
message: `invoice document ${row.documentId ?? row._id} is missing its canonical invoiceHash`
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
return row.invoiceHash;
|
|
1988
|
+
}
|
|
1989
|
+
function mapInvoiceRow(row) {
|
|
1990
|
+
const status = row.status === "cancelled" ? "canceled" : row.status === "pending" ? "open" : row.status === "overdue" ? "expired" : row.status;
|
|
1791
1991
|
return {
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1992
|
+
object: "document",
|
|
1993
|
+
id: row.documentId ?? row._id,
|
|
1994
|
+
type: "invoice",
|
|
1995
|
+
owner: {
|
|
1996
|
+
kind: row.scope === "org" ? "organization" : "account",
|
|
1997
|
+
id: row.orgId ?? row.payeeEmail ?? row.payeeLabel
|
|
1998
|
+
},
|
|
1999
|
+
recipient: { email: row.payerEmail },
|
|
2000
|
+
amount: {
|
|
2001
|
+
value: row.amount,
|
|
2002
|
+
currency: row.currency
|
|
2003
|
+
},
|
|
2004
|
+
reference: row.note,
|
|
2005
|
+
lineItems: row.items,
|
|
2006
|
+
invoiceHash: requireInvoiceHash(row),
|
|
2007
|
+
dueAt: row.dueDate,
|
|
2008
|
+
status,
|
|
2009
|
+
createdAt: new Date(row.createdAt).toISOString()
|
|
1796
2010
|
};
|
|
1797
2011
|
}
|
|
1798
|
-
function
|
|
2012
|
+
function mapDocumentError(cause) {
|
|
2013
|
+
return fromConvexError(cause);
|
|
2014
|
+
}
|
|
2015
|
+
function createDocumentsClient(config = {}) {
|
|
2016
|
+
return {
|
|
2017
|
+
create: async (input) => {
|
|
2018
|
+
if (!config._data) return stub("documents.create");
|
|
2019
|
+
if (input.type !== "invoice") {
|
|
2020
|
+
return [
|
|
2021
|
+
new CapxulError({
|
|
2022
|
+
code: "INVALID_INPUT",
|
|
2023
|
+
message: "documents.create currently supports personal invoice documents only."
|
|
2024
|
+
}),
|
|
2025
|
+
null
|
|
2026
|
+
];
|
|
2027
|
+
}
|
|
2028
|
+
if (!("email" in input.recipient)) {
|
|
2029
|
+
return [
|
|
2030
|
+
new CapxulError({
|
|
2031
|
+
code: "INVALID_INPUT",
|
|
2032
|
+
message: "personal invoice documents currently require an email recipient."
|
|
2033
|
+
}),
|
|
2034
|
+
null
|
|
2035
|
+
];
|
|
2036
|
+
}
|
|
2037
|
+
try {
|
|
2038
|
+
const created = await config._data.mutation(
|
|
2039
|
+
api.paymentRecords.mutations.createInvoice,
|
|
2040
|
+
{
|
|
2041
|
+
scope: "personal",
|
|
2042
|
+
payerEmail: input.recipient.email,
|
|
2043
|
+
amount: input.amount.value,
|
|
2044
|
+
currency: input.amount.currency,
|
|
2045
|
+
dueDate: input.dueAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
2046
|
+
note: input.reference,
|
|
2047
|
+
items: input.lineItems
|
|
2048
|
+
}
|
|
2049
|
+
);
|
|
2050
|
+
const row = await config._data.query(
|
|
2051
|
+
api.paymentRecords.queries.getInvoiceByDocumentId,
|
|
2052
|
+
{ documentId: created.documentId }
|
|
2053
|
+
);
|
|
2054
|
+
if (!row) throw new Error("created invoice was not readable");
|
|
2055
|
+
return [null, mapInvoiceRow(row)];
|
|
2056
|
+
} catch (cause) {
|
|
2057
|
+
return [mapDocumentError(cause), null];
|
|
2058
|
+
}
|
|
2059
|
+
},
|
|
2060
|
+
retrieve: async (documentId) => {
|
|
2061
|
+
if (!config._data)
|
|
2062
|
+
return stub("documents.retrieve");
|
|
2063
|
+
try {
|
|
2064
|
+
const row = await config._data.query(
|
|
2065
|
+
api.paymentRecords.queries.getInvoiceByDocumentId,
|
|
2066
|
+
{ documentId }
|
|
2067
|
+
);
|
|
2068
|
+
if (!row) {
|
|
2069
|
+
return [
|
|
2070
|
+
new CapxulError({
|
|
2071
|
+
code: "NOT_FOUND",
|
|
2072
|
+
message: `document ${documentId} not found`
|
|
2073
|
+
}),
|
|
2074
|
+
null
|
|
2075
|
+
];
|
|
2076
|
+
}
|
|
2077
|
+
return [null, mapInvoiceRow(row)];
|
|
2078
|
+
} catch (cause) {
|
|
2079
|
+
return [mapDocumentError(cause), null];
|
|
2080
|
+
}
|
|
2081
|
+
},
|
|
2082
|
+
list: async (input = {}) => {
|
|
2083
|
+
if (!config._data)
|
|
2084
|
+
return stub("documents.list");
|
|
2085
|
+
try {
|
|
2086
|
+
if (input.type && input.type !== "invoice") {
|
|
2087
|
+
return [null, { object: "list", data: [], page: { hasMore: false } }];
|
|
2088
|
+
}
|
|
2089
|
+
const rows = await config._data.query(
|
|
2090
|
+
api.paymentRecords.queries.listMyInvoices,
|
|
2091
|
+
{
|
|
2092
|
+
limit: input.limit,
|
|
2093
|
+
cursor: input.cursor
|
|
2094
|
+
}
|
|
2095
|
+
);
|
|
2096
|
+
const page = rows;
|
|
2097
|
+
const data = page.data.map((row) => mapInvoiceRow(row));
|
|
2098
|
+
return [null, { object: "list", data, page: page.page }];
|
|
2099
|
+
} catch (cause) {
|
|
2100
|
+
return [mapDocumentError(cause), null];
|
|
2101
|
+
}
|
|
2102
|
+
},
|
|
2103
|
+
cancel: async (documentId) => {
|
|
2104
|
+
if (!config._data) return stub("documents.cancel");
|
|
2105
|
+
try {
|
|
2106
|
+
const row = await config._data.mutation(
|
|
2107
|
+
api.paymentRecords.mutations.cancelInvoice,
|
|
2108
|
+
{ documentId }
|
|
2109
|
+
);
|
|
2110
|
+
return [null, mapInvoiceRow(row)];
|
|
2111
|
+
} catch (cause) {
|
|
2112
|
+
return [mapDocumentError(cause), null];
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
};
|
|
2116
|
+
}
|
|
2117
|
+
function createOrgDocumentsClient(_config = {}) {
|
|
1799
2118
|
return {
|
|
1800
2119
|
create: async () => stub("organizations.documents.create"),
|
|
1801
2120
|
retrieve: async () => stub("organizations.documents.retrieve"),
|
|
@@ -3123,7 +3442,9 @@ function createOrganizationsClient(config = {}) {
|
|
|
3123
3442
|
},
|
|
3124
3443
|
invite: async (input) => {
|
|
3125
3444
|
if (!config._data?.action) {
|
|
3126
|
-
return stub(
|
|
3445
|
+
return stub(
|
|
3446
|
+
"organizations.members.invite"
|
|
3447
|
+
);
|
|
3127
3448
|
}
|
|
3128
3449
|
try {
|
|
3129
3450
|
const orgId = input.organizationId.replace(/^org_/, "");
|
|
@@ -3211,7 +3532,9 @@ function createOrganizationsClient(config = {}) {
|
|
|
3211
3532
|
},
|
|
3212
3533
|
resend: async (input) => {
|
|
3213
3534
|
if (!config._data?.action) {
|
|
3214
|
-
return stub(
|
|
3535
|
+
return stub(
|
|
3536
|
+
"organizations.members.resend"
|
|
3537
|
+
);
|
|
3215
3538
|
}
|
|
3216
3539
|
try {
|
|
3217
3540
|
const orgId = input.organizationId.replace(/^org_/, "");
|
|
@@ -3279,7 +3602,7 @@ function createOrganizationsClient(config = {}) {
|
|
|
3279
3602
|
payments: createOrgPaymentsClient(),
|
|
3280
3603
|
transfers: createOrgTransfersClient(),
|
|
3281
3604
|
withdrawals: createOrgWithdrawalsClient(config),
|
|
3282
|
-
documents: createOrgDocumentsClient(),
|
|
3605
|
+
documents: createOrgDocumentsClient(config),
|
|
3283
3606
|
webhookEndpoints: createWebhookEndpointsClient(),
|
|
3284
3607
|
webhookEvents: createWebhookEventsClient()
|
|
3285
3608
|
};
|
|
@@ -3396,609 +3719,6 @@ function createVirtualCardsClient() {
|
|
|
3396
3719
|
cancel: async () => stub("virtualCards.cancel")
|
|
3397
3720
|
};
|
|
3398
3721
|
}
|
|
3399
|
-
function createAuthFlowMachine(client) {
|
|
3400
|
-
return setup({
|
|
3401
|
-
types: {},
|
|
3402
|
-
actors: {
|
|
3403
|
-
// XState v5's `fromPromise` injects an `AbortSignal` that aborts
|
|
3404
|
-
// when the actor is stopped (parent transition fires, machine is
|
|
3405
|
-
// disposed, etc.). Plumbing it through `client.auth.sendOtp` /
|
|
3406
|
-
// `client.auth.verifyOtp` makes the in-flight HTTP request
|
|
3407
|
-
// cancellable: stale responses can't race a state machine
|
|
3408
|
-
// that's already moved on. See PR #406 S5.
|
|
3409
|
-
sendOtp: fromPromise(async ({ input, signal }) => {
|
|
3410
|
-
const [error] = await client.auth.sendOtp(
|
|
3411
|
-
{ email: input.email },
|
|
3412
|
-
{ signal }
|
|
3413
|
-
);
|
|
3414
|
-
if (error) throw error;
|
|
3415
|
-
}),
|
|
3416
|
-
verifyOtp: fromPromise(
|
|
3417
|
-
async ({ input, signal }) => {
|
|
3418
|
-
const [error, result] = await client.auth.verifyOtp(
|
|
3419
|
-
{
|
|
3420
|
-
email: input.email,
|
|
3421
|
-
otp: input.code
|
|
3422
|
-
},
|
|
3423
|
-
{ signal }
|
|
3424
|
-
);
|
|
3425
|
-
if (error) throw error;
|
|
3426
|
-
if (result.kind === "bootstrap_required") {
|
|
3427
|
-
throw new CapxulError({
|
|
3428
|
-
code: "ACTION_REQUIRED",
|
|
3429
|
-
message: "OTP verified but auth bootstrap is required. Use createAuthBootstrapFlowMachine for product sign-up.",
|
|
3430
|
-
details: { reason: result.reason }
|
|
3431
|
-
});
|
|
3432
|
-
}
|
|
3433
|
-
return result.session;
|
|
3434
|
-
}
|
|
3435
|
-
),
|
|
3436
|
-
signOut: fromPromise(async () => {
|
|
3437
|
-
const [error] = await client.auth.signOut();
|
|
3438
|
-
if (error) throw error;
|
|
3439
|
-
})
|
|
3440
|
-
},
|
|
3441
|
-
actions: {
|
|
3442
|
-
trackOtpRequested: ({ context }) => {
|
|
3443
|
-
if (!context.email) return;
|
|
3444
|
-
track("auth_otp_requested", {
|
|
3445
|
-
email_domain: emailDomain(context.email)
|
|
3446
|
-
});
|
|
3447
|
-
},
|
|
3448
|
-
trackOtpFailed: ({ event }) => {
|
|
3449
|
-
const error = errorFromEvent(event);
|
|
3450
|
-
track("auth_failed", {
|
|
3451
|
-
auth_type: "email_otp",
|
|
3452
|
-
reason: error.code
|
|
3453
|
-
});
|
|
3454
|
-
},
|
|
3455
|
-
trackTimeoutFailed: () => {
|
|
3456
|
-
track("auth_failed", {
|
|
3457
|
-
auth_type: "email_otp",
|
|
3458
|
-
reason: "timeout"
|
|
3459
|
-
});
|
|
3460
|
-
},
|
|
3461
|
-
trackVerified: () => {
|
|
3462
|
-
track("auth_verified", { auth_type: "email_otp" });
|
|
3463
|
-
},
|
|
3464
|
-
identifyAndTrack: ({ context }) => {
|
|
3465
|
-
if (!context.session) return;
|
|
3466
|
-
identify(context.session.authUserId, {
|
|
3467
|
-
email_domain: emailDomain(context.session.email)
|
|
3468
|
-
});
|
|
3469
|
-
track("auth_identified", {
|
|
3470
|
-
email_domain: emailDomain(context.session.email)
|
|
3471
|
-
});
|
|
3472
|
-
},
|
|
3473
|
-
trackSignedOut: () => {
|
|
3474
|
-
track("auth_signed_out");
|
|
3475
|
-
}
|
|
3476
|
-
}
|
|
3477
|
-
}).createMachine({
|
|
3478
|
-
id: "auth",
|
|
3479
|
-
initial: "idle",
|
|
3480
|
-
context: { email: null, session: null, error: null },
|
|
3481
|
-
states: {
|
|
3482
|
-
idle: {
|
|
3483
|
-
on: {
|
|
3484
|
-
REQUEST_OTP: {
|
|
3485
|
-
target: "sending_otp",
|
|
3486
|
-
actions: assign({
|
|
3487
|
-
email: ({ event }) => event.email,
|
|
3488
|
-
error: () => null
|
|
3489
|
-
})
|
|
3490
|
-
}
|
|
3491
|
-
}
|
|
3492
|
-
},
|
|
3493
|
-
sending_otp: {
|
|
3494
|
-
invoke: {
|
|
3495
|
-
src: "sendOtp",
|
|
3496
|
-
input: ({ context }) => ({ email: requireEmail(context) }),
|
|
3497
|
-
onDone: {
|
|
3498
|
-
target: "otp_requested",
|
|
3499
|
-
actions: ["trackOtpRequested"]
|
|
3500
|
-
},
|
|
3501
|
-
onError: {
|
|
3502
|
-
target: "error",
|
|
3503
|
-
actions: [
|
|
3504
|
-
assign({ error: ({ event }) => errorFromEvent(event) }),
|
|
3505
|
-
"trackOtpFailed"
|
|
3506
|
-
]
|
|
3507
|
-
}
|
|
3508
|
-
},
|
|
3509
|
-
after: {
|
|
3510
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3511
|
-
target: "error",
|
|
3512
|
-
actions: [
|
|
3513
|
-
assign({
|
|
3514
|
-
error: () => timeoutError("sending_otp")
|
|
3515
|
-
}),
|
|
3516
|
-
"trackTimeoutFailed"
|
|
3517
|
-
]
|
|
3518
|
-
}
|
|
3519
|
-
}
|
|
3520
|
-
},
|
|
3521
|
-
otp_requested: {
|
|
3522
|
-
on: {
|
|
3523
|
-
VERIFY: { target: "verifying" },
|
|
3524
|
-
RESET: {
|
|
3525
|
-
target: "idle",
|
|
3526
|
-
actions: assign({ email: () => null, error: () => null })
|
|
3527
|
-
}
|
|
3528
|
-
}
|
|
3529
|
-
},
|
|
3530
|
-
verifying: {
|
|
3531
|
-
invoke: {
|
|
3532
|
-
src: "verifyOtp",
|
|
3533
|
-
input: ({ context, event }) => ({
|
|
3534
|
-
email: requireEmail(context),
|
|
3535
|
-
code: requireCodeFromEvent(event)
|
|
3536
|
-
}),
|
|
3537
|
-
onDone: {
|
|
3538
|
-
target: "authenticated",
|
|
3539
|
-
actions: [
|
|
3540
|
-
// Scrub the duplicate `context.email` (input value
|
|
3541
|
-
// captured during sendOtp) since the verified
|
|
3542
|
-
// `session.email` is now the canonical source
|
|
3543
|
-
// post-authentication. The session's email is
|
|
3544
|
-
// intentionally retained — it's the auth result, not
|
|
3545
|
-
// lingering input. See PR #406 S2.
|
|
3546
|
-
assign({
|
|
3547
|
-
session: ({ event }) => event.output,
|
|
3548
|
-
email: () => null
|
|
3549
|
-
}),
|
|
3550
|
-
"trackVerified",
|
|
3551
|
-
"identifyAndTrack"
|
|
3552
|
-
]
|
|
3553
|
-
},
|
|
3554
|
-
onError: {
|
|
3555
|
-
target: "error",
|
|
3556
|
-
actions: [
|
|
3557
|
-
assign({ error: ({ event }) => errorFromEvent(event) }),
|
|
3558
|
-
"trackOtpFailed"
|
|
3559
|
-
]
|
|
3560
|
-
}
|
|
3561
|
-
},
|
|
3562
|
-
after: {
|
|
3563
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3564
|
-
target: "error",
|
|
3565
|
-
actions: [
|
|
3566
|
-
assign({
|
|
3567
|
-
error: () => timeoutError("verifying")
|
|
3568
|
-
}),
|
|
3569
|
-
"trackTimeoutFailed"
|
|
3570
|
-
]
|
|
3571
|
-
}
|
|
3572
|
-
}
|
|
3573
|
-
},
|
|
3574
|
-
authenticated: {
|
|
3575
|
-
on: {
|
|
3576
|
-
SIGN_OUT: { target: "signing_out" }
|
|
3577
|
-
}
|
|
3578
|
-
},
|
|
3579
|
-
signing_out: {
|
|
3580
|
-
invoke: {
|
|
3581
|
-
src: "signOut",
|
|
3582
|
-
onDone: {
|
|
3583
|
-
target: "idle",
|
|
3584
|
-
actions: [
|
|
3585
|
-
assign({
|
|
3586
|
-
session: () => null,
|
|
3587
|
-
email: () => null,
|
|
3588
|
-
error: () => null
|
|
3589
|
-
}),
|
|
3590
|
-
"trackSignedOut"
|
|
3591
|
-
]
|
|
3592
|
-
},
|
|
3593
|
-
onError: {
|
|
3594
|
-
target: "error",
|
|
3595
|
-
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
3596
|
-
}
|
|
3597
|
-
}
|
|
3598
|
-
},
|
|
3599
|
-
error: {
|
|
3600
|
-
on: {
|
|
3601
|
-
RESET: {
|
|
3602
|
-
target: "idle",
|
|
3603
|
-
actions: assign({ error: () => null })
|
|
3604
|
-
}
|
|
3605
|
-
}
|
|
3606
|
-
}
|
|
3607
|
-
}
|
|
3608
|
-
});
|
|
3609
|
-
}
|
|
3610
|
-
function requireEmail(context) {
|
|
3611
|
-
if (!context.email) {
|
|
3612
|
-
throw Errors.invalidInput(
|
|
3613
|
-
"email",
|
|
3614
|
-
"Auth flow advanced without an email captured in context."
|
|
3615
|
-
);
|
|
3616
|
-
}
|
|
3617
|
-
return context.email;
|
|
3618
|
-
}
|
|
3619
|
-
function requireCodeFromEvent(event) {
|
|
3620
|
-
if (event.type !== "VERIFY") {
|
|
3621
|
-
throw Errors.invalidInput(
|
|
3622
|
-
"code",
|
|
3623
|
-
`Auth flow's verifying state requires a VERIFY event, got ${event.type}.`
|
|
3624
|
-
);
|
|
3625
|
-
}
|
|
3626
|
-
return event.code;
|
|
3627
|
-
}
|
|
3628
|
-
function errorFromEvent(event) {
|
|
3629
|
-
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3630
|
-
if (cause instanceof CapxulError) {
|
|
3631
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
3632
|
-
return new CapxulError({
|
|
3633
|
-
code: cause.code,
|
|
3634
|
-
message: redactEmail(cause.message),
|
|
3635
|
-
cause,
|
|
3636
|
-
details: cause.details,
|
|
3637
|
-
operationId: cause.operationId,
|
|
3638
|
-
correlationId: cause.correlationId,
|
|
3639
|
-
retryable: cause.retryable
|
|
3640
|
-
});
|
|
3641
|
-
}
|
|
3642
|
-
if (cause instanceof CapxulError2) {
|
|
3643
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
3644
|
-
return new CapxulError2(cause.code, redactEmail(cause.message), {
|
|
3645
|
-
cause,
|
|
3646
|
-
details: cause.details,
|
|
3647
|
-
correlationId: cause.correlationId,
|
|
3648
|
-
layer: cause.layer
|
|
3649
|
-
});
|
|
3650
|
-
}
|
|
3651
|
-
return Errors.providerError("auth", "flow", redactCauseEmail(cause));
|
|
3652
|
-
}
|
|
3653
|
-
var EMAIL_MATCH_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
|
|
3654
|
-
var EMAIL_REDACT_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
|
|
3655
|
-
function redactEmail(message) {
|
|
3656
|
-
return message.replace(EMAIL_REDACT_PATTERN, "<redacted>");
|
|
3657
|
-
}
|
|
3658
|
-
function redactCauseEmail(cause) {
|
|
3659
|
-
if (cause instanceof Error) {
|
|
3660
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
3661
|
-
const redacted = new Error(redactEmail(cause.message));
|
|
3662
|
-
redacted.cause = cause;
|
|
3663
|
-
return redacted;
|
|
3664
|
-
}
|
|
3665
|
-
if (typeof cause === "string") {
|
|
3666
|
-
return redactEmail(cause);
|
|
3667
|
-
}
|
|
3668
|
-
return cause;
|
|
3669
|
-
}
|
|
3670
|
-
function timeoutError(state) {
|
|
3671
|
-
return Errors.providerError(
|
|
3672
|
-
"auth",
|
|
3673
|
-
"flow",
|
|
3674
|
-
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
3675
|
-
);
|
|
3676
|
-
}
|
|
3677
|
-
function emailDomain(email) {
|
|
3678
|
-
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
3679
|
-
return domain || "unknown";
|
|
3680
|
-
}
|
|
3681
|
-
var initialContext = {
|
|
3682
|
-
email: null,
|
|
3683
|
-
code: null,
|
|
3684
|
-
username: null,
|
|
3685
|
-
bootstrapToken: null,
|
|
3686
|
-
bootstrapReason: null,
|
|
3687
|
-
session: null,
|
|
3688
|
-
account: null,
|
|
3689
|
-
safe: null,
|
|
3690
|
-
error: null
|
|
3691
|
-
};
|
|
3692
|
-
function createAuthBootstrapFlowMachine(client) {
|
|
3693
|
-
return setup({
|
|
3694
|
-
types: {},
|
|
3695
|
-
actors: {
|
|
3696
|
-
sendOtp: fromPromise(async ({ input, signal }) => {
|
|
3697
|
-
const [error] = await client.auth.sendOtp(
|
|
3698
|
-
{ email: input.email },
|
|
3699
|
-
{ signal }
|
|
3700
|
-
);
|
|
3701
|
-
if (error) throw error;
|
|
3702
|
-
}),
|
|
3703
|
-
verifyOtp: fromPromise(
|
|
3704
|
-
async ({ input, signal }) => {
|
|
3705
|
-
const [error, result] = await client.auth.verifyOtp(
|
|
3706
|
-
{ email: input.email, otp: input.code },
|
|
3707
|
-
{ signal }
|
|
3708
|
-
);
|
|
3709
|
-
if (error) throw error;
|
|
3710
|
-
return result;
|
|
3711
|
-
}
|
|
3712
|
-
),
|
|
3713
|
-
completeBootstrap: fromPromise(async ({ input }) => {
|
|
3714
|
-
const [error, result] = await client.auth.completeBootstrap(input);
|
|
3715
|
-
if (error) throw error;
|
|
3716
|
-
return result;
|
|
3717
|
-
}),
|
|
3718
|
-
signOut: fromPromise(async () => {
|
|
3719
|
-
const [error] = await client.auth.signOut();
|
|
3720
|
-
if (error) throw error;
|
|
3721
|
-
})
|
|
3722
|
-
},
|
|
3723
|
-
actions: {
|
|
3724
|
-
trackOtpRequested: ({ context }) => {
|
|
3725
|
-
if (!context.email) return;
|
|
3726
|
-
track("auth_otp_requested", {
|
|
3727
|
-
email_domain: emailDomain2(context.email)
|
|
3728
|
-
});
|
|
3729
|
-
},
|
|
3730
|
-
trackFailed: ({ event }) => {
|
|
3731
|
-
track("auth_failed", {
|
|
3732
|
-
auth_type: "email_otp",
|
|
3733
|
-
reason: errorFromEvent2(event).code
|
|
3734
|
-
});
|
|
3735
|
-
},
|
|
3736
|
-
trackTimeoutFailed: () => {
|
|
3737
|
-
track("auth_failed", {
|
|
3738
|
-
auth_type: "email_otp",
|
|
3739
|
-
reason: "timeout"
|
|
3740
|
-
});
|
|
3741
|
-
},
|
|
3742
|
-
trackVerified: () => {
|
|
3743
|
-
track("auth_verified", { auth_type: "email_otp" });
|
|
3744
|
-
},
|
|
3745
|
-
trackBootstrapRequired: ({ context }) => {
|
|
3746
|
-
track("auth_verified", {
|
|
3747
|
-
auth_type: "email_otp",
|
|
3748
|
-
auth_mode: context.bootstrapReason ?? "bootstrap_required"
|
|
3749
|
-
});
|
|
3750
|
-
},
|
|
3751
|
-
identifyAndTrack: ({ context }) => {
|
|
3752
|
-
if (!context.session) return;
|
|
3753
|
-
identify(context.session.authUserId, {
|
|
3754
|
-
email_domain: emailDomain2(context.session.email)
|
|
3755
|
-
});
|
|
3756
|
-
track("auth_identified", {
|
|
3757
|
-
email_domain: emailDomain2(context.session.email)
|
|
3758
|
-
});
|
|
3759
|
-
},
|
|
3760
|
-
trackSignedOut: () => {
|
|
3761
|
-
track("auth_signed_out");
|
|
3762
|
-
}
|
|
3763
|
-
}
|
|
3764
|
-
}).createMachine({
|
|
3765
|
-
id: "authBootstrap",
|
|
3766
|
-
initial: "email",
|
|
3767
|
-
context: initialContext,
|
|
3768
|
-
states: {
|
|
3769
|
-
email: {
|
|
3770
|
-
on: {
|
|
3771
|
-
ENTER_EMAIL: {
|
|
3772
|
-
actions: assign({
|
|
3773
|
-
email: ({ event }) => event.email,
|
|
3774
|
-
error: () => null
|
|
3775
|
-
})
|
|
3776
|
-
},
|
|
3777
|
-
REQUEST_OTP: { target: "sending_otp" }
|
|
3778
|
-
}
|
|
3779
|
-
},
|
|
3780
|
-
sending_otp: {
|
|
3781
|
-
invoke: {
|
|
3782
|
-
src: "sendOtp",
|
|
3783
|
-
input: ({ context }) => ({ email: requireEmail2(context) }),
|
|
3784
|
-
onDone: { target: "otp_requested", actions: "trackOtpRequested" },
|
|
3785
|
-
onError: {
|
|
3786
|
-
target: "otp_requested",
|
|
3787
|
-
actions: [
|
|
3788
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3789
|
-
"trackFailed"
|
|
3790
|
-
]
|
|
3791
|
-
}
|
|
3792
|
-
},
|
|
3793
|
-
after: {
|
|
3794
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3795
|
-
target: "otp_requested",
|
|
3796
|
-
actions: [
|
|
3797
|
-
assign({ error: () => timeoutError2("sending_otp") }),
|
|
3798
|
-
"trackTimeoutFailed"
|
|
3799
|
-
]
|
|
3800
|
-
}
|
|
3801
|
-
}
|
|
3802
|
-
},
|
|
3803
|
-
otp_requested: {
|
|
3804
|
-
on: {
|
|
3805
|
-
ENTER_OTP: {
|
|
3806
|
-
actions: assign({
|
|
3807
|
-
code: ({ event }) => event.code,
|
|
3808
|
-
error: () => null
|
|
3809
|
-
})
|
|
3810
|
-
},
|
|
3811
|
-
VERIFY_OTP: { target: "verifying_otp" },
|
|
3812
|
-
BACK: { target: "email" },
|
|
3813
|
-
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3814
|
-
}
|
|
3815
|
-
},
|
|
3816
|
-
verifying_otp: {
|
|
3817
|
-
invoke: {
|
|
3818
|
-
src: "verifyOtp",
|
|
3819
|
-
input: ({ context }) => ({
|
|
3820
|
-
email: requireEmail2(context),
|
|
3821
|
-
code: requireCode(context)
|
|
3822
|
-
}),
|
|
3823
|
-
onDone: [
|
|
3824
|
-
{
|
|
3825
|
-
guard: ({ event }) => event.output.kind === "existing_member",
|
|
3826
|
-
target: "authenticated",
|
|
3827
|
-
actions: [
|
|
3828
|
-
assign({
|
|
3829
|
-
session: ({ event }) => event.output.session,
|
|
3830
|
-
account: ({ event }) => event.output.kind === "existing_member" ? event.output.account : null,
|
|
3831
|
-
username: ({ event }) => event.output.kind === "existing_member" ? event.output.username : null,
|
|
3832
|
-
safe: ({ event }) => event.output.kind === "existing_member" ? event.output.safe : null,
|
|
3833
|
-
email: () => null,
|
|
3834
|
-
error: () => null
|
|
3835
|
-
}),
|
|
3836
|
-
"trackVerified",
|
|
3837
|
-
"identifyAndTrack"
|
|
3838
|
-
]
|
|
3839
|
-
},
|
|
3840
|
-
{
|
|
3841
|
-
target: "bootstrap_required",
|
|
3842
|
-
actions: [
|
|
3843
|
-
assign({
|
|
3844
|
-
session: ({ event }) => event.output.session,
|
|
3845
|
-
bootstrapToken: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.bootstrapToken : null,
|
|
3846
|
-
bootstrapReason: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.reason : null,
|
|
3847
|
-
username: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.username ?? null : null,
|
|
3848
|
-
email: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.email : null,
|
|
3849
|
-
error: () => null
|
|
3850
|
-
}),
|
|
3851
|
-
"trackVerified",
|
|
3852
|
-
"trackBootstrapRequired"
|
|
3853
|
-
]
|
|
3854
|
-
}
|
|
3855
|
-
],
|
|
3856
|
-
onError: {
|
|
3857
|
-
target: "otp_requested",
|
|
3858
|
-
actions: [
|
|
3859
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3860
|
-
"trackFailed"
|
|
3861
|
-
]
|
|
3862
|
-
}
|
|
3863
|
-
},
|
|
3864
|
-
after: {
|
|
3865
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3866
|
-
target: "otp_requested",
|
|
3867
|
-
actions: [
|
|
3868
|
-
assign({ error: () => timeoutError2("verifying_otp") }),
|
|
3869
|
-
"trackTimeoutFailed"
|
|
3870
|
-
]
|
|
3871
|
-
}
|
|
3872
|
-
}
|
|
3873
|
-
},
|
|
3874
|
-
bootstrap_required: {
|
|
3875
|
-
on: {
|
|
3876
|
-
ENTER_USERNAME: {
|
|
3877
|
-
actions: assign({
|
|
3878
|
-
username: ({ event }) => event.username,
|
|
3879
|
-
error: () => null
|
|
3880
|
-
})
|
|
3881
|
-
},
|
|
3882
|
-
COMPLETE_BOOTSTRAP: { target: "completing_bootstrap" },
|
|
3883
|
-
BACK: { target: "otp_requested" },
|
|
3884
|
-
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3885
|
-
}
|
|
3886
|
-
},
|
|
3887
|
-
completing_bootstrap: {
|
|
3888
|
-
invoke: {
|
|
3889
|
-
src: "completeBootstrap",
|
|
3890
|
-
input: ({ context }) => ({
|
|
3891
|
-
bootstrapToken: requireBootstrapToken(context),
|
|
3892
|
-
username: requireUsername(context)
|
|
3893
|
-
}),
|
|
3894
|
-
onDone: {
|
|
3895
|
-
target: "authenticated",
|
|
3896
|
-
actions: [
|
|
3897
|
-
assign({
|
|
3898
|
-
session: ({ event }) => event.output.session,
|
|
3899
|
-
account: ({ event }) => event.output.account,
|
|
3900
|
-
username: ({ event }) => event.output.username,
|
|
3901
|
-
safe: ({ event }) => event.output.safe,
|
|
3902
|
-
bootstrapToken: () => null,
|
|
3903
|
-
bootstrapReason: () => null,
|
|
3904
|
-
email: () => null,
|
|
3905
|
-
error: () => null
|
|
3906
|
-
}),
|
|
3907
|
-
"identifyAndTrack"
|
|
3908
|
-
]
|
|
3909
|
-
},
|
|
3910
|
-
onError: {
|
|
3911
|
-
target: "bootstrap_required",
|
|
3912
|
-
actions: [
|
|
3913
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3914
|
-
"trackFailed"
|
|
3915
|
-
]
|
|
3916
|
-
}
|
|
3917
|
-
},
|
|
3918
|
-
after: {
|
|
3919
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3920
|
-
target: "bootstrap_required",
|
|
3921
|
-
actions: [
|
|
3922
|
-
assign({ error: () => timeoutError2("completing_bootstrap") }),
|
|
3923
|
-
"trackTimeoutFailed"
|
|
3924
|
-
]
|
|
3925
|
-
}
|
|
3926
|
-
}
|
|
3927
|
-
},
|
|
3928
|
-
authenticated: {
|
|
3929
|
-
on: {
|
|
3930
|
-
SIGN_OUT: { target: "signing_out" }
|
|
3931
|
-
}
|
|
3932
|
-
},
|
|
3933
|
-
signing_out: {
|
|
3934
|
-
invoke: {
|
|
3935
|
-
src: "signOut",
|
|
3936
|
-
onDone: {
|
|
3937
|
-
target: "email",
|
|
3938
|
-
actions: [
|
|
3939
|
-
assign(() => initialContext),
|
|
3940
|
-
"trackSignedOut"
|
|
3941
|
-
]
|
|
3942
|
-
},
|
|
3943
|
-
onError: {
|
|
3944
|
-
target: "error",
|
|
3945
|
-
actions: assign({ error: ({ event }) => errorFromEvent2(event) })
|
|
3946
|
-
}
|
|
3947
|
-
}
|
|
3948
|
-
},
|
|
3949
|
-
error: {
|
|
3950
|
-
on: {
|
|
3951
|
-
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3952
|
-
}
|
|
3953
|
-
}
|
|
3954
|
-
}
|
|
3955
|
-
});
|
|
3956
|
-
}
|
|
3957
|
-
function requireEmail2(context) {
|
|
3958
|
-
if (!context.email) {
|
|
3959
|
-
throw Errors.invalidInput("email", "Auth bootstrap requires an email.");
|
|
3960
|
-
}
|
|
3961
|
-
return context.email;
|
|
3962
|
-
}
|
|
3963
|
-
function requireCode(context) {
|
|
3964
|
-
if (!context.code) {
|
|
3965
|
-
throw Errors.invalidInput("code", "Auth bootstrap requires an OTP code.");
|
|
3966
|
-
}
|
|
3967
|
-
return context.code;
|
|
3968
|
-
}
|
|
3969
|
-
function requireBootstrapToken(context) {
|
|
3970
|
-
if (!context.bootstrapToken) {
|
|
3971
|
-
throw Errors.invalidInput(
|
|
3972
|
-
"bootstrapToken",
|
|
3973
|
-
"Auth bootstrap requires a continuation token."
|
|
3974
|
-
);
|
|
3975
|
-
}
|
|
3976
|
-
return context.bootstrapToken;
|
|
3977
|
-
}
|
|
3978
|
-
function requireUsername(context) {
|
|
3979
|
-
if (!context.username) {
|
|
3980
|
-
throw Errors.invalidInput("username", "Auth bootstrap requires a username.");
|
|
3981
|
-
}
|
|
3982
|
-
return context.username;
|
|
3983
|
-
}
|
|
3984
|
-
function errorFromEvent2(event) {
|
|
3985
|
-
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3986
|
-
if (cause instanceof CapxulError || cause instanceof CapxulError2) {
|
|
3987
|
-
return cause;
|
|
3988
|
-
}
|
|
3989
|
-
return Errors.providerError("auth", "bootstrap", cause);
|
|
3990
|
-
}
|
|
3991
|
-
function timeoutError2(state) {
|
|
3992
|
-
return Errors.providerError(
|
|
3993
|
-
"auth",
|
|
3994
|
-
"bootstrap",
|
|
3995
|
-
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
3996
|
-
);
|
|
3997
|
-
}
|
|
3998
|
-
function emailDomain2(email) {
|
|
3999
|
-
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
4000
|
-
return domain || "unknown";
|
|
4001
|
-
}
|
|
4002
3722
|
function createProvisioningMachine(client) {
|
|
4003
3723
|
return setup({
|
|
4004
3724
|
types: {},
|
|
@@ -4026,7 +3746,7 @@ function createProvisioningMachine(client) {
|
|
|
4026
3746
|
const provider = context.input?.signerProvider;
|
|
4027
3747
|
if (!provider) return;
|
|
4028
3748
|
track("provisioning_safe_created", {
|
|
4029
|
-
safe_address:
|
|
3749
|
+
safe_address: deriveSafeAddress2(provider.signerAddress)
|
|
4030
3750
|
});
|
|
4031
3751
|
}
|
|
4032
3752
|
}
|
|
@@ -4071,13 +3791,13 @@ function createProvisioningMachine(client) {
|
|
|
4071
3791
|
},
|
|
4072
3792
|
onError: {
|
|
4073
3793
|
target: "error",
|
|
4074
|
-
actions: assign({ error: ({ event }) =>
|
|
3794
|
+
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
4075
3795
|
}
|
|
4076
3796
|
},
|
|
4077
3797
|
after: {
|
|
4078
3798
|
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
4079
3799
|
target: "error",
|
|
4080
|
-
actions: assign({ error: () =>
|
|
3800
|
+
actions: assign({ error: () => timeoutError() })
|
|
4081
3801
|
}
|
|
4082
3802
|
}
|
|
4083
3803
|
},
|
|
@@ -4095,7 +3815,7 @@ function createProvisioningMachine(client) {
|
|
|
4095
3815
|
* this payload on its `onDone` transition and branches via guards
|
|
4096
3816
|
* on `event.output.error`.
|
|
4097
3817
|
*/
|
|
4098
|
-
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error:
|
|
3818
|
+
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error: timeoutError() }
|
|
4099
3819
|
});
|
|
4100
3820
|
}
|
|
4101
3821
|
function requireProvisionInput(context) {
|
|
@@ -4107,13 +3827,13 @@ function requireProvisionInput(context) {
|
|
|
4107
3827
|
}
|
|
4108
3828
|
return context.input;
|
|
4109
3829
|
}
|
|
4110
|
-
function
|
|
3830
|
+
function errorFromEvent(event) {
|
|
4111
3831
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
4112
3832
|
if (cause instanceof CapxulError) return cause;
|
|
4113
3833
|
if (cause instanceof CapxulError2) return cause;
|
|
4114
3834
|
return Errors.providerError("provisioning", "flow", cause);
|
|
4115
3835
|
}
|
|
4116
|
-
function
|
|
3836
|
+
function timeoutError() {
|
|
4117
3837
|
return Errors.providerError(
|
|
4118
3838
|
"provisioning",
|
|
4119
3839
|
"flow",
|
|
@@ -4206,7 +3926,7 @@ function createOnboardingFlowMachine(client) {
|
|
|
4206
3926
|
error: ({ event }) => extractChildErrorOrFallback(event)
|
|
4207
3927
|
}),
|
|
4208
3928
|
assignChildThrown: assign({
|
|
4209
|
-
error: ({ event }) =>
|
|
3929
|
+
error: ({ event }) => errorFromEvent2(event)
|
|
4210
3930
|
}),
|
|
4211
3931
|
assignAccountFromChild: assign({
|
|
4212
3932
|
account: ({ event }) => extractChildAccountOrNull(event)
|
|
@@ -4368,7 +4088,7 @@ function extractChildAccountOrNull(event) {
|
|
|
4368
4088
|
if (output && "account" in output && output.account) return output.account;
|
|
4369
4089
|
return null;
|
|
4370
4090
|
}
|
|
4371
|
-
function
|
|
4091
|
+
function errorFromEvent2(event) {
|
|
4372
4092
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
4373
4093
|
if (cause instanceof CapxulError) return cause;
|
|
4374
4094
|
if (cause instanceof CapxulError2) return cause;
|
|
@@ -4379,7 +4099,7 @@ function errorFromEvent4(event) {
|
|
|
4379
4099
|
function createCapxulClient(config = {}) {
|
|
4380
4100
|
const clientWithoutFlows = {
|
|
4381
4101
|
id: crypto.randomUUID(),
|
|
4382
|
-
auth:
|
|
4102
|
+
auth: new AuthService(config),
|
|
4383
4103
|
me: createMeClient(config),
|
|
4384
4104
|
accounts: createAccountsClient(config),
|
|
4385
4105
|
organizations: createOrganizationsClient(config),
|
|
@@ -4387,7 +4107,7 @@ function createCapxulClient(config = {}) {
|
|
|
4387
4107
|
transfers: createTransfersClient(),
|
|
4388
4108
|
tokenTransfers: createTokenTransfersClient(config),
|
|
4389
4109
|
withdrawals: createWithdrawalsClient(config),
|
|
4390
|
-
documents: createDocumentsClient(),
|
|
4110
|
+
documents: createDocumentsClient(config),
|
|
4391
4111
|
subAccounts: createSubAccountsClient(config),
|
|
4392
4112
|
virtualAccounts: createVirtualAccountsClient(),
|
|
4393
4113
|
virtualCards: createVirtualCardsClient(),
|
|
@@ -4399,8 +4119,6 @@ function createCapxulClient(config = {}) {
|
|
|
4399
4119
|
};
|
|
4400
4120
|
const client = clientWithoutFlows;
|
|
4401
4121
|
client.flows = {
|
|
4402
|
-
auth: () => createAuthFlowMachine(client),
|
|
4403
|
-
authBootstrap: () => createAuthBootstrapFlowMachine(client),
|
|
4404
4122
|
onboarding: () => createOnboardingFlowMachine(client),
|
|
4405
4123
|
provisioning: () => createProvisioningMachine(client)
|
|
4406
4124
|
};
|
|
@@ -4504,82 +4222,13 @@ function isWebhookEvent(value) {
|
|
|
4504
4222
|
const candidate = value;
|
|
4505
4223
|
return typeof candidate.id === "string" && typeof candidate.type === "string" && typeof candidate.createdAt === "string" && (candidate.operationId === void 0 || typeof candidate.operationId === "string") && (candidate.correlationId === void 0 || typeof candidate.correlationId === "string") && !!candidate.data && typeof candidate.data === "object" && !Array.isArray(candidate.data);
|
|
4506
4224
|
}
|
|
4507
|
-
|
|
4508
|
-
// src/core/auth-service.ts
|
|
4509
|
-
var AuthService = class {
|
|
4510
|
-
authClient;
|
|
4511
|
-
sessionStore;
|
|
4512
|
-
config;
|
|
4513
|
-
constructor(config = {}) {
|
|
4514
|
-
this.config = config;
|
|
4515
|
-
this.sessionStore = config.auth?.sessionStore ?? createMemorySessionStore2();
|
|
4516
|
-
this.authClient = createAuthClient({
|
|
4517
|
-
...config,
|
|
4518
|
-
auth: { ...config.auth, sessionStore: this.sessionStore }
|
|
4519
|
-
});
|
|
4520
|
-
}
|
|
4521
|
-
async sendOtp(email) {
|
|
4522
|
-
const [err] = await this.authClient.sendOtp({ email });
|
|
4523
|
-
if (err) throw err;
|
|
4524
|
-
}
|
|
4525
|
-
async verifyOtp(email, otp) {
|
|
4526
|
-
const [err, result] = await this.authClient.verifyOtp({ email, otp });
|
|
4527
|
-
if (err) throw err;
|
|
4528
|
-
return result;
|
|
4529
|
-
}
|
|
4530
|
-
async completeBootstrap(params, signer) {
|
|
4531
|
-
if (signer) {
|
|
4532
|
-
const tempClient = createAuthClient({
|
|
4533
|
-
...this.config,
|
|
4534
|
-
signer
|
|
4535
|
-
});
|
|
4536
|
-
const [err2, result2] = await tempClient.completeBootstrap(params);
|
|
4537
|
-
if (err2) throw err2;
|
|
4538
|
-
return result2;
|
|
4539
|
-
}
|
|
4540
|
-
const [err, result] = await this.authClient.completeBootstrap(params);
|
|
4541
|
-
if (err) throw err;
|
|
4542
|
-
return result;
|
|
4543
|
-
}
|
|
4544
|
-
/**
|
|
4545
|
-
* Clears the persisted session and, when a transport was pre-injected,
|
|
4546
|
-
* drops the cached auth header.
|
|
4547
|
-
*
|
|
4548
|
-
* **Transport safety note:** `clearAuth()` is only invoked when
|
|
4549
|
-
* `config._transport` was supplied at construction (e.g. by the React
|
|
4550
|
-
* provider). If `AuthService` is instantiated directly in a Node/CLI
|
|
4551
|
-
* context without an injected transport, the transport-side auth cache
|
|
4552
|
-
* is the caller's responsibility.
|
|
4553
|
-
*/
|
|
4554
|
-
async signOut() {
|
|
4555
|
-
this.sessionStore.clear();
|
|
4556
|
-
this.config._transport?.clearAuth();
|
|
4557
|
-
}
|
|
4558
|
-
async getSession() {
|
|
4559
|
-
const [err, session] = await this.authClient.getSession();
|
|
4560
|
-
if (err) throw err;
|
|
4561
|
-
return session;
|
|
4562
|
-
}
|
|
4563
|
-
};
|
|
4564
|
-
function createMemorySessionStore2() {
|
|
4565
|
-
let current = null;
|
|
4566
|
-
return {
|
|
4567
|
-
get: () => current,
|
|
4568
|
-
set: (session) => {
|
|
4569
|
-
current = session;
|
|
4570
|
-
},
|
|
4571
|
-
clear: () => {
|
|
4572
|
-
current = null;
|
|
4573
|
-
}
|
|
4574
|
-
};
|
|
4575
|
-
}
|
|
4576
4225
|
var SignerProvisioner = class {
|
|
4577
4226
|
provision() {
|
|
4578
4227
|
const privateKey = generatePrivateKey();
|
|
4579
4228
|
const signer = privateKeyToAccount(privateKey);
|
|
4580
|
-
const safeAddress =
|
|
4229
|
+
const safeAddress = deriveSafeAddress2(signer.address);
|
|
4581
4230
|
return { signer, safeAddress };
|
|
4582
4231
|
}
|
|
4583
4232
|
};
|
|
4584
4233
|
|
|
4585
|
-
export { AuthService, CapxulError, SignerProvisioner,
|
|
4234
|
+
export { AuthService, CapxulError, SignerProvisioner, createCapxulClient, createLocalSigner, createOnboardingFlowMachine, createProvisioningMachine as createProvisioningFlowMachine, makeHttpTransport, matchAction, matchError, matchStatus, resolvePaymentToken, toAccountId, toApiKeyId, toBalanceLedgerEntryId, toDocumentId, toEmail, toExternalAccountId, toKybProfileId, toKycProfileId, toMemberId, toOperationId, toOrganizationId, toPaymentId, toPhoneNumber, toSafeId, toSubAccountId, toTokenTransferId, toTransferId, toTreasuryId, toUsername, toVirtualAccountId, toVirtualCardId, toWebhookEndpointId, toWebhookEventId, toWithdrawalId, tryCatch, verifyWebhook };
|