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