@capxul/sdk 2.1.1 → 2.3.0
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/README.md +24 -0
- package/dist/{InMemoryAuthCacheAdapter-Rc8tCtml.mjs → InMemoryAuthCacheAdapter-qMpBOGb3.mjs} +15 -2
- package/dist/{create-capxul-client-CPhTPz_9.mjs → create-capxul-client-mArFr_Os.mjs} +675 -532
- package/dist/index.d.mts +25 -64
- package/dist/index.mjs +260 -103
- package/dist/node/index.d.mts +1 -1
- package/dist/node/index.mjs +1 -1
- package/dist/{create-capxul-client-BI-6Za6X.d.mts → observation-Ci8gIQjm.d.mts} +193 -20
- package/dist/{signer-Bj4F-RwT.d.mts → signer-BejoR3bA.d.mts} +116 -1
- package/dist/testing/index.d.mts +3 -1
- package/dist/testing/index.mjs +4 -3
- package/package.json +5 -5
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { concat, encodeAbiParameters, encodeFunctionData, encodePacked, formatUnits, getContractAddress, keccak256, padHex, parseUnits, stringToHex, toBytes, toEventSelector, toFunctionSelector, toFunctionSignature } from "viem";
|
|
1
|
+
import { A as toPartyId, I as CapxulError, L as EXPECTED_OPERATION_OUTCOMES, M as toRoleKey, R as Errors, S as toCurrencyCode, b as toChainId, c as BYTES32_RE, d as WEI_RE, f as ZERO_BYTES32, h as toAddress, k as toOrgId, l as EVM_ADDRESS_RE$1, m as toAccountId, n as BrowserAuthCacheAdapter, s as APP_ID_RE, t as InMemoryAuthCacheAdapter, u as SUPPORTED_CURRENCY_CODES, v as toAuthUserId, w as toEmail, x as toCountryCode, y as toBudgetId, z as isCapxulError } from "./InMemoryAuthCacheAdapter-qMpBOGb3.mjs";
|
|
2
|
+
import { concat, encodeAbiParameters, encodeFunctionData, encodePacked, formatUnits, getContractAddress, keccak256, padHex, parseUnits, recoverAddress, stringToHex, toBytes, toEventSelector, toFunctionSelector, toFunctionSignature } from "viem";
|
|
3
3
|
import { Context, Data, Deferred, Effect, Exit, Fiber, Layer, Queue, Ref, Result, Schema, SchemaGetter, Scope } from "effect";
|
|
4
4
|
import { makeFunctionReference } from "convex/server";
|
|
5
5
|
//#region src/domain/identity/model.ts
|
|
@@ -14,6 +14,8 @@ const isRetryable = (failure) => {
|
|
|
14
14
|
return failure.code === "NETWORK_ERROR" || failure.code === "UNKNOWN";
|
|
15
15
|
};
|
|
16
16
|
const SIGNED_OUT = { phase: "signed_out" };
|
|
17
|
+
/** Where every client starts. `SessionRestored` / `SessionAbsent` settle it. */
|
|
18
|
+
const RESTORING = { phase: "restoring" };
|
|
17
19
|
const label = (state) => {
|
|
18
20
|
if (state.phase !== "authenticated") return state.phase;
|
|
19
21
|
if (state.account.at !== "claimed") return `authenticated:${state.account.at}`;
|
|
@@ -28,6 +30,8 @@ const EVENT_TAGS = [
|
|
|
28
30
|
"RestoreSession",
|
|
29
31
|
"ResumeOtpEntry",
|
|
30
32
|
"Reset",
|
|
33
|
+
"SessionRestored",
|
|
34
|
+
"SessionAbsent",
|
|
31
35
|
"EnsureAccount",
|
|
32
36
|
"ClaimAccount",
|
|
33
37
|
"RetryAccount",
|
|
@@ -62,6 +66,13 @@ const SESSION_EVENTS = [
|
|
|
62
66
|
"Reset"
|
|
63
67
|
];
|
|
64
68
|
const TRANSITION_TABLE = {
|
|
69
|
+
restoring: [
|
|
70
|
+
"SessionRestored",
|
|
71
|
+
"SessionAbsent",
|
|
72
|
+
"ReadSession",
|
|
73
|
+
"RequestOtp",
|
|
74
|
+
"Reset"
|
|
75
|
+
],
|
|
65
76
|
signed_out: [
|
|
66
77
|
"RequestOtp",
|
|
67
78
|
"ReadSession",
|
|
@@ -253,6 +264,8 @@ const transition = (state, event, config = DEFAULT_CONFIG) => {
|
|
|
253
264
|
requestedAt: state.resume.requestedAt
|
|
254
265
|
} };
|
|
255
266
|
case "Reset": return { next: SIGNED_OUT };
|
|
267
|
+
case "SessionRestored": return { next: authenticated(event.session, event.profileComplete, { at: "unknown" }) };
|
|
268
|
+
case "SessionAbsent": return { next: SIGNED_OUT };
|
|
256
269
|
case "EnsureAccount":
|
|
257
270
|
if (config.requirement === "none") return WRONG;
|
|
258
271
|
return state.phase === "authenticated" ? { next: withAccount(state, {
|
|
@@ -320,6 +333,7 @@ const isPrivate = (event) => PRIVATE_TAGS.has(event._tag);
|
|
|
320
333
|
* there is no org list in the state, only the ONE active lane.
|
|
321
334
|
*/
|
|
322
335
|
const destination = (state) => {
|
|
336
|
+
if (state.phase === "restoring") return null;
|
|
323
337
|
if (state.phase !== "authenticated") return { to: "home" };
|
|
324
338
|
if (!state.profileComplete) return { to: "selectUserType" };
|
|
325
339
|
if (state.account.at === "unknown") return null;
|
|
@@ -339,6 +353,33 @@ const destination = (state) => {
|
|
|
339
353
|
orgId: org.at === "creating" ? null : org.orgId
|
|
340
354
|
};
|
|
341
355
|
};
|
|
356
|
+
/**
|
|
357
|
+
* True while the machine has not settled enough to route or to gate on.
|
|
358
|
+
*
|
|
359
|
+
* NEGATIVE classification, deliberately: the SETTLED positions are the ones
|
|
360
|
+
* enumerated, and everything else waits. A phase or readiness variant added
|
|
361
|
+
* later therefore defaults to holding, never to redirecting a member who is in
|
|
362
|
+
* fact signed in. Terminal for the account lane is `claimed | failed`.
|
|
363
|
+
*
|
|
364
|
+
* The org lane's own settledness (`ready | failed`) is the route gate's
|
|
365
|
+
* question, not this one: every org lane sits under a CLAIMED account, and
|
|
366
|
+
* `destination()` already names a real screen for each of its positions.
|
|
367
|
+
*/
|
|
368
|
+
const isRestoring = (state) => {
|
|
369
|
+
switch (state.phase) {
|
|
370
|
+
case "signed_out":
|
|
371
|
+
case "otp_sending":
|
|
372
|
+
case "otp_pending":
|
|
373
|
+
case "otp_verifying":
|
|
374
|
+
case "signing_out":
|
|
375
|
+
case "faulted": return false;
|
|
376
|
+
case "authenticated": return state.account.at !== "claimed" && state.account.at !== "failed";
|
|
377
|
+
default: return true;
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
/** The claimed-account gate as one function. The inlined consumers move onto
|
|
381
|
+
* it in #1521; this ticket ships the selector they move onto. */
|
|
382
|
+
const isClaimed = (state) => state.phase === "authenticated" && state.account.at === "claimed";
|
|
342
383
|
//#endregion
|
|
343
384
|
//#region ../config/src/tokens.ts
|
|
344
385
|
/** `TestUSDC` ("USDX") — Base Sepolia, 6 decimals, open `mint`. (Canon §1.) */
|
|
@@ -1209,48 +1250,7 @@ const USDX_BASE_SEPOLIA_TOKEN = {
|
|
|
1209
1250
|
};
|
|
1210
1251
|
USDX_BASE_SEPOLIA_TOKEN.chainId;
|
|
1211
1252
|
USDX_BASE_SEPOLIA_TOKEN.chainId;
|
|
1212
|
-
|
|
1213
|
-
//#region ../config/src/role-dsl.ts
|
|
1214
|
-
const USD_DECIMALS = 6;
|
|
1215
|
-
const USD_SCALE = 10n ** BigInt(USD_DECIMALS);
|
|
1216
|
-
const USD_DISPLAY_RE = /^\d+(?:\.\d{1,6})?$/;
|
|
1217
|
-
const USD_BASE_UNIT_RE = /^\d+$/;
|
|
1218
|
-
const EXEC_TRANSACTION_WITH_ROLE = "zodiac.roles.execTransactionWithRole";
|
|
1219
|
-
const ASSIGN_ROLES = "zodiac.roles.assignRoles";
|
|
1220
|
-
const SCOPE_TARGET = "zodiac.roles.scopeTarget";
|
|
1221
|
-
const OWNER_ROLE_LABEL = "Owner";
|
|
1222
|
-
const FOUNDER_BUDGET_ROLE_LABEL = "Founder Budget";
|
|
1223
|
-
const FOUNDER_BUDGET_LIMIT = {
|
|
1224
|
-
currency: "USD",
|
|
1225
|
-
value: "1000000000000",
|
|
1226
|
-
decimals: 6
|
|
1227
|
-
};
|
|
1228
|
-
function usd(value) {
|
|
1229
|
-
return {
|
|
1230
|
-
currency: "USD",
|
|
1231
|
-
value: usdDisplayToBaseUnits(value),
|
|
1232
|
-
decimals: USD_DECIMALS
|
|
1233
|
-
};
|
|
1234
|
-
}
|
|
1235
|
-
function usdDisplayToBaseUnits(value) {
|
|
1236
|
-
if (value.trim() !== value || !USD_DISPLAY_RE.test(value)) throw Errors.invalidInput("role.spend", "USD caps must be unsigned decimal strings with at most 6 fractional digits");
|
|
1237
|
-
const parts = value.split(".");
|
|
1238
|
-
const whole = parts[0] ?? "0";
|
|
1239
|
-
const fraction = parts[1] ?? "";
|
|
1240
|
-
return (BigInt(whole) * USD_SCALE + BigInt(fraction.padEnd(USD_DECIMALS, "0"))).toString();
|
|
1241
|
-
}
|
|
1242
|
-
function normalizeOrgRoleMoney(money, field) {
|
|
1243
|
-
if (money.currency !== "USD" || money.decimals !== USD_DECIMALS || !USD_BASE_UNIT_RE.test(money.value)) throw Errors.invalidInput(field, `must be USD base units with ${USD_DECIMALS} decimals`);
|
|
1244
|
-
return money;
|
|
1245
|
-
}
|
|
1246
|
-
function normalizeOrgRoleSpendCap(spend) {
|
|
1247
|
-
if (spend === void 0) return void 0;
|
|
1248
|
-
return {
|
|
1249
|
-
...spend.perTx === void 0 ? {} : { perTx: normalizeOrgRoleMoney(spend.perTx, "roles.spend.perTx") },
|
|
1250
|
-
...spend.perDay === void 0 ? {} : { perDay: normalizeOrgRoleMoney(spend.perDay, "roles.spend.perDay") },
|
|
1251
|
-
...spend.toRecipients === void 0 ? {} : { toRecipients: spend.toRecipients }
|
|
1252
|
-
};
|
|
1253
|
-
}
|
|
1253
|
+
10n ** BigInt(6);
|
|
1254
1254
|
function normalizeOrgRoleLabel(label) {
|
|
1255
1255
|
const normalized = label.trim().replace(/\s+/g, " ");
|
|
1256
1256
|
if (normalized.length === 0) throw Errors.invalidInput("role.label", "must be a non-empty role label");
|
|
@@ -1259,84 +1259,6 @@ function normalizeOrgRoleLabel(label) {
|
|
|
1259
1259
|
function orgRoleKeyForLabel(label) {
|
|
1260
1260
|
return keccak256(toBytes(normalizeOrgRoleLabel(label).toLowerCase()));
|
|
1261
1261
|
}
|
|
1262
|
-
function soloOrgRoleTemplate() {
|
|
1263
|
-
return [{
|
|
1264
|
-
label: "Owner",
|
|
1265
|
-
canManageMembers: true,
|
|
1266
|
-
canManageRoles: true
|
|
1267
|
-
}, {
|
|
1268
|
-
label: FOUNDER_BUDGET_ROLE_LABEL,
|
|
1269
|
-
spend: {
|
|
1270
|
-
perTx: FOUNDER_BUDGET_LIMIT,
|
|
1271
|
-
perDay: FOUNDER_BUDGET_LIMIT,
|
|
1272
|
-
toRecipients: "anyone"
|
|
1273
|
-
}
|
|
1274
|
-
}];
|
|
1275
|
-
}
|
|
1276
|
-
function startupOrgRoleTemplate() {
|
|
1277
|
-
return [
|
|
1278
|
-
...soloOrgRoleTemplate(),
|
|
1279
|
-
{
|
|
1280
|
-
label: "Finance Manager",
|
|
1281
|
-
spend: {
|
|
1282
|
-
perTx: usd("25000"),
|
|
1283
|
-
perDay: usd("100000"),
|
|
1284
|
-
toRecipients: "anyone"
|
|
1285
|
-
}
|
|
1286
|
-
},
|
|
1287
|
-
{
|
|
1288
|
-
label: "Team Lead",
|
|
1289
|
-
spend: {
|
|
1290
|
-
perTx: usd("5000"),
|
|
1291
|
-
perDay: usd("15000"),
|
|
1292
|
-
toRecipients: "anyone"
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
];
|
|
1296
|
-
}
|
|
1297
|
-
function orgRoleTemplateDefinitions(template, customRoles = []) {
|
|
1298
|
-
switch (template) {
|
|
1299
|
-
case "Solo": return soloOrgRoleTemplate();
|
|
1300
|
-
case "Startup": return startupOrgRoleTemplate();
|
|
1301
|
-
case "Custom": return customRoles.length === 0 ? soloOrgRoleTemplate() : customRoles;
|
|
1302
|
-
default: return template;
|
|
1303
|
-
}
|
|
1304
|
-
}
|
|
1305
|
-
function compileOrgRoleDefinitions(definitions) {
|
|
1306
|
-
if (definitions.length === 0) throw Errors.invalidInput("roles", "must include at least one role");
|
|
1307
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1308
|
-
const roles = definitions.map((definition) => {
|
|
1309
|
-
const label = normalizeOrgRoleLabel(definition.label);
|
|
1310
|
-
const roleKey = orgRoleKeyForLabel(label);
|
|
1311
|
-
if (seen.has(roleKey)) throw Errors.invalidInput("roles", `duplicate role label: ${label}`);
|
|
1312
|
-
seen.add(roleKey);
|
|
1313
|
-
const spend = normalizeOrgRoleSpendCap(definition.spend);
|
|
1314
|
-
const permissions = [];
|
|
1315
|
-
if (spend !== void 0 || label === OWNER_ROLE_LABEL) permissions.push(EXEC_TRANSACTION_WITH_ROLE);
|
|
1316
|
-
if (definition.canManageMembers === true) permissions.push(ASSIGN_ROLES);
|
|
1317
|
-
if (definition.canManageRoles === true) permissions.push(SCOPE_TARGET);
|
|
1318
|
-
return {
|
|
1319
|
-
label,
|
|
1320
|
-
roleKey,
|
|
1321
|
-
definition: {
|
|
1322
|
-
...definition,
|
|
1323
|
-
label,
|
|
1324
|
-
...spend === void 0 ? {} : { spend }
|
|
1325
|
-
},
|
|
1326
|
-
permissions,
|
|
1327
|
-
allowance: spend ?? null
|
|
1328
|
-
};
|
|
1329
|
-
});
|
|
1330
|
-
const manager = roles.find((role) => role.definition.canManageMembers === true);
|
|
1331
|
-
if (manager === void 0) throw Errors.invalidInput("roles.canManageMembers", "at least one role must compile to the on-chain member-management permission");
|
|
1332
|
-
return {
|
|
1333
|
-
roles,
|
|
1334
|
-
memberManagementRole: {
|
|
1335
|
-
roleKey: manager.roleKey,
|
|
1336
|
-
permission: ASSIGN_ROLES
|
|
1337
|
-
}
|
|
1338
|
-
};
|
|
1339
|
-
}
|
|
1340
1262
|
padHex(stringToHex("FM_DAILY"), {
|
|
1341
1263
|
size: 32,
|
|
1342
1264
|
dir: "right"
|
|
@@ -1369,86 +1291,24 @@ new Map([
|
|
|
1369
1291
|
["setAllowance(bytes32,uint128,uint128,uint128,uint64,uint64)", "SetAllowance(bytes32,uint128,uint128,uint128,uint64,uint64)"]
|
|
1370
1292
|
].map(([functionSignature, eventSignature]) => [toFunctionSelector(functionSignature), toEventSelector(eventSignature)]));
|
|
1371
1293
|
//#endregion
|
|
1372
|
-
//#region src/
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
* `at new ClassName (url:line:col)`
|
|
1380
|
-
*/
|
|
1381
|
-
const V8_FRAME_RE = /^\s*at\s+(?:(.+?)\s+\()?(?:(.+?)(?::(\d+):(\d+))?|(.+?))\)?\s*$/;
|
|
1382
|
-
function isNonUrlName(name) {
|
|
1383
|
-
return name === "<anonymous>" || name.startsWith("eval") || name.startsWith("new ") || name.startsWith("async ");
|
|
1294
|
+
//#region src/surface/_shared/provisioning-telemetry.ts
|
|
1295
|
+
async function emitProvisioningTelemetry(telemetry, smartAccount) {
|
|
1296
|
+
if (telemetry === void 0) return;
|
|
1297
|
+
await Effect.runPromise(telemetry.emit({
|
|
1298
|
+
name: "provisioning_safe_created",
|
|
1299
|
+
props: { safe_address: smartAccount.smartAccountAddress }
|
|
1300
|
+
}).pipe(Effect.catch((cause) => Effect.sync(() => reportProvisioningTelemetryFailure("error", smartAccount, cause))), Effect.catchDefect((cause) => Effect.sync(() => reportProvisioningTelemetryFailure("defect", smartAccount, cause)))));
|
|
1384
1301
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
* - `at async functionName (url:line:col)`
|
|
1393
|
-
* - `at new ClassName (url:line:col)`
|
|
1394
|
-
* - Native frames: `at Array.forEach (<anonymous>)`
|
|
1395
|
-
*/
|
|
1396
|
-
function parseV8StackFrames(error) {
|
|
1397
|
-
const stack = error.stack;
|
|
1398
|
-
if (stack === void 0 || stack === null || stack === "") return [];
|
|
1399
|
-
const lines = stack.split("\n");
|
|
1400
|
-
const frames = [];
|
|
1401
|
-
for (const line of lines) {
|
|
1402
|
-
const trimmed = line.trim();
|
|
1403
|
-
if (!trimmed.startsWith("at ")) continue;
|
|
1404
|
-
const match = V8_FRAME_RE.exec(trimmed);
|
|
1405
|
-
if (match === null) continue;
|
|
1406
|
-
if (match[1] !== void 0) frames.push({
|
|
1407
|
-
function: match[1],
|
|
1408
|
-
filename: match[2],
|
|
1409
|
-
lineno: match[3] !== void 0 ? Number(match[3]) : null,
|
|
1410
|
-
colno: match[4] !== void 0 ? Number(match[4]) : null
|
|
1411
|
-
});
|
|
1412
|
-
else if (match[2] !== void 0 && !isNonUrlName(match[2])) frames.push({
|
|
1413
|
-
function: "<anonymous>",
|
|
1414
|
-
filename: match[2],
|
|
1415
|
-
lineno: match[3] !== void 0 ? Number(match[3]) : null,
|
|
1416
|
-
colno: match[4] !== void 0 ? Number(match[4]) : null
|
|
1417
|
-
});
|
|
1418
|
-
else frames.push({
|
|
1419
|
-
function: match[1] ?? match[2] ?? match[5] ?? "<anonymous>",
|
|
1420
|
-
filename: match[2] ?? match[5] ?? "<anonymous>",
|
|
1421
|
-
lineno: match[3] !== void 0 ? Number(match[3]) : null,
|
|
1422
|
-
colno: match[4] !== void 0 ? Number(match[4]) : null
|
|
1423
|
-
});
|
|
1424
|
-
}
|
|
1425
|
-
return frames;
|
|
1302
|
+
function reportProvisioningTelemetryFailure(kind, smartAccount, cause) {
|
|
1303
|
+
if (!isProvisioningTelemetryDebugEnabled()) return;
|
|
1304
|
+
globalThis.console?.warn?.("[capxul] provisioning telemetry dropped", {
|
|
1305
|
+
kind,
|
|
1306
|
+
safeAddress: smartAccount.smartAccountAddress,
|
|
1307
|
+
cause
|
|
1308
|
+
});
|
|
1426
1309
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
/**
|
|
1430
|
-
* Build PostHog's `$exception_list` (always a single entry). Error Tracking
|
|
1431
|
-
* groups on `type`, so it is ALWAYS present (the CapxulError code) — the
|
|
1432
|
-
* previous `[{ frames }]` shape omitted it and PostHog dropped the event as
|
|
1433
|
-
* "missing field `type`". When the error has no parseable stack, a synthetic
|
|
1434
|
-
* boundary frame stands in so the event still ingests as a real Issue (#1031).
|
|
1435
|
-
*/
|
|
1436
|
-
function buildExceptionList(input) {
|
|
1437
|
-
const frames = input.frames.length > 0 ? input.frames : [{
|
|
1438
|
-
filename: SDK_BOUNDARY_FILENAME,
|
|
1439
|
-
function: input.operation ?? "unknown",
|
|
1440
|
-
lineno: 1,
|
|
1441
|
-
colno: 1
|
|
1442
|
-
}];
|
|
1443
|
-
return [{
|
|
1444
|
-
type: input.type,
|
|
1445
|
-
value: input.value,
|
|
1446
|
-
mechanism: {
|
|
1447
|
-
handled: true,
|
|
1448
|
-
type: "capxul_sdk_boundary"
|
|
1449
|
-
},
|
|
1450
|
-
stacktrace: { frames }
|
|
1451
|
-
}];
|
|
1310
|
+
function isProvisioningTelemetryDebugEnabled() {
|
|
1311
|
+
return globalThis.process?.env?.CAPXUL_DEBUG_TELEMETRY === "1";
|
|
1452
1312
|
}
|
|
1453
1313
|
//#endregion
|
|
1454
1314
|
//#region src/telemetry/get-failure-mode.ts
|
|
@@ -1498,77 +1358,94 @@ function resolveFailureMode(error, contextFailureMode) {
|
|
|
1498
1358
|
return getFailureMode(error) ?? (isFailureMode(contextFailureMode) ? contextFailureMode : "unknown");
|
|
1499
1359
|
}
|
|
1500
1360
|
//#endregion
|
|
1501
|
-
//#region src/
|
|
1502
|
-
|
|
1503
|
-
const
|
|
1361
|
+
//#region src/signer.ts
|
|
1362
|
+
const EVM_ADDRESS_HEX = /^0x[0-9a-fA-F]{40}$/;
|
|
1363
|
+
const ECDSA_SIGNATURE_HEX = /^0x[0-9a-fA-F]{130}$/;
|
|
1364
|
+
const SAFE_OP_DIGEST_HEX = /^0x[0-9a-fA-F]{64}$/;
|
|
1504
1365
|
/**
|
|
1505
|
-
*
|
|
1506
|
-
*
|
|
1507
|
-
*
|
|
1508
|
-
* Parses stack traces into `$exception_list` format, extracts structured
|
|
1509
|
-
* metadata from CapxulError objects, and supplements with context props.
|
|
1510
|
-
* Fire-and-forget: telemetry defects are silently swallowed.
|
|
1511
|
-
* Returns `Effect<void, never>` for use in Effect pipelines; the underlying
|
|
1512
|
-
* adapter work is synchronous, so callers outside Effect contexts can
|
|
1513
|
-
* use `Effect.runSync`.
|
|
1366
|
+
* The readiness store a signer reports when it runs no readiness cycle. It
|
|
1367
|
+
* fails CLOSED: a node key signer or an injected wallet never claims `ready`,
|
|
1368
|
+
* so a gate that reads this never opens on a guess.
|
|
1514
1369
|
*/
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
const errorCode = capxulError?.code ?? context?.capxul_error_code ?? "UNKNOWN";
|
|
1520
|
-
const props = {
|
|
1521
|
-
capxul_error_code: errorCode,
|
|
1522
|
-
$exception_type: errorCode,
|
|
1523
|
-
$exception_message: EXCEPTION_MESSAGE,
|
|
1524
|
-
$exception_list: buildExceptionList({
|
|
1525
|
-
type: errorCode,
|
|
1526
|
-
value: EXCEPTION_MESSAGE,
|
|
1527
|
-
...context?.operation === void 0 ? {} : { operation: context.operation },
|
|
1528
|
-
frames
|
|
1529
|
-
}),
|
|
1530
|
-
layer: capxulError?.layer ?? context?.layer,
|
|
1531
|
-
operation: context?.operation,
|
|
1532
|
-
provider: context?.provider,
|
|
1533
|
-
failure_mode: resolveFailureMode(error, context?.failure_mode)
|
|
1534
|
-
};
|
|
1535
|
-
if (capxulError?.details !== void 0) props.details = JSON.stringify(capxulError.details);
|
|
1536
|
-
for (const key of Object.keys(props)) if (props[key] === void 0) delete props[key];
|
|
1537
|
-
return telemetry.emit({
|
|
1538
|
-
name: "$exception",
|
|
1539
|
-
props
|
|
1540
|
-
});
|
|
1541
|
-
}).pipe(Effect.flatten), () => Effect.void);
|
|
1542
|
-
}
|
|
1370
|
+
const UNOBSERVABLE_SIGNER_STATUS = {
|
|
1371
|
+
status: () => "unknown",
|
|
1372
|
+
subscribe: () => () => void 0
|
|
1373
|
+
};
|
|
1543
1374
|
/**
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
1546
|
-
* hooks before throwing) can report errors without awaiting.
|
|
1375
|
+
* Walk an error and its `cause` links once each. A self-referential chain
|
|
1376
|
+
* terminates. Both signer predicates read the chain, so they read it here.
|
|
1547
1377
|
*/
|
|
1548
|
-
function
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1378
|
+
function* causeChain(cause) {
|
|
1379
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1380
|
+
let current = cause;
|
|
1381
|
+
while (typeof current === "object" && current !== null && !seen.has(current)) {
|
|
1382
|
+
seen.add(current);
|
|
1383
|
+
yield current;
|
|
1384
|
+
current = current.cause;
|
|
1385
|
+
}
|
|
1552
1386
|
}
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1387
|
+
/** Fold a signer throw into the public error contract. */
|
|
1388
|
+
function signerFailure(source, operation, cause) {
|
|
1389
|
+
let failureMode;
|
|
1390
|
+
for (const link of causeChain(cause)) {
|
|
1391
|
+
if (link instanceof CapxulError && link.code === "SIGNER_REJECTED") return link;
|
|
1392
|
+
failureMode = getFailureMode(link) ?? failureMode;
|
|
1393
|
+
const error = link;
|
|
1394
|
+
if (error.code === 4001 || error.error === "passkey_user_cancelled") return Errors.signerRejected({
|
|
1395
|
+
source,
|
|
1396
|
+
cause
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
return Errors.providerError("signer", operation, cause, failureMode === void 0 ? void 0 : { failure_mode: failureMode });
|
|
1561
1400
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1401
|
+
/**
|
|
1402
|
+
* Browser `CapxulSigner` backed by an injected EIP-1193 wallet (MetaMask, etc.).
|
|
1403
|
+
* Signs the SafeOp digest via `eth_sign`, then verifies the returned signature
|
|
1404
|
+
* recovers the selected account against that raw digest. Wallets that prefix
|
|
1405
|
+
* `eth_sign` payloads are rejected before the backend submits an invalid SafeOp.
|
|
1406
|
+
* The node key signer lives in `@capxul/sdk/node` (`localPrivateKeySigner`).
|
|
1407
|
+
*/
|
|
1408
|
+
function injectedWalletSigner(provider) {
|
|
1409
|
+
const resolveAddress = async () => {
|
|
1410
|
+
const accounts = await provider.request({ method: "eth_requestAccounts" });
|
|
1411
|
+
const first = Array.isArray(accounts) ? accounts[0] : void 0;
|
|
1412
|
+
if (typeof first !== "string") throw new Error("injectedWalletSigner: wallet returned no accounts");
|
|
1413
|
+
if (!EVM_ADDRESS_HEX.test(first)) throw new Error("injectedWalletSigner: wallet returned invalid address format");
|
|
1414
|
+
return toAddress(first);
|
|
1415
|
+
};
|
|
1416
|
+
return {
|
|
1417
|
+
source: "injected-eip1193",
|
|
1418
|
+
getAddress: resolveAddress,
|
|
1419
|
+
async signUserOpHash(hash) {
|
|
1420
|
+
if (!SAFE_OP_DIGEST_HEX.test(hash)) throw new Error("injectedWalletSigner: SafeOp digest must be a 0x-prefixed 32-byte hex");
|
|
1421
|
+
const address = await resolveAddress();
|
|
1422
|
+
let signature;
|
|
1423
|
+
try {
|
|
1424
|
+
signature = await provider.request({
|
|
1425
|
+
method: "eth_sign",
|
|
1426
|
+
params: [address, hash]
|
|
1427
|
+
});
|
|
1428
|
+
} catch (cause) {
|
|
1429
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
1430
|
+
throw new Error(`injectedWalletSigner: eth_sign failed; enable raw-hash signing for deployment (${detail})`, { cause });
|
|
1431
|
+
}
|
|
1432
|
+
if (typeof signature !== "string") throw new Error("injectedWalletSigner: wallet returned a non-string signature");
|
|
1433
|
+
if (!ECDSA_SIGNATURE_HEX.test(signature)) throw new Error("injectedWalletSigner: wallet returned invalid signature format");
|
|
1434
|
+
if ((await recoverRawDigestSigner({
|
|
1435
|
+
hash,
|
|
1436
|
+
signature
|
|
1437
|
+
})).toLowerCase() !== address.toLowerCase()) throw new Error("injectedWalletSigner: wallet signature did not recover the selected account for the raw SafeOp digest; use a raw-hash-capable wallet or @capxul/sdk/node localPrivateKeySigner for deployed flows");
|
|
1438
|
+
return signature;
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1569
1441
|
}
|
|
1570
|
-
function
|
|
1571
|
-
|
|
1442
|
+
async function recoverRawDigestSigner(input) {
|
|
1443
|
+
try {
|
|
1444
|
+
return toAddress(await recoverAddress(input));
|
|
1445
|
+
} catch (cause) {
|
|
1446
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
1447
|
+
throw new Error(`injectedWalletSigner: could not verify raw SafeOp digest signature (${detail})`, { cause });
|
|
1448
|
+
}
|
|
1572
1449
|
}
|
|
1573
1450
|
//#endregion
|
|
1574
1451
|
//#region src/internal/invocation-observation.ts
|
|
@@ -2137,7 +2014,7 @@ const accountStatusProgram = Effect.gen(function* () {
|
|
|
2137
2014
|
};
|
|
2138
2015
|
const signerAddress = yield* Effect.tryPromise({
|
|
2139
2016
|
try: () => signer.getAddress(),
|
|
2140
|
-
catch: (cause) =>
|
|
2017
|
+
catch: (cause) => signerFailure(signer.source, "getAddress", cause)
|
|
2141
2018
|
});
|
|
2142
2019
|
return {
|
|
2143
2020
|
status: "accountProviderReady",
|
|
@@ -2473,7 +2350,8 @@ const CAPXUL_FUNCTIONS = {
|
|
|
2473
2350
|
listMembersByOrgId: "org/queries:listMembersByOrgId",
|
|
2474
2351
|
listMine: "org/queries:listMine",
|
|
2475
2352
|
listRolesByOrgId: "org/queries:listRolesByOrgId",
|
|
2476
|
-
loadByOrgId: "org/queries:loadByOrgId"
|
|
2353
|
+
loadByOrgId: "org/queries:loadByOrgId",
|
|
2354
|
+
me: "org/queries:me"
|
|
2477
2355
|
},
|
|
2478
2356
|
"smartAccount/actions": {
|
|
2479
2357
|
claim: "smartAccount/actions:claim",
|
|
@@ -2537,6 +2415,7 @@ const PAYMENT_ID_RE = /^payment_[0-9A-Za-z]+$/;
|
|
|
2537
2415
|
const PAYEE_ID_RE = /^payee_[0-9A-Za-z]+$/;
|
|
2538
2416
|
const ORG_ID_RE = /^org_[0-9A-Za-z]+$/;
|
|
2539
2417
|
const USER_ID_RE = /^user_[0-9A-Za-z]+$/;
|
|
2418
|
+
const PARTY_ID_RE = /^party_[0-9A-Za-z]+$/;
|
|
2540
2419
|
const HANDLE_RE = /^@?[a-z0-9][a-z0-9-]{2,31}$/;
|
|
2541
2420
|
const ORG_HANDLE_RE = /^[a-z0-9][a-z0-9-]{2,31}$/;
|
|
2542
2421
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
@@ -2545,6 +2424,7 @@ const PaymentIdSchema$1 = Schema.String.pipe(Schema.check(Schema.makeFilter((val
|
|
|
2545
2424
|
const PayeeIdSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((value) => PAYEE_ID_RE.test(value), { message: "must be payee_ plus an alphanumeric id" })));
|
|
2546
2425
|
const OrgIdSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((value) => ORG_ID_RE.test(value), { message: "must be org_ plus an alphanumeric id" })));
|
|
2547
2426
|
const UserIdSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((value) => USER_ID_RE.test(value), { message: "must be user_ plus an alphanumeric id" })));
|
|
2427
|
+
const PartyIdSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((value) => PARTY_ID_RE.test(value), { message: "must be party_ plus an alphanumeric id" })));
|
|
2548
2428
|
const DecimalStringSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((value) => DECIMAL_STRING_RE.test(value), { message: "must be a non-negative decimal string" })));
|
|
2549
2429
|
const HandleValueSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((value) => !EVM_ADDRESS_RE.test(value) && HANDLE_RE.test(value), { message: "must be a handle; raw addresses are not accepted" })));
|
|
2550
2430
|
const OrgHandleValueSchema = Schema.String.pipe(Schema.check(Schema.makeFilter((value) => !EVM_ADDRESS_RE.test(value) && ORG_HANDLE_RE.test(value), { message: "must be an org handle; raw addresses are not accepted" })));
|
|
@@ -2691,6 +2571,7 @@ const PaymentRecipient = Schema.Struct({
|
|
|
2691
2571
|
"capxulUserId",
|
|
2692
2572
|
"me",
|
|
2693
2573
|
"org",
|
|
2574
|
+
"party",
|
|
2694
2575
|
"external_address"
|
|
2695
2576
|
]),
|
|
2696
2577
|
label: Schema.String,
|
|
@@ -2737,6 +2618,10 @@ const PaymentRef = Schema.Union([
|
|
|
2737
2618
|
Schema.Struct({
|
|
2738
2619
|
kind: Schema.Literal("payeeId"),
|
|
2739
2620
|
payeeId: PayeeIdSchema
|
|
2621
|
+
}),
|
|
2622
|
+
Schema.Struct({
|
|
2623
|
+
kind: Schema.Literal("party"),
|
|
2624
|
+
partyId: PartyIdSchema
|
|
2740
2625
|
})
|
|
2741
2626
|
]);
|
|
2742
2627
|
const Payment = Schema.Struct({
|
|
@@ -4013,55 +3898,42 @@ function makeActorRelationshipMethods(deps) {
|
|
|
4013
3898
|
const fns = actorScopeContract;
|
|
4014
3899
|
return {
|
|
4015
3900
|
addressBook: {
|
|
4016
|
-
list: (options) => mapOk$1(awaitableConvex(options?.signal, "addressBook.list", () => convexCall.query(fns.addressBookList, {
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
},
|
|
3901
|
+
list: (input, options) => mapOk$1("addressBook.list", awaitableConvex(options?.signal, "addressBook.list", () => convexCall.query(fns.addressBookList, {
|
|
3902
|
+
actor,
|
|
3903
|
+
...input?.includeHidden === void 0 ? {} : { includeHidden: input.includeHidden }
|
|
3904
|
+
})), (entries) => entries.map(mapAddressBookEntry)),
|
|
3905
|
+
get: (entryId, options) => mapOk$1("addressBook.get", awaitableConvex(options?.signal, "addressBook.get", () => convexCall.query(fns.addressBookGet, {
|
|
3906
|
+
actor,
|
|
3907
|
+
partyId: entryId
|
|
3908
|
+
})), (entry) => entry === null ? null : mapAddressBookEntry(entry)),
|
|
4025
3909
|
add: async (input, options) => {
|
|
4026
3910
|
const ref = normalizeRefForBackend$1(input.ref, "ref");
|
|
4027
3911
|
if (!ref.ok) return ref;
|
|
4028
|
-
return mapOk$1(await awaitableConvex(options?.signal, "addressBook.add", () => convexCall.mutation(fns.addressBookAdd, {
|
|
3912
|
+
return mapOk$1("addressBook.add", await awaitableConvex(options?.signal, "addressBook.add", () => convexCall.mutation(fns.addressBookAdd, {
|
|
4029
3913
|
actor,
|
|
4030
3914
|
ref: ref.value,
|
|
4031
3915
|
...input.label === void 0 ? {} : { label: input.label }
|
|
4032
3916
|
})), mapAddressBookEntry);
|
|
4033
3917
|
},
|
|
4034
|
-
hide:
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
},
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
ref: ref.value
|
|
4048
|
-
})), mapAddressBookEntry);
|
|
4049
|
-
},
|
|
4050
|
-
label: async (input, options) => {
|
|
4051
|
-
const ref = refFromEntryId(input.entryId);
|
|
4052
|
-
if (!ref.ok) return ref;
|
|
4053
|
-
return mapOk$1(await awaitableConvex(options?.signal, "addressBook.label", () => convexCall.mutation(fns.addressBookLabel, {
|
|
4054
|
-
actor,
|
|
4055
|
-
ref: ref.value,
|
|
4056
|
-
label: input.label
|
|
4057
|
-
})), mapAddressBookEntry);
|
|
4058
|
-
}
|
|
3918
|
+
hide: (entryId, options) => mapOk$1("addressBook.hide", awaitableConvex(options?.signal, "addressBook.hide", () => convexCall.mutation(fns.addressBookHide, {
|
|
3919
|
+
actor,
|
|
3920
|
+
partyId: entryId
|
|
3921
|
+
})), mapAddressBookEntry),
|
|
3922
|
+
unhide: (entryId, options) => mapOk$1("addressBook.unhide", awaitableConvex(options?.signal, "addressBook.unhide", () => convexCall.mutation(fns.addressBookUnhide, {
|
|
3923
|
+
actor,
|
|
3924
|
+
partyId: entryId
|
|
3925
|
+
})), mapAddressBookEntry),
|
|
3926
|
+
label: (input, options) => mapOk$1("addressBook.label", awaitableConvex(options?.signal, "addressBook.label", () => convexCall.mutation(fns.addressBookLabel, {
|
|
3927
|
+
actor,
|
|
3928
|
+
partyId: input.entryId,
|
|
3929
|
+
label: input.label
|
|
3930
|
+
})), mapAddressBookEntry)
|
|
4059
3931
|
},
|
|
4060
3932
|
requests: {
|
|
4061
3933
|
issue: async (input, options) => {
|
|
4062
3934
|
const payer = normalizeRefForBackend$1(input.payer, "payer");
|
|
4063
3935
|
if (!payer.ok) return payer;
|
|
4064
|
-
return mapOk$1(await awaitableConvex(options?.signal, "requests.issue", () => convexCall.mutation(fns.requestsIssue, {
|
|
3936
|
+
return mapOk$1("requests.issue", await awaitableConvex(options?.signal, "requests.issue", () => convexCall.mutation(fns.requestsIssue, {
|
|
4065
3937
|
actor,
|
|
4066
3938
|
payer: payer.value,
|
|
4067
3939
|
amount: input.amount,
|
|
@@ -4070,18 +3942,18 @@ function makeActorRelationshipMethods(deps) {
|
|
|
4070
3942
|
...input.expiresAt === void 0 ? {} : { expiresAt: input.expiresAt }
|
|
4071
3943
|
})), (request) => mapActorRequest(request, input.payer));
|
|
4072
3944
|
},
|
|
4073
|
-
list: (options) => mapOk$1(awaitableConvex(options?.signal, "requests.list", () => convexCall.query(fns.requestsList, { actor })), (requests) => requests.map((request) => mapActorRequest(request))),
|
|
4074
|
-
get: (requestId, options) => mapOk$1(awaitableConvex(options?.signal, "requests.get", () => convexCall.query(fns.requestsGet, {
|
|
3945
|
+
list: (options) => mapOk$1("requests.list", awaitableConvex(options?.signal, "requests.list", () => convexCall.query(fns.requestsList, { actor })), (requests) => requests.map((request) => mapActorRequest(request))),
|
|
3946
|
+
get: (requestId, options) => mapOk$1("requests.get", awaitableConvex(options?.signal, "requests.get", () => convexCall.query(fns.requestsGet, {
|
|
4075
3947
|
actor,
|
|
4076
3948
|
paymentRequestId: requestId
|
|
4077
3949
|
})), (request) => request === null ? null : mapActorRequest(request)),
|
|
4078
|
-
cancel: (requestId, options) => mapOk$1(awaitableConvex(options?.signal, "requests.cancel", () => convexCall.mutation(fns.requestsCancel, {
|
|
3950
|
+
cancel: (requestId, options) => mapOk$1("requests.cancel", awaitableConvex(options?.signal, "requests.cancel", () => convexCall.mutation(fns.requestsCancel, {
|
|
4079
3951
|
actor,
|
|
4080
3952
|
paymentRequestId: requestId
|
|
4081
3953
|
})), (request) => mapActorRequest(request))
|
|
4082
3954
|
},
|
|
4083
3955
|
inbox: {
|
|
4084
|
-
list: (options) => mapOk$1(awaitableConvex(options?.signal, "inbox.list", () => convexCall.query(fns.inboxList, { actor })), (items) => items.map(mapInboxItem)),
|
|
3956
|
+
list: (options) => mapOk$1("inbox.list", awaitableConvex(options?.signal, "inbox.list", () => convexCall.query(fns.inboxList, { actor })), (items) => items.map(mapInboxItem)),
|
|
4085
3957
|
approve: async (input, options) => {
|
|
4086
3958
|
const result = await awaitableConvex(options?.signal, "inbox.approve", () => convexCall.mutation(fns.inboxApprove, {
|
|
4087
3959
|
actor,
|
|
@@ -4092,7 +3964,7 @@ function makeActorRelationshipMethods(deps) {
|
|
|
4092
3964
|
if (!result.ok) return result;
|
|
4093
3965
|
return mapApprovedInboxPayment(result.value, input);
|
|
4094
3966
|
},
|
|
4095
|
-
decline: (requestId, options) => mapOk$1(awaitableConvex(options?.signal, "inbox.decline", () => convexCall.mutation(fns.inboxDecline, {
|
|
3967
|
+
decline: (requestId, options) => mapOk$1("inbox.decline", awaitableConvex(options?.signal, "inbox.decline", () => convexCall.mutation(fns.inboxDecline, {
|
|
4096
3968
|
actor,
|
|
4097
3969
|
paymentRequestId: requestId
|
|
4098
3970
|
})), mapInboxItem)
|
|
@@ -4160,30 +4032,52 @@ function missingConvexCall(operation) {
|
|
|
4160
4032
|
error: Errors.providerError("convex", operation, "ConvexCallPort is required")
|
|
4161
4033
|
});
|
|
4162
4034
|
}
|
|
4163
|
-
|
|
4035
|
+
/**
|
|
4036
|
+
* Project a successful backend reply, WITHOUT leaving the result boundary.
|
|
4037
|
+
*
|
|
4038
|
+
* The projection can refuse: `mapAddressBookEntry` proves the entry id is a
|
|
4039
|
+
* `PartyId` rather than trusting the wire, and `toPartyId` throws on a
|
|
4040
|
+
* malformed one. Every verb on this surface returns `CapxulResult`, so that
|
|
4041
|
+
* throw has to become a value here — otherwise a malformed reply rejects the
|
|
4042
|
+
* promise and the caller's `if (!result.ok)` never runs (ADR-0023: errors are
|
|
4043
|
+
* values, and a code crosses the seam).
|
|
4044
|
+
*/
|
|
4045
|
+
async function mapOk$1(operation, resultOrPromise, f) {
|
|
4164
4046
|
const result = await resultOrPromise;
|
|
4165
4047
|
if (!result.ok) return result;
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4048
|
+
try {
|
|
4049
|
+
return {
|
|
4050
|
+
ok: true,
|
|
4051
|
+
value: f(result.value)
|
|
4052
|
+
};
|
|
4053
|
+
} catch (cause) {
|
|
4054
|
+
return {
|
|
4055
|
+
ok: false,
|
|
4056
|
+
error: cause instanceof CapxulError ? cause : Errors.providerError("convex", operation, cause)
|
|
4057
|
+
};
|
|
4058
|
+
}
|
|
4170
4059
|
}
|
|
4171
4060
|
const awaitableConvex = runIfActive;
|
|
4061
|
+
const ADDRESS_BOOK_RELATIONSHIPS = [
|
|
4062
|
+
"paid",
|
|
4063
|
+
"paidBy",
|
|
4064
|
+
"invoiced",
|
|
4065
|
+
"invoicedBy",
|
|
4066
|
+
"member",
|
|
4067
|
+
"manual",
|
|
4068
|
+
"employed"
|
|
4069
|
+
];
|
|
4070
|
+
function isAddressBookRelationship(value) {
|
|
4071
|
+
return ADDRESS_BOOK_RELATIONSHIPS.includes(value);
|
|
4072
|
+
}
|
|
4172
4073
|
function mapAddressBookEntry(entry) {
|
|
4173
|
-
const relationship = /* @__PURE__ */ new Set();
|
|
4174
|
-
for (const edge of entry.edges) {
|
|
4175
|
-
if (edge === "paid") relationship.add("paid");
|
|
4176
|
-
if (edge === "paidBy") relationship.add("paidBy");
|
|
4177
|
-
if (edge === "requested" || edge === "requestedBy") relationship.add("requested");
|
|
4178
|
-
if (edge === "member") relationship.add("member");
|
|
4179
|
-
if (edge === "employee") relationship.add("employee");
|
|
4180
|
-
}
|
|
4181
4074
|
return {
|
|
4182
|
-
id: entry.id,
|
|
4075
|
+
id: toPartyId(entry.id),
|
|
4183
4076
|
ref: entry.ref,
|
|
4184
|
-
label: entry.label
|
|
4185
|
-
relationship:
|
|
4186
|
-
hidden: entry.hidden
|
|
4077
|
+
label: entry.label,
|
|
4078
|
+
relationship: entry.relationship.filter(isAddressBookRelationship),
|
|
4079
|
+
hidden: entry.hidden,
|
|
4080
|
+
lastActivityAt: entry.lastActivityAt
|
|
4187
4081
|
};
|
|
4188
4082
|
}
|
|
4189
4083
|
function mapActorRequest(request, payer) {
|
|
@@ -4277,8 +4171,14 @@ function mapInboxStatus(status) {
|
|
|
4277
4171
|
}
|
|
4278
4172
|
function normalizeRefForBackend$1(ref, field) {
|
|
4279
4173
|
try {
|
|
4280
|
-
if (typeof ref === "string")
|
|
4281
|
-
|
|
4174
|
+
if (typeof ref === "string") return {
|
|
4175
|
+
ok: false,
|
|
4176
|
+
error: Errors.invalidInput(field, "recipient must be a typed Ref variant")
|
|
4177
|
+
};
|
|
4178
|
+
if (typeof ref !== "object" || ref === null || !("kind" in ref)) return {
|
|
4179
|
+
ok: false,
|
|
4180
|
+
error: Errors.invalidInput(field, "recipient must be a typed Ref variant")
|
|
4181
|
+
};
|
|
4282
4182
|
switch (ref.kind) {
|
|
4283
4183
|
case "handle": return {
|
|
4284
4184
|
ok: true,
|
|
@@ -4315,55 +4215,22 @@ function normalizeRefForBackend$1(ref, field) {
|
|
|
4315
4215
|
payeeId: nonEmptyRefValue$1(ref.payeeId, "payeeId")
|
|
4316
4216
|
}
|
|
4317
4217
|
};
|
|
4318
|
-
|
|
4218
|
+
case "party": return {
|
|
4219
|
+
ok: true,
|
|
4220
|
+
value: {
|
|
4221
|
+
kind: "party",
|
|
4222
|
+
partyId: toPartyId(ref.partyId)
|
|
4223
|
+
}
|
|
4224
|
+
};
|
|
4225
|
+
default: return {
|
|
4226
|
+
ok: false,
|
|
4227
|
+
error: Errors.invalidInput(field, "recipient must be a known Ref variant")
|
|
4228
|
+
};
|
|
4319
4229
|
}
|
|
4320
4230
|
} catch (cause) {
|
|
4321
|
-
if (cause instanceof Error && "code" in cause) return {
|
|
4322
|
-
ok: false,
|
|
4323
|
-
error: cause
|
|
4324
|
-
};
|
|
4325
4231
|
return {
|
|
4326
4232
|
ok: false,
|
|
4327
|
-
error: Errors.invalidInput(field, "recipient must be a typed Ref variant")
|
|
4328
|
-
};
|
|
4329
|
-
}
|
|
4330
|
-
}
|
|
4331
|
-
function refFromEntryId(entryId) {
|
|
4332
|
-
try {
|
|
4333
|
-
const parsed = JSON.parse(entryId);
|
|
4334
|
-
if (typeof parsed === "object" && parsed !== null && "kind" in parsed) return normalizeRefForBackend$1(parsed, "entryId");
|
|
4335
|
-
} catch {}
|
|
4336
|
-
const separator = entryId.indexOf(":");
|
|
4337
|
-
if (separator === -1) return {
|
|
4338
|
-
ok: false,
|
|
4339
|
-
error: Errors.invalidInput("entryId", "must be an address-book entry id")
|
|
4340
|
-
};
|
|
4341
|
-
const prefix = entryId.slice(0, separator);
|
|
4342
|
-
const value = entryId.slice(separator + 1);
|
|
4343
|
-
switch (prefix) {
|
|
4344
|
-
case "email": return normalizeRefForBackend$1({
|
|
4345
|
-
kind: "email",
|
|
4346
|
-
email: value
|
|
4347
|
-
}, "entryId");
|
|
4348
|
-
case "user": return normalizeRefForBackend$1({
|
|
4349
|
-
kind: "capxulUserId",
|
|
4350
|
-
capxulUserId: value
|
|
4351
|
-
}, "entryId");
|
|
4352
|
-
case "org": return normalizeRefForBackend$1({
|
|
4353
|
-
kind: "orgHandle",
|
|
4354
|
-
orgHandle: value
|
|
4355
|
-
}, "entryId");
|
|
4356
|
-
case "payee": return normalizeRefForBackend$1({
|
|
4357
|
-
kind: "payeeId",
|
|
4358
|
-
payeeId: value
|
|
4359
|
-
}, "entryId");
|
|
4360
|
-
case "handle": return normalizeRefForBackend$1({
|
|
4361
|
-
kind: "handle",
|
|
4362
|
-
handle: value
|
|
4363
|
-
}, "entryId");
|
|
4364
|
-
default: return {
|
|
4365
|
-
ok: false,
|
|
4366
|
-
error: Errors.invalidInput("entryId", "must be an address-book entry id")
|
|
4233
|
+
error: cause instanceof CapxulError ? cause : Errors.invalidInput(field, "recipient must be a typed Ref variant")
|
|
4367
4234
|
};
|
|
4368
4235
|
}
|
|
4369
4236
|
}
|
|
@@ -4377,15 +4244,6 @@ function handleRefValue$1(value, field) {
|
|
|
4377
4244
|
const trimmed = nonEmptyRefValue$1(value, field);
|
|
4378
4245
|
return trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
4379
4246
|
}
|
|
4380
|
-
function refLabel(ref) {
|
|
4381
|
-
switch (ref.kind) {
|
|
4382
|
-
case "handle": return ref.handle;
|
|
4383
|
-
case "email": return ref.email;
|
|
4384
|
-
case "orgHandle": return ref.orgHandle;
|
|
4385
|
-
case "capxulUserId": return ref.capxulUserId;
|
|
4386
|
-
case "payeeId": return ref.payeeId;
|
|
4387
|
-
}
|
|
4388
|
-
}
|
|
4389
4247
|
//#endregion
|
|
4390
4248
|
//#region src/surface/account.ts
|
|
4391
4249
|
const provisioningPhase = (state) => {
|
|
@@ -4408,6 +4266,10 @@ const actorFailure = (failure) => new CapxulError(failure.reason === "WORK_DIED"
|
|
|
4408
4266
|
...failure.details === void 0 ? {} : { details: failure.details },
|
|
4409
4267
|
layer: "identity"
|
|
4410
4268
|
});
|
|
4269
|
+
const accountFailureResult = (error) => ({
|
|
4270
|
+
ok: false,
|
|
4271
|
+
error
|
|
4272
|
+
});
|
|
4411
4273
|
function makeAccountMethods(deps) {
|
|
4412
4274
|
toChainId(deps.chainId);
|
|
4413
4275
|
const requirement = deps.requirement;
|
|
@@ -4550,26 +4412,16 @@ function makeAccountMethods(deps) {
|
|
|
4550
4412
|
value: provisioningPhase(deps.actor.snapshot())
|
|
4551
4413
|
};
|
|
4552
4414
|
};
|
|
4553
|
-
const reportAndReturn = (error, operation = "getLifecycle") => {
|
|
4554
|
-
if (deps.telemetry) captureExceptionSync(deps.telemetry, error, {
|
|
4555
|
-
layer: "account",
|
|
4556
|
-
operation
|
|
4557
|
-
});
|
|
4558
|
-
return {
|
|
4559
|
-
ok: false,
|
|
4560
|
-
error
|
|
4561
|
-
};
|
|
4562
|
-
};
|
|
4563
4415
|
const resolveLifecycle = async () => {
|
|
4564
4416
|
const phase = provisioningPhase(deps.actor.snapshot());
|
|
4565
4417
|
const status = await getStatus();
|
|
4566
|
-
if (!status.ok) return
|
|
4418
|
+
if (!status.ok) return accountFailureResult(status.error);
|
|
4567
4419
|
let accountId;
|
|
4568
4420
|
if (status.value.status !== "notAuthenticated" && (phase.status === "ready" || isRequirementMet(status.value, requirement))) {
|
|
4569
4421
|
const accountReadPort = deps.accountReadPort;
|
|
4570
|
-
if (accountReadPort === void 0) return
|
|
4422
|
+
if (accountReadPort === void 0) return accountFailureResult(Errors.invalidInput("account", "accountReadPort is required to resolve ready lifecycle"));
|
|
4571
4423
|
const account = await runPortEffect(accountReadPort.readBalance({ chainId: toChainId(deps.chainId) }));
|
|
4572
|
-
if (!account.ok) return
|
|
4424
|
+
if (!account.ok) return accountFailureResult(account.error);
|
|
4573
4425
|
accountId = String(account.value.id);
|
|
4574
4426
|
}
|
|
4575
4427
|
return {
|
|
@@ -4588,10 +4440,10 @@ function makeAccountMethods(deps) {
|
|
|
4588
4440
|
if (typeof resetSession === "function") try {
|
|
4589
4441
|
resetSession.call(deps.signer);
|
|
4590
4442
|
} catch (cause) {
|
|
4591
|
-
return
|
|
4443
|
+
return accountFailureResult(signerFailure(deps.signer.source, "resetSession", cause));
|
|
4592
4444
|
}
|
|
4593
4445
|
const retried = await drive({ _tag: "RetryAccount" });
|
|
4594
|
-
if (!retried.ok) return
|
|
4446
|
+
if (!retried.ok) return accountFailureResult(retried.error);
|
|
4595
4447
|
return resolveLifecycle();
|
|
4596
4448
|
};
|
|
4597
4449
|
return {
|
|
@@ -4744,7 +4596,7 @@ function cancelled(operation) {
|
|
|
4744
4596
|
function isAborted$2(signal) {
|
|
4745
4597
|
return signal?.aborted === true;
|
|
4746
4598
|
}
|
|
4747
|
-
async function signerCall(operation, run) {
|
|
4599
|
+
async function signerCall(source, operation, run) {
|
|
4748
4600
|
try {
|
|
4749
4601
|
return {
|
|
4750
4602
|
ok: true,
|
|
@@ -4753,7 +4605,7 @@ async function signerCall(operation, run) {
|
|
|
4753
4605
|
} catch (cause) {
|
|
4754
4606
|
return {
|
|
4755
4607
|
ok: false,
|
|
4756
|
-
error:
|
|
4608
|
+
error: signerFailure(source, operation, cause)
|
|
4757
4609
|
};
|
|
4758
4610
|
}
|
|
4759
4611
|
}
|
|
@@ -4765,7 +4617,7 @@ async function executePersonalPayment(deps, payment, signal, requestKey) {
|
|
|
4765
4617
|
ok: false,
|
|
4766
4618
|
error: Errors.notAuthenticated()
|
|
4767
4619
|
};
|
|
4768
|
-
const signerAddress = await signerCall("getAddress", () => deps.signer.getAddress());
|
|
4620
|
+
const signerAddress = await signerCall(deps.signer.source, "getAddress", () => deps.signer.getAddress());
|
|
4769
4621
|
if (!signerAddress.ok) return signerAddress;
|
|
4770
4622
|
const expectedSafe = deriveCapxulSafeAddress({ email: session.email });
|
|
4771
4623
|
const resolvedRequestKey = requestKey ?? `pay_${crypto.randomUUID()}`;
|
|
@@ -4784,7 +4636,7 @@ async function executePersonalPayment(deps, payment, signal, requestKey) {
|
|
|
4784
4636
|
paymentId: prepared.value.paymentId
|
|
4785
4637
|
});
|
|
4786
4638
|
if (isAborted$2(signal)) return cancelled("payments.pay");
|
|
4787
|
-
const signature = await signerCall("signUserOpHash", () => deps.signer.signUserOpHash(prepared.value.digest));
|
|
4639
|
+
const signature = await signerCall(deps.signer.source, "signUserOpHash", () => deps.signer.signUserOpHash(prepared.value.digest));
|
|
4788
4640
|
if (!signature.ok) return signature;
|
|
4789
4641
|
if (isAborted$2(signal)) return cancelled("payments.pay");
|
|
4790
4642
|
return runIfActive(void 0, "payments.submitExecution", () => deps.convexCall.action(deps.functions.submitPaymentExecution, { input: {
|
|
@@ -4797,12 +4649,6 @@ async function executePersonalPayment(deps, payment, signal, requestKey) {
|
|
|
4797
4649
|
function isAborted$1(signal) {
|
|
4798
4650
|
return signal?.aborted === true;
|
|
4799
4651
|
}
|
|
4800
|
-
function signerFailure(operation, cause) {
|
|
4801
|
-
return {
|
|
4802
|
-
ok: false,
|
|
4803
|
-
error: cause instanceof CapxulError ? cause : Errors.providerError("wallet-signer", operation, cause)
|
|
4804
|
-
};
|
|
4805
|
-
}
|
|
4806
4652
|
/** Return one stable fingerprint for one JSON payment intent. */
|
|
4807
4653
|
async function fingerprintPaymentIntent(intent) {
|
|
4808
4654
|
const canonical = JSON.stringify(intent, (_key, value) => value !== null && typeof value === "object" && !Array.isArray(value) ? Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right))) : value);
|
|
@@ -4823,7 +4669,10 @@ async function executePrepared(deps, prepare, expectedRequest, signal) {
|
|
|
4823
4669
|
try {
|
|
4824
4670
|
signerAddress = await deps.signer.getAddress();
|
|
4825
4671
|
} catch (cause) {
|
|
4826
|
-
return
|
|
4672
|
+
return {
|
|
4673
|
+
ok: false,
|
|
4674
|
+
error: signerFailure(deps.signer.source, "getAddress", cause)
|
|
4675
|
+
};
|
|
4827
4676
|
}
|
|
4828
4677
|
const prepared = await prepare(signerAddress);
|
|
4829
4678
|
if (!prepared.ok) return prepared;
|
|
@@ -4844,7 +4693,10 @@ async function executePrepared(deps, prepare, expectedRequest, signal) {
|
|
|
4844
4693
|
try {
|
|
4845
4694
|
signature = await deps.signer.signUserOpHash(prepared.value.digest);
|
|
4846
4695
|
} catch (cause) {
|
|
4847
|
-
return
|
|
4696
|
+
return {
|
|
4697
|
+
ok: false,
|
|
4698
|
+
error: signerFailure(deps.signer.source, "signUserOpHash", cause)
|
|
4699
|
+
};
|
|
4848
4700
|
}
|
|
4849
4701
|
if (isAborted$1(signal)) return {
|
|
4850
4702
|
ok: false,
|
|
@@ -4943,36 +4795,36 @@ async function paymentRequestKeyLifecycle(operation, intent, provided) {
|
|
|
4943
4795
|
key: provided,
|
|
4944
4796
|
finish: async () => void 0
|
|
4945
4797
|
};
|
|
4946
|
-
const slot = `capxul.payment.request-key.v3:${await fingerprintPaymentIntent({
|
|
4947
|
-
operation,
|
|
4948
|
-
intent
|
|
4949
|
-
})}`;
|
|
4950
|
-
if (typeof window === "undefined") {
|
|
4951
|
-
const attemptId = randomPaymentRequestKey();
|
|
4952
|
-
const state = memoryPaymentRequestKeys.get(slot) ?? {
|
|
4953
|
-
key: randomPaymentRequestKey(),
|
|
4954
|
-
active: [],
|
|
4955
|
-
resolved: false
|
|
4956
|
-
};
|
|
4957
|
-
state.active.push(attemptId);
|
|
4958
|
-
memoryPaymentRequestKeys.set(slot, state);
|
|
4959
|
-
let finished = false;
|
|
4960
|
-
return {
|
|
4961
|
-
key: state.key,
|
|
4962
|
-
finish: async (succeeded) => {
|
|
4963
|
-
if (finished) return;
|
|
4964
|
-
finished = true;
|
|
4965
|
-
const attemptIndex = state.active.indexOf(attemptId);
|
|
4966
|
-
if (attemptIndex < 0) return;
|
|
4967
|
-
state.active.splice(attemptIndex, 1);
|
|
4968
|
-
state.resolved = succeeded;
|
|
4969
|
-
if (state.active.length === 0 && state.resolved) memoryPaymentRequestKeys.delete(slot);
|
|
4970
|
-
}
|
|
4971
|
-
};
|
|
4972
|
-
}
|
|
4973
4798
|
let releaseAttemptLock;
|
|
4974
4799
|
let forgetPagehideRelease;
|
|
4975
4800
|
try {
|
|
4801
|
+
const slot = `capxul.payment.request-key.v3:${await fingerprintPaymentIntent({
|
|
4802
|
+
operation,
|
|
4803
|
+
intent
|
|
4804
|
+
})}`;
|
|
4805
|
+
if (typeof window === "undefined") {
|
|
4806
|
+
const attemptId = randomPaymentRequestKey();
|
|
4807
|
+
const state = memoryPaymentRequestKeys.get(slot) ?? {
|
|
4808
|
+
key: randomPaymentRequestKey(),
|
|
4809
|
+
active: [],
|
|
4810
|
+
resolved: false
|
|
4811
|
+
};
|
|
4812
|
+
state.active.push(attemptId);
|
|
4813
|
+
memoryPaymentRequestKeys.set(slot, state);
|
|
4814
|
+
let finished = false;
|
|
4815
|
+
return {
|
|
4816
|
+
key: state.key,
|
|
4817
|
+
finish: async (succeeded) => {
|
|
4818
|
+
if (finished) return;
|
|
4819
|
+
finished = true;
|
|
4820
|
+
const attemptIndex = state.active.indexOf(attemptId);
|
|
4821
|
+
if (attemptIndex < 0) return;
|
|
4822
|
+
state.active.splice(attemptIndex, 1);
|
|
4823
|
+
state.resolved = succeeded;
|
|
4824
|
+
if (state.active.length === 0 && state.resolved) memoryPaymentRequestKeys.delete(slot);
|
|
4825
|
+
}
|
|
4826
|
+
};
|
|
4827
|
+
}
|
|
4976
4828
|
const attemptId = randomPaymentRequestKey();
|
|
4977
4829
|
releaseAttemptLock = await holdPaymentAttemptLock(paymentAttemptLockName(slot, attemptId));
|
|
4978
4830
|
forgetPagehideRelease = releasePaymentAttemptOnPagehide(releaseAttemptLock);
|
|
@@ -5027,13 +4879,20 @@ async function paymentRequestKeyLifecycle(operation, intent, provided) {
|
|
|
5027
4879
|
throw Errors.providerError("sdk", "paymentRequestKey", cause);
|
|
5028
4880
|
}
|
|
5029
4881
|
}
|
|
4882
|
+
function paymentSubmissionFailure(cause) {
|
|
4883
|
+
return {
|
|
4884
|
+
ok: false,
|
|
4885
|
+
error: cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
4886
|
+
};
|
|
4887
|
+
}
|
|
5030
4888
|
async function waitForPaymentSubmission(submission, signal, operation, onCancel = () => false) {
|
|
5031
|
-
|
|
5032
|
-
if (signal
|
|
4889
|
+
const foldedSubmission = submission.catch((cause) => paymentSubmissionFailure(cause));
|
|
4890
|
+
if (signal === void 0) return foldedSubmission;
|
|
4891
|
+
if (signal.aborted) return onCancel() ? foldedSubmission : {
|
|
5033
4892
|
ok: false,
|
|
5034
4893
|
error: Errors.cancelled({ operation })
|
|
5035
4894
|
};
|
|
5036
|
-
return new Promise((resolve
|
|
4895
|
+
return new Promise((resolve) => {
|
|
5037
4896
|
const onAbort = () => {
|
|
5038
4897
|
signal.removeEventListener("abort", onAbort);
|
|
5039
4898
|
if (!onCancel()) resolve({
|
|
@@ -5042,12 +4901,9 @@ async function waitForPaymentSubmission(submission, signal, operation, onCancel
|
|
|
5042
4901
|
});
|
|
5043
4902
|
};
|
|
5044
4903
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5045
|
-
|
|
4904
|
+
foldedSubmission.then((result) => {
|
|
5046
4905
|
signal.removeEventListener("abort", onAbort);
|
|
5047
4906
|
resolve(result);
|
|
5048
|
-
}, (cause) => {
|
|
5049
|
-
signal.removeEventListener("abort", onAbort);
|
|
5050
|
-
reject(cause instanceof Error ? cause : new Error(String(cause)));
|
|
5051
4907
|
});
|
|
5052
4908
|
});
|
|
5053
4909
|
}
|
|
@@ -5092,7 +4948,7 @@ function makeFinancialOpsMethods(deps) {
|
|
|
5092
4948
|
} catch (cause) {
|
|
5093
4949
|
return {
|
|
5094
4950
|
ok: false,
|
|
5095
|
-
error: cause instanceof CapxulError ? cause : Errors.
|
|
4951
|
+
error: cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
5096
4952
|
};
|
|
5097
4953
|
}
|
|
5098
4954
|
const sharedKey = `${requestKeyScope}:${requestKey.key}`;
|
|
@@ -5140,7 +4996,10 @@ function makeFinancialOpsMethods(deps) {
|
|
|
5140
4996
|
try {
|
|
5141
4997
|
await requestKey.finish(false);
|
|
5142
4998
|
} catch {}
|
|
5143
|
-
|
|
4999
|
+
return {
|
|
5000
|
+
ok: false,
|
|
5001
|
+
error: cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
5002
|
+
};
|
|
5144
5003
|
}
|
|
5145
5004
|
release(false);
|
|
5146
5005
|
try {
|
|
@@ -5164,11 +5023,25 @@ function makeFinancialOpsMethods(deps) {
|
|
|
5164
5023
|
const runLifecycle = async (intent, signal) => {
|
|
5165
5024
|
const execution = lifecycleDependencies();
|
|
5166
5025
|
if (!execution.ok) return execution;
|
|
5167
|
-
|
|
5168
|
-
const
|
|
5169
|
-
if (
|
|
5170
|
-
|
|
5171
|
-
|
|
5026
|
+
try {
|
|
5027
|
+
const submitted = await executePaymentLifecycle(execution.value, intent, signal);
|
|
5028
|
+
if (!submitted.ok) return submitted;
|
|
5029
|
+
const payments = submitted.value.payments;
|
|
5030
|
+
const payment = payments[0];
|
|
5031
|
+
if (payment === void 0 || payments.length !== 1) return {
|
|
5032
|
+
ok: false,
|
|
5033
|
+
error: Errors.unknown()
|
|
5034
|
+
};
|
|
5035
|
+
return {
|
|
5036
|
+
ok: true,
|
|
5037
|
+
value: normalizePaymentTiming(payment)
|
|
5038
|
+
};
|
|
5039
|
+
} catch (cause) {
|
|
5040
|
+
return {
|
|
5041
|
+
ok: false,
|
|
5042
|
+
error: cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
5043
|
+
};
|
|
5044
|
+
}
|
|
5172
5045
|
};
|
|
5173
5046
|
return {
|
|
5174
5047
|
me: {
|
|
@@ -5219,9 +5092,10 @@ function makeFinancialOpsMethods(deps) {
|
|
|
5219
5092
|
value: resolvedTargetFromPayee(reference, payee.value)
|
|
5220
5093
|
};
|
|
5221
5094
|
}
|
|
5095
|
+
case "party":
|
|
5222
5096
|
case "destination": return Promise.resolve({
|
|
5223
5097
|
ok: false,
|
|
5224
|
-
error: Errors.notImplemented("targets",
|
|
5098
|
+
error: Errors.notImplemented("targets", `resolve.${reference.kind}`)
|
|
5225
5099
|
});
|
|
5226
5100
|
}
|
|
5227
5101
|
} },
|
|
@@ -5355,8 +5229,14 @@ function handleRefValue(value, field) {
|
|
|
5355
5229
|
}
|
|
5356
5230
|
function refFromTargetReference(reference, field) {
|
|
5357
5231
|
try {
|
|
5358
|
-
if (typeof reference === "string")
|
|
5359
|
-
|
|
5232
|
+
if (typeof reference === "string") return {
|
|
5233
|
+
ok: false,
|
|
5234
|
+
error: Errors.invalidInput(field, "target must be a typed TargetReference variant")
|
|
5235
|
+
};
|
|
5236
|
+
if (typeof reference !== "object" || reference === null || !("kind" in reference)) return {
|
|
5237
|
+
ok: false,
|
|
5238
|
+
error: Errors.invalidInput(field, "target must be a typed TargetReference variant")
|
|
5239
|
+
};
|
|
5360
5240
|
switch (reference.kind) {
|
|
5361
5241
|
case "handle": return {
|
|
5362
5242
|
ok: true,
|
|
@@ -5386,20 +5266,26 @@ function refFromTargetReference(reference, field) {
|
|
|
5386
5266
|
payeeId: reference.id
|
|
5387
5267
|
}
|
|
5388
5268
|
};
|
|
5269
|
+
case "party": return {
|
|
5270
|
+
ok: true,
|
|
5271
|
+
value: {
|
|
5272
|
+
kind: "party",
|
|
5273
|
+
partyId: reference.partyId
|
|
5274
|
+
}
|
|
5275
|
+
};
|
|
5389
5276
|
case "destination": return {
|
|
5390
5277
|
ok: false,
|
|
5391
5278
|
error: Errors.notImplemented("targets", "reference.destination")
|
|
5392
5279
|
};
|
|
5393
|
-
default:
|
|
5280
|
+
default: return {
|
|
5281
|
+
ok: false,
|
|
5282
|
+
error: Errors.invalidInput(field, "target must be a known TargetReference variant")
|
|
5283
|
+
};
|
|
5394
5284
|
}
|
|
5395
5285
|
} catch (cause) {
|
|
5396
|
-
if (cause instanceof Error && "code" in cause) return {
|
|
5397
|
-
ok: false,
|
|
5398
|
-
error: cause
|
|
5399
|
-
};
|
|
5400
5286
|
return {
|
|
5401
5287
|
ok: false,
|
|
5402
|
-
error: Errors.invalidInput(field, "target must be a typed TargetReference variant")
|
|
5288
|
+
error: cause instanceof CapxulError ? cause : Errors.invalidInput(field, "target must be a typed TargetReference variant")
|
|
5403
5289
|
};
|
|
5404
5290
|
}
|
|
5405
5291
|
}
|
|
@@ -5453,6 +5339,10 @@ function targetReferenceFromBackendRef(ref) {
|
|
|
5453
5339
|
kind: "payee",
|
|
5454
5340
|
id: ref.payeeId
|
|
5455
5341
|
};
|
|
5342
|
+
case "party": return {
|
|
5343
|
+
kind: "party",
|
|
5344
|
+
partyId: ref.partyId
|
|
5345
|
+
};
|
|
5456
5346
|
case "capxulUserId": throw Errors.notImplemented("targets", "reference.capxulUserId");
|
|
5457
5347
|
}
|
|
5458
5348
|
}
|
|
@@ -5539,8 +5429,14 @@ function normalizeDestinationRefForBackend(ref, field) {
|
|
|
5539
5429
|
}
|
|
5540
5430
|
function normalizeRefForBackend(ref, field) {
|
|
5541
5431
|
try {
|
|
5542
|
-
if (typeof ref === "string")
|
|
5543
|
-
|
|
5432
|
+
if (typeof ref === "string") return {
|
|
5433
|
+
ok: false,
|
|
5434
|
+
error: Errors.invalidInput(field, "recipient must be a typed Ref variant")
|
|
5435
|
+
};
|
|
5436
|
+
if (typeof ref !== "object" || ref === null || !("kind" in ref)) return {
|
|
5437
|
+
ok: false,
|
|
5438
|
+
error: Errors.invalidInput(field, "recipient must be a typed Ref variant")
|
|
5439
|
+
};
|
|
5544
5440
|
switch (ref.kind) {
|
|
5545
5441
|
case "handle": return {
|
|
5546
5442
|
ok: true,
|
|
@@ -5577,16 +5473,22 @@ function normalizeRefForBackend(ref, field) {
|
|
|
5577
5473
|
payeeId: nonEmptyRefValue(ref.payeeId, "payeeId")
|
|
5578
5474
|
}
|
|
5579
5475
|
};
|
|
5580
|
-
|
|
5476
|
+
case "party": return {
|
|
5477
|
+
ok: true,
|
|
5478
|
+
value: {
|
|
5479
|
+
kind: "party",
|
|
5480
|
+
partyId: toPartyId(ref.partyId)
|
|
5481
|
+
}
|
|
5482
|
+
};
|
|
5483
|
+
default: return {
|
|
5484
|
+
ok: false,
|
|
5485
|
+
error: Errors.invalidInput(field, "recipient must be a known Ref variant")
|
|
5486
|
+
};
|
|
5581
5487
|
}
|
|
5582
5488
|
} catch (cause) {
|
|
5583
|
-
if (cause instanceof Error && "code" in cause) return {
|
|
5584
|
-
ok: false,
|
|
5585
|
-
error: cause
|
|
5586
|
-
};
|
|
5587
5489
|
return {
|
|
5588
5490
|
ok: false,
|
|
5589
|
-
error: Errors.invalidInput(field, "recipient must be a typed Ref variant")
|
|
5491
|
+
error: cause instanceof CapxulError ? cause : Errors.invalidInput(field, "recipient must be a typed Ref variant")
|
|
5590
5492
|
};
|
|
5591
5493
|
}
|
|
5592
5494
|
}
|
|
@@ -5605,16 +5507,15 @@ function mapOk(result, f) {
|
|
|
5605
5507
|
value: f(result.value)
|
|
5606
5508
|
};
|
|
5607
5509
|
} catch (cause) {
|
|
5608
|
-
|
|
5510
|
+
return {
|
|
5609
5511
|
ok: false,
|
|
5610
|
-
error: cause
|
|
5512
|
+
error: cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
5611
5513
|
};
|
|
5612
|
-
throw cause;
|
|
5613
5514
|
}
|
|
5614
5515
|
}
|
|
5615
5516
|
//#endregion
|
|
5616
5517
|
//#region package.json
|
|
5617
|
-
var version = "2.
|
|
5518
|
+
var version = "2.3.0";
|
|
5618
5519
|
//#endregion
|
|
5619
5520
|
//#region src/ports/auth-client.ts
|
|
5620
5521
|
var AuthClientError = class extends Data.TaggedError("AuthClientError") {};
|
|
@@ -6560,6 +6461,8 @@ const IDENTITY_SLOT = {
|
|
|
6560
6461
|
const IDENTITY_SLOT_BY_EVENT = {
|
|
6561
6462
|
ReadSession: IDENTITY_SLOT.session,
|
|
6562
6463
|
RestoreSession: IDENTITY_SLOT.session,
|
|
6464
|
+
SessionRestored: IDENTITY_SLOT.session,
|
|
6465
|
+
SessionAbsent: IDENTITY_SLOT.session,
|
|
6563
6466
|
SessionRead: IDENTITY_SLOT.session,
|
|
6564
6467
|
SessionReadFailed: IDENTITY_SLOT.session,
|
|
6565
6468
|
RequestOtp: IDENTITY_SLOT.auth,
|
|
@@ -6625,7 +6528,7 @@ const modelSession = (session) => ({
|
|
|
6625
6528
|
});
|
|
6626
6529
|
const claimAccount = (input, authUserId, signer) => call("smart-account.claim", Effect.tryPromise({
|
|
6627
6530
|
try: () => signer.getAddress(),
|
|
6628
|
-
catch: (cause) =>
|
|
6531
|
+
catch: (cause) => signerFailure(signer.source, "getAddress", cause)
|
|
6629
6532
|
}).pipe(Effect.flatMap((signerAddress) => input.ports.smartAccount.claim({
|
|
6630
6533
|
authUserId: toAuthUserId(authUserId),
|
|
6631
6534
|
chainId: toChainId(input.chainId),
|
|
@@ -6871,7 +6774,7 @@ const identitySpec = (input, sessionStore = { current: null }) => {
|
|
|
6871
6774
|
};
|
|
6872
6775
|
return {
|
|
6873
6776
|
machine: "identity",
|
|
6874
|
-
initial:
|
|
6777
|
+
initial: RESTORING,
|
|
6875
6778
|
label,
|
|
6876
6779
|
slot: identitySlot,
|
|
6877
6780
|
transition: (state, event) => transition(state, event, config),
|
|
@@ -7007,7 +6910,7 @@ const bootIdentityFlow = (input, options = {}) => Effect.gen(function* () {
|
|
|
7007
6910
|
sessionStore.current = null;
|
|
7008
6911
|
}) : Effect.void)),
|
|
7009
6912
|
restoreAuthSession: (session, controls) => actor.ask({
|
|
7010
|
-
_tag: "RestoreSession",
|
|
6913
|
+
_tag: actor.snapshot().phase === "restoring" ? "SessionRestored" : "RestoreSession",
|
|
7011
6914
|
session: modelSession(session),
|
|
7012
6915
|
profileComplete: false
|
|
7013
6916
|
}, controls).pipe(Effect.tap(() => Effect.sync(() => {
|
|
@@ -7045,13 +6948,13 @@ const ask = (actor, event, controls, wrongState) => actor.ask(event, controls).p
|
|
|
7045
6948
|
*/
|
|
7046
6949
|
const getSessionProgramWithOptions = (options) => Effect.gen(function* () {
|
|
7047
6950
|
const deps = yield* CapxulDepsTag;
|
|
7048
|
-
const cached = yield* deps.authCache.getSession.pipe(Effect.mapError((e) => Errors.providerError("auth-cache", "getSession", e)));
|
|
6951
|
+
const cached = yield* deps.authCache.getSession.pipe(Effect.mapError((e) => Errors.providerError("auth-cache", "getSession", e)), Effect.catch((failure) => deps.actor.snapshot().phase === "restoring" ? Effect.succeed(null) : Effect.fail(failure)));
|
|
7049
6952
|
const observed = deps.actor.snapshot();
|
|
7050
6953
|
const actorState = observed.phase;
|
|
7051
6954
|
if (observed.phase === "faulted") return yield* Effect.fail(publicIdentityFailure(observed.failure));
|
|
7052
6955
|
if (cached === null && (actorState === "otp_pending" || actorState === "otp_sending" || actorState === "otp_verifying")) return null;
|
|
7053
|
-
if (cached !== null && actorState
|
|
7054
|
-
if (cached !== null
|
|
6956
|
+
if (cached !== null && !(actorState === "signed_out" || actorState === "restoring")) return cached;
|
|
6957
|
+
if (cached !== null) {
|
|
7055
6958
|
yield* deps.actor.restoreAuthSession(cached, depsRequestOptions(deps, options)).pipe(Effect.mapError(actorError));
|
|
7056
6959
|
return cached;
|
|
7057
6960
|
}
|
|
@@ -7154,6 +7057,7 @@ const signInProgram = (input, options) => Effect.gen(function* () {
|
|
|
7154
7057
|
}, depsRequestOptions(deps, options), {
|
|
7155
7058
|
method: "signIn",
|
|
7156
7059
|
validStates: [
|
|
7060
|
+
"restoring",
|
|
7157
7061
|
"signed_out",
|
|
7158
7062
|
"otp_pending",
|
|
7159
7063
|
"faulted"
|
|
@@ -7177,7 +7081,7 @@ const signInProgram = (input, options) => Effect.gen(function* () {
|
|
|
7177
7081
|
const signOutProgramWithOptions = (options) => Effect.gen(function* () {
|
|
7178
7082
|
const deps = yield* CapxulDepsTag;
|
|
7179
7083
|
let phase = deps.actor.snapshot().phase;
|
|
7180
|
-
if (phase === "signed_out") {
|
|
7084
|
+
if (phase === "signed_out" || phase === "restoring") {
|
|
7181
7085
|
const cached = yield* deps.authCache.getSession.pipe(Effect.mapError((e) => Errors.providerError("auth-cache", "getSession", e)));
|
|
7182
7086
|
if (cached !== null) {
|
|
7183
7087
|
yield* deps.actor.restoreAuthSession(cached, depsRequestOptions(deps, options)).pipe(Effect.mapError(actorError));
|
|
@@ -7553,6 +7457,32 @@ function makeSystemMethods(deps) {
|
|
|
7553
7457
|
return { health: (nonce, options) => runIfActive(options?.signal, "system.health", () => deps.convexCall.query(healthQuery, { nonce })) };
|
|
7554
7458
|
}
|
|
7555
7459
|
//#endregion
|
|
7460
|
+
//#region src/contract/org.ts
|
|
7461
|
+
const orgReadContract = { me: makeFunctionReference(CAPXUL_FUNCTIONS["org/queries"].me) };
|
|
7462
|
+
//#endregion
|
|
7463
|
+
//#region src/surface/org-me.ts
|
|
7464
|
+
function toBudget(wire) {
|
|
7465
|
+
return {
|
|
7466
|
+
id: toBudgetId(wire.id),
|
|
7467
|
+
label: wire.label,
|
|
7468
|
+
limit: wire.limitRaw === null ? null : fromWei(wire.limitRaw, wire.decimals, wire.currency)
|
|
7469
|
+
};
|
|
7470
|
+
}
|
|
7471
|
+
function toOrgMe(wire) {
|
|
7472
|
+
return {
|
|
7473
|
+
role: wire.role === null ? null : { label: wire.role.label },
|
|
7474
|
+
capabilities: {
|
|
7475
|
+
canManagePeople: wire.capabilities.canManagePeople,
|
|
7476
|
+
canSpend: wire.capabilities.canSpend
|
|
7477
|
+
},
|
|
7478
|
+
budgets: wire.budgets.map(toBudget),
|
|
7479
|
+
observedAt: wire.observedAt
|
|
7480
|
+
};
|
|
7481
|
+
}
|
|
7482
|
+
function makeOrgMeMethod(deps, orgId) {
|
|
7483
|
+
return (options) => runIfActive(options?.signal, "org.me", () => Effect.map(deps.convexCall.query(orgReadContract.me, { orgId }), toOrgMe));
|
|
7484
|
+
}
|
|
7485
|
+
//#endregion
|
|
7556
7486
|
//#region src/contract/permission.ts
|
|
7557
7487
|
const permissionContract = { read: makeFunctionReference(CAPXUL_FUNCTIONS["permission/queries"].read) };
|
|
7558
7488
|
//#endregion
|
|
@@ -7560,12 +7490,6 @@ const permissionContract = { read: makeFunctionReference(CAPXUL_FUNCTIONS["permi
|
|
|
7560
7490
|
function isAborted(signal) {
|
|
7561
7491
|
return signal?.aborted === true;
|
|
7562
7492
|
}
|
|
7563
|
-
function fail$1(cause, operation) {
|
|
7564
|
-
return {
|
|
7565
|
-
ok: false,
|
|
7566
|
-
error: cause instanceof CapxulError ? cause : Errors.providerError("wallet-signer", operation, cause)
|
|
7567
|
-
};
|
|
7568
|
-
}
|
|
7569
7493
|
async function execute(deps, orgId, command, signal) {
|
|
7570
7494
|
if (isAborted(signal)) return {
|
|
7571
7495
|
ok: false,
|
|
@@ -7584,7 +7508,10 @@ async function execute(deps, orgId, command, signal) {
|
|
|
7584
7508
|
try {
|
|
7585
7509
|
signerAddress = await deps.signer.getAddress();
|
|
7586
7510
|
} catch (cause) {
|
|
7587
|
-
return
|
|
7511
|
+
return {
|
|
7512
|
+
ok: false,
|
|
7513
|
+
error: signerFailure(deps.signer.source, "getAddress", cause)
|
|
7514
|
+
};
|
|
7588
7515
|
}
|
|
7589
7516
|
const executionFns = deps.executionFunctions ?? moneyExecutionContract;
|
|
7590
7517
|
const prepared = await runIfActive(signal, "permissions.prepareExecution", () => deps.convexCall.action(executionFns.preparePermissionExecution, { input: {
|
|
@@ -7606,7 +7533,10 @@ async function execute(deps, orgId, command, signal) {
|
|
|
7606
7533
|
try {
|
|
7607
7534
|
signature = await deps.signer.signUserOpHash(prepared.value.digest);
|
|
7608
7535
|
} catch (cause) {
|
|
7609
|
-
return
|
|
7536
|
+
return {
|
|
7537
|
+
ok: false,
|
|
7538
|
+
error: signerFailure(deps.signer.source, "signUserOpHash", cause)
|
|
7539
|
+
};
|
|
7610
7540
|
}
|
|
7611
7541
|
if (isAborted(signal)) return {
|
|
7612
7542
|
ok: false,
|
|
@@ -7684,7 +7614,7 @@ function makeOrganizationPaymentsMethods(deps, orgId) {
|
|
|
7684
7614
|
} catch (cause) {
|
|
7685
7615
|
return {
|
|
7686
7616
|
ok: false,
|
|
7687
|
-
error: cause instanceof CapxulError ? cause : Errors.
|
|
7617
|
+
error: cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
7688
7618
|
};
|
|
7689
7619
|
}
|
|
7690
7620
|
const flightKey = `${requestKeyScope}:${operation}:${requestKey.key}`;
|
|
@@ -7731,16 +7661,16 @@ function makeOrganizationPaymentsMethods(deps, orgId) {
|
|
|
7731
7661
|
try {
|
|
7732
7662
|
await requestKey.finish(false);
|
|
7733
7663
|
} catch {}
|
|
7734
|
-
|
|
7664
|
+
return {
|
|
7665
|
+
ok: false,
|
|
7666
|
+
error: cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
7667
|
+
};
|
|
7735
7668
|
}
|
|
7736
7669
|
release(false);
|
|
7737
7670
|
try {
|
|
7738
7671
|
await requestKey.finish(result.ok);
|
|
7739
7672
|
} catch {}
|
|
7740
|
-
return result.
|
|
7741
|
-
ok: true,
|
|
7742
|
-
value: result.value.payments.map((payment) => normalizePaymentTiming(payment))
|
|
7743
|
-
} : result;
|
|
7673
|
+
return mapOk(result, (value) => value.payments.map((payment) => normalizePaymentTiming(payment)));
|
|
7744
7674
|
};
|
|
7745
7675
|
return {
|
|
7746
7676
|
pay: async (input, options) => {
|
|
@@ -7910,38 +7840,6 @@ function hermeticOrgView(input) {
|
|
|
7910
7840
|
logoUrl: null
|
|
7911
7841
|
};
|
|
7912
7842
|
}
|
|
7913
|
-
function moneyFromConfig(input) {
|
|
7914
|
-
return {
|
|
7915
|
-
currency: toCurrencyCode(input.currency),
|
|
7916
|
-
value: input.value,
|
|
7917
|
-
decimals: input.decimals
|
|
7918
|
-
};
|
|
7919
|
-
}
|
|
7920
|
-
function recipientsFromConfig(toRecipients) {
|
|
7921
|
-
if (toRecipients === void 0 || toRecipients === "anyone") return toRecipients;
|
|
7922
|
-
return toRecipients.map((recipient) => toAddress(recipient));
|
|
7923
|
-
}
|
|
7924
|
-
function roleDefinitionFromConfig(definition) {
|
|
7925
|
-
const toRecipients = recipientsFromConfig(definition.spend?.toRecipients);
|
|
7926
|
-
return {
|
|
7927
|
-
label: definition.label,
|
|
7928
|
-
...definition.spend === void 0 ? {} : { spend: {
|
|
7929
|
-
...definition.spend.perTx === void 0 ? {} : { perTx: moneyFromConfig(definition.spend.perTx) },
|
|
7930
|
-
...definition.spend.perDay === void 0 ? {} : { perDay: moneyFromConfig(definition.spend.perDay) },
|
|
7931
|
-
...toRecipients === void 0 ? {} : { toRecipients }
|
|
7932
|
-
} },
|
|
7933
|
-
...definition.canManageMembers === void 0 ? {} : { canManageMembers: definition.canManageMembers },
|
|
7934
|
-
...definition.canManageRoles === void 0 ? {} : { canManageRoles: definition.canManageRoles }
|
|
7935
|
-
};
|
|
7936
|
-
}
|
|
7937
|
-
function startupRoleViews(orgId) {
|
|
7938
|
-
return compileOrgRoleDefinitions(orgRoleTemplateDefinitions("Startup")).roles.map((role) => ({
|
|
7939
|
-
orgId,
|
|
7940
|
-
label: role.label,
|
|
7941
|
-
roleKey: toRoleKey(role.roleKey),
|
|
7942
|
-
definition: roleDefinitionFromConfig(role.definition)
|
|
7943
|
-
}));
|
|
7944
|
-
}
|
|
7945
7843
|
function hermeticMember(input) {
|
|
7946
7844
|
return {
|
|
7947
7845
|
orgId: input.orgId,
|
|
@@ -8043,7 +7941,7 @@ function listRolesProgram(orgId) {
|
|
|
8043
7941
|
return Effect.gen(function* () {
|
|
8044
7942
|
const deps = yield* OrgDepsTag;
|
|
8045
7943
|
if (deps.orgPort !== void 0) return yield* deps.orgPort.listRoles({ orgId }).pipe(Effect.mapError((error) => error.publicError));
|
|
8046
|
-
return
|
|
7944
|
+
return [];
|
|
8047
7945
|
});
|
|
8048
7946
|
}
|
|
8049
7947
|
function listMembersProgram(orgId) {
|
|
@@ -8208,6 +8106,7 @@ function makeOrgMethods(deps) {
|
|
|
8208
8106
|
},
|
|
8209
8107
|
...convexCall === void 0 ? {} : { convexCall }
|
|
8210
8108
|
}),
|
|
8109
|
+
me: convexCall === void 0 ? orgMeUnavailable : makeOrgMeMethod({ convexCall }, String(orgId)),
|
|
8211
8110
|
async getLifecycle(options) {
|
|
8212
8111
|
if (options?.signal?.aborted) return {
|
|
8213
8112
|
ok: false,
|
|
@@ -8355,6 +8254,10 @@ function makeNotImplementedOrganizationPaymentsMethods() {
|
|
|
8355
8254
|
payBatch: organizationPaymentExecutionUnavailable
|
|
8356
8255
|
};
|
|
8357
8256
|
}
|
|
8257
|
+
const orgMeUnavailable = () => Promise.resolve({
|
|
8258
|
+
ok: false,
|
|
8259
|
+
error: Errors.notImplemented("org", "me")
|
|
8260
|
+
});
|
|
8358
8261
|
const permissionExecutionUnavailable = () => Promise.resolve({
|
|
8359
8262
|
ok: false,
|
|
8360
8263
|
error: Errors.notImplemented("permissions", "executionComposition")
|
|
@@ -8383,6 +8286,142 @@ function detectAuthCacheAdapter() {
|
|
|
8383
8286
|
return new InMemoryAuthCacheAdapter();
|
|
8384
8287
|
}
|
|
8385
8288
|
//#endregion
|
|
8289
|
+
//#region src/telemetry/stack-frame-parser.ts
|
|
8290
|
+
/**
|
|
8291
|
+
* Regex for V8/Chrome stack trace frame lines.
|
|
8292
|
+
* Matches:
|
|
8293
|
+
* `at functionName (url:line:col)`
|
|
8294
|
+
* `at url:line:col`
|
|
8295
|
+
* `at async functionName (url:line:col)`
|
|
8296
|
+
* `at new ClassName (url:line:col)`
|
|
8297
|
+
*/
|
|
8298
|
+
const V8_FRAME_RE = /^\s*at\s+(?:(.+?)\s+\()?(?:(.+?)(?::(\d+):(\d+))?|(.+?))\)?\s*$/;
|
|
8299
|
+
function isNonUrlName(name) {
|
|
8300
|
+
return name === "<anonymous>" || name.startsWith("eval") || name.startsWith("new ") || name.startsWith("async ");
|
|
8301
|
+
}
|
|
8302
|
+
/**
|
|
8303
|
+
* Parse a V8/Chrome-style stack trace string into PostHog `ExceptionFrame` objects.
|
|
8304
|
+
* Returns an empty array when `error.stack` is absent or empty.
|
|
8305
|
+
*
|
|
8306
|
+
* Handles:
|
|
8307
|
+
* - Standard `at functionName (url:line:col)`
|
|
8308
|
+
* - Bare `at url:line:col` (no function name)
|
|
8309
|
+
* - `at async functionName (url:line:col)`
|
|
8310
|
+
* - `at new ClassName (url:line:col)`
|
|
8311
|
+
* - Native frames: `at Array.forEach (<anonymous>)`
|
|
8312
|
+
*/
|
|
8313
|
+
function parseV8StackFrames(error) {
|
|
8314
|
+
const stack = error.stack;
|
|
8315
|
+
if (stack === void 0 || stack === null || stack === "") return [];
|
|
8316
|
+
const lines = stack.split("\n");
|
|
8317
|
+
const frames = [];
|
|
8318
|
+
for (const line of lines) {
|
|
8319
|
+
const trimmed = line.trim();
|
|
8320
|
+
if (!trimmed.startsWith("at ")) continue;
|
|
8321
|
+
const match = V8_FRAME_RE.exec(trimmed);
|
|
8322
|
+
if (match === null) continue;
|
|
8323
|
+
if (match[1] !== void 0) frames.push({
|
|
8324
|
+
function: match[1],
|
|
8325
|
+
filename: match[2],
|
|
8326
|
+
lineno: match[3] !== void 0 ? Number(match[3]) : null,
|
|
8327
|
+
colno: match[4] !== void 0 ? Number(match[4]) : null
|
|
8328
|
+
});
|
|
8329
|
+
else if (match[2] !== void 0 && !isNonUrlName(match[2])) frames.push({
|
|
8330
|
+
function: "<anonymous>",
|
|
8331
|
+
filename: match[2],
|
|
8332
|
+
lineno: match[3] !== void 0 ? Number(match[3]) : null,
|
|
8333
|
+
colno: match[4] !== void 0 ? Number(match[4]) : null
|
|
8334
|
+
});
|
|
8335
|
+
else frames.push({
|
|
8336
|
+
function: match[1] ?? match[2] ?? match[5] ?? "<anonymous>",
|
|
8337
|
+
filename: match[2] ?? match[5] ?? "<anonymous>",
|
|
8338
|
+
lineno: match[3] !== void 0 ? Number(match[3]) : null,
|
|
8339
|
+
colno: match[4] !== void 0 ? Number(match[4]) : null
|
|
8340
|
+
});
|
|
8341
|
+
}
|
|
8342
|
+
return frames;
|
|
8343
|
+
}
|
|
8344
|
+
/** Fixed, leak-safe frame used when the error carries no parseable stack. */
|
|
8345
|
+
const SDK_BOUNDARY_FILENAME = "capxul-sdk-observation://boundary";
|
|
8346
|
+
/**
|
|
8347
|
+
* Build PostHog's `$exception_list` (always a single entry). Error Tracking
|
|
8348
|
+
* groups on `type`, so it is ALWAYS present (the CapxulError code) — the
|
|
8349
|
+
* previous `[{ frames }]` shape omitted it and PostHog dropped the event as
|
|
8350
|
+
* "missing field `type`". When the error has no parseable stack, a synthetic
|
|
8351
|
+
* boundary frame stands in so the event still ingests as a real Issue (#1031).
|
|
8352
|
+
*/
|
|
8353
|
+
function buildExceptionList(input) {
|
|
8354
|
+
const frames = input.frames.length > 0 ? input.frames : [{
|
|
8355
|
+
filename: SDK_BOUNDARY_FILENAME,
|
|
8356
|
+
function: input.operation ?? "unknown",
|
|
8357
|
+
lineno: 1,
|
|
8358
|
+
colno: 1
|
|
8359
|
+
}];
|
|
8360
|
+
return [{
|
|
8361
|
+
type: input.type,
|
|
8362
|
+
value: input.value,
|
|
8363
|
+
mechanism: {
|
|
8364
|
+
handled: true,
|
|
8365
|
+
type: "capxul_sdk_boundary"
|
|
8366
|
+
},
|
|
8367
|
+
stacktrace: { frames }
|
|
8368
|
+
}];
|
|
8369
|
+
}
|
|
8370
|
+
//#endregion
|
|
8371
|
+
//#region src/telemetry/capture-exception.ts
|
|
8372
|
+
/** Fixed, leak-safe message — the raw error message may carry PII and never ships. */
|
|
8373
|
+
const EXCEPTION_MESSAGE = "Capxul SDK operation failed";
|
|
8374
|
+
/**
|
|
8375
|
+
* Capture an error as a `$exception` event through the telemetry port,
|
|
8376
|
+
* formatted for PostHog Error Tracking.
|
|
8377
|
+
*
|
|
8378
|
+
* Parses stack traces into `$exception_list` format, extracts structured
|
|
8379
|
+
* metadata from CapxulError objects, and supplements with context props.
|
|
8380
|
+
* Fire-and-forget: telemetry defects are silently swallowed.
|
|
8381
|
+
* Returns `Effect<void, never>` for use in Effect pipelines; the underlying
|
|
8382
|
+
* adapter work is synchronous, so callers outside Effect contexts can
|
|
8383
|
+
* use `Effect.runSync`.
|
|
8384
|
+
*/
|
|
8385
|
+
function captureException(telemetry, error, context) {
|
|
8386
|
+
return Effect.catchDefect(Effect.sync(() => {
|
|
8387
|
+
const frames = error instanceof Error ? parseV8StackFrames(error) : [];
|
|
8388
|
+
const capxulError = isCapxulError(error) ? error : null;
|
|
8389
|
+
const errorCode = capxulError?.code ?? context?.capxul_error_code ?? "UNKNOWN";
|
|
8390
|
+
const props = {
|
|
8391
|
+
capxul_error_code: errorCode,
|
|
8392
|
+
$exception_type: errorCode,
|
|
8393
|
+
$exception_message: EXCEPTION_MESSAGE,
|
|
8394
|
+
$exception_list: buildExceptionList({
|
|
8395
|
+
type: errorCode,
|
|
8396
|
+
value: EXCEPTION_MESSAGE,
|
|
8397
|
+
...context?.operation === void 0 ? {} : { operation: context.operation },
|
|
8398
|
+
frames
|
|
8399
|
+
}),
|
|
8400
|
+
layer: capxulError?.layer ?? context?.layer,
|
|
8401
|
+
operation: context?.operation,
|
|
8402
|
+
provider: context?.provider,
|
|
8403
|
+
failure_mode: resolveFailureMode(error, context?.failure_mode)
|
|
8404
|
+
};
|
|
8405
|
+
if (capxulError?.details !== void 0) props.details = JSON.stringify(capxulError.details);
|
|
8406
|
+
for (const key of Object.keys(props)) if (props[key] === void 0) delete props[key];
|
|
8407
|
+
return telemetry.emit({
|
|
8408
|
+
name: "$exception",
|
|
8409
|
+
props
|
|
8410
|
+
});
|
|
8411
|
+
}).pipe(Effect.flatten), () => Effect.void);
|
|
8412
|
+
}
|
|
8413
|
+
/**
|
|
8414
|
+
* Synchronous fire-and-forget capture. Runs the Effect inline with
|
|
8415
|
+
* `Effect.runSync` so callers outside an Effect context can report errors
|
|
8416
|
+
* without awaiting. Core SDK public methods use the assembled observation
|
|
8417
|
+
* boundary instead.
|
|
8418
|
+
*/
|
|
8419
|
+
function captureExceptionSync(telemetry, error, context) {
|
|
8420
|
+
try {
|
|
8421
|
+
Effect.runSync(captureException(telemetry, error, context));
|
|
8422
|
+
} catch {}
|
|
8423
|
+
}
|
|
8424
|
+
//#endregion
|
|
8386
8425
|
//#region src/observation.ts
|
|
8387
8426
|
const SDK_VERSION = version;
|
|
8388
8427
|
/** Stable PostHog event used for typed failures that are expected product outcomes. */
|
|
@@ -8431,16 +8470,98 @@ function postHogFailureObservation(policy, fixedSnapshot) {
|
|
|
8431
8470
|
function classifyOperationOutcome(kind) {
|
|
8432
8471
|
return EXPECTED_OPERATION_OUTCOMES.has(kind) ? "expected" : "unexpected";
|
|
8433
8472
|
}
|
|
8473
|
+
/** @internal Observe public result methods at the assembled Core SDK boundary. */
|
|
8474
|
+
function observeSdkClient(client, adapter, snapshot) {
|
|
8475
|
+
if (adapter === void 0) return client;
|
|
8476
|
+
const objectProxies = /* @__PURE__ */ new WeakMap();
|
|
8477
|
+
const proxyTargets = /* @__PURE__ */ new WeakMap();
|
|
8478
|
+
const functionWrappers = /* @__PURE__ */ new WeakMap();
|
|
8479
|
+
const wrapObject = (target, path, internal = false) => {
|
|
8480
|
+
const cacheKey = `${internal ? "internal" : "public"}:${path.join(".")}`;
|
|
8481
|
+
let targetProxies = objectProxies.get(target);
|
|
8482
|
+
const cached = targetProxies?.get(cacheKey);
|
|
8483
|
+
if (cached !== void 0) return cached;
|
|
8484
|
+
const proxy = new Proxy(target, { get(currentTarget, property, receiver) {
|
|
8485
|
+
const value = Reflect.get(currentTarget, property, receiver);
|
|
8486
|
+
if (typeof property !== "string") return value;
|
|
8487
|
+
if (path.length === 0 && property === "_internal" && isPlainObject(value)) return wrapObject(value, ["_internal"], true);
|
|
8488
|
+
if (internal && property !== "accounts") return value;
|
|
8489
|
+
return wrapValue(value, [...path, property], currentTarget);
|
|
8490
|
+
} });
|
|
8491
|
+
proxyTargets.set(proxy, target);
|
|
8492
|
+
if (targetProxies === void 0) {
|
|
8493
|
+
targetProxies = /* @__PURE__ */ new Map();
|
|
8494
|
+
objectProxies.set(target, targetProxies);
|
|
8495
|
+
}
|
|
8496
|
+
targetProxies.set(cacheKey, proxy);
|
|
8497
|
+
return proxy;
|
|
8498
|
+
};
|
|
8499
|
+
const wrapValue = (value, path, owner) => {
|
|
8500
|
+
if (typeof value === "function") {
|
|
8501
|
+
const callable = value;
|
|
8502
|
+
const operation = path.join(".");
|
|
8503
|
+
let ownerWrappers = functionWrappers.get(owner);
|
|
8504
|
+
if (ownerWrappers === void 0) {
|
|
8505
|
+
ownerWrappers = /* @__PURE__ */ new Map();
|
|
8506
|
+
functionWrappers.set(owner, ownerWrappers);
|
|
8507
|
+
}
|
|
8508
|
+
const cached = ownerWrappers.get(operation);
|
|
8509
|
+
if (cached !== void 0) return cached;
|
|
8510
|
+
let wrapped;
|
|
8511
|
+
wrapped = new Proxy(callable, {
|
|
8512
|
+
apply(currentTarget, thisArg, args) {
|
|
8513
|
+
const invocation = resolveInvocationSnapshot(adapter, snapshot);
|
|
8514
|
+
let output;
|
|
8515
|
+
try {
|
|
8516
|
+
output = Reflect.apply(currentTarget, unwrapReceiver(thisArg), args);
|
|
8517
|
+
} catch (cause) {
|
|
8518
|
+
report(adapter, "exception", operation, cause, invocation);
|
|
8519
|
+
throw cause;
|
|
8520
|
+
}
|
|
8521
|
+
if (isPromiseLike(output)) return Promise.resolve(output).then((result) => processOutput(result, path, invocation), (cause) => {
|
|
8522
|
+
report(adapter, "exception", operation, cause, invocation);
|
|
8523
|
+
throw cause;
|
|
8524
|
+
});
|
|
8525
|
+
return processOutput(output, path, invocation);
|
|
8526
|
+
},
|
|
8527
|
+
get(currentTarget, property) {
|
|
8528
|
+
if (property === "bind") return Function.prototype.bind.bind(wrapped);
|
|
8529
|
+
if (property === "call") return Function.prototype.call.bind(wrapped);
|
|
8530
|
+
if (property === "apply") return Function.prototype.apply.bind(wrapped);
|
|
8531
|
+
const attached = Reflect.get(currentTarget, property, currentTarget);
|
|
8532
|
+
if (typeof property !== "string") return attached;
|
|
8533
|
+
return wrapValue(attached, [...path, property], currentTarget);
|
|
8534
|
+
}
|
|
8535
|
+
});
|
|
8536
|
+
proxyTargets.set(wrapped, callable);
|
|
8537
|
+
ownerWrappers.set(operation, wrapped);
|
|
8538
|
+
return wrapped;
|
|
8539
|
+
}
|
|
8540
|
+
return isPlainObject(value) ? wrapObject(value, path) : value;
|
|
8541
|
+
};
|
|
8542
|
+
const processOutput = (output, path, invocation) => {
|
|
8543
|
+
if (isFailedResult(output)) {
|
|
8544
|
+
report(adapter, "operation", path.join("."), output.error, invocation);
|
|
8545
|
+
return output;
|
|
8546
|
+
}
|
|
8547
|
+
if (isCapxulResult(output)) return output;
|
|
8548
|
+
return isPlainObject(output) ? wrapObject(output, path) : output;
|
|
8549
|
+
};
|
|
8550
|
+
return wrapObject(client, []);
|
|
8551
|
+
function unwrapReceiver(receiver) {
|
|
8552
|
+
return (typeof receiver === "object" || typeof receiver === "function") && receiver !== null ? proxyTargets.get(receiver) ?? receiver : receiver;
|
|
8553
|
+
}
|
|
8554
|
+
}
|
|
8434
8555
|
/** @internal Reports a factory-level typed failure without changing its identity. */
|
|
8435
8556
|
function observeFailedResult(result, adapter, operation) {
|
|
8436
|
-
if (adapter !== void 0 && isFailedResult(result)) report(adapter, "operation", operation, result.error,
|
|
8557
|
+
if (adapter !== void 0 && isFailedResult(result)) report(adapter, "operation", operation, result.error, resolveAdapterSnapshot(adapter));
|
|
8437
8558
|
return result;
|
|
8438
8559
|
}
|
|
8439
|
-
function report(adapter, kind, operation, cause,
|
|
8560
|
+
function report(adapter, kind, operation, cause, invocation) {
|
|
8440
8561
|
const operationName = normalizeOperation(operation);
|
|
8441
8562
|
const kindName = normalizeErrorKind(errorKind(cause));
|
|
8442
8563
|
const context = sanitizeObservationContext({
|
|
8443
|
-
...
|
|
8564
|
+
...invocation.context,
|
|
8444
8565
|
...isCapxulError(cause) && cause.correlationId !== void 0 ? { correlationId: cause.correlationId } : {}
|
|
8445
8566
|
});
|
|
8446
8567
|
const failure = markFailureInvocationSnapshot({
|
|
@@ -8450,13 +8571,27 @@ function report(adapter, kind, operation, cause, invocationContext) {
|
|
|
8450
8571
|
errorKind: kindName,
|
|
8451
8572
|
...context === void 0 ? {} : { context }
|
|
8452
8573
|
}, {
|
|
8453
|
-
active:
|
|
8574
|
+
active: invocation.active,
|
|
8454
8575
|
...context === void 0 ? {} : { context }
|
|
8455
8576
|
});
|
|
8456
8577
|
try {
|
|
8457
8578
|
ignoreDeliveryFailure(kind === "operation" ? adapter.captureOperationFailure(failure) : adapter.captureException(failure));
|
|
8458
8579
|
} catch {}
|
|
8459
8580
|
}
|
|
8581
|
+
function resolveInvocationSnapshot(adapter, snapshot) {
|
|
8582
|
+
if (snapshot !== void 0) try {
|
|
8583
|
+
const captured = snapshot();
|
|
8584
|
+
if (captured !== void 0) return captured;
|
|
8585
|
+
} catch {}
|
|
8586
|
+
return resolveAdapterSnapshot(adapter);
|
|
8587
|
+
}
|
|
8588
|
+
function resolveAdapterSnapshot(adapter) {
|
|
8589
|
+
const context = resolveAdapterContext(adapter);
|
|
8590
|
+
return context === void 0 ? { active: false } : {
|
|
8591
|
+
active: true,
|
|
8592
|
+
context
|
|
8593
|
+
};
|
|
8594
|
+
}
|
|
8460
8595
|
function resolveAdapterContext(adapter) {
|
|
8461
8596
|
try {
|
|
8462
8597
|
return adapter.resolveContext?.();
|
|
@@ -8663,6 +8798,8 @@ const APPLIED_ACTION_BY_EVENT = {
|
|
|
8663
8798
|
RestoreSession: "none",
|
|
8664
8799
|
ResumeOtpEntry: "none",
|
|
8665
8800
|
Reset: "none",
|
|
8801
|
+
SessionRestored: "none",
|
|
8802
|
+
SessionAbsent: "none",
|
|
8666
8803
|
EnsureAccount: "none",
|
|
8667
8804
|
ClaimAccount: "none",
|
|
8668
8805
|
RetryAccount: "none",
|
|
@@ -8747,6 +8884,7 @@ function executeIdentityProductObservation(telemetry, record, state) {
|
|
|
8747
8884
|
//#endregion
|
|
8748
8885
|
//#region src/surface/create-capxul-client.ts
|
|
8749
8886
|
function assembleCapxulClient(input) {
|
|
8887
|
+
const observation = input;
|
|
8750
8888
|
const authCache = input.authCache ?? detectAuthCacheAdapter();
|
|
8751
8889
|
const effectRunner = input.effectRunner ?? {
|
|
8752
8890
|
runSync: Effect.runSync,
|
|
@@ -8760,7 +8898,7 @@ function assembleCapxulClient(input) {
|
|
|
8760
8898
|
...input.signer === void 0 ? {} : { signer: input.signer },
|
|
8761
8899
|
...input.organizationSetup === void 0 ? {} : { organizationSetup: input.organizationSetup },
|
|
8762
8900
|
...input.otpTtlMs === void 0 ? {} : { otpTtlMs: input.otpTtlMs }
|
|
8763
|
-
}), scope)),
|
|
8901
|
+
}), scope)), observation.hostObservationSnapshot);
|
|
8764
8902
|
const unsubscribeProductTelemetry = actor.subscribeTransitions((record) => {
|
|
8765
8903
|
effectRunner.runPromise(executeIdentityProductObservation(input.ports.telemetry, record, actor.snapshot())).catch(() => {});
|
|
8766
8904
|
});
|
|
@@ -8809,7 +8947,11 @@ function assembleCapxulClient(input) {
|
|
|
8809
8947
|
...input.invokeTimeoutMs === void 0 ? {} : { invokeTimeoutMs: input.invokeTimeoutMs },
|
|
8810
8948
|
afterVerifyOtp: async () => {
|
|
8811
8949
|
const browserSigner = input.signer;
|
|
8812
|
-
if (browserSigner !== void 0 && "resetSession" in browserSigner && typeof browserSigner.resetSession === "function")
|
|
8950
|
+
if (browserSigner !== void 0 && "resetSession" in browserSigner && typeof browserSigner.resetSession === "function") try {
|
|
8951
|
+
browserSigner.resetSession();
|
|
8952
|
+
} catch (cause) {
|
|
8953
|
+
throw signerFailure(browserSigner.source, "resetSession", cause);
|
|
8954
|
+
}
|
|
8813
8955
|
await detectPendingOrgInvitations?.();
|
|
8814
8956
|
kickProvisioning?.();
|
|
8815
8957
|
}
|
|
@@ -8915,7 +9057,7 @@ function assembleCapxulClient(input) {
|
|
|
8915
9057
|
};
|
|
8916
9058
|
}
|
|
8917
9059
|
};
|
|
8918
|
-
return {
|
|
9060
|
+
return observeSdkClient({
|
|
8919
9061
|
auth,
|
|
8920
9062
|
smartAccount,
|
|
8921
9063
|
identity,
|
|
@@ -8937,6 +9079,7 @@ function assembleCapxulClient(input) {
|
|
|
8937
9079
|
createOrg: orgMethods.createOrg,
|
|
8938
9080
|
orgs: orgMethods.orgs,
|
|
8939
9081
|
org: orgMethods.org,
|
|
9082
|
+
signer: input.signer?.statusStore ?? UNOBSERVABLE_SIGNER_STATUS,
|
|
8940
9083
|
_internal: {
|
|
8941
9084
|
identity: identityRuntime,
|
|
8942
9085
|
bootstrap: input.bootstrap,
|
|
@@ -8945,7 +9088,7 @@ function assembleCapxulClient(input) {
|
|
|
8945
9088
|
telemetry: input.ports.telemetry,
|
|
8946
9089
|
close: stopActor
|
|
8947
9090
|
}
|
|
8948
|
-
};
|
|
9091
|
+
}, observation.failureObservation, observation.hostObservationSnapshot);
|
|
8949
9092
|
}
|
|
8950
9093
|
function withHostObservation(actor, snapshot) {
|
|
8951
9094
|
if (snapshot === void 0) return actor;
|
|
@@ -8962,4 +9105,4 @@ function withHostObservation(actor, snapshot) {
|
|
|
8962
9105
|
};
|
|
8963
9106
|
}
|
|
8964
9107
|
//#endregion
|
|
8965
|
-
export {
|
|
9108
|
+
export { fingerprintPaymentIntent as A, formatTraceparent as B, ClockPortTag as C, AuthClientError as D, authClientPortFromPromiseAdapter as E, sanitizeObservationContext as F, signerFailure as G, readInvocationObservation as H, CAPXUL_FUNCTIONS as I, BASE_SEPOLIA_CHAIN_ID as J, CAPXUL_PAYMENTS_V2_ADDRESS as K, BootstrapEnvelope as L, fromWei as M, OBSERVATION_CONTEXT_HEADER as N, AuthClientPortTag as O, encodeObservationContextHeader as P, isRestoring as Q, EngineeringTelemetryBootstrapPolicy as R, ClockError as S, bootstrapErrorFromCapxul as T, causeChain as U, copyInvocationObservation as V, injectedWalletSigner as W, destination as X, deriveCapxulSafeAddress as Y, isClaimed as Z, wireChainId as _, observeFailedResult as a, ConvexCallPortTag as b, captureExceptionSync as c, TelemetryPortTag as d, redactTelemetryEvent as f, accountReadErrorFromCapxul as g, AccountReadPortTag as h, observationContextProps as i, toWei as j, version as k, detectAuthCacheAdapter as l, smartAccountErrorFromCapxul as m, postHogProductTelemetry as n, postHogFailureObservation as o, SmartAccountPortTag as p, normalizeBindingEmail as q, CAPXUL_SDK_EXPECTED_OUTCOME_EVENT as r, captureException as s, assembleCapxulClient as t, PostHogTelemetryLayer as u, IdentityPortTag as v, BootstrapPortTag as w, convexCallErrorFromCapxul as x, identityErrorFromCapxul as y, isSettingUpLifecycle as z };
|