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