@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/client.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, parseUnits, encodeFunctionData, encodePacked, keccak256, getContractAddress, 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
|
|
|
@@ -109,18 +108,6 @@ function track(...args) {
|
|
|
109
108
|
const [name, props] = args;
|
|
110
109
|
debugLog(`[TRACK] ${name} ${formatDebugValue(props ?? "")}`);
|
|
111
110
|
}
|
|
112
|
-
function formatDebugValue2(value) {
|
|
113
|
-
if (value === void 0 || value === "") return "";
|
|
114
|
-
if (typeof value === "string") return value;
|
|
115
|
-
try {
|
|
116
|
-
return JSON.stringify(value);
|
|
117
|
-
} catch {
|
|
118
|
-
return String(value);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
function identify(userId, traits) {
|
|
122
|
-
debugLog(`[IDENTIFY] ${userId} ${formatDebugValue2(traits ?? "")}`);
|
|
123
|
-
}
|
|
124
111
|
|
|
125
112
|
// ../config/src/chain.ts
|
|
126
113
|
var CAPXUL_PAYMENTS_ADDRESS = "0xe740ea65521edc9bef0ea75d30b5334711db99f4";
|
|
@@ -230,6 +217,7 @@ var SAFE_PROXY_FACTORY = "0x4e1dcf7ad4e460cfd30791ccc4f9c8a4f820ec67";
|
|
|
230
217
|
var SAFE_L2_SINGLETON = "0x29fcb43b46531bca003ddc8fcb67ffe91900c762";
|
|
231
218
|
var SAFE_MODULE_SETUP = "0x2dd68b007b46fbe91b9a7c3eda5a7a1063cb5b47";
|
|
232
219
|
var SAFE_4337_MODULE = "0x75cf11467937ce3f2f357ce24ffc3dbf8fd5c226";
|
|
220
|
+
var MULTI_SEND = "0x38869bf66a61cf6bdb996a6ae40d5853fd43b526";
|
|
233
221
|
|
|
234
222
|
// ../config/src/org-roles.ts
|
|
235
223
|
function roleKeyFromLabel(label) {
|
|
@@ -240,6 +228,117 @@ function roleKeyFromLabel(label) {
|
|
|
240
228
|
roleKeyFromLabel("OWNER");
|
|
241
229
|
roleKeyFromLabel("FINANCE_MANAGER");
|
|
242
230
|
roleKeyFromLabel("PAYMENTS_OPERATOR");
|
|
231
|
+
var defaultSafeDeriveConfig = {
|
|
232
|
+
safeProxyFactory: SAFE_PROXY_FACTORY,
|
|
233
|
+
safeL2Singleton: SAFE_L2_SINGLETON,
|
|
234
|
+
safeModuleSetup: SAFE_MODULE_SETUP,
|
|
235
|
+
safe4337Module: SAFE_4337_MODULE,
|
|
236
|
+
multiSend: MULTI_SEND
|
|
237
|
+
};
|
|
238
|
+
var SAFE_PROXY_CREATION_CODE = "0x608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564";
|
|
239
|
+
var enableModulesAbi = [
|
|
240
|
+
{
|
|
241
|
+
type: "function",
|
|
242
|
+
name: "enableModules",
|
|
243
|
+
inputs: [{ type: "address[]", name: "modules" }],
|
|
244
|
+
outputs: [],
|
|
245
|
+
stateMutability: "nonpayable"
|
|
246
|
+
}
|
|
247
|
+
];
|
|
248
|
+
var multiSendAbi = [
|
|
249
|
+
{
|
|
250
|
+
type: "function",
|
|
251
|
+
name: "multiSend",
|
|
252
|
+
inputs: [{ type: "bytes", name: "transactions" }],
|
|
253
|
+
outputs: [],
|
|
254
|
+
stateMutability: "payable"
|
|
255
|
+
}
|
|
256
|
+
];
|
|
257
|
+
var setupAbi = [
|
|
258
|
+
{
|
|
259
|
+
type: "function",
|
|
260
|
+
name: "setup",
|
|
261
|
+
inputs: [
|
|
262
|
+
{ type: "address[]", name: "owners" },
|
|
263
|
+
{ type: "uint256", name: "threshold" },
|
|
264
|
+
{ type: "address", name: "to" },
|
|
265
|
+
{ type: "bytes", name: "data" },
|
|
266
|
+
{ type: "address", name: "fallbackHandler" },
|
|
267
|
+
{ type: "address", name: "paymentToken" },
|
|
268
|
+
{ type: "uint256", name: "payment" },
|
|
269
|
+
{ type: "address", name: "paymentReceiver" }
|
|
270
|
+
],
|
|
271
|
+
outputs: [],
|
|
272
|
+
stateMutability: "nonpayable"
|
|
273
|
+
}
|
|
274
|
+
];
|
|
275
|
+
function encodeInternalTransaction(tx) {
|
|
276
|
+
const encoded = encodePacked(
|
|
277
|
+
["uint8", "address", "uint256", "uint256", "bytes"],
|
|
278
|
+
[
|
|
279
|
+
tx.operation,
|
|
280
|
+
tx.to,
|
|
281
|
+
tx.value,
|
|
282
|
+
BigInt(tx.data.slice(2).length / 2),
|
|
283
|
+
tx.data
|
|
284
|
+
]
|
|
285
|
+
);
|
|
286
|
+
return encoded.slice(2);
|
|
287
|
+
}
|
|
288
|
+
function computeSaltNonce(ownerAddress) {
|
|
289
|
+
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
290
|
+
}
|
|
291
|
+
function deriveSafeAddress(signerAddress, config = defaultSafeDeriveConfig) {
|
|
292
|
+
const saltNonce = computeSaltNonce(signerAddress);
|
|
293
|
+
const enableModulesData = encodeFunctionData({
|
|
294
|
+
abi: enableModulesAbi,
|
|
295
|
+
functionName: "enableModules",
|
|
296
|
+
args: [[config.safe4337Module]]
|
|
297
|
+
});
|
|
298
|
+
const innerTx = encodeInternalTransaction({
|
|
299
|
+
operation: 1,
|
|
300
|
+
to: config.safeModuleSetup,
|
|
301
|
+
value: 0n,
|
|
302
|
+
data: enableModulesData
|
|
303
|
+
});
|
|
304
|
+
const multiSendCallData = encodeFunctionData({
|
|
305
|
+
abi: multiSendAbi,
|
|
306
|
+
functionName: "multiSend",
|
|
307
|
+
args: [`0x${innerTx}`]
|
|
308
|
+
});
|
|
309
|
+
const initializer = encodeFunctionData({
|
|
310
|
+
abi: setupAbi,
|
|
311
|
+
functionName: "setup",
|
|
312
|
+
args: [
|
|
313
|
+
[signerAddress],
|
|
314
|
+
1n,
|
|
315
|
+
config.multiSend,
|
|
316
|
+
multiSendCallData,
|
|
317
|
+
config.safe4337Module,
|
|
318
|
+
"0x0000000000000000000000000000000000000000",
|
|
319
|
+
0n,
|
|
320
|
+
"0x0000000000000000000000000000000000000000"
|
|
321
|
+
]
|
|
322
|
+
});
|
|
323
|
+
const deploymentCode = encodePacked(
|
|
324
|
+
["bytes", "uint256"],
|
|
325
|
+
[SAFE_PROXY_CREATION_CODE, BigInt(config.safeL2Singleton)]
|
|
326
|
+
);
|
|
327
|
+
const salt = keccak256(
|
|
328
|
+
encodePacked(
|
|
329
|
+
["bytes32", "uint256"],
|
|
330
|
+
[keccak256(encodePacked(["bytes"], [initializer])), saltNonce]
|
|
331
|
+
)
|
|
332
|
+
);
|
|
333
|
+
return getContractAddress({
|
|
334
|
+
from: config.safeProxyFactory,
|
|
335
|
+
salt,
|
|
336
|
+
bytecode: deploymentCode,
|
|
337
|
+
opcode: "CREATE2"
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// src/internal/safe/account.ts
|
|
243
342
|
async function buildSafeAccount(signer, chain) {
|
|
244
343
|
try {
|
|
245
344
|
const publicClient = createPublicClient({
|
|
@@ -251,7 +350,7 @@ async function buildSafeAccount(signer, chain) {
|
|
|
251
350
|
entryPoint: { address: entryPoint07Address, version: "0.7" },
|
|
252
351
|
version: "1.4.1",
|
|
253
352
|
owners: [signer],
|
|
254
|
-
saltNonce:
|
|
353
|
+
saltNonce: computeSaltNonce2(signer.address),
|
|
255
354
|
safeSingletonAddress: SAFE_L2_SINGLETON,
|
|
256
355
|
safeProxyFactoryAddress: SAFE_PROXY_FACTORY,
|
|
257
356
|
safeModuleSetupAddress: SAFE_MODULE_SETUP,
|
|
@@ -268,11 +367,11 @@ async function buildSafeAccount(signer, chain) {
|
|
|
268
367
|
});
|
|
269
368
|
}
|
|
270
369
|
}
|
|
271
|
-
function
|
|
370
|
+
function computeSaltNonce2(ownerAddress) {
|
|
272
371
|
return BigInt(`0x${ownerAddress.toLowerCase().slice(2).padEnd(64, "0")}`);
|
|
273
372
|
}
|
|
274
|
-
function
|
|
275
|
-
return deriveSafeAddress
|
|
373
|
+
function deriveSafeAddress2(signerAddress) {
|
|
374
|
+
return deriveSafeAddress(signerAddress, defaultSafeDeriveConfig);
|
|
276
375
|
}
|
|
277
376
|
|
|
278
377
|
// ../platform-kernel/src/ids.ts
|
|
@@ -928,7 +1027,7 @@ function createAccountsClient(config = {}) {
|
|
|
928
1027
|
username: input.username,
|
|
929
1028
|
countryCode: input.countryCode,
|
|
930
1029
|
eoaAddress: input.signerProvider.signerAddress,
|
|
931
|
-
safeAddress:
|
|
1030
|
+
safeAddress: deriveSafeAddress2(input.signerProvider.signerAddress)
|
|
932
1031
|
}
|
|
933
1032
|
);
|
|
934
1033
|
const account = await config._data.query(
|
|
@@ -1514,8 +1613,17 @@ function createAuthClient(config = {}) {
|
|
|
1514
1613
|
];
|
|
1515
1614
|
}
|
|
1516
1615
|
try {
|
|
1517
|
-
const safeAddress =
|
|
1518
|
-
|
|
1616
|
+
const safeAddress = deriveSafeAddress2(signerAddress);
|
|
1617
|
+
if (!data.action) {
|
|
1618
|
+
return [
|
|
1619
|
+
new CapxulError({
|
|
1620
|
+
code: "INVALID_INPUT",
|
|
1621
|
+
message: "completeBootstrap requires a data client that can execute Convex actions."
|
|
1622
|
+
}),
|
|
1623
|
+
null
|
|
1624
|
+
];
|
|
1625
|
+
}
|
|
1626
|
+
const result = await data.action(api.authBootstrap.completeBootstrap, {
|
|
1519
1627
|
bootstrapToken: input.bootstrapToken,
|
|
1520
1628
|
sessionToken: session.token,
|
|
1521
1629
|
username: input.username,
|
|
@@ -1698,16 +1806,227 @@ function mutableConfig(config) {
|
|
|
1698
1806
|
return config;
|
|
1699
1807
|
}
|
|
1700
1808
|
|
|
1809
|
+
// src/core/auth-service.ts
|
|
1810
|
+
var AuthService = class {
|
|
1811
|
+
authClient;
|
|
1812
|
+
sessionStore;
|
|
1813
|
+
config;
|
|
1814
|
+
constructor(config = {}) {
|
|
1815
|
+
this.config = config;
|
|
1816
|
+
this.sessionStore = config.auth?.sessionStore ?? createMemorySessionStore2();
|
|
1817
|
+
this.authClient = createAuthClient({
|
|
1818
|
+
...config,
|
|
1819
|
+
auth: { ...config.auth, sessionStore: this.sessionStore }
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
async sendOtp(email, options) {
|
|
1823
|
+
const [err] = await this.authClient.sendOtp({ email }, options);
|
|
1824
|
+
if (err) throw err;
|
|
1825
|
+
}
|
|
1826
|
+
async verifyOtp(email, otp, options) {
|
|
1827
|
+
const [err, result] = await this.authClient.verifyOtp(
|
|
1828
|
+
{ email, otp },
|
|
1829
|
+
options
|
|
1830
|
+
);
|
|
1831
|
+
if (err) throw err;
|
|
1832
|
+
return result;
|
|
1833
|
+
}
|
|
1834
|
+
async completeBootstrap(params, signer) {
|
|
1835
|
+
if (signer) {
|
|
1836
|
+
const tempClient = createAuthClient({
|
|
1837
|
+
...this.config,
|
|
1838
|
+
signer,
|
|
1839
|
+
auth: { ...this.config.auth, sessionStore: this.sessionStore }
|
|
1840
|
+
});
|
|
1841
|
+
const [err2, result2] = await tempClient.completeBootstrap(params);
|
|
1842
|
+
if (err2) throw err2;
|
|
1843
|
+
return result2;
|
|
1844
|
+
}
|
|
1845
|
+
const [err, result] = await this.authClient.completeBootstrap(params);
|
|
1846
|
+
if (err) throw err;
|
|
1847
|
+
return result;
|
|
1848
|
+
}
|
|
1849
|
+
/**
|
|
1850
|
+
* Clears the persisted session and, when a transport was pre-injected,
|
|
1851
|
+
* drops the cached auth header.
|
|
1852
|
+
*
|
|
1853
|
+
* **Transport safety note:** `clearAuth()` is only invoked when
|
|
1854
|
+
* `config._transport` was supplied at construction (e.g. by the React
|
|
1855
|
+
* provider). If `AuthService` is instantiated directly in a Node/CLI
|
|
1856
|
+
* context without an injected transport, the transport-side auth cache
|
|
1857
|
+
* is the caller's responsibility.
|
|
1858
|
+
*/
|
|
1859
|
+
async signOut() {
|
|
1860
|
+
if (!this.config._transport) {
|
|
1861
|
+
const [err] = await this.authClient.signOut();
|
|
1862
|
+
if (err) throw err;
|
|
1863
|
+
mutableConfig2(this.config)._data = void 0;
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
this.sessionStore.clear();
|
|
1867
|
+
this.config._transport.clearAuth();
|
|
1868
|
+
}
|
|
1869
|
+
async getSession() {
|
|
1870
|
+
const [err, session] = await this.authClient.getSession();
|
|
1871
|
+
if (err) throw err;
|
|
1872
|
+
return session;
|
|
1873
|
+
}
|
|
1874
|
+
};
|
|
1875
|
+
function mutableConfig2(config) {
|
|
1876
|
+
return config;
|
|
1877
|
+
}
|
|
1878
|
+
function createMemorySessionStore2() {
|
|
1879
|
+
let current = null;
|
|
1880
|
+
return {
|
|
1881
|
+
get: () => current,
|
|
1882
|
+
set: (session) => {
|
|
1883
|
+
current = session;
|
|
1884
|
+
},
|
|
1885
|
+
clear: () => {
|
|
1886
|
+
current = null;
|
|
1887
|
+
}
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1701
1891
|
// src/core/documents.ts
|
|
1702
|
-
function
|
|
1892
|
+
function requireInvoiceHash(row) {
|
|
1893
|
+
if (!row.invoiceHash) {
|
|
1894
|
+
throw new CapxulError({
|
|
1895
|
+
code: "INVALID_INPUT",
|
|
1896
|
+
message: `invoice document ${row.documentId ?? row._id} is missing its canonical invoiceHash`
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1899
|
+
return row.invoiceHash;
|
|
1900
|
+
}
|
|
1901
|
+
function mapInvoiceRow(row) {
|
|
1902
|
+
const status = row.status === "cancelled" ? "canceled" : row.status === "pending" ? "open" : row.status === "overdue" ? "expired" : row.status;
|
|
1703
1903
|
return {
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1904
|
+
object: "document",
|
|
1905
|
+
id: row.documentId ?? row._id,
|
|
1906
|
+
type: "invoice",
|
|
1907
|
+
owner: {
|
|
1908
|
+
kind: row.scope === "org" ? "organization" : "account",
|
|
1909
|
+
id: row.orgId ?? row.payeeEmail ?? row.payeeLabel
|
|
1910
|
+
},
|
|
1911
|
+
recipient: { email: row.payerEmail },
|
|
1912
|
+
amount: {
|
|
1913
|
+
value: row.amount,
|
|
1914
|
+
currency: row.currency
|
|
1915
|
+
},
|
|
1916
|
+
reference: row.note,
|
|
1917
|
+
lineItems: row.items,
|
|
1918
|
+
invoiceHash: requireInvoiceHash(row),
|
|
1919
|
+
dueAt: row.dueDate,
|
|
1920
|
+
status,
|
|
1921
|
+
createdAt: new Date(row.createdAt).toISOString()
|
|
1708
1922
|
};
|
|
1709
1923
|
}
|
|
1710
|
-
function
|
|
1924
|
+
function mapDocumentError(cause) {
|
|
1925
|
+
return fromConvexError(cause);
|
|
1926
|
+
}
|
|
1927
|
+
function createDocumentsClient(config = {}) {
|
|
1928
|
+
return {
|
|
1929
|
+
create: async (input) => {
|
|
1930
|
+
if (!config._data) return stub("documents.create");
|
|
1931
|
+
if (input.type !== "invoice") {
|
|
1932
|
+
return [
|
|
1933
|
+
new CapxulError({
|
|
1934
|
+
code: "INVALID_INPUT",
|
|
1935
|
+
message: "documents.create currently supports personal invoice documents only."
|
|
1936
|
+
}),
|
|
1937
|
+
null
|
|
1938
|
+
];
|
|
1939
|
+
}
|
|
1940
|
+
if (!("email" in input.recipient)) {
|
|
1941
|
+
return [
|
|
1942
|
+
new CapxulError({
|
|
1943
|
+
code: "INVALID_INPUT",
|
|
1944
|
+
message: "personal invoice documents currently require an email recipient."
|
|
1945
|
+
}),
|
|
1946
|
+
null
|
|
1947
|
+
];
|
|
1948
|
+
}
|
|
1949
|
+
try {
|
|
1950
|
+
const created = await config._data.mutation(
|
|
1951
|
+
api.paymentRecords.mutations.createInvoice,
|
|
1952
|
+
{
|
|
1953
|
+
scope: "personal",
|
|
1954
|
+
payerEmail: input.recipient.email,
|
|
1955
|
+
amount: input.amount.value,
|
|
1956
|
+
currency: input.amount.currency,
|
|
1957
|
+
dueDate: input.dueAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
1958
|
+
note: input.reference,
|
|
1959
|
+
items: input.lineItems
|
|
1960
|
+
}
|
|
1961
|
+
);
|
|
1962
|
+
const row = await config._data.query(
|
|
1963
|
+
api.paymentRecords.queries.getInvoiceByDocumentId,
|
|
1964
|
+
{ documentId: created.documentId }
|
|
1965
|
+
);
|
|
1966
|
+
if (!row) throw new Error("created invoice was not readable");
|
|
1967
|
+
return [null, mapInvoiceRow(row)];
|
|
1968
|
+
} catch (cause) {
|
|
1969
|
+
return [mapDocumentError(cause), null];
|
|
1970
|
+
}
|
|
1971
|
+
},
|
|
1972
|
+
retrieve: async (documentId) => {
|
|
1973
|
+
if (!config._data)
|
|
1974
|
+
return stub("documents.retrieve");
|
|
1975
|
+
try {
|
|
1976
|
+
const row = await config._data.query(
|
|
1977
|
+
api.paymentRecords.queries.getInvoiceByDocumentId,
|
|
1978
|
+
{ documentId }
|
|
1979
|
+
);
|
|
1980
|
+
if (!row) {
|
|
1981
|
+
return [
|
|
1982
|
+
new CapxulError({
|
|
1983
|
+
code: "NOT_FOUND",
|
|
1984
|
+
message: `document ${documentId} not found`
|
|
1985
|
+
}),
|
|
1986
|
+
null
|
|
1987
|
+
];
|
|
1988
|
+
}
|
|
1989
|
+
return [null, mapInvoiceRow(row)];
|
|
1990
|
+
} catch (cause) {
|
|
1991
|
+
return [mapDocumentError(cause), null];
|
|
1992
|
+
}
|
|
1993
|
+
},
|
|
1994
|
+
list: async (input = {}) => {
|
|
1995
|
+
if (!config._data)
|
|
1996
|
+
return stub("documents.list");
|
|
1997
|
+
try {
|
|
1998
|
+
if (input.type && input.type !== "invoice") {
|
|
1999
|
+
return [null, { object: "list", data: [], page: { hasMore: false } }];
|
|
2000
|
+
}
|
|
2001
|
+
const rows = await config._data.query(
|
|
2002
|
+
api.paymentRecords.queries.listMyInvoices,
|
|
2003
|
+
{
|
|
2004
|
+
limit: input.limit,
|
|
2005
|
+
cursor: input.cursor
|
|
2006
|
+
}
|
|
2007
|
+
);
|
|
2008
|
+
const page = rows;
|
|
2009
|
+
const data = page.data.map((row) => mapInvoiceRow(row));
|
|
2010
|
+
return [null, { object: "list", data, page: page.page }];
|
|
2011
|
+
} catch (cause) {
|
|
2012
|
+
return [mapDocumentError(cause), null];
|
|
2013
|
+
}
|
|
2014
|
+
},
|
|
2015
|
+
cancel: async (documentId) => {
|
|
2016
|
+
if (!config._data) return stub("documents.cancel");
|
|
2017
|
+
try {
|
|
2018
|
+
const row = await config._data.mutation(
|
|
2019
|
+
api.paymentRecords.mutations.cancelInvoice,
|
|
2020
|
+
{ documentId }
|
|
2021
|
+
);
|
|
2022
|
+
return [null, mapInvoiceRow(row)];
|
|
2023
|
+
} catch (cause) {
|
|
2024
|
+
return [mapDocumentError(cause), null];
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
function createOrgDocumentsClient(_config = {}) {
|
|
1711
2030
|
return {
|
|
1712
2031
|
create: async () => stub("organizations.documents.create"),
|
|
1713
2032
|
retrieve: async () => stub("organizations.documents.retrieve"),
|
|
@@ -3035,7 +3354,9 @@ function createOrganizationsClient(config = {}) {
|
|
|
3035
3354
|
},
|
|
3036
3355
|
invite: async (input) => {
|
|
3037
3356
|
if (!config._data?.action) {
|
|
3038
|
-
return stub(
|
|
3357
|
+
return stub(
|
|
3358
|
+
"organizations.members.invite"
|
|
3359
|
+
);
|
|
3039
3360
|
}
|
|
3040
3361
|
try {
|
|
3041
3362
|
const orgId = input.organizationId.replace(/^org_/, "");
|
|
@@ -3123,7 +3444,9 @@ function createOrganizationsClient(config = {}) {
|
|
|
3123
3444
|
},
|
|
3124
3445
|
resend: async (input) => {
|
|
3125
3446
|
if (!config._data?.action) {
|
|
3126
|
-
return stub(
|
|
3447
|
+
return stub(
|
|
3448
|
+
"organizations.members.resend"
|
|
3449
|
+
);
|
|
3127
3450
|
}
|
|
3128
3451
|
try {
|
|
3129
3452
|
const orgId = input.organizationId.replace(/^org_/, "");
|
|
@@ -3191,7 +3514,7 @@ function createOrganizationsClient(config = {}) {
|
|
|
3191
3514
|
payments: createOrgPaymentsClient(),
|
|
3192
3515
|
transfers: createOrgTransfersClient(),
|
|
3193
3516
|
withdrawals: createOrgWithdrawalsClient(config),
|
|
3194
|
-
documents: createOrgDocumentsClient(),
|
|
3517
|
+
documents: createOrgDocumentsClient(config),
|
|
3195
3518
|
webhookEndpoints: createWebhookEndpointsClient(),
|
|
3196
3519
|
webhookEvents: createWebhookEventsClient()
|
|
3197
3520
|
};
|
|
@@ -3308,609 +3631,6 @@ function createVirtualCardsClient() {
|
|
|
3308
3631
|
cancel: async () => stub("virtualCards.cancel")
|
|
3309
3632
|
};
|
|
3310
3633
|
}
|
|
3311
|
-
function createAuthFlowMachine(client) {
|
|
3312
|
-
return setup({
|
|
3313
|
-
types: {},
|
|
3314
|
-
actors: {
|
|
3315
|
-
// XState v5's `fromPromise` injects an `AbortSignal` that aborts
|
|
3316
|
-
// when the actor is stopped (parent transition fires, machine is
|
|
3317
|
-
// disposed, etc.). Plumbing it through `client.auth.sendOtp` /
|
|
3318
|
-
// `client.auth.verifyOtp` makes the in-flight HTTP request
|
|
3319
|
-
// cancellable: stale responses can't race a state machine
|
|
3320
|
-
// that's already moved on. See PR #406 S5.
|
|
3321
|
-
sendOtp: fromPromise(async ({ input, signal }) => {
|
|
3322
|
-
const [error] = await client.auth.sendOtp(
|
|
3323
|
-
{ email: input.email },
|
|
3324
|
-
{ signal }
|
|
3325
|
-
);
|
|
3326
|
-
if (error) throw error;
|
|
3327
|
-
}),
|
|
3328
|
-
verifyOtp: fromPromise(
|
|
3329
|
-
async ({ input, signal }) => {
|
|
3330
|
-
const [error, result] = await client.auth.verifyOtp(
|
|
3331
|
-
{
|
|
3332
|
-
email: input.email,
|
|
3333
|
-
otp: input.code
|
|
3334
|
-
},
|
|
3335
|
-
{ signal }
|
|
3336
|
-
);
|
|
3337
|
-
if (error) throw error;
|
|
3338
|
-
if (result.kind === "bootstrap_required") {
|
|
3339
|
-
throw new CapxulError({
|
|
3340
|
-
code: "ACTION_REQUIRED",
|
|
3341
|
-
message: "OTP verified but auth bootstrap is required. Use createAuthBootstrapFlowMachine for product sign-up.",
|
|
3342
|
-
details: { reason: result.reason }
|
|
3343
|
-
});
|
|
3344
|
-
}
|
|
3345
|
-
return result.session;
|
|
3346
|
-
}
|
|
3347
|
-
),
|
|
3348
|
-
signOut: fromPromise(async () => {
|
|
3349
|
-
const [error] = await client.auth.signOut();
|
|
3350
|
-
if (error) throw error;
|
|
3351
|
-
})
|
|
3352
|
-
},
|
|
3353
|
-
actions: {
|
|
3354
|
-
trackOtpRequested: ({ context }) => {
|
|
3355
|
-
if (!context.email) return;
|
|
3356
|
-
track("auth_otp_requested", {
|
|
3357
|
-
email_domain: emailDomain(context.email)
|
|
3358
|
-
});
|
|
3359
|
-
},
|
|
3360
|
-
trackOtpFailed: ({ event }) => {
|
|
3361
|
-
const error = errorFromEvent(event);
|
|
3362
|
-
track("auth_failed", {
|
|
3363
|
-
auth_type: "email_otp",
|
|
3364
|
-
reason: error.code
|
|
3365
|
-
});
|
|
3366
|
-
},
|
|
3367
|
-
trackTimeoutFailed: () => {
|
|
3368
|
-
track("auth_failed", {
|
|
3369
|
-
auth_type: "email_otp",
|
|
3370
|
-
reason: "timeout"
|
|
3371
|
-
});
|
|
3372
|
-
},
|
|
3373
|
-
trackVerified: () => {
|
|
3374
|
-
track("auth_verified", { auth_type: "email_otp" });
|
|
3375
|
-
},
|
|
3376
|
-
identifyAndTrack: ({ context }) => {
|
|
3377
|
-
if (!context.session) return;
|
|
3378
|
-
identify(context.session.authUserId, {
|
|
3379
|
-
email_domain: emailDomain(context.session.email)
|
|
3380
|
-
});
|
|
3381
|
-
track("auth_identified", {
|
|
3382
|
-
email_domain: emailDomain(context.session.email)
|
|
3383
|
-
});
|
|
3384
|
-
},
|
|
3385
|
-
trackSignedOut: () => {
|
|
3386
|
-
track("auth_signed_out");
|
|
3387
|
-
}
|
|
3388
|
-
}
|
|
3389
|
-
}).createMachine({
|
|
3390
|
-
id: "auth",
|
|
3391
|
-
initial: "idle",
|
|
3392
|
-
context: { email: null, session: null, error: null },
|
|
3393
|
-
states: {
|
|
3394
|
-
idle: {
|
|
3395
|
-
on: {
|
|
3396
|
-
REQUEST_OTP: {
|
|
3397
|
-
target: "sending_otp",
|
|
3398
|
-
actions: assign({
|
|
3399
|
-
email: ({ event }) => event.email,
|
|
3400
|
-
error: () => null
|
|
3401
|
-
})
|
|
3402
|
-
}
|
|
3403
|
-
}
|
|
3404
|
-
},
|
|
3405
|
-
sending_otp: {
|
|
3406
|
-
invoke: {
|
|
3407
|
-
src: "sendOtp",
|
|
3408
|
-
input: ({ context }) => ({ email: requireEmail(context) }),
|
|
3409
|
-
onDone: {
|
|
3410
|
-
target: "otp_requested",
|
|
3411
|
-
actions: ["trackOtpRequested"]
|
|
3412
|
-
},
|
|
3413
|
-
onError: {
|
|
3414
|
-
target: "error",
|
|
3415
|
-
actions: [
|
|
3416
|
-
assign({ error: ({ event }) => errorFromEvent(event) }),
|
|
3417
|
-
"trackOtpFailed"
|
|
3418
|
-
]
|
|
3419
|
-
}
|
|
3420
|
-
},
|
|
3421
|
-
after: {
|
|
3422
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3423
|
-
target: "error",
|
|
3424
|
-
actions: [
|
|
3425
|
-
assign({
|
|
3426
|
-
error: () => timeoutError("sending_otp")
|
|
3427
|
-
}),
|
|
3428
|
-
"trackTimeoutFailed"
|
|
3429
|
-
]
|
|
3430
|
-
}
|
|
3431
|
-
}
|
|
3432
|
-
},
|
|
3433
|
-
otp_requested: {
|
|
3434
|
-
on: {
|
|
3435
|
-
VERIFY: { target: "verifying" },
|
|
3436
|
-
RESET: {
|
|
3437
|
-
target: "idle",
|
|
3438
|
-
actions: assign({ email: () => null, error: () => null })
|
|
3439
|
-
}
|
|
3440
|
-
}
|
|
3441
|
-
},
|
|
3442
|
-
verifying: {
|
|
3443
|
-
invoke: {
|
|
3444
|
-
src: "verifyOtp",
|
|
3445
|
-
input: ({ context, event }) => ({
|
|
3446
|
-
email: requireEmail(context),
|
|
3447
|
-
code: requireCodeFromEvent(event)
|
|
3448
|
-
}),
|
|
3449
|
-
onDone: {
|
|
3450
|
-
target: "authenticated",
|
|
3451
|
-
actions: [
|
|
3452
|
-
// Scrub the duplicate `context.email` (input value
|
|
3453
|
-
// captured during sendOtp) since the verified
|
|
3454
|
-
// `session.email` is now the canonical source
|
|
3455
|
-
// post-authentication. The session's email is
|
|
3456
|
-
// intentionally retained — it's the auth result, not
|
|
3457
|
-
// lingering input. See PR #406 S2.
|
|
3458
|
-
assign({
|
|
3459
|
-
session: ({ event }) => event.output,
|
|
3460
|
-
email: () => null
|
|
3461
|
-
}),
|
|
3462
|
-
"trackVerified",
|
|
3463
|
-
"identifyAndTrack"
|
|
3464
|
-
]
|
|
3465
|
-
},
|
|
3466
|
-
onError: {
|
|
3467
|
-
target: "error",
|
|
3468
|
-
actions: [
|
|
3469
|
-
assign({ error: ({ event }) => errorFromEvent(event) }),
|
|
3470
|
-
"trackOtpFailed"
|
|
3471
|
-
]
|
|
3472
|
-
}
|
|
3473
|
-
},
|
|
3474
|
-
after: {
|
|
3475
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3476
|
-
target: "error",
|
|
3477
|
-
actions: [
|
|
3478
|
-
assign({
|
|
3479
|
-
error: () => timeoutError("verifying")
|
|
3480
|
-
}),
|
|
3481
|
-
"trackTimeoutFailed"
|
|
3482
|
-
]
|
|
3483
|
-
}
|
|
3484
|
-
}
|
|
3485
|
-
},
|
|
3486
|
-
authenticated: {
|
|
3487
|
-
on: {
|
|
3488
|
-
SIGN_OUT: { target: "signing_out" }
|
|
3489
|
-
}
|
|
3490
|
-
},
|
|
3491
|
-
signing_out: {
|
|
3492
|
-
invoke: {
|
|
3493
|
-
src: "signOut",
|
|
3494
|
-
onDone: {
|
|
3495
|
-
target: "idle",
|
|
3496
|
-
actions: [
|
|
3497
|
-
assign({
|
|
3498
|
-
session: () => null,
|
|
3499
|
-
email: () => null,
|
|
3500
|
-
error: () => null
|
|
3501
|
-
}),
|
|
3502
|
-
"trackSignedOut"
|
|
3503
|
-
]
|
|
3504
|
-
},
|
|
3505
|
-
onError: {
|
|
3506
|
-
target: "error",
|
|
3507
|
-
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
3508
|
-
}
|
|
3509
|
-
}
|
|
3510
|
-
},
|
|
3511
|
-
error: {
|
|
3512
|
-
on: {
|
|
3513
|
-
RESET: {
|
|
3514
|
-
target: "idle",
|
|
3515
|
-
actions: assign({ error: () => null })
|
|
3516
|
-
}
|
|
3517
|
-
}
|
|
3518
|
-
}
|
|
3519
|
-
}
|
|
3520
|
-
});
|
|
3521
|
-
}
|
|
3522
|
-
function requireEmail(context) {
|
|
3523
|
-
if (!context.email) {
|
|
3524
|
-
throw Errors.invalidInput(
|
|
3525
|
-
"email",
|
|
3526
|
-
"Auth flow advanced without an email captured in context."
|
|
3527
|
-
);
|
|
3528
|
-
}
|
|
3529
|
-
return context.email;
|
|
3530
|
-
}
|
|
3531
|
-
function requireCodeFromEvent(event) {
|
|
3532
|
-
if (event.type !== "VERIFY") {
|
|
3533
|
-
throw Errors.invalidInput(
|
|
3534
|
-
"code",
|
|
3535
|
-
`Auth flow's verifying state requires a VERIFY event, got ${event.type}.`
|
|
3536
|
-
);
|
|
3537
|
-
}
|
|
3538
|
-
return event.code;
|
|
3539
|
-
}
|
|
3540
|
-
function errorFromEvent(event) {
|
|
3541
|
-
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3542
|
-
if (cause instanceof CapxulError) {
|
|
3543
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
3544
|
-
return new CapxulError({
|
|
3545
|
-
code: cause.code,
|
|
3546
|
-
message: redactEmail(cause.message),
|
|
3547
|
-
cause,
|
|
3548
|
-
details: cause.details,
|
|
3549
|
-
operationId: cause.operationId,
|
|
3550
|
-
correlationId: cause.correlationId,
|
|
3551
|
-
retryable: cause.retryable
|
|
3552
|
-
});
|
|
3553
|
-
}
|
|
3554
|
-
if (cause instanceof CapxulError2) {
|
|
3555
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
3556
|
-
return new CapxulError2(cause.code, redactEmail(cause.message), {
|
|
3557
|
-
cause,
|
|
3558
|
-
details: cause.details,
|
|
3559
|
-
correlationId: cause.correlationId,
|
|
3560
|
-
layer: cause.layer
|
|
3561
|
-
});
|
|
3562
|
-
}
|
|
3563
|
-
return Errors.providerError("auth", "flow", redactCauseEmail(cause));
|
|
3564
|
-
}
|
|
3565
|
-
var EMAIL_MATCH_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/;
|
|
3566
|
-
var EMAIL_REDACT_PATTERN = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
|
|
3567
|
-
function redactEmail(message) {
|
|
3568
|
-
return message.replace(EMAIL_REDACT_PATTERN, "<redacted>");
|
|
3569
|
-
}
|
|
3570
|
-
function redactCauseEmail(cause) {
|
|
3571
|
-
if (cause instanceof Error) {
|
|
3572
|
-
if (!EMAIL_MATCH_PATTERN.test(cause.message)) return cause;
|
|
3573
|
-
const redacted = new Error(redactEmail(cause.message));
|
|
3574
|
-
redacted.cause = cause;
|
|
3575
|
-
return redacted;
|
|
3576
|
-
}
|
|
3577
|
-
if (typeof cause === "string") {
|
|
3578
|
-
return redactEmail(cause);
|
|
3579
|
-
}
|
|
3580
|
-
return cause;
|
|
3581
|
-
}
|
|
3582
|
-
function timeoutError(state) {
|
|
3583
|
-
return Errors.providerError(
|
|
3584
|
-
"auth",
|
|
3585
|
-
"flow",
|
|
3586
|
-
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
3587
|
-
);
|
|
3588
|
-
}
|
|
3589
|
-
function emailDomain(email) {
|
|
3590
|
-
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
3591
|
-
return domain || "unknown";
|
|
3592
|
-
}
|
|
3593
|
-
var initialContext = {
|
|
3594
|
-
email: null,
|
|
3595
|
-
code: null,
|
|
3596
|
-
username: null,
|
|
3597
|
-
bootstrapToken: null,
|
|
3598
|
-
bootstrapReason: null,
|
|
3599
|
-
session: null,
|
|
3600
|
-
account: null,
|
|
3601
|
-
safe: null,
|
|
3602
|
-
error: null
|
|
3603
|
-
};
|
|
3604
|
-
function createAuthBootstrapFlowMachine(client) {
|
|
3605
|
-
return setup({
|
|
3606
|
-
types: {},
|
|
3607
|
-
actors: {
|
|
3608
|
-
sendOtp: fromPromise(async ({ input, signal }) => {
|
|
3609
|
-
const [error] = await client.auth.sendOtp(
|
|
3610
|
-
{ email: input.email },
|
|
3611
|
-
{ signal }
|
|
3612
|
-
);
|
|
3613
|
-
if (error) throw error;
|
|
3614
|
-
}),
|
|
3615
|
-
verifyOtp: fromPromise(
|
|
3616
|
-
async ({ input, signal }) => {
|
|
3617
|
-
const [error, result] = await client.auth.verifyOtp(
|
|
3618
|
-
{ email: input.email, otp: input.code },
|
|
3619
|
-
{ signal }
|
|
3620
|
-
);
|
|
3621
|
-
if (error) throw error;
|
|
3622
|
-
return result;
|
|
3623
|
-
}
|
|
3624
|
-
),
|
|
3625
|
-
completeBootstrap: fromPromise(async ({ input }) => {
|
|
3626
|
-
const [error, result] = await client.auth.completeBootstrap(input);
|
|
3627
|
-
if (error) throw error;
|
|
3628
|
-
return result;
|
|
3629
|
-
}),
|
|
3630
|
-
signOut: fromPromise(async () => {
|
|
3631
|
-
const [error] = await client.auth.signOut();
|
|
3632
|
-
if (error) throw error;
|
|
3633
|
-
})
|
|
3634
|
-
},
|
|
3635
|
-
actions: {
|
|
3636
|
-
trackOtpRequested: ({ context }) => {
|
|
3637
|
-
if (!context.email) return;
|
|
3638
|
-
track("auth_otp_requested", {
|
|
3639
|
-
email_domain: emailDomain2(context.email)
|
|
3640
|
-
});
|
|
3641
|
-
},
|
|
3642
|
-
trackFailed: ({ event }) => {
|
|
3643
|
-
track("auth_failed", {
|
|
3644
|
-
auth_type: "email_otp",
|
|
3645
|
-
reason: errorFromEvent2(event).code
|
|
3646
|
-
});
|
|
3647
|
-
},
|
|
3648
|
-
trackTimeoutFailed: () => {
|
|
3649
|
-
track("auth_failed", {
|
|
3650
|
-
auth_type: "email_otp",
|
|
3651
|
-
reason: "timeout"
|
|
3652
|
-
});
|
|
3653
|
-
},
|
|
3654
|
-
trackVerified: () => {
|
|
3655
|
-
track("auth_verified", { auth_type: "email_otp" });
|
|
3656
|
-
},
|
|
3657
|
-
trackBootstrapRequired: ({ context }) => {
|
|
3658
|
-
track("auth_verified", {
|
|
3659
|
-
auth_type: "email_otp",
|
|
3660
|
-
auth_mode: context.bootstrapReason ?? "bootstrap_required"
|
|
3661
|
-
});
|
|
3662
|
-
},
|
|
3663
|
-
identifyAndTrack: ({ context }) => {
|
|
3664
|
-
if (!context.session) return;
|
|
3665
|
-
identify(context.session.authUserId, {
|
|
3666
|
-
email_domain: emailDomain2(context.session.email)
|
|
3667
|
-
});
|
|
3668
|
-
track("auth_identified", {
|
|
3669
|
-
email_domain: emailDomain2(context.session.email)
|
|
3670
|
-
});
|
|
3671
|
-
},
|
|
3672
|
-
trackSignedOut: () => {
|
|
3673
|
-
track("auth_signed_out");
|
|
3674
|
-
}
|
|
3675
|
-
}
|
|
3676
|
-
}).createMachine({
|
|
3677
|
-
id: "authBootstrap",
|
|
3678
|
-
initial: "email",
|
|
3679
|
-
context: initialContext,
|
|
3680
|
-
states: {
|
|
3681
|
-
email: {
|
|
3682
|
-
on: {
|
|
3683
|
-
ENTER_EMAIL: {
|
|
3684
|
-
actions: assign({
|
|
3685
|
-
email: ({ event }) => event.email,
|
|
3686
|
-
error: () => null
|
|
3687
|
-
})
|
|
3688
|
-
},
|
|
3689
|
-
REQUEST_OTP: { target: "sending_otp" }
|
|
3690
|
-
}
|
|
3691
|
-
},
|
|
3692
|
-
sending_otp: {
|
|
3693
|
-
invoke: {
|
|
3694
|
-
src: "sendOtp",
|
|
3695
|
-
input: ({ context }) => ({ email: requireEmail2(context) }),
|
|
3696
|
-
onDone: { target: "otp_requested", actions: "trackOtpRequested" },
|
|
3697
|
-
onError: {
|
|
3698
|
-
target: "otp_requested",
|
|
3699
|
-
actions: [
|
|
3700
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3701
|
-
"trackFailed"
|
|
3702
|
-
]
|
|
3703
|
-
}
|
|
3704
|
-
},
|
|
3705
|
-
after: {
|
|
3706
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3707
|
-
target: "otp_requested",
|
|
3708
|
-
actions: [
|
|
3709
|
-
assign({ error: () => timeoutError2("sending_otp") }),
|
|
3710
|
-
"trackTimeoutFailed"
|
|
3711
|
-
]
|
|
3712
|
-
}
|
|
3713
|
-
}
|
|
3714
|
-
},
|
|
3715
|
-
otp_requested: {
|
|
3716
|
-
on: {
|
|
3717
|
-
ENTER_OTP: {
|
|
3718
|
-
actions: assign({
|
|
3719
|
-
code: ({ event }) => event.code,
|
|
3720
|
-
error: () => null
|
|
3721
|
-
})
|
|
3722
|
-
},
|
|
3723
|
-
VERIFY_OTP: { target: "verifying_otp" },
|
|
3724
|
-
BACK: { target: "email" },
|
|
3725
|
-
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3726
|
-
}
|
|
3727
|
-
},
|
|
3728
|
-
verifying_otp: {
|
|
3729
|
-
invoke: {
|
|
3730
|
-
src: "verifyOtp",
|
|
3731
|
-
input: ({ context }) => ({
|
|
3732
|
-
email: requireEmail2(context),
|
|
3733
|
-
code: requireCode(context)
|
|
3734
|
-
}),
|
|
3735
|
-
onDone: [
|
|
3736
|
-
{
|
|
3737
|
-
guard: ({ event }) => event.output.kind === "existing_member",
|
|
3738
|
-
target: "authenticated",
|
|
3739
|
-
actions: [
|
|
3740
|
-
assign({
|
|
3741
|
-
session: ({ event }) => event.output.session,
|
|
3742
|
-
account: ({ event }) => event.output.kind === "existing_member" ? event.output.account : null,
|
|
3743
|
-
username: ({ event }) => event.output.kind === "existing_member" ? event.output.username : null,
|
|
3744
|
-
safe: ({ event }) => event.output.kind === "existing_member" ? event.output.safe : null,
|
|
3745
|
-
email: () => null,
|
|
3746
|
-
error: () => null
|
|
3747
|
-
}),
|
|
3748
|
-
"trackVerified",
|
|
3749
|
-
"identifyAndTrack"
|
|
3750
|
-
]
|
|
3751
|
-
},
|
|
3752
|
-
{
|
|
3753
|
-
target: "bootstrap_required",
|
|
3754
|
-
actions: [
|
|
3755
|
-
assign({
|
|
3756
|
-
session: ({ event }) => event.output.session,
|
|
3757
|
-
bootstrapToken: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.bootstrapToken : null,
|
|
3758
|
-
bootstrapReason: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.reason : null,
|
|
3759
|
-
username: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.username ?? null : null,
|
|
3760
|
-
email: ({ event }) => event.output.kind === "bootstrap_required" ? event.output.email : null,
|
|
3761
|
-
error: () => null
|
|
3762
|
-
}),
|
|
3763
|
-
"trackVerified",
|
|
3764
|
-
"trackBootstrapRequired"
|
|
3765
|
-
]
|
|
3766
|
-
}
|
|
3767
|
-
],
|
|
3768
|
-
onError: {
|
|
3769
|
-
target: "otp_requested",
|
|
3770
|
-
actions: [
|
|
3771
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3772
|
-
"trackFailed"
|
|
3773
|
-
]
|
|
3774
|
-
}
|
|
3775
|
-
},
|
|
3776
|
-
after: {
|
|
3777
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3778
|
-
target: "otp_requested",
|
|
3779
|
-
actions: [
|
|
3780
|
-
assign({ error: () => timeoutError2("verifying_otp") }),
|
|
3781
|
-
"trackTimeoutFailed"
|
|
3782
|
-
]
|
|
3783
|
-
}
|
|
3784
|
-
}
|
|
3785
|
-
},
|
|
3786
|
-
bootstrap_required: {
|
|
3787
|
-
on: {
|
|
3788
|
-
ENTER_USERNAME: {
|
|
3789
|
-
actions: assign({
|
|
3790
|
-
username: ({ event }) => event.username,
|
|
3791
|
-
error: () => null
|
|
3792
|
-
})
|
|
3793
|
-
},
|
|
3794
|
-
COMPLETE_BOOTSTRAP: { target: "completing_bootstrap" },
|
|
3795
|
-
BACK: { target: "otp_requested" },
|
|
3796
|
-
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3797
|
-
}
|
|
3798
|
-
},
|
|
3799
|
-
completing_bootstrap: {
|
|
3800
|
-
invoke: {
|
|
3801
|
-
src: "completeBootstrap",
|
|
3802
|
-
input: ({ context }) => ({
|
|
3803
|
-
bootstrapToken: requireBootstrapToken(context),
|
|
3804
|
-
username: requireUsername(context)
|
|
3805
|
-
}),
|
|
3806
|
-
onDone: {
|
|
3807
|
-
target: "authenticated",
|
|
3808
|
-
actions: [
|
|
3809
|
-
assign({
|
|
3810
|
-
session: ({ event }) => event.output.session,
|
|
3811
|
-
account: ({ event }) => event.output.account,
|
|
3812
|
-
username: ({ event }) => event.output.username,
|
|
3813
|
-
safe: ({ event }) => event.output.safe,
|
|
3814
|
-
bootstrapToken: () => null,
|
|
3815
|
-
bootstrapReason: () => null,
|
|
3816
|
-
email: () => null,
|
|
3817
|
-
error: () => null
|
|
3818
|
-
}),
|
|
3819
|
-
"identifyAndTrack"
|
|
3820
|
-
]
|
|
3821
|
-
},
|
|
3822
|
-
onError: {
|
|
3823
|
-
target: "bootstrap_required",
|
|
3824
|
-
actions: [
|
|
3825
|
-
assign({ error: ({ event }) => errorFromEvent2(event) }),
|
|
3826
|
-
"trackFailed"
|
|
3827
|
-
]
|
|
3828
|
-
}
|
|
3829
|
-
},
|
|
3830
|
-
after: {
|
|
3831
|
-
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3832
|
-
target: "bootstrap_required",
|
|
3833
|
-
actions: [
|
|
3834
|
-
assign({ error: () => timeoutError2("completing_bootstrap") }),
|
|
3835
|
-
"trackTimeoutFailed"
|
|
3836
|
-
]
|
|
3837
|
-
}
|
|
3838
|
-
}
|
|
3839
|
-
},
|
|
3840
|
-
authenticated: {
|
|
3841
|
-
on: {
|
|
3842
|
-
SIGN_OUT: { target: "signing_out" }
|
|
3843
|
-
}
|
|
3844
|
-
},
|
|
3845
|
-
signing_out: {
|
|
3846
|
-
invoke: {
|
|
3847
|
-
src: "signOut",
|
|
3848
|
-
onDone: {
|
|
3849
|
-
target: "email",
|
|
3850
|
-
actions: [
|
|
3851
|
-
assign(() => initialContext),
|
|
3852
|
-
"trackSignedOut"
|
|
3853
|
-
]
|
|
3854
|
-
},
|
|
3855
|
-
onError: {
|
|
3856
|
-
target: "error",
|
|
3857
|
-
actions: assign({ error: ({ event }) => errorFromEvent2(event) })
|
|
3858
|
-
}
|
|
3859
|
-
}
|
|
3860
|
-
},
|
|
3861
|
-
error: {
|
|
3862
|
-
on: {
|
|
3863
|
-
RESET: { target: "email", actions: assign(() => initialContext) }
|
|
3864
|
-
}
|
|
3865
|
-
}
|
|
3866
|
-
}
|
|
3867
|
-
});
|
|
3868
|
-
}
|
|
3869
|
-
function requireEmail2(context) {
|
|
3870
|
-
if (!context.email) {
|
|
3871
|
-
throw Errors.invalidInput("email", "Auth bootstrap requires an email.");
|
|
3872
|
-
}
|
|
3873
|
-
return context.email;
|
|
3874
|
-
}
|
|
3875
|
-
function requireCode(context) {
|
|
3876
|
-
if (!context.code) {
|
|
3877
|
-
throw Errors.invalidInput("code", "Auth bootstrap requires an OTP code.");
|
|
3878
|
-
}
|
|
3879
|
-
return context.code;
|
|
3880
|
-
}
|
|
3881
|
-
function requireBootstrapToken(context) {
|
|
3882
|
-
if (!context.bootstrapToken) {
|
|
3883
|
-
throw Errors.invalidInput(
|
|
3884
|
-
"bootstrapToken",
|
|
3885
|
-
"Auth bootstrap requires a continuation token."
|
|
3886
|
-
);
|
|
3887
|
-
}
|
|
3888
|
-
return context.bootstrapToken;
|
|
3889
|
-
}
|
|
3890
|
-
function requireUsername(context) {
|
|
3891
|
-
if (!context.username) {
|
|
3892
|
-
throw Errors.invalidInput("username", "Auth bootstrap requires a username.");
|
|
3893
|
-
}
|
|
3894
|
-
return context.username;
|
|
3895
|
-
}
|
|
3896
|
-
function errorFromEvent2(event) {
|
|
3897
|
-
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
3898
|
-
if (cause instanceof CapxulError || cause instanceof CapxulError2) {
|
|
3899
|
-
return cause;
|
|
3900
|
-
}
|
|
3901
|
-
return Errors.providerError("auth", "bootstrap", cause);
|
|
3902
|
-
}
|
|
3903
|
-
function timeoutError2(state) {
|
|
3904
|
-
return Errors.providerError(
|
|
3905
|
-
"auth",
|
|
3906
|
-
"bootstrap",
|
|
3907
|
-
new Error(`timeout: ${state} exceeded ${FLOW_INVOKE_TIMEOUT_MS}ms`)
|
|
3908
|
-
);
|
|
3909
|
-
}
|
|
3910
|
-
function emailDomain2(email) {
|
|
3911
|
-
const domain = email.split("@")[1]?.trim().toLowerCase();
|
|
3912
|
-
return domain || "unknown";
|
|
3913
|
-
}
|
|
3914
3634
|
function createProvisioningMachine(client) {
|
|
3915
3635
|
return setup({
|
|
3916
3636
|
types: {},
|
|
@@ -3938,7 +3658,7 @@ function createProvisioningMachine(client) {
|
|
|
3938
3658
|
const provider = context.input?.signerProvider;
|
|
3939
3659
|
if (!provider) return;
|
|
3940
3660
|
track("provisioning_safe_created", {
|
|
3941
|
-
safe_address:
|
|
3661
|
+
safe_address: deriveSafeAddress2(provider.signerAddress)
|
|
3942
3662
|
});
|
|
3943
3663
|
}
|
|
3944
3664
|
}
|
|
@@ -3983,13 +3703,13 @@ function createProvisioningMachine(client) {
|
|
|
3983
3703
|
},
|
|
3984
3704
|
onError: {
|
|
3985
3705
|
target: "error",
|
|
3986
|
-
actions: assign({ error: ({ event }) =>
|
|
3706
|
+
actions: assign({ error: ({ event }) => errorFromEvent(event) })
|
|
3987
3707
|
}
|
|
3988
3708
|
},
|
|
3989
3709
|
after: {
|
|
3990
3710
|
[FLOW_INVOKE_TIMEOUT_MS]: {
|
|
3991
3711
|
target: "error",
|
|
3992
|
-
actions: assign({ error: () =>
|
|
3712
|
+
actions: assign({ error: () => timeoutError() })
|
|
3993
3713
|
}
|
|
3994
3714
|
}
|
|
3995
3715
|
},
|
|
@@ -4007,7 +3727,7 @@ function createProvisioningMachine(client) {
|
|
|
4007
3727
|
* this payload on its `onDone` transition and branches via guards
|
|
4008
3728
|
* on `event.output.error`.
|
|
4009
3729
|
*/
|
|
4010
|
-
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error:
|
|
3730
|
+
output: ({ context }) => context.error ? { error: context.error } : context.account ? { account: context.account } : { error: timeoutError() }
|
|
4011
3731
|
});
|
|
4012
3732
|
}
|
|
4013
3733
|
function requireProvisionInput(context) {
|
|
@@ -4019,13 +3739,13 @@ function requireProvisionInput(context) {
|
|
|
4019
3739
|
}
|
|
4020
3740
|
return context.input;
|
|
4021
3741
|
}
|
|
4022
|
-
function
|
|
3742
|
+
function errorFromEvent(event) {
|
|
4023
3743
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
4024
3744
|
if (cause instanceof CapxulError) return cause;
|
|
4025
3745
|
if (cause instanceof CapxulError2) return cause;
|
|
4026
3746
|
return Errors.providerError("provisioning", "flow", cause);
|
|
4027
3747
|
}
|
|
4028
|
-
function
|
|
3748
|
+
function timeoutError() {
|
|
4029
3749
|
return Errors.providerError(
|
|
4030
3750
|
"provisioning",
|
|
4031
3751
|
"flow",
|
|
@@ -4118,7 +3838,7 @@ function createOnboardingFlowMachine(client) {
|
|
|
4118
3838
|
error: ({ event }) => extractChildErrorOrFallback(event)
|
|
4119
3839
|
}),
|
|
4120
3840
|
assignChildThrown: assign({
|
|
4121
|
-
error: ({ event }) =>
|
|
3841
|
+
error: ({ event }) => errorFromEvent2(event)
|
|
4122
3842
|
}),
|
|
4123
3843
|
assignAccountFromChild: assign({
|
|
4124
3844
|
account: ({ event }) => extractChildAccountOrNull(event)
|
|
@@ -4280,7 +4000,7 @@ function extractChildAccountOrNull(event) {
|
|
|
4280
4000
|
if (output && "account" in output && output.account) return output.account;
|
|
4281
4001
|
return null;
|
|
4282
4002
|
}
|
|
4283
|
-
function
|
|
4003
|
+
function errorFromEvent2(event) {
|
|
4284
4004
|
const cause = typeof event === "object" && event !== null && "error" in event ? event.error : event;
|
|
4285
4005
|
if (cause instanceof CapxulError) return cause;
|
|
4286
4006
|
if (cause instanceof CapxulError2) return cause;
|
|
@@ -4291,7 +4011,7 @@ function errorFromEvent4(event) {
|
|
|
4291
4011
|
function createCapxulClient(config = {}) {
|
|
4292
4012
|
const clientWithoutFlows = {
|
|
4293
4013
|
id: crypto.randomUUID(),
|
|
4294
|
-
auth:
|
|
4014
|
+
auth: new AuthService(config),
|
|
4295
4015
|
me: createMeClient(config),
|
|
4296
4016
|
accounts: createAccountsClient(config),
|
|
4297
4017
|
organizations: createOrganizationsClient(config),
|
|
@@ -4299,7 +4019,7 @@ function createCapxulClient(config = {}) {
|
|
|
4299
4019
|
transfers: createTransfersClient(),
|
|
4300
4020
|
tokenTransfers: createTokenTransfersClient(config),
|
|
4301
4021
|
withdrawals: createWithdrawalsClient(config),
|
|
4302
|
-
documents: createDocumentsClient(),
|
|
4022
|
+
documents: createDocumentsClient(config),
|
|
4303
4023
|
subAccounts: createSubAccountsClient(config),
|
|
4304
4024
|
virtualAccounts: createVirtualAccountsClient(),
|
|
4305
4025
|
virtualCards: createVirtualCardsClient(),
|
|
@@ -4311,8 +4031,6 @@ function createCapxulClient(config = {}) {
|
|
|
4311
4031
|
};
|
|
4312
4032
|
const client = clientWithoutFlows;
|
|
4313
4033
|
client.flows = {
|
|
4314
|
-
auth: () => createAuthFlowMachine(client),
|
|
4315
|
-
authBootstrap: () => createAuthBootstrapFlowMachine(client),
|
|
4316
4034
|
onboarding: () => createOnboardingFlowMachine(client),
|
|
4317
4035
|
provisioning: () => createProvisioningMachine(client)
|
|
4318
4036
|
};
|