@capxul/mcp 4.2.0-rc.10 → 4.2.0-rc.11
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/dist/capxul-source.json +3 -3
- package/dist/main.mjs +645 -73
- package/package.json +3 -3
package/dist/capxul-source.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": {
|
|
3
|
-
"commit": "
|
|
4
|
-
"tree": "
|
|
3
|
+
"commit": "12a590f10914e8b056ce54732e6f484f36e060f3",
|
|
4
|
+
"tree": "90adc6656be3c1fb0a6e18170877d46081fa2538",
|
|
5
5
|
"branch": "codex/programme-rc",
|
|
6
6
|
"repository": "https://github.com/Xelmar-tech/infrastructure",
|
|
7
7
|
"lockfileSha256": "5870f53b72706d103220c1bcf733cb4fb71196aea32a9cfbdc277d73cc959264"
|
|
8
8
|
},
|
|
9
9
|
"name": "@capxul/mcp",
|
|
10
|
-
"version": "4.2.0-rc.
|
|
10
|
+
"version": "4.2.0-rc.11"
|
|
11
11
|
}
|
package/dist/main.mjs
CHANGED
|
@@ -931,6 +931,10 @@ function toChainId(raw) {
|
|
|
931
931
|
if (typeof raw !== "number" || !Number.isSafeInteger(raw) || raw <= 0) throw Errors.invalidInput("chainId", invalidValueReason("must be a positive safe integer", raw));
|
|
932
932
|
return raw;
|
|
933
933
|
}
|
|
934
|
+
function toWeiAmount(raw) {
|
|
935
|
+
if (typeof raw !== "string" || !WEI_RE.test(raw)) throw Errors.invalidInput("weiAmount", invalidValueReason("must be a non-negative integer string", raw));
|
|
936
|
+
return raw;
|
|
937
|
+
}
|
|
934
938
|
function toCountryCode(raw) {
|
|
935
939
|
if (typeof raw !== "string") throw Errors.invalidInput("countryCode", "must be a string");
|
|
936
940
|
const upper = raw.toUpperCase();
|
|
@@ -1087,8 +1091,18 @@ const SYNTHETIC_TEST_ASSETS = [
|
|
|
1087
1091
|
}
|
|
1088
1092
|
];
|
|
1089
1093
|
toChainId(84532);
|
|
1090
|
-
|
|
1094
|
+
/**
|
|
1095
|
+
* Every known asset in ONE identity space. The tiers above declare admission;
|
|
1096
|
+
* this is the only list an identity resolves against, so an asset is never
|
|
1097
|
+
* two different things depending on which list a caller happened to read.
|
|
1098
|
+
*/
|
|
1099
|
+
const MONEY_ASSET_REGISTRY = [...CONFIGURED_MONEY_ASSETS, ...SYNTHETIC_TEST_ASSETS];
|
|
1091
1100
|
CONFIGURED_MONEY_ASSETS.map((asset) => asset.tokenAddress.toLowerCase());
|
|
1101
|
+
/** The registry row for `assetId` across every tier, or `null`. */
|
|
1102
|
+
function configuredMoneyAssetById(assetId) {
|
|
1103
|
+
const canonical = toAssetId(assetId);
|
|
1104
|
+
return MONEY_ASSET_REGISTRY.find((asset) => asset.assetId === canonical) ?? null;
|
|
1105
|
+
}
|
|
1092
1106
|
//#endregion
|
|
1093
1107
|
//#region ../../node_modules/.pnpm/abitype@1.2.3_typescript@7.0.2_zod@4.4.3/node_modules/abitype/dist/esm/regex.js
|
|
1094
1108
|
function execTyped(regex, string) {
|
|
@@ -7788,7 +7802,27 @@ const PermissionMirrorVerificationProps = Schema.Struct({
|
|
|
7788
7802
|
"conflicting_replay",
|
|
7789
7803
|
"revision_mismatch"
|
|
7790
7804
|
])),
|
|
7791
|
-
command_id: OptionalString
|
|
7805
|
+
command_id: OptionalString,
|
|
7806
|
+
/**
|
|
7807
|
+
* #1961 R03. The authorized stored row names the Permission it changed; the
|
|
7808
|
+
* verified receipt names the chain facts that prove it. Every field is
|
|
7809
|
+
* optional because a pending or provider-failed verification has neither an
|
|
7810
|
+
* application result nor a receipt to report.
|
|
7811
|
+
*/
|
|
7812
|
+
permission_id: OptionalString,
|
|
7813
|
+
permission_assignment_id: OptionalString,
|
|
7814
|
+
permission_operation: Schema.optional(Schema.Literals([
|
|
7815
|
+
"create",
|
|
7816
|
+
"change",
|
|
7817
|
+
"assign",
|
|
7818
|
+
"revoke",
|
|
7819
|
+
"replace"
|
|
7820
|
+
])),
|
|
7821
|
+
revision: Schema.optional(Schema.Number),
|
|
7822
|
+
user_op_hash: OptionalString,
|
|
7823
|
+
transaction_hash: OptionalString,
|
|
7824
|
+
block_number: Schema.optional(Schema.Number),
|
|
7825
|
+
log_index: Schema.optional(Schema.Number)
|
|
7792
7826
|
});
|
|
7793
7827
|
const MovementScanWindowProps = Schema.Struct({
|
|
7794
7828
|
...TelemetryEnvelopeProps,
|
|
@@ -8713,6 +8747,7 @@ const CAPXUL_FUNCTIONS = {
|
|
|
8713
8747
|
list: "movement/activity:list",
|
|
8714
8748
|
summary: "movement/activity:summary"
|
|
8715
8749
|
},
|
|
8750
|
+
"movement/annotations": { overlay: "movement/annotations:overlay" },
|
|
8716
8751
|
"moneyExecution/actions": {
|
|
8717
8752
|
abandonPaymentExecution: "moneyExecution/actions:abandonPaymentExecution",
|
|
8718
8753
|
preparePermissionExecution: "moneyExecution/actions:preparePermissionExecution",
|
|
@@ -9311,7 +9346,19 @@ const StoredPermissionCommandSchema = Schema.Struct({
|
|
|
9311
9346
|
roleKey: RoleKeySchema,
|
|
9312
9347
|
allowanceKey: Schema.NullOr(AllowanceKeySchema),
|
|
9313
9348
|
memberSafe: Schema.NullOr(SafeAddressSchema),
|
|
9314
|
-
expectedAuthorityEvents: Schema.Array(Bytes32Schema)
|
|
9349
|
+
expectedAuthorityEvents: Schema.Array(Bytes32Schema),
|
|
9350
|
+
/**
|
|
9351
|
+
* #1961 R03. The authenticated user who created the command, and the browser
|
|
9352
|
+
* linkage captured with it. Delayed verification and bounded retries read
|
|
9353
|
+
* this snapshot instead of the current viewer, so one command keeps one
|
|
9354
|
+
* origin. Both are absent on commands created before this contract.
|
|
9355
|
+
*
|
|
9356
|
+
* The context stays `unknown` on purpose: `sanitizeObservationContext` owns
|
|
9357
|
+
* the field allowlist, and every reader passes the stored value through it
|
|
9358
|
+
* rather than repeating those rules here.
|
|
9359
|
+
*/
|
|
9360
|
+
originatingAuthUserId: Schema.optional(Schema.String),
|
|
9361
|
+
originatingObservationContext: Schema.optional(Schema.Unknown)
|
|
9315
9362
|
});
|
|
9316
9363
|
Schema.Struct({
|
|
9317
9364
|
command: StoredPermissionCommandSchema,
|
|
@@ -12361,6 +12408,7 @@ const financialOpsContract = {
|
|
|
12361
12408
|
activitySummary: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].summary),
|
|
12362
12409
|
activityGet: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].get),
|
|
12363
12410
|
activityAnnotate: makeFunctionReference(CAPXUL_FUNCTIONS["movement/activity"].annotate),
|
|
12411
|
+
activityOverlay: makeFunctionReference(CAPXUL_FUNCTIONS["movement/annotations"].overlay),
|
|
12364
12412
|
verifyPaymentDocument: makeFunctionReference(CAPXUL_FUNCTIONS["financialOps/queries"].verifyPaymentDocument),
|
|
12365
12413
|
renderStoredDocument: makeFunctionReference(CAPXUL_FUNCTIONS["financialOps/queries"].renderStoredDocument)
|
|
12366
12414
|
};
|
|
@@ -12377,8 +12425,357 @@ const moneyExecutionContract = {
|
|
|
12377
12425
|
submitPaymentCommandExecution: makeFunctionReference(CAPXUL_FUNCTIONS["moneyExecution/paymentCommandActions"].submitPaymentCommandExecution)
|
|
12378
12426
|
};
|
|
12379
12427
|
//#endregion
|
|
12428
|
+
//#region ../../packages/sdk/src/ports/indexer-read.ts
|
|
12429
|
+
/** The indexer's own page bound. Exceeding it is a caller defect, not a refusal. */
|
|
12430
|
+
const INDEXER_MAX_LIMIT = 1e3;
|
|
12431
|
+
const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
|
|
12432
|
+
/**
|
|
12433
|
+
* Refuse a page the indexer would refuse, before any implementation spends a
|
|
12434
|
+
* round trip on it. Every implementation calls this, so a consumer test written
|
|
12435
|
+
* against the hermetic adapter cannot pass on input production rejects. Throws
|
|
12436
|
+
* a `CapxulError`; callers convert it to an `IndexerReadError`.
|
|
12437
|
+
*/
|
|
12438
|
+
function assertIndexerPage(input) {
|
|
12439
|
+
const safe = String(input.safe).toLowerCase();
|
|
12440
|
+
if (!LOWER_CASE_ADDRESS.test(safe)) throw Errors.invalidInput("safe", "must be a lower-case EVM address");
|
|
12441
|
+
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1e3) throw Errors.invalidInput("limit", `must be an integer from 1 to ${INDEXER_MAX_LIMIT}`);
|
|
12442
|
+
const offset = input.offset ?? 0;
|
|
12443
|
+
if (!Number.isSafeInteger(offset) || offset < 0) throw Errors.invalidInput("offset", "must be a non-negative integer");
|
|
12444
|
+
return safe;
|
|
12445
|
+
}
|
|
12446
|
+
var IndexerReadError = class extends Data.TaggedError("IndexerReadError") {};
|
|
12447
|
+
function indexerReadErrorFromCapxul(operation, error, cause = error) {
|
|
12448
|
+
return new IndexerReadError({
|
|
12449
|
+
operation,
|
|
12450
|
+
publicCode: error.code,
|
|
12451
|
+
publicError: error,
|
|
12452
|
+
cause,
|
|
12453
|
+
...error.details === void 0 ? {} : { details: error.details }
|
|
12454
|
+
});
|
|
12455
|
+
}
|
|
12456
|
+
Context.Service()("@capxul/sdk/ports/IndexerReadPort");
|
|
12457
|
+
//#endregion
|
|
12458
|
+
//#region ../../packages/sdk/src/surface/activity-stitch.ts
|
|
12459
|
+
/** Epoch milliseconds of the block that carried the row. */
|
|
12460
|
+
function blockMillis(row) {
|
|
12461
|
+
return Number(row.timestamp) * 1e3;
|
|
12462
|
+
}
|
|
12463
|
+
/** `0x1234…abcd` — the counterparty of an unclaimed transfer is an address. */
|
|
12464
|
+
function shortAddressLabel(address) {
|
|
12465
|
+
return address.length <= 12 ? address : `${address.slice(0, 6)}…${address.slice(-4)}`;
|
|
12466
|
+
}
|
|
12467
|
+
function directionFor(safe, transfer) {
|
|
12468
|
+
const from = transfer.from.toLowerCase();
|
|
12469
|
+
const to = transfer.to.toLowerCase();
|
|
12470
|
+
if (from === safe && to === safe) return "self";
|
|
12471
|
+
return to === safe ? "in" : "out";
|
|
12472
|
+
}
|
|
12473
|
+
/**
|
|
12474
|
+
* The Transfer a protocol Payment moved is the same money as its `payment`
|
|
12475
|
+
* row. One actor sees one item for it, so the Transfer is claimed and does not
|
|
12476
|
+
* become a second row. Another transfer in the same transaction that this
|
|
12477
|
+
* payment did not move stays unclaimed and keeps its own row.
|
|
12478
|
+
*/
|
|
12479
|
+
function claimedTransferIds(transfers, payments) {
|
|
12480
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
12481
|
+
for (const payment of payments) {
|
|
12482
|
+
const match = transfers.find((transfer) => !claimed.has(transfer.id) && transfer.txHash === payment.txHash && transfer.token.toLowerCase() === payment.token.toLowerCase() && transfer.amount === payment.amount && transfer.to.toLowerCase() === payment.recipient.toLowerCase());
|
|
12483
|
+
if (match !== void 0) claimed.add(match.id);
|
|
12484
|
+
}
|
|
12485
|
+
return claimed;
|
|
12486
|
+
}
|
|
12487
|
+
function withAnnotation(item, annotation) {
|
|
12488
|
+
return annotation?.counterpartyLabel === void 0 ? item : {
|
|
12489
|
+
...item,
|
|
12490
|
+
counterpartyLabel: annotation.counterpartyLabel
|
|
12491
|
+
};
|
|
12492
|
+
}
|
|
12493
|
+
/**
|
|
12494
|
+
* Confirmation comes from the chain, never from Convex.
|
|
12495
|
+
*
|
|
12496
|
+
* A Ponder row for this Payment's settlement means settled, and its receipt is
|
|
12497
|
+
* the indexed transaction. No Ponder row and a Convex row that still says
|
|
12498
|
+
* settled means the block that carried it was dropped: the row goes back to
|
|
12499
|
+
* `settling` and its annotation, which keys on the Payment id, is untouched.
|
|
12500
|
+
*/
|
|
12501
|
+
function confirmPayment(intent, chain, hasSettlement) {
|
|
12502
|
+
if (chain !== void 0) return {
|
|
12503
|
+
...intent,
|
|
12504
|
+
status: "settled",
|
|
12505
|
+
receipt: {
|
|
12506
|
+
chainId: chain.chainId,
|
|
12507
|
+
transactionHash: chain.txHash
|
|
12508
|
+
},
|
|
12509
|
+
updatedAt: blockMillis(chain)
|
|
12510
|
+
};
|
|
12511
|
+
if (hasSettlement && intent.status === "settled") return {
|
|
12512
|
+
...intent,
|
|
12513
|
+
status: "settling",
|
|
12514
|
+
receipt: null
|
|
12515
|
+
};
|
|
12516
|
+
return intent;
|
|
12517
|
+
}
|
|
12518
|
+
/**
|
|
12519
|
+
* One unclaimed Transfer as an Activity row, or `null` when this SDK cannot
|
|
12520
|
+
* denominate its asset. The indexer serves only configured assets, so a row
|
|
12521
|
+
* the registry does not know means the SDK and that deployment disagree; it is
|
|
12522
|
+
* dropped rather than shown with a guessed currency.
|
|
12523
|
+
*/
|
|
12524
|
+
function transferItem(safe, transfer, annotation) {
|
|
12525
|
+
const asset = configuredMoneyAssetById(transfer.assetId);
|
|
12526
|
+
if (asset === null) return null;
|
|
12527
|
+
const direction = directionFor(safe, transfer);
|
|
12528
|
+
const counterparty = direction === "in" ? transfer.from : transfer.to;
|
|
12529
|
+
const at = blockMillis(transfer);
|
|
12530
|
+
return withAnnotation({
|
|
12531
|
+
kind: "movement",
|
|
12532
|
+
id: transfer.id,
|
|
12533
|
+
classification: "movement_only_outflow",
|
|
12534
|
+
amount: {
|
|
12535
|
+
currency: asset.peg ?? asset.symbol,
|
|
12536
|
+
value: formatUnits(transfer.amount, asset.decimals),
|
|
12537
|
+
decimals: asset.decimals
|
|
12538
|
+
},
|
|
12539
|
+
direction,
|
|
12540
|
+
counterpartyLabel: shortAddressLabel(counterparty),
|
|
12541
|
+
receipt: {
|
|
12542
|
+
chainId: transfer.chainId,
|
|
12543
|
+
transactionHash: transfer.txHash
|
|
12544
|
+
},
|
|
12545
|
+
createdAt: at,
|
|
12546
|
+
updatedAt: at
|
|
12547
|
+
}, annotation);
|
|
12548
|
+
}
|
|
12549
|
+
/** Newest first. A Payment precedes a Movement at one instant, as the ledger reader orders them. */
|
|
12550
|
+
function compareItems(left, right) {
|
|
12551
|
+
if (right.createdAt !== left.createdAt) return right.createdAt - left.createdAt;
|
|
12552
|
+
if (left.kind !== right.kind) return left.kind === "payment" ? -1 : 1;
|
|
12553
|
+
if (left.id === right.id) return 0;
|
|
12554
|
+
return left.id < right.id ? 1 : -1;
|
|
12555
|
+
}
|
|
12556
|
+
function stitchActivity(input) {
|
|
12557
|
+
const safe = input.safe.toLowerCase();
|
|
12558
|
+
const chainBySettlement = /* @__PURE__ */ new Map();
|
|
12559
|
+
for (const row of input.payments) chainBySettlement.set(row.settlementId.toLowerCase(), row);
|
|
12560
|
+
const chainByPaymentId = /* @__PURE__ */ new Map();
|
|
12561
|
+
const settledPaymentIds = /* @__PURE__ */ new Set();
|
|
12562
|
+
for (const link of input.links) {
|
|
12563
|
+
settledPaymentIds.add(link.paymentId);
|
|
12564
|
+
const row = chainBySettlement.get(link.settlementId.toLowerCase());
|
|
12565
|
+
if (row !== void 0) chainByPaymentId.set(link.paymentId, row);
|
|
12566
|
+
}
|
|
12567
|
+
const annotations = /* @__PURE__ */ new Map();
|
|
12568
|
+
for (const annotation of input.annotations) annotations.set(`${annotation.reference.kind}:${annotation.reference.id}`, annotation);
|
|
12569
|
+
const items = [];
|
|
12570
|
+
const claiming = [];
|
|
12571
|
+
for (const intent of input.intents) {
|
|
12572
|
+
if (intent.kind !== "payment") continue;
|
|
12573
|
+
const chain = chainByPaymentId.get(intent.id);
|
|
12574
|
+
if (chain !== void 0) claiming.push(chain);
|
|
12575
|
+
items.push(withAnnotation(confirmPayment(intent, chain, settledPaymentIds.has(intent.id)), annotations.get(`payment:${intent.id}`)));
|
|
12576
|
+
}
|
|
12577
|
+
const claimed = claimedTransferIds(input.transfers, claiming);
|
|
12578
|
+
for (const transfer of input.transfers) {
|
|
12579
|
+
if (claimed.has(transfer.id)) continue;
|
|
12580
|
+
const item = transferItem(safe, transfer, annotations.get(`movement:${transfer.id}`));
|
|
12581
|
+
if (item !== null) items.push(item);
|
|
12582
|
+
}
|
|
12583
|
+
return items.sort(compareItems);
|
|
12584
|
+
}
|
|
12585
|
+
/** The reference ids one stitched page needs its Convex overlay for. */
|
|
12586
|
+
function overlayReferences(items) {
|
|
12587
|
+
return items.map((item) => ({
|
|
12588
|
+
kind: item.kind,
|
|
12589
|
+
id: item.id
|
|
12590
|
+
}));
|
|
12591
|
+
}
|
|
12592
|
+
/**
|
|
12593
|
+
* Money in, money out and the pending share, one bucket per currency and
|
|
12594
|
+
* precision. Two assets that peg to the same currency at different precision
|
|
12595
|
+
* stay distinct buckets: their raw units are not interchangeable.
|
|
12596
|
+
*/
|
|
12597
|
+
function summarizeItems(items) {
|
|
12598
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
12599
|
+
for (const item of items) {
|
|
12600
|
+
const key = `${item.amount.currency}:${String(item.amount.decimals)}`;
|
|
12601
|
+
const bucket = buckets.get(key) ?? {
|
|
12602
|
+
currency: item.amount.currency,
|
|
12603
|
+
decimals: item.amount.decimals,
|
|
12604
|
+
in: 0n,
|
|
12605
|
+
out: 0n,
|
|
12606
|
+
pendingIn: 0n
|
|
12607
|
+
};
|
|
12608
|
+
const raw = rawUnits(item.amount.value, item.amount.decimals);
|
|
12609
|
+
if (item.direction === "in") {
|
|
12610
|
+
bucket.in += raw;
|
|
12611
|
+
if (item.kind === "payment" && item.status !== "settled") bucket.pendingIn += raw;
|
|
12612
|
+
} else if (item.direction === "out") bucket.out += raw;
|
|
12613
|
+
buckets.set(key, bucket);
|
|
12614
|
+
}
|
|
12615
|
+
return [...buckets.values()].map((bucket) => ({
|
|
12616
|
+
currency: bucket.currency,
|
|
12617
|
+
decimals: bucket.decimals,
|
|
12618
|
+
in: bucket.in.toString(),
|
|
12619
|
+
out: bucket.out.toString(),
|
|
12620
|
+
net: (bucket.in - bucket.out).toString(),
|
|
12621
|
+
pendingIn: bucket.pendingIn.toString()
|
|
12622
|
+
}));
|
|
12623
|
+
}
|
|
12624
|
+
/** The inverse of `formatUnits`, kept exact: `"1.25"` at 6 decimals is `1250000n`. */
|
|
12625
|
+
function rawUnits(value, decimals) {
|
|
12626
|
+
const negative = value.startsWith("-");
|
|
12627
|
+
const [whole = "0", fraction = ""] = (negative ? value.slice(1) : value).split(".");
|
|
12628
|
+
const raw = BigInt(`${whole}${fraction.padEnd(decimals, "0").slice(0, decimals)}`);
|
|
12629
|
+
return negative ? -raw : raw;
|
|
12630
|
+
}
|
|
12631
|
+
//#endregion
|
|
12632
|
+
//#region ../../packages/sdk/src/surface/activity-read.ts
|
|
12633
|
+
/** How many Convex intent rows one page reads for its labels and pending rows. */
|
|
12634
|
+
const INTENT_WINDOW = 100;
|
|
12635
|
+
/** The window a summary aggregates over. The indexer's own page bound. */
|
|
12636
|
+
const SUMMARY_WINDOW = INDEXER_MAX_LIMIT;
|
|
12637
|
+
function parseCursor(value) {
|
|
12638
|
+
if (value === void 0) return 0;
|
|
12639
|
+
try {
|
|
12640
|
+
const parsed = JSON.parse(value);
|
|
12641
|
+
return Number.isSafeInteger(parsed.offset) && parsed.offset >= 0 ? parsed.offset : 0;
|
|
12642
|
+
} catch {
|
|
12643
|
+
return 0;
|
|
12644
|
+
}
|
|
12645
|
+
}
|
|
12646
|
+
function inRange(item, range) {
|
|
12647
|
+
if (range?.from !== void 0 && item.createdAt < range.from) return false;
|
|
12648
|
+
return range?.to === void 0 || item.createdAt <= range.to;
|
|
12649
|
+
}
|
|
12650
|
+
/** The caller's filter applied to the merged page. The join owns the order. */
|
|
12651
|
+
function matchesFilter(item, filter) {
|
|
12652
|
+
if (filter === void 0) return true;
|
|
12653
|
+
if (filter.kind !== void 0 && item.kind !== filter.kind) return false;
|
|
12654
|
+
if (filter.direction !== void 0 && item.direction !== filter.direction) return false;
|
|
12655
|
+
if (filter.status === void 0) return true;
|
|
12656
|
+
return item.kind === "payment" && filter.status.includes(item.status);
|
|
12657
|
+
}
|
|
12658
|
+
function overlay(deps, actor, controls, input) {
|
|
12659
|
+
return deps.convexCall.query(deps.functions.activityOverlay, copyInvocationObservation(controls, { input: {
|
|
12660
|
+
...actor === void 0 ? {} : { actor },
|
|
12661
|
+
...input.references === void 0 ? {} : { references: input.references },
|
|
12662
|
+
...input.settlementIds === void 0 ? {} : { settlementIds: input.settlementIds }
|
|
12663
|
+
} }));
|
|
12664
|
+
}
|
|
12665
|
+
function convexPage(deps, actor, controls, input) {
|
|
12666
|
+
return deps.convexCall.query(deps.functions.activityList, copyInvocationObservation(controls, { input: {
|
|
12667
|
+
...actor === void 0 ? {} : { actor },
|
|
12668
|
+
...input.cursor === void 0 ? {} : { cursor: input.cursor },
|
|
12669
|
+
...input.limit === void 0 ? {} : { limit: input.limit },
|
|
12670
|
+
...input.range === void 0 ? {} : { range: input.range }
|
|
12671
|
+
} }));
|
|
12672
|
+
}
|
|
12673
|
+
/** Both indexed tables for one Safe, or `null` when the indexer cannot answer. */
|
|
12674
|
+
function chainRows(deps, safe, limit) {
|
|
12675
|
+
const page = {
|
|
12676
|
+
safe,
|
|
12677
|
+
limit: Math.min(limit, INDEXER_MAX_LIMIT)
|
|
12678
|
+
};
|
|
12679
|
+
return Effect.all([deps.indexer.read("transfer", page), deps.indexer.read("payment", page)], { concurrency: 2 }).pipe(Effect.map(([transfers, payments]) => ({
|
|
12680
|
+
transfers,
|
|
12681
|
+
payments
|
|
12682
|
+
})), Effect.catch(() => Effect.succeed(null)));
|
|
12683
|
+
}
|
|
12684
|
+
/** The stitched, filtered rows of one window, newest first. */
|
|
12685
|
+
function stitchedWindow(deps, actor, controls, window, params) {
|
|
12686
|
+
return Effect.gen(function* () {
|
|
12687
|
+
const scope = yield* overlay(deps, actor, controls, {});
|
|
12688
|
+
const convex = yield* convexPage(deps, actor, controls, {
|
|
12689
|
+
limit: INTENT_WINDOW,
|
|
12690
|
+
...params.range === void 0 ? {} : { range: params.range }
|
|
12691
|
+
});
|
|
12692
|
+
const rows = scope.safe === null ? null : yield* chainRows(deps, scope.safe, window);
|
|
12693
|
+
if (rows === null || scope.safe === null) return {
|
|
12694
|
+
items: convex.items.filter((item) => matchesFilter(item, params.filter)),
|
|
12695
|
+
stitched: false
|
|
12696
|
+
};
|
|
12697
|
+
const decoration = yield* overlay(deps, actor, controls, {
|
|
12698
|
+
references: [...overlayReferences(convex.items), ...rows.transfers.map((row) => ({
|
|
12699
|
+
kind: "movement",
|
|
12700
|
+
id: row.id
|
|
12701
|
+
}))],
|
|
12702
|
+
settlementIds: rows.payments.map((row) => row.settlementId)
|
|
12703
|
+
});
|
|
12704
|
+
return {
|
|
12705
|
+
items: stitchActivity({
|
|
12706
|
+
safe: scope.safe,
|
|
12707
|
+
transfers: rows.transfers,
|
|
12708
|
+
payments: rows.payments,
|
|
12709
|
+
intents: convex.items,
|
|
12710
|
+
links: decoration.links,
|
|
12711
|
+
annotations: decoration.annotations
|
|
12712
|
+
}).filter((item) => inRange(item, params.range) && matchesFilter(item, params.filter)),
|
|
12713
|
+
stitched: true
|
|
12714
|
+
};
|
|
12715
|
+
});
|
|
12716
|
+
}
|
|
12717
|
+
function readActivityPage(deps, actor, controls, params) {
|
|
12718
|
+
const limit = params?.limit ?? 25;
|
|
12719
|
+
const offset = parseCursor(params?.cursor);
|
|
12720
|
+
return stitchedWindow(deps, actor, controls, offset + limit + 1, {
|
|
12721
|
+
...params?.range === void 0 ? {} : { range: params.range },
|
|
12722
|
+
...params?.filter === void 0 ? {} : { filter: params.filter }
|
|
12723
|
+
}).pipe(Effect.map(({ items, stitched }) => {
|
|
12724
|
+
const observedAt = Date.now();
|
|
12725
|
+
if (!stitched) return {
|
|
12726
|
+
items: items.slice(0, limit),
|
|
12727
|
+
cursor: null,
|
|
12728
|
+
checkpoint: observedAt,
|
|
12729
|
+
observedAt
|
|
12730
|
+
};
|
|
12731
|
+
return {
|
|
12732
|
+
items: items.slice(offset, offset + limit),
|
|
12733
|
+
cursor: items.length > offset + limit ? JSON.stringify({ offset: offset + limit }) : null,
|
|
12734
|
+
checkpoint: observedAt,
|
|
12735
|
+
observedAt
|
|
12736
|
+
};
|
|
12737
|
+
}));
|
|
12738
|
+
}
|
|
12739
|
+
function readActivitySummary(deps, actor, controls, params) {
|
|
12740
|
+
return stitchedWindow(deps, actor, controls, SUMMARY_WINDOW, params?.window === void 0 ? {} : { range: params.window }).pipe(Effect.map(({ items }) => ({
|
|
12741
|
+
window: {
|
|
12742
|
+
from: params?.window?.from ?? null,
|
|
12743
|
+
to: params?.window?.to ?? null
|
|
12744
|
+
},
|
|
12745
|
+
totals: summarizeItems(items),
|
|
12746
|
+
count: items.length,
|
|
12747
|
+
observedAt: Date.now()
|
|
12748
|
+
})));
|
|
12749
|
+
}
|
|
12750
|
+
/**
|
|
12751
|
+
* Tell the caller when the indexed page for this Safe changed.
|
|
12752
|
+
*
|
|
12753
|
+
* The transport is the indexer's one SSE connection, wired in the Ponder
|
|
12754
|
+
* adapter under `activity.subscribe`. A reactive snapshot is not a product
|
|
12755
|
+
* event, so nothing here emits telemetry: the adapter reports a teardown, and
|
|
12756
|
+
* the caller re-reads.
|
|
12757
|
+
*/
|
|
12758
|
+
function subscribeActivity(deps, actor, controls, onChange) {
|
|
12759
|
+
return Effect.gen(function* () {
|
|
12760
|
+
const scope = yield* overlay(deps, actor, controls, {});
|
|
12761
|
+
if (scope.safe === null) return () => {};
|
|
12762
|
+
const page = {
|
|
12763
|
+
safe: scope.safe,
|
|
12764
|
+
limit: INTENT_WINDOW
|
|
12765
|
+
};
|
|
12766
|
+
let delivered = false;
|
|
12767
|
+
const notify = () => {
|
|
12768
|
+
if (delivered) onChange();
|
|
12769
|
+
delivered = true;
|
|
12770
|
+
};
|
|
12771
|
+
return yield* deps.indexer.subscribe("transfer", page, (snapshot) => {
|
|
12772
|
+
if (snapshot.status === "ok") notify();
|
|
12773
|
+
});
|
|
12774
|
+
});
|
|
12775
|
+
}
|
|
12776
|
+
//#endregion
|
|
12380
12777
|
//#region ../../packages/sdk/package.json
|
|
12381
|
-
var version$1 = "4.2.0-rc.
|
|
12778
|
+
var version$1 = "4.2.0-rc.11";
|
|
12382
12779
|
//#endregion
|
|
12383
12780
|
//#region ../../packages/sdk/src/telemetry/exception-projection.ts
|
|
12384
12781
|
/** Fixed fallback for failures that have no safe message. */
|
|
@@ -12480,10 +12877,15 @@ function observeFailedResult(result, adapter, operation, origin) {
|
|
|
12480
12877
|
* A reactive stream is torn down after its call already returned, so nothing
|
|
12481
12878
|
* downstream observes it. `captureException` is the right kind: the caller did
|
|
12482
12879
|
* not ask for the end, so it is not an expected product outcome.
|
|
12880
|
+
*
|
|
12881
|
+
* A caller that DID ask for the end — the session it authenticated with
|
|
12882
|
+
* expired, and the service closed the stream on purpose — passes
|
|
12883
|
+
* `kind: "operation"` instead, so the refusal lands in the expected-outcome
|
|
12884
|
+
* stream its code already declares.
|
|
12483
12885
|
*/
|
|
12484
|
-
function observeStreamFailure(adapter, operation, cause) {
|
|
12886
|
+
function observeStreamFailure(adapter, operation, cause, kind = "exception") {
|
|
12485
12887
|
if (adapter === void 0) return;
|
|
12486
|
-
report(adapter,
|
|
12888
|
+
report(adapter, kind, operation, cause, resolveAdapterSnapshot(adapter));
|
|
12487
12889
|
}
|
|
12488
12890
|
/**
|
|
12489
12891
|
* One failure, one event. The identity machine reports a failed transition
|
|
@@ -13475,6 +13877,11 @@ function paymentExecutionIntent(input) {
|
|
|
13475
13877
|
}
|
|
13476
13878
|
function makeFinancialOpsMethods(deps) {
|
|
13477
13879
|
const fns = deps.functions ?? financialOpsContract;
|
|
13880
|
+
const indexerDeps = deps.indexerRead === void 0 ? void 0 : {
|
|
13881
|
+
indexer: deps.indexerRead,
|
|
13882
|
+
convexCall: deps.convexCall,
|
|
13883
|
+
functions: fns
|
|
13884
|
+
};
|
|
13478
13885
|
const executionFns = deps.moneyExecutionFunctions ?? moneyExecutionContract;
|
|
13479
13886
|
const requestKeyScope = deps.requestKeyScope ?? randomPaymentRequestKey();
|
|
13480
13887
|
const inFlightPersonalPayments = /* @__PURE__ */ new Map();
|
|
@@ -13705,22 +14112,26 @@ function makeFinancialOpsMethods(deps) {
|
|
|
13705
14112
|
}
|
|
13706
14113
|
},
|
|
13707
14114
|
activity: {
|
|
14115
|
+
subscribe: (onChange, params, options) => {
|
|
14116
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
14117
|
+
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => indexerDeps === void 0 ? Effect.succeed(() => {}) : Effect.suspend(() => subscribeActivity(indexerDeps, actor, controls, onChange)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.subscribe, deps.runPromise);
|
|
14118
|
+
},
|
|
13708
14119
|
list: (params, options) => {
|
|
13709
14120
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
13710
|
-
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => deps.convexCall.query(fns.activityList, copyInvocationObservation(controls, { input: {
|
|
14121
|
+
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => indexerDeps === void 0 ? deps.convexCall.query(fns.activityList, copyInvocationObservation(controls, { input: {
|
|
13711
14122
|
...actor === void 0 ? {} : { actor },
|
|
13712
14123
|
...params?.cursor === void 0 ? {} : { cursor: params.cursor },
|
|
13713
14124
|
...params?.limit === void 0 ? {} : { limit: params.limit },
|
|
13714
14125
|
...params?.range === void 0 ? {} : { range: params.range },
|
|
13715
14126
|
...params?.filter === void 0 ? {} : { filter: params.filter }
|
|
13716
|
-
} }))).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
|
|
14127
|
+
} })) : readActivityPage(indexerDeps, actor, controls, params)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.list, deps.runPromise);
|
|
13717
14128
|
},
|
|
13718
14129
|
summary: (params, options) => {
|
|
13719
14130
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
13720
|
-
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => deps.convexCall.query(fns.activitySummary, copyInvocationObservation(controls, { input: {
|
|
14131
|
+
return runPortEffect(captureActivityInput(() => Effect.succeed(activityActorField(params?.actor).actor)).pipe(Effect.flatMap((actor) => Effect.suspend(() => indexerDeps === void 0 ? deps.convexCall.query(fns.activitySummary, copyInvocationObservation(controls, { input: {
|
|
13721
14132
|
...actor === void 0 ? {} : { actor },
|
|
13722
14133
|
...params?.window === void 0 ? {} : { window: params.window }
|
|
13723
|
-
} }))).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.summary, deps.runPromise);
|
|
14134
|
+
} })) : readActivitySummary(indexerDeps, actor, controls, params)).pipe(Effect.tap(() => observeActivityScope(actor))))), controls, CAPXUL_OPERATIONS.activity.summary, deps.runPromise);
|
|
13724
14135
|
},
|
|
13725
14136
|
get: (reference, options) => {
|
|
13726
14137
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
@@ -18687,6 +19098,9 @@ const OBSERVED_CONVEX_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
18687
19098
|
"org/actions:resumeBootstrapSubmission",
|
|
18688
19099
|
"org/actions:confirmBootstrap",
|
|
18689
19100
|
"org/actions:readTreasury",
|
|
19101
|
+
"moneyExecution/actions:preparePermissionExecution",
|
|
19102
|
+
"moneyExecution/actions:submitPermissionExecution",
|
|
19103
|
+
"permission/actions:verify",
|
|
18690
19104
|
"moneyExecution/actions:preparePaymentExecution",
|
|
18691
19105
|
"moneyExecution/actions:abandonPaymentExecution",
|
|
18692
19106
|
"moneyExecution/actions:submitPaymentExecution",
|
|
@@ -18711,6 +19125,9 @@ const OBSERVED_CONVEX_QUERIES = /* @__PURE__ */ new Set([
|
|
|
18711
19125
|
"payroll/queries:groups",
|
|
18712
19126
|
"payroll/queries:terms",
|
|
18713
19127
|
"financialOps/queries:resolveRecipient",
|
|
19128
|
+
"org/queries:me",
|
|
19129
|
+
"permission/queries:read",
|
|
19130
|
+
"permission/queries:authorize",
|
|
18714
19131
|
"identity/queries:loadByAuthUserId",
|
|
18715
19132
|
"smartAccount/queries:loadByAuthUserId",
|
|
18716
19133
|
"org/lifecycle:load"
|
|
@@ -18729,6 +19146,7 @@ const OBSERVED_CONVEX_MUTATIONS = /* @__PURE__ */ new Set([
|
|
|
18729
19146
|
"financialOps/requestsInbox:decline",
|
|
18730
19147
|
"payroll/mutations:saveGroup",
|
|
18731
19148
|
"payroll/mutations:removeGroup",
|
|
19149
|
+
"permission/mutations:command",
|
|
18732
19150
|
"identity/mutations:create",
|
|
18733
19151
|
"identity/mutations:update",
|
|
18734
19152
|
"identity/mutations:completeOnboarding",
|
|
@@ -44732,8 +45150,33 @@ function toOrgMe(wire) {
|
|
|
44732
45150
|
observedAt: wire.observedAt
|
|
44733
45151
|
};
|
|
44734
45152
|
}
|
|
45153
|
+
/**
|
|
45154
|
+
* The read runs through the canonical observed runner, so `org.me` owns one
|
|
45155
|
+
* `capxul_sdk_operation` record and one span like every other public method.
|
|
45156
|
+
*
|
|
45157
|
+
* The call-start invocation snapshot travels on the query arguments: the
|
|
45158
|
+
* Convex adapter reads it there and sends the browser linkage with the call,
|
|
45159
|
+
* so an account switch mid-flight cannot re-resolve the actor. A successful
|
|
45160
|
+
* read proves participation in this Organization, so the owning span carries
|
|
45161
|
+
* the verified Organization and the two authority booleans the backend
|
|
45162
|
+
* actually enforces. Labels and Budget caps stay off the record.
|
|
45163
|
+
*/
|
|
44735
45164
|
function makeOrgMeMethod(deps, orgId) {
|
|
44736
|
-
return (options) =>
|
|
45165
|
+
return (options) => {
|
|
45166
|
+
const controls = deps.invocationControls?.(options) ?? options;
|
|
45167
|
+
return runCapxulEffect(Effect.gen(function* () {
|
|
45168
|
+
const wire = yield* deps.convexCall.query(orgReadContract.me, copyInvocationObservation(controls, { orgId })).pipe(Effect.mapError((failure) => failure.publicError));
|
|
45169
|
+
yield* Effect.annotateCurrentSpan({
|
|
45170
|
+
verified_organization_id: orgId,
|
|
45171
|
+
scope_kind: "organization",
|
|
45172
|
+
can_manage_people: wire.capabilities.canManagePeople,
|
|
45173
|
+
can_spend: wire.capabilities.canSpend,
|
|
45174
|
+
budget_count: wire.budgets.length,
|
|
45175
|
+
observed_at: wire.observedAt
|
|
45176
|
+
}).pipe(Effect.catchCause(() => Effect.void));
|
|
45177
|
+
return toOrgMe(wire);
|
|
45178
|
+
}), controls, CAPXUL_OPERATIONS.org.me, deps.runPromise);
|
|
45179
|
+
};
|
|
44737
45180
|
}
|
|
44738
45181
|
//#endregion
|
|
44739
45182
|
//#region ../../packages/sdk/src/contract/permission.ts
|
|
@@ -44753,16 +45196,24 @@ function isAborted(signal) {
|
|
|
44753
45196
|
*/
|
|
44754
45197
|
function observed(deps, operation, options, run) {
|
|
44755
45198
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
45199
|
+
let verifiedOrganizationId;
|
|
44756
45200
|
return runCapxulEffect(Effect.gen(function* () {
|
|
44757
45201
|
if (controls?.signal?.aborted === true) return yield* Effect.fail(Errors.cancelled({ operation }));
|
|
45202
|
+
const parent = yield* Effect.currentSpan.pipe(Effect.orDie);
|
|
45203
|
+
const captured = carryInvocationParentSpan(controls, parent);
|
|
44758
45204
|
const result = yield* Effect.tryPromise({
|
|
44759
|
-
try: () => run(controls?.signal)
|
|
45205
|
+
try: () => run(controls?.signal, captured, (orgId) => {
|
|
45206
|
+
verifiedOrganizationId = orgId;
|
|
45207
|
+
}),
|
|
44760
45208
|
catch: (cause) => cause instanceof CapxulError ? cause : Errors.unknown(cause)
|
|
44761
45209
|
});
|
|
44762
45210
|
return yield* result.ok ? Effect.succeed(result.value) : Effect.fail(result.error);
|
|
44763
|
-
})
|
|
45211
|
+
}).pipe(Effect.ensuring(Effect.suspend(() => verifiedOrganizationId === void 0 ? Effect.void : Effect.annotateCurrentSpan({
|
|
45212
|
+
verified_organization_id: verifiedOrganizationId,
|
|
45213
|
+
scope_kind: "organization"
|
|
45214
|
+
})).pipe(Effect.catchCause(() => Effect.void)))), observationOnlyControls(controls), operation, deps.runPromise);
|
|
44764
45215
|
}
|
|
44765
|
-
async function execute(deps, orgId, command, signal) {
|
|
45216
|
+
async function execute(deps, orgId, command, signal, controls, verifiedOrganization) {
|
|
44766
45217
|
if (isAborted(signal)) return {
|
|
44767
45218
|
ok: false,
|
|
44768
45219
|
error: Errors.cancelled({ operation: "permissions" })
|
|
@@ -44786,17 +45237,18 @@ async function execute(deps, orgId, command, signal) {
|
|
|
44786
45237
|
};
|
|
44787
45238
|
}
|
|
44788
45239
|
const executionFns = deps.executionFunctions ?? moneyExecutionContract;
|
|
44789
|
-
const prepared = await runIfActive(signal, CAPXUL_OPERATIONS.permissions.prepareExecution, () => deps.convexCall.action(executionFns.preparePermissionExecution, { input: {
|
|
45240
|
+
const prepared = await runIfActive(signal, CAPXUL_OPERATIONS.permissions.prepareExecution, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.action(executionFns.preparePermissionExecution, copyInvocationObservation(controls, { input: {
|
|
44790
45241
|
orgId,
|
|
44791
45242
|
signerAddress,
|
|
44792
45243
|
command
|
|
44793
|
-
} }));
|
|
45244
|
+
} }))), controls), deps.runPromise);
|
|
44794
45245
|
if (!prepared.ok) return prepared;
|
|
44795
45246
|
const expectedSafe = deriveCapxulSafeAddress({ email: session.email });
|
|
44796
45247
|
if (prepared.value.chainId !== deps.chainId || prepared.value.signerAddress.toLowerCase() !== signerAddress.toLowerCase() || prepared.value.userOpSenderSafe.toLowerCase() !== expectedSafe.toLowerCase() || prepared.value.operation !== command.operation || prepared.value.orgId !== orgId || canonicalJson(prepared.value.command) !== canonicalJson(command)) return {
|
|
44797
45248
|
ok: false,
|
|
44798
45249
|
error: Errors.invalidInput("permission", "prepared authority mismatch")
|
|
44799
45250
|
};
|
|
45251
|
+
verifiedOrganization(prepared.value.orgId);
|
|
44800
45252
|
if (isAborted(signal)) return {
|
|
44801
45253
|
ok: false,
|
|
44802
45254
|
error: Errors.cancelled({ operation: "permissions" })
|
|
@@ -44814,38 +45266,40 @@ async function execute(deps, orgId, command, signal) {
|
|
|
44814
45266
|
ok: false,
|
|
44815
45267
|
error: Errors.cancelled({ operation: "permissions" })
|
|
44816
45268
|
};
|
|
44817
|
-
return runIfActive(void 0, CAPXUL_OPERATIONS.permissions.submitExecution, () => deps.convexCall.action(executionFns.submitPermissionExecution, { input: {
|
|
45269
|
+
return runIfActive(void 0, CAPXUL_OPERATIONS.permissions.submitExecution, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.action(executionFns.submitPermissionExecution, copyInvocationObservation(controls, { input: {
|
|
44818
45270
|
executionId: prepared.value.executionId,
|
|
44819
45271
|
signature
|
|
44820
|
-
} }));
|
|
45272
|
+
} }))), controls), deps.runPromise);
|
|
44821
45273
|
}
|
|
44822
45274
|
function makePermissionMethods(deps, orgId) {
|
|
44823
45275
|
const reads = deps.permissionFunctions ?? permissionContract;
|
|
44824
45276
|
const ops = CAPXUL_OPERATIONS.org.permissions;
|
|
45277
|
+
const read = (signal, operation, controls) => runIfActive(signal, operation, () => withInvocationParentSpan(Effect.suspend(() => deps.convexCall.query(reads.read, copyInvocationObservation(controls, { orgId }))), controls), deps.runPromise);
|
|
45278
|
+
const command = (operation, build, options) => observed(deps, operation, options, (signal, captured, verifiedOrganization) => execute(deps, orgId, build(), signal, captured, verifiedOrganization));
|
|
44825
45279
|
return {
|
|
44826
|
-
create: (input, options) =>
|
|
45280
|
+
create: (input, options) => command(ops.create, () => ({
|
|
44827
45281
|
operation: "create",
|
|
44828
45282
|
...input
|
|
44829
|
-
},
|
|
44830
|
-
change: (input, options) =>
|
|
45283
|
+
}), options),
|
|
45284
|
+
change: (input, options) => command(ops.change, () => ({
|
|
44831
45285
|
operation: "change",
|
|
44832
45286
|
...input
|
|
44833
|
-
},
|
|
44834
|
-
assign: (input, options) =>
|
|
45287
|
+
}), options),
|
|
45288
|
+
assign: (input, options) => command(ops.assign, () => ({
|
|
44835
45289
|
operation: "assign",
|
|
44836
45290
|
...input
|
|
44837
|
-
},
|
|
44838
|
-
revoke: (input, options) =>
|
|
45291
|
+
}), options),
|
|
45292
|
+
revoke: (input, options) => command(ops.revoke, () => ({
|
|
44839
45293
|
operation: "revoke",
|
|
44840
45294
|
...input
|
|
44841
|
-
},
|
|
44842
|
-
replace: (input, options) =>
|
|
45295
|
+
}), options),
|
|
45296
|
+
replace: (input, options) => command(ops.replace, () => ({
|
|
44843
45297
|
operation: "replace",
|
|
44844
45298
|
...input
|
|
44845
|
-
},
|
|
44846
|
-
list: (options) => observed(deps, ops.list, options, (signal) =>
|
|
44847
|
-
get: (permissionId, options) => observed(deps, ops.get, options, async (signal) => {
|
|
44848
|
-
const listed = await
|
|
45299
|
+
}), options),
|
|
45300
|
+
list: (options) => observed(deps, ops.list, options, (signal, captured) => read(signal, CAPXUL_OPERATIONS.permissions.list, captured)),
|
|
45301
|
+
get: (permissionId, options) => observed(deps, ops.get, options, async (signal, captured) => {
|
|
45302
|
+
const listed = await read(signal, CAPXUL_OPERATIONS.permissions.get, captured);
|
|
44849
45303
|
if (!listed.ok) return listed;
|
|
44850
45304
|
return {
|
|
44851
45305
|
ok: true,
|
|
@@ -45716,7 +46170,10 @@ function makeOrgMethods(deps) {
|
|
|
45716
46170
|
},
|
|
45717
46171
|
...convexCall === void 0 ? {} : { convexCall }
|
|
45718
46172
|
}),
|
|
45719
|
-
me: convexCall === void 0 ? orgMeUnavailable : makeOrgMeMethod({
|
|
46173
|
+
me: convexCall === void 0 ? orgMeUnavailable : makeOrgMeMethod({
|
|
46174
|
+
convexCall,
|
|
46175
|
+
...observedRunnerDeps(deps)
|
|
46176
|
+
}, String(orgId)),
|
|
45720
46177
|
async getLifecycle(options) {
|
|
45721
46178
|
if (options?.signal?.aborted) return {
|
|
45722
46179
|
ok: false,
|
|
@@ -45953,14 +46410,65 @@ function compareDecimal(first, second) {
|
|
|
45953
46410
|
}
|
|
45954
46411
|
//#endregion
|
|
45955
46412
|
//#region ../../packages/sdk/src/surface/holdings.ts
|
|
46413
|
+
/** SPEC Freshness: past this block age the read is labelled stale. Nothing refuses. */
|
|
46414
|
+
const FRESHNESS_LIMIT_SECONDS = 60;
|
|
46415
|
+
/**
|
|
46416
|
+
* The Ponder balance view for one Safe as `CurrentHoldings`.
|
|
46417
|
+
*
|
|
46418
|
+
* The view is the signed sum of every indexed transfer, so the balance IS what
|
|
46419
|
+
* the chain said — there is no snapshot to go stale behind it. `observedAt` is
|
|
46420
|
+
* the indexed block's own timestamp, which is what the last-good label reads,
|
|
46421
|
+
* and `stale` is that block's age. A stopped indexer therefore shows an old
|
|
46422
|
+
* "as of" and the stale flag; it never turns the read into a refusal.
|
|
46423
|
+
*/
|
|
46424
|
+
function indexerHoldings(indexer, convexCall, overlay, actor, controls) {
|
|
46425
|
+
return Effect.gen(function* () {
|
|
46426
|
+
const scope = yield* convexCall.query(overlay, copyInvocationObservation(controls, actor?.kind === "organization" ? { input: { actor: {
|
|
46427
|
+
kind: "organization",
|
|
46428
|
+
orgId: actor.organizationId
|
|
46429
|
+
} } } : { input: {} }));
|
|
46430
|
+
if (scope.safe === null) return null;
|
|
46431
|
+
const balances = yield* indexer.read("balance", {
|
|
46432
|
+
safe: toAddress(scope.safe),
|
|
46433
|
+
limit: INDEXER_MAX_LIMIT
|
|
46434
|
+
});
|
|
46435
|
+
const status = yield* indexer.status.pipe(Effect.catch(() => Effect.succeed([])));
|
|
46436
|
+
const rows = [];
|
|
46437
|
+
for (const balance of balances) {
|
|
46438
|
+
const asset = configuredMoneyAssetById(balance.assetId);
|
|
46439
|
+
if (asset === null || balance.amount < 0n) continue;
|
|
46440
|
+
rows.push({
|
|
46441
|
+
assetKind: "erc20",
|
|
46442
|
+
tokenAddress: toAddress(asset.tokenAddress),
|
|
46443
|
+
symbol: asset.symbol,
|
|
46444
|
+
decimals: asset.decimals,
|
|
46445
|
+
rawBalance: toWeiAmount(balance.amount.toString())
|
|
46446
|
+
});
|
|
46447
|
+
}
|
|
46448
|
+
const chainId = balances[0]?.chainId ?? status[0]?.chainId;
|
|
46449
|
+
if (chainId === void 0) return null;
|
|
46450
|
+
const head = status.find((entry) => entry.chainId === chainId);
|
|
46451
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
46452
|
+
const headSeconds = head === void 0 ? void 0 : Number(head.blockTimestamp);
|
|
46453
|
+
return {
|
|
46454
|
+
actor: scope.actor,
|
|
46455
|
+
chainId: toChainId(chainId),
|
|
46456
|
+
observedAt: headSeconds === void 0 ? Date.now() : headSeconds * 1e3,
|
|
46457
|
+
stale: headSeconds === void 0 || nowSeconds - headSeconds > FRESHNESS_LIMIT_SECONDS,
|
|
46458
|
+
rows
|
|
46459
|
+
};
|
|
46460
|
+
}).pipe(Effect.catch(() => Effect.succeed(null)));
|
|
46461
|
+
}
|
|
45956
46462
|
function makeHoldingsMethods(deps) {
|
|
45957
46463
|
const functions = deps.functions ?? holdingsContract;
|
|
46464
|
+
const overlay = (deps.financialOpsFunctions ?? financialOpsContract).activityOverlay;
|
|
45958
46465
|
const read = (operation, actor, options, pick) => {
|
|
45959
46466
|
const controls = deps.invocationControls?.(options) ?? options;
|
|
45960
|
-
|
|
46467
|
+
const convexSnapshot = retryIdempotentRead(deps.convexCall.action(functions.current, copyInvocationObservation(controls, actor?.kind === "organization" ? { actor: {
|
|
45961
46468
|
kind: "organization",
|
|
45962
46469
|
orgId: actor.organizationId
|
|
45963
|
-
} } : {})), operation, deps.telemetry, controls).pipe(Effect.
|
|
46470
|
+
} } : {})), operation, deps.telemetry, controls).pipe(Effect.mapError((error) => error.publicError));
|
|
46471
|
+
return runCapxulEffect((deps.indexerRead === void 0 ? convexSnapshot : indexerHoldings(deps.indexerRead, deps.convexCall, overlay, actor, controls).pipe(Effect.flatMap((current) => current === null ? convexSnapshot : Effect.succeed(current)))).pipe(Effect.map(pick)), controls, operation, deps.runPromise);
|
|
45964
46472
|
};
|
|
45965
46473
|
return {
|
|
45966
46474
|
current: (input, options) => read(CAPXUL_OPERATIONS.holdings.current, input?.actor, options, (snapshot) => snapshot),
|
|
@@ -46094,8 +46602,8 @@ const APPLIED_ACTION_BY_EVENT = {
|
|
|
46094
46602
|
RestoreSession: "none",
|
|
46095
46603
|
ResumeOtpEntry: "none",
|
|
46096
46604
|
Reset: "none",
|
|
46097
|
-
SessionRestored: "
|
|
46098
|
-
SessionAbsent: "
|
|
46605
|
+
SessionRestored: "restoration",
|
|
46606
|
+
SessionAbsent: "restoration",
|
|
46099
46607
|
EnsureAccount: "none",
|
|
46100
46608
|
ClaimAccount: "none",
|
|
46101
46609
|
RetryAccount: "none",
|
|
@@ -46107,8 +46615,8 @@ const APPLIED_ACTION_BY_EVENT = {
|
|
|
46107
46615
|
OtpFailed: "failed",
|
|
46108
46616
|
Verified: "verified",
|
|
46109
46617
|
VerifyFailed: "failed",
|
|
46110
|
-
SessionRead: "
|
|
46111
|
-
SessionReadFailed: "
|
|
46618
|
+
SessionRead: "restoration",
|
|
46619
|
+
SessionReadFailed: "restoration",
|
|
46112
46620
|
SignedOut: "signed-out",
|
|
46113
46621
|
SignOutFailed: "failed",
|
|
46114
46622
|
AccountAt: "none",
|
|
@@ -46134,6 +46642,49 @@ const authFailure = (record, reason, mode) => ({
|
|
|
46134
46642
|
...linkage(record)
|
|
46135
46643
|
}
|
|
46136
46644
|
});
|
|
46645
|
+
/**
|
|
46646
|
+
* The label of the restore window every client boots into. A settled session
|
|
46647
|
+
* fact that left this label is the restoration result (#1962 R04); the same
|
|
46648
|
+
* facts from a signed-out or authenticated state are the routine session probe
|
|
46649
|
+
* that `getSession()` runs, and a probe is not a restoration attempt.
|
|
46650
|
+
*/
|
|
46651
|
+
const RESTORE_WINDOW = "restoring";
|
|
46652
|
+
/**
|
|
46653
|
+
* Which result the window settled on. `SessionRestored` and `SessionAbsent` are
|
|
46654
|
+
* the cache door and say it themselves. `ReadSession` is also valid inside the
|
|
46655
|
+
* window — `getSession()` drives it on a cache miss and its `SessionRead`
|
|
46656
|
+
* completion settles the window — so that one event reports both halves and the
|
|
46657
|
+
* state it produced is what separates them.
|
|
46658
|
+
*/
|
|
46659
|
+
const restorationOutcome = (event, state) => {
|
|
46660
|
+
switch (event) {
|
|
46661
|
+
case "SessionRestored": return "restored";
|
|
46662
|
+
case "SessionAbsent": return "absent";
|
|
46663
|
+
case "SessionReadFailed": return "failed";
|
|
46664
|
+
case "SessionRead":
|
|
46665
|
+
if (state.phase === "authenticated") return "restored";
|
|
46666
|
+
return state.phase === "signed_out" ? "absent" : void 0;
|
|
46667
|
+
default: return;
|
|
46668
|
+
}
|
|
46669
|
+
};
|
|
46670
|
+
/**
|
|
46671
|
+
* The restore window's one result, or nothing when this settled session fact
|
|
46672
|
+
* belongs to a probe rather than to the window.
|
|
46673
|
+
*/
|
|
46674
|
+
const restorationObservation = (record, state) => {
|
|
46675
|
+
if (record.slot !== "identity:session" || record.from !== RESTORE_WINDOW) return NONE;
|
|
46676
|
+
const outcome = restorationOutcome(record.event, state);
|
|
46677
|
+
if (outcome === void 0) return NONE;
|
|
46678
|
+
return {
|
|
46679
|
+
name: "access_recovery_completed",
|
|
46680
|
+
props: {
|
|
46681
|
+
recovery: "session_restoration",
|
|
46682
|
+
outcome,
|
|
46683
|
+
...outcome === "failed" && state.phase === "faulted" ? { reason_code: state.failure.code } : {},
|
|
46684
|
+
...linkage(record)
|
|
46685
|
+
}
|
|
46686
|
+
};
|
|
46687
|
+
};
|
|
46137
46688
|
const REFUSAL_EVENTS = /* @__PURE__ */ new Set([
|
|
46138
46689
|
"ClaimAccount",
|
|
46139
46690
|
"RetryAccount",
|
|
@@ -46178,6 +46729,7 @@ function mapIdentityProductObservation(record, state) {
|
|
|
46178
46729
|
name: "auth_signed_out",
|
|
46179
46730
|
props: linkage(record)
|
|
46180
46731
|
};
|
|
46732
|
+
case "restoration": return restorationObservation(record, state);
|
|
46181
46733
|
}
|
|
46182
46734
|
}
|
|
46183
46735
|
const ignoreTransportFailure = (operation, operationName, eventName) => Effect.suspend(operation).pipe(Effect.catchCause(() => Effect.logWarning("identity.product.telemetry.dropped").pipe(Effect.annotateLogs({
|
|
@@ -46189,7 +46741,7 @@ function executeIdentityProductObservation(telemetry, record, state) {
|
|
|
46189
46741
|
if (mapped === null) return Effect.void;
|
|
46190
46742
|
copyInvocationObservation(record, mapped);
|
|
46191
46743
|
const invocationTelemetry = bindProductTelemetryInvocation(telemetry, mapped);
|
|
46192
|
-
const after = () => mapped.name === "auth_verified"
|
|
46744
|
+
const after = () => state.phase === "authenticated" && (mapped.name === "auth_verified" || mapped.name === "access_recovery_completed") ? invocationTelemetry.identify({
|
|
46193
46745
|
distinctId: state.session.authUserId,
|
|
46194
46746
|
traits: { email_domain: emailDomain(state.session.email) }
|
|
46195
46747
|
}) : mapped.name === "auth_signed_out" ? invocationTelemetry.reset() : Effect.void;
|
|
@@ -46234,6 +46786,51 @@ function startSignerReadinessOnClaim(actor, signer) {
|
|
|
46234
46786
|
browserSigner.ensureWalletReady?.().catch(() => {});
|
|
46235
46787
|
});
|
|
46236
46788
|
}
|
|
46789
|
+
/**
|
|
46790
|
+
* Report the result of each signer readiness cycle (#1962 R04).
|
|
46791
|
+
*
|
|
46792
|
+
* The readiness store already carries the cycle boundary this needs, so no
|
|
46793
|
+
* public signer hook, second identity subscriber, or render counter is added.
|
|
46794
|
+
* `ensureOpenfortWalletReady` writes `recovering` synchronously when it starts
|
|
46795
|
+
* a cycle, and only the cycle that is still the current one writes `ready` or
|
|
46796
|
+
* `unavailable` (`create-openfort-browser-signer.ts:501-521`). Callers that
|
|
46797
|
+
* join a live cycle share that single write, and a `resetSession` writes
|
|
46798
|
+
* `unknown` first, so a cycle that a reset or an account replacement outran
|
|
46799
|
+
* reports nothing.
|
|
46800
|
+
*
|
|
46801
|
+
* The host context is bound when the cycle starts, so a person who signs out
|
|
46802
|
+
* and back in while a cycle runs cannot relabel the result that began under
|
|
46803
|
+
* the previous person. A signer with no readiness cycle — a node or dev key,
|
|
46804
|
+
* and a headless client whose requirement never opens the account lane —
|
|
46805
|
+
* writes no status and reports nothing.
|
|
46806
|
+
*/
|
|
46807
|
+
function observeSignerReadinessCycles(signer, telemetry, hostObservationSnapshot, runPromise) {
|
|
46808
|
+
const statusStore = signer?.statusStore;
|
|
46809
|
+
if (statusStore === void 0 || telemetry === void 0) return () => {};
|
|
46810
|
+
let running = false;
|
|
46811
|
+
let startContext;
|
|
46812
|
+
return statusStore.subscribe((status) => {
|
|
46813
|
+
if (status === "recovering") {
|
|
46814
|
+
running = true;
|
|
46815
|
+
startContext = hostObservationSnapshot?.();
|
|
46816
|
+
return;
|
|
46817
|
+
}
|
|
46818
|
+
const cycleContext = startContext;
|
|
46819
|
+
const completesCycle = running;
|
|
46820
|
+
running = false;
|
|
46821
|
+
startContext = void 0;
|
|
46822
|
+
if (!completesCycle || status !== "ready" && status !== "unavailable") return;
|
|
46823
|
+
const event = {
|
|
46824
|
+
name: "access_recovery_completed",
|
|
46825
|
+
props: {
|
|
46826
|
+
recovery: "signer_readiness",
|
|
46827
|
+
outcome: status
|
|
46828
|
+
}
|
|
46829
|
+
};
|
|
46830
|
+
if (cycleContext !== void 0) attachInvocationObservation(event, cycleContext);
|
|
46831
|
+
runPromise(Effect.suspend(() => bindProductTelemetryInvocation(telemetry, event).emit(event)).pipe(Effect.catchCause(() => Effect.void))).catch(() => {});
|
|
46832
|
+
});
|
|
46833
|
+
}
|
|
46237
46834
|
function assembleCapxulClient(input) {
|
|
46238
46835
|
const observation = input;
|
|
46239
46836
|
const authCache = input.authCache ?? detectAuthCacheAdapter();
|
|
@@ -46263,12 +46860,14 @@ function assembleCapxulClient(input) {
|
|
|
46263
46860
|
}, failureObservation, normalizeCapxulOperation(`identity.${record.event}`), "machine");
|
|
46264
46861
|
});
|
|
46265
46862
|
const unsubscribeSignerReadiness = startSignerReadinessOnClaim(actor, input.signer);
|
|
46863
|
+
const unsubscribeReadinessObservation = observeSignerReadinessCycles(input.signer, input.ports.telemetry, observation.hostObservationSnapshot, effectRunner.runPromise);
|
|
46266
46864
|
let stopPromise = null;
|
|
46267
46865
|
const stopActor = () => {
|
|
46268
46866
|
if (stopPromise === null) {
|
|
46269
46867
|
unsubscribeProductTelemetry();
|
|
46270
46868
|
unsubscribeFailureObservation();
|
|
46271
46869
|
unsubscribeSignerReadiness();
|
|
46870
|
+
unsubscribeReadinessObservation();
|
|
46272
46871
|
stopPromise = effectRunner.runPromise(Scope.close(scope, Exit.void));
|
|
46273
46872
|
}
|
|
46274
46873
|
return stopPromise;
|
|
@@ -46285,7 +46884,8 @@ function assembleCapxulClient(input) {
|
|
|
46285
46884
|
convexCall: input.ports.convexCall,
|
|
46286
46885
|
...input.signer === void 0 ? {} : { signer: input.signer },
|
|
46287
46886
|
telemetry: input.ports.telemetry,
|
|
46288
|
-
requestKeyScope: `${input.bootstrap.convexUrl}:${String(input.bootstrap.chainId)}
|
|
46887
|
+
requestKeyScope: `${input.bootstrap.convexUrl}:${String(input.bootstrap.chainId)}`,
|
|
46888
|
+
...input.ports.indexerRead === void 0 ? {} : { indexerRead: input.ports.indexerRead }
|
|
46289
46889
|
});
|
|
46290
46890
|
const accountBundle = makeAccountMethods({
|
|
46291
46891
|
actor,
|
|
@@ -46356,7 +46956,8 @@ function assembleCapxulClient(input) {
|
|
|
46356
46956
|
convexCall: input.ports.convexCall,
|
|
46357
46957
|
telemetry: input.ports.telemetry,
|
|
46358
46958
|
runPromise: effectRunner.runPromise,
|
|
46359
|
-
invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls, actor.authSession()?.authUserId)
|
|
46959
|
+
invocationControls: (controls) => withHostObservationControls(observation.hostObservationSnapshot, controls, actor.authSession()?.authUserId),
|
|
46960
|
+
...input.ports.indexerRead === void 0 ? {} : { indexerRead: input.ports.indexerRead }
|
|
46360
46961
|
});
|
|
46361
46962
|
const accounts = makeAccountsMethods({
|
|
46362
46963
|
accountReadPort: input.ports.accountRead,
|
|
@@ -46563,36 +47164,6 @@ function snapshotHostObservability(observability) {
|
|
|
46563
47164
|
};
|
|
46564
47165
|
}
|
|
46565
47166
|
//#endregion
|
|
46566
|
-
//#region ../../packages/sdk/src/ports/indexer-read.ts
|
|
46567
|
-
/** The indexer's own page bound. Exceeding it is a caller defect, not a refusal. */
|
|
46568
|
-
const INDEXER_MAX_LIMIT = 1e3;
|
|
46569
|
-
const LOWER_CASE_ADDRESS = /^0x[0-9a-f]{40}$/;
|
|
46570
|
-
/**
|
|
46571
|
-
* Refuse a page the indexer would refuse, before any implementation spends a
|
|
46572
|
-
* round trip on it. Every implementation calls this, so a consumer test written
|
|
46573
|
-
* against the hermetic adapter cannot pass on input production rejects. Throws
|
|
46574
|
-
* a `CapxulError`; callers convert it to an `IndexerReadError`.
|
|
46575
|
-
*/
|
|
46576
|
-
function assertIndexerPage(input) {
|
|
46577
|
-
const safe = String(input.safe).toLowerCase();
|
|
46578
|
-
if (!LOWER_CASE_ADDRESS.test(safe)) throw Errors.invalidInput("safe", "must be a lower-case EVM address");
|
|
46579
|
-
if (!Number.isSafeInteger(input.limit) || input.limit < 1 || input.limit > 1e3) throw Errors.invalidInput("limit", `must be an integer from 1 to ${INDEXER_MAX_LIMIT}`);
|
|
46580
|
-
const offset = input.offset ?? 0;
|
|
46581
|
-
if (!Number.isSafeInteger(offset) || offset < 0) throw Errors.invalidInput("offset", "must be a non-negative integer");
|
|
46582
|
-
return safe;
|
|
46583
|
-
}
|
|
46584
|
-
var IndexerReadError = class extends Data.TaggedError("IndexerReadError") {};
|
|
46585
|
-
function indexerReadErrorFromCapxul(operation, error, cause = error) {
|
|
46586
|
-
return new IndexerReadError({
|
|
46587
|
-
operation,
|
|
46588
|
-
publicCode: error.code,
|
|
46589
|
-
publicError: error,
|
|
46590
|
-
cause,
|
|
46591
|
-
...error.details === void 0 ? {} : { details: error.details }
|
|
46592
|
-
});
|
|
46593
|
-
}
|
|
46594
|
-
Context.Service()("@capxul/sdk/ports/IndexerReadPort");
|
|
46595
|
-
//#endregion
|
|
46596
47167
|
//#region ../../packages/sdk/src/adapters/ponder/decode.ts
|
|
46597
47168
|
/**
|
|
46598
47169
|
* Decode the indexer's rows at the trust boundary.
|
|
@@ -46898,7 +47469,7 @@ var PonderIndexerAdapter = class {
|
|
|
46898
47469
|
}
|
|
46899
47470
|
if (stopped()) return;
|
|
46900
47471
|
const error = failure ?? Errors.capabilityUnavailable("indexer", operation);
|
|
46901
|
-
observeStreamFailure(this.#observation, CAPXUL_OPERATIONS.activity.subscribe, error);
|
|
47472
|
+
observeStreamFailure(this.#observation, CAPXUL_OPERATIONS.activity.subscribe, error, error.code === "NOT_AUTHENTICATED" ? "operation" : "exception");
|
|
46902
47473
|
callback({
|
|
46903
47474
|
status: "error",
|
|
46904
47475
|
error
|
|
@@ -47743,6 +48314,7 @@ function idempotentClose(close) {
|
|
|
47743
48314
|
* and Convex see one session with one scope.
|
|
47744
48315
|
*/
|
|
47745
48316
|
function productionIndexerReadPort(input, ports, observation) {
|
|
48317
|
+
if (input.activityReadSource === "convex") return void 0;
|
|
47746
48318
|
if (input.indexerUrl === void 0 || input.indexerUrl === "") return void 0;
|
|
47747
48319
|
return new PonderIndexerAdapter({
|
|
47748
48320
|
baseUrl: normalizeHttpUrl("indexerUrl", input.indexerUrl),
|
|
@@ -48369,7 +48941,7 @@ function stdioIdentity(env = process.env, options = {}) {
|
|
|
48369
48941
|
}
|
|
48370
48942
|
//#endregion
|
|
48371
48943
|
//#region package.json
|
|
48372
|
-
var version = "4.2.0-rc.
|
|
48944
|
+
var version = "4.2.0-rc.11";
|
|
48373
48945
|
//#endregion
|
|
48374
48946
|
//#region src/deps.ts
|
|
48375
48947
|
const NO_IDENTITY = async () => void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capxul/mcp",
|
|
3
|
-
"version": "4.2.0-rc.
|
|
3
|
+
"version": "4.2.0-rc.11",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Capxul MCP server for auth, Account readiness, identity, Organizations, relationships, requests, destinations, and testnet funding over Streamable HTTP.",
|
|
6
6
|
"keywords": [
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"vite": "npm:@voidzero-dev/vite-plus-core@0.3.0",
|
|
52
52
|
"vite-plus": "0.3.0",
|
|
53
53
|
"@capxul/config": "0.3.0",
|
|
54
|
-
"@capxul/
|
|
55
|
-
"@capxul/
|
|
54
|
+
"@capxul/typescript-config": "0.0.0",
|
|
55
|
+
"@capxul/sdk": "4.2.0-rc.11"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"dev": "vp exec tsx src/main.ts serve",
|