@sm-lab/recipes 0.2.0 → 0.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.
@@ -1,6 +1,6 @@
1
- import { _ as contract, h as roleMember, i as getPubkey, l as SETTLE_GENERAL_DELAYED_PENALTY_ROLE, m as actAs, o as DEFAULT_ADMIN_ROLE, p as randomSeed, r as getKeyBalance, s as REPORT_GENERAL_DELAYED_PENALTY_ROLE, u as SET_TREE_ROLE, v as resolveGate } from "./topup-B2NzJV7_.mjs";
2
- import { encodeAbiParameters, keccak256, maxUint256, parseAbiParameters, parseEther, toBytes, toHex } from "viem";
3
- import { curatedGateAbi, feeDistributorAbi, feeOracleAbi, hashConsensusAbi, lidoAbi, vettedGateAbi } from "@sm-lab/receipts";
1
+ import { C as roleMember, E as resolveGate, S as actAs, T as contract, _ as SETTLE_GENERAL_DELAYED_PENALTY_ROLE, c as getPubkey, g as RESUME_ROLE, h as REPORT_GENERAL_DELAYED_PENALTY_ROLE, m as PAUSE_ROLE, o as getKeyBalance, p as DEFAULT_ADMIN_ROLE, v as SET_TREE_ROLE, x as randomSeed } from "./topup-CuqmB14u.mjs";
2
+ import { encodeAbiParameters, encodePacked, keccak256, maxUint256, numberToHex, parseAbiParameters, parseEther, toBytes, toHex } from "viem";
3
+ import { curatedGateAbi, feeDistributorAbi, feeOracleAbi, hashConsensusAbi, lidoAbi, stakingRouterAbi, vEBOAbi, vettedGateAbi } from "@sm-lab/receipts";
4
4
  import { buildAddressesTree, ipfsOptionsFromEnv, makeRewards, pinJsonToIpfs, shouldAttemptPin } from "@sm-lab/merkle";
5
5
  //#region src/recipes/operator-info.ts
6
6
  /** Typed read of a node operator's on-chain record. (Port of `NodeOperators.operatorInfo`.) */
@@ -37,6 +37,48 @@ function snapshot(ctx) {
37
37
  async function revert(ctx, id) {
38
38
  await ctx.client.revert({ id });
39
39
  }
40
+ /**
41
+ * Fund an account on the fork by setting its balance (anvil_setBalance). `amountWei` defaults to
42
+ * 100 ETH. Port of `NodeOperators` `topup`.
43
+ */
44
+ async function topUpAccount(ctx, opts) {
45
+ const amountWei = opts.amountWei ?? 100n * 10n ** 18n;
46
+ await ctx.client.setBalance({
47
+ address: opts.address,
48
+ value: amountWei
49
+ });
50
+ return {
51
+ address: opts.address,
52
+ amountWei
53
+ };
54
+ }
55
+ //#endregion
56
+ //#region src/recipes/target-limit.ts
57
+ /**
58
+ * Set an operator's target validator limit (StakingRouter-gated). Port of
59
+ * `NodeOperators.targetLimit` → `updateTargetValidatorsLimits(noId, mode, limit)`.
60
+ */
61
+ async function setTargetLimit(ctx, opts) {
62
+ if (opts.mode !== 0 && opts.mode !== 1 && opts.mode !== 2) throw new Error(`@sm-lab/recipes: target limit mode must be 0, 1, or 2 (got ${opts.mode})`);
63
+ const limit = opts.mode === 0 ? 0n : opts.limit ?? 0n;
64
+ const m = contract(ctx, "module");
65
+ await actAs(ctx, ctx.addresses.stakingRouter, (from) => ctx.client.writeContract({
66
+ ...m,
67
+ functionName: "updateTargetValidatorsLimits",
68
+ args: [
69
+ opts.noId,
70
+ BigInt(opts.mode),
71
+ limit
72
+ ],
73
+ account: from,
74
+ chain: null
75
+ }));
76
+ return {
77
+ noId: opts.noId,
78
+ mode: opts.mode,
79
+ limit
80
+ };
81
+ }
40
82
  //#endregion
41
83
  //#region src/recipes/address-changes.ts
42
84
  /** Propose a new manager address for an operator (signed by the current manager). */
@@ -133,6 +175,32 @@ async function exit(ctx, opts) {
133
175
  chain: null
134
176
  }));
135
177
  }
178
+ /** Remove `count` keys (default 1) from operator `noId` starting at `keyIndex`, as the operator's manager. */
179
+ async function removeKey(ctx, opts) {
180
+ const count = opts.count ?? 1n;
181
+ const m = contract(ctx, "module");
182
+ const manager = (await ctx.client.readContract({
183
+ ...m,
184
+ functionName: "getNodeOperator",
185
+ args: [opts.noId]
186
+ })).managerAddress;
187
+ await actAs(ctx, manager, (from) => ctx.client.writeContract({
188
+ ...m,
189
+ functionName: "removeKeys",
190
+ args: [
191
+ opts.noId,
192
+ opts.keyIndex,
193
+ count
194
+ ],
195
+ account: from,
196
+ chain: null
197
+ }));
198
+ return {
199
+ noId: opts.noId,
200
+ keyIndex: opts.keyIndex,
201
+ count
202
+ };
203
+ }
136
204
  //#endregion
137
205
  //#region src/recipes/validators.ts
138
206
  /** Report a validator slashing for an operator's key (Verifier-gated). `keyIndex` is the storage index. */
@@ -165,6 +233,89 @@ async function withdraw(ctx, opts) {
165
233
  chain: null
166
234
  }));
167
235
  }
236
+ /** Effective balance the source reports to mark a key active: 32 ETH + 1 gwei. */
237
+ const ACTIVE_BALANCE = 32n * 10n ** 18n + 10n ** 9n;
238
+ /**
239
+ * Activate `count` deposited-but-not-yet-active keys of an operator (Verifier-gated) by reporting
240
+ * an effective balance of 32 ETH + 1 gwei on each. Skips keys that already have a confirmed
241
+ * balance or are withdrawn. Port of `NodeOperators.activateKeys`. Returns the count activated.
242
+ */
243
+ async function activateKeys(ctx, opts) {
244
+ const m = contract(ctx, "module");
245
+ const { noId, count } = opts;
246
+ const total = (await ctx.client.readContract({
247
+ ...m,
248
+ functionName: "getNodeOperator",
249
+ args: [noId]
250
+ })).totalDepositedKeys;
251
+ const eligible = (await Promise.all(Array.from({ length: total }, (_, i) => i).map(async (i) => ({
252
+ i,
253
+ confirmed: await ctx.client.readContract({
254
+ ...m,
255
+ functionName: "getKeyConfirmedBalances",
256
+ args: [
257
+ noId,
258
+ BigInt(i),
259
+ 1n
260
+ ]
261
+ }),
262
+ withdrawn: await ctx.client.readContract({
263
+ ...m,
264
+ functionName: "isValidatorWithdrawn",
265
+ args: [noId, BigInt(i)]
266
+ })
267
+ })))).filter((s) => s.confirmed[0] === 0n && !s.withdrawn).slice(0, count);
268
+ if (eligible.length < count) throw new Error(`@sm-lab/recipes: operator ${noId} has only ${eligible.length} activatable key(s), need ${count}`);
269
+ await actAs(ctx, ctx.addresses.Verifier, async (from) => {
270
+ for (const { i } of eligible) await ctx.client.writeContract({
271
+ ...m,
272
+ functionName: "reportValidatorBalance",
273
+ args: [
274
+ noId,
275
+ BigInt(i),
276
+ ACTIVE_BALANCE
277
+ ],
278
+ account: from,
279
+ chain: null
280
+ });
281
+ });
282
+ return { activated: eligible.length };
283
+ }
284
+ /**
285
+ * Report an arbitrary CL balance (wei) for one deposited key (Verifier-gated). Validates the key
286
+ * index is in range and not withdrawn. Port of `NodeOperators.reportBalance`.
287
+ */
288
+ async function reportBalance(ctx, opts) {
289
+ const m = contract(ctx, "module");
290
+ const { noId, keyIndex, balanceWei } = opts;
291
+ const total = (await ctx.client.readContract({
292
+ ...m,
293
+ functionName: "getNodeOperator",
294
+ args: [noId]
295
+ })).totalDepositedKeys;
296
+ if (keyIndex >= BigInt(total)) throw new Error(`@sm-lab/recipes: key index ${keyIndex} out of bounds (operator ${noId} has ${total} deposited keys)`);
297
+ if (await ctx.client.readContract({
298
+ ...m,
299
+ functionName: "isValidatorWithdrawn",
300
+ args: [noId, keyIndex]
301
+ })) throw new Error(`@sm-lab/recipes: key ${keyIndex} of operator ${noId} is withdrawn`);
302
+ await actAs(ctx, ctx.addresses.Verifier, (from) => ctx.client.writeContract({
303
+ ...m,
304
+ functionName: "reportValidatorBalance",
305
+ args: [
306
+ noId,
307
+ keyIndex,
308
+ balanceWei
309
+ ],
310
+ account: from,
311
+ chain: null
312
+ }));
313
+ return {
314
+ noId,
315
+ keyIndex,
316
+ balanceWei
317
+ };
318
+ }
168
319
  //#endregion
169
320
  //#region src/recipes/penalties.ts
170
321
  /** Report a general delayed penalty against an operator (penalty-reporter role). */
@@ -268,7 +419,7 @@ async function createBondDebt(ctx, opts) {
268
419
  }
269
420
  //#endregion
270
421
  //#region src/recipes/set-gate.ts
271
- /** Default gate selector per module: cm → 'po' (CuratedGates[0]); csm → 'ics' (VettedGate). */
422
+ /** Default gate selector per module: cm → 'po' (CuratedGatePO); csm → 'ics' (IcsGate). */
272
423
  function defaultSelector(ctx) {
273
424
  return ctx.module === "cm" ? "po" : "ics";
274
425
  }
@@ -444,7 +595,7 @@ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
444
595
  * into 9 top-level params — that drops the tuple offset and changes the hash. This is the exact
445
596
  * reportHash transcription trap.
446
597
  */
447
- const REPORT_DATA_PARAMS = parseAbiParameters("(uint256 consensusVersion, uint256 refSlot, bytes32 treeRoot, string treeCid, string logCid, uint256 distributed, uint256 rebate, bytes32 strikesTreeRoot, string strikesTreeCid)");
598
+ const REPORT_DATA_PARAMS$1 = parseAbiParameters("(uint256 consensusVersion, uint256 refSlot, bytes32 treeRoot, string treeCid, string logCid, uint256 distributed, uint256 rebate, bytes32 strikesTreeRoot, string strikesTreeCid)");
448
599
  /**
449
600
  * Submit a `RewardsReport` (from `makeRewards`) on-chain: fund the FeeDistributor, warp to the next
450
601
  * consensus frame, build the `ReportData` tuple, reach consensus across the fast-lane members (with
@@ -581,7 +732,7 @@ async function submitRewards(ctx, report) {
581
732
  }
582
733
  /** keccak256(abi.encode(data)) — encode the 9-field struct as ONE tuple param (see REPORT_DATA_PARAMS). */
583
734
  function reportHash(data) {
584
- return keccak256(encodeAbiParameters(REPORT_DATA_PARAMS, [data]));
735
+ return keccak256(encodeAbiParameters(REPORT_DATA_PARAMS$1, [data]));
585
736
  }
586
737
  /**
587
738
  * Mock strikes root: `keccak256(abi.encode("mock-strikes", refSlot))` — TWO top-level params
@@ -626,6 +777,14 @@ async function setClValidator(clMockUrl, input) {
626
777
  const GWEI_PER_ETH = 1000000000n;
627
778
  const BASE_ETH_GWEI = 32n * GWEI_PER_ETH;
628
779
  /**
780
+ * Effective balance of an active validator, in gwei: 32 ETH + the key's on-chain allocated balance
781
+ * (sub-gwei dust floored). Shared by `clActivate` (`active_ongoing`) and `exitRequest`'s optional
782
+ * cl-mock flip (`active_exiting`) so both bridges report the same balance for the same key.
783
+ */
784
+ async function activeEffectiveBalanceGwei(ctx, opts) {
785
+ return BASE_ETH_GWEI + await getKeyBalance(ctx, opts) / GWEI_PER_ETH;
786
+ }
787
+ /**
629
788
  * Read a key's pubkey + allocated balance on-chain, then mark it `active_ongoing` on a running
630
789
  * cl-mock with effective balance = 32 ETH + allocated balance, in gwei. Port of
631
790
  * `cl-mock.just:cl-activate`. Diverges from the Solidity helper's integer-ETH truncation
@@ -635,7 +794,7 @@ const BASE_ETH_GWEI = 32n * GWEI_PER_ETH;
635
794
  async function clActivate(ctx, opts) {
636
795
  if (!ctx.clMockUrl) throw new Error("@sm-lab/recipes: clActivate needs ctx.clMockUrl (a running cl-mock)");
637
796
  const pubkey = await getPubkey(ctx, opts);
638
- const effectiveBalanceGwei = BASE_ETH_GWEI + await getKeyBalance(ctx, opts) / GWEI_PER_ETH;
797
+ const effectiveBalanceGwei = await activeEffectiveBalanceGwei(ctx, opts);
639
798
  await setClValidator(ctx.clMockUrl, {
640
799
  pubkey,
641
800
  status: "active_ongoing",
@@ -648,6 +807,255 @@ async function clActivate(ctx, opts) {
648
807
  };
649
808
  }
650
809
  //#endregion
651
- export { snapshot as C, operatorInfo as E, revert as S, warpTo as T, nodeOperatorIdBytes as _, setGateAddrs as a, proposeManager as b, cancelPenalty as c, settlePenalty as d, slash as f, keyCountBytes as g, unvet as h, submitRewards as i, compensatePenalty as l, exit as m, setClValidator as n, addBond as o, withdraw as p, makeRewards$1 as r, createBondDebt as s, clActivate as t, reportPenalty as u, confirmManager as v, warpBy as w, proposeReward as x, confirmReward as y };
810
+ //#region src/recipes/pause.ts
811
+ /**
812
+ * Resolve a pause target keyword to a contract handle. `module` and `accounting` are reserved;
813
+ * anything else is a gate selector resolved via `resolveGate` (ics/idvtc for csm; po…iodcp/index
814
+ * for cm; 0x… for either).
815
+ */
816
+ function resolveTarget(ctx, target) {
817
+ if (target === "module") {
818
+ const m = contract(ctx, "module");
819
+ return {
820
+ address: m.address,
821
+ abi: m.abi
822
+ };
823
+ }
824
+ if (target === "accounting") {
825
+ const a = contract(ctx, "Accounting");
826
+ return {
827
+ address: a.address,
828
+ abi: a.abi
829
+ };
830
+ }
831
+ const abi = ctx.module === "cm" ? curatedGateAbi : vettedGateAbi;
832
+ return {
833
+ address: resolveGate(ctx, target),
834
+ abi
835
+ };
836
+ }
837
+ /** Pause a target (module | accounting | gate selector). Idempotent: no-op if already paused. */
838
+ async function pause(ctx, opts) {
839
+ const t = resolveTarget(ctx, opts.target);
840
+ if (await ctx.client.readContract({
841
+ ...t,
842
+ functionName: "isPaused"
843
+ })) return {
844
+ target: opts.target,
845
+ address: t.address,
846
+ paused: true
847
+ };
848
+ const admin = await roleMember(ctx, t, DEFAULT_ADMIN_ROLE);
849
+ await actAs(ctx, admin, async (from) => {
850
+ await ctx.client.writeContract({
851
+ ...t,
852
+ functionName: "grantRole",
853
+ args: [PAUSE_ROLE, admin],
854
+ account: from,
855
+ chain: null
856
+ });
857
+ await ctx.client.writeContract({
858
+ ...t,
859
+ functionName: "pauseFor",
860
+ args: [maxUint256],
861
+ account: from,
862
+ chain: null
863
+ });
864
+ });
865
+ return {
866
+ target: opts.target,
867
+ address: t.address,
868
+ paused: true
869
+ };
870
+ }
871
+ /** Resume a target (module | accounting | gate selector). Idempotent: no-op if not paused. */
872
+ async function resume(ctx, opts) {
873
+ const t = resolveTarget(ctx, opts.target);
874
+ if (!await ctx.client.readContract({
875
+ ...t,
876
+ functionName: "isPaused"
877
+ })) return {
878
+ target: opts.target,
879
+ address: t.address,
880
+ paused: false
881
+ };
882
+ const admin = await roleMember(ctx, t, DEFAULT_ADMIN_ROLE);
883
+ await actAs(ctx, admin, async (from) => {
884
+ await ctx.client.writeContract({
885
+ ...t,
886
+ functionName: "grantRole",
887
+ args: [RESUME_ROLE, admin],
888
+ account: from,
889
+ chain: null
890
+ });
891
+ await ctx.client.writeContract({
892
+ ...t,
893
+ functionName: "resume",
894
+ account: from,
895
+ chain: null
896
+ });
897
+ });
898
+ return {
899
+ target: opts.target,
900
+ address: t.address,
901
+ paused: false
902
+ };
903
+ }
904
+ //#endregion
905
+ //#region src/recipes/exit-request.ts
906
+ /** DATA_FORMAT_LIST — the single supported VEBO exit-request data format. */
907
+ const DATA_FORMAT = 1n;
908
+ /** processing deadline offset — `block.timestamp + 1 days` (matches the source). */
909
+ const ONE_DAY = 86400n;
910
+ /**
911
+ * The VEBO `ReportData` struct as ONE tuple parameter (components in declaration order, verified
912
+ * against `fixtures/receipts/src/abi/VEBO.ts`). `abi.encode(report)` for a single struct ==
913
+ * ABI-encoding one tuple parameter — do NOT flatten into 5 top-level params (that drops the tuple
914
+ * offset and changes the hash). Same trap `rewards.ts` documents for the fee-oracle report.
915
+ */
916
+ const REPORT_DATA_PARAMS = parseAbiParameters("(uint256 consensusVersion, uint256 refSlot, uint256 requestsCount, uint256 dataFormat, bytes data)");
917
+ /**
918
+ * Request a single validator exit via the Validators Exit Bus Oracle. Port of
919
+ * `NodeOperators.s.sol:_exitRequest`. Reads the key pubkey + discovers the module id, packs the
920
+ * 64-byte exit request, then fakes VEBO consensus by impersonating the consensus contract
921
+ * (`submitConsensusReport`) and submits the data as the VEBO admin (`grantRole` + `submitReportData`).
922
+ *
923
+ * Module-agnostic: `contract(ctx,'module')` picks CSModule/CuratedModule by `ctx.module`, and the
924
+ * module-id scan matches that same address — no csm/cm branching.
925
+ *
926
+ * Optional cl-mock reflection (beyond the source): when `ctx.clMockUrl` is set, the validator is
927
+ * additionally marked `active_exiting` on the running cl-mock (mirroring `clActivate`); skipped
928
+ * silently otherwise.
929
+ *
930
+ * Deliberate divergences from the source (identical on-chain effect):
931
+ * - reuses the VEBO admin as the `submitReportData` submitter (source grants a fresh address);
932
+ * `grantRole` is idempotent so re-granting the admin never reverts.
933
+ * - scans ALL staking-module ids (source's `for (i=len-1; i>0; i--)` skips index 0).
934
+ */
935
+ async function exitRequest(ctx, opts) {
936
+ const validatorIndex = opts.validatorIndex ?? 900000n;
937
+ const m = contract(ctx, "module");
938
+ const vebo = {
939
+ address: ctx.addresses.vebo,
940
+ abi: vEBOAbi
941
+ };
942
+ const pubkey = await ctx.client.readContract({
943
+ ...m,
944
+ functionName: "getSigningKeys",
945
+ args: [
946
+ opts.noId,
947
+ opts.keyIndex,
948
+ 1n
949
+ ]
950
+ });
951
+ const moduleId = await resolveModuleId(ctx, m.address);
952
+ const data = encodePacked([
953
+ "bytes3",
954
+ "bytes5",
955
+ "bytes8",
956
+ "bytes"
957
+ ], [
958
+ numberToHex(moduleId, { size: 3 }),
959
+ numberToHex(opts.noId, { size: 5 }),
960
+ numberToHex(validatorIndex, { size: 8 }),
961
+ pubkey
962
+ ]);
963
+ const refSlot = (await ctx.client.readContract({
964
+ ...vebo,
965
+ functionName: "getConsensusReport"
966
+ }))[1] + 1n;
967
+ const report = {
968
+ consensusVersion: await ctx.client.readContract({
969
+ ...vebo,
970
+ functionName: "getConsensusVersion"
971
+ }),
972
+ refSlot,
973
+ requestsCount: 1n,
974
+ dataFormat: DATA_FORMAT,
975
+ data
976
+ };
977
+ const reportHash = keccak256(encodeAbiParameters(REPORT_DATA_PARAMS, [report]));
978
+ const consensus = await ctx.client.readContract({
979
+ ...vebo,
980
+ functionName: "getConsensusContract"
981
+ });
982
+ const deadline = (await ctx.client.getBlock()).timestamp + ONE_DAY;
983
+ await actAs(ctx, consensus, (from) => ctx.client.writeContract({
984
+ ...vebo,
985
+ functionName: "submitConsensusReport",
986
+ args: [
987
+ reportHash,
988
+ refSlot,
989
+ deadline
990
+ ],
991
+ account: from,
992
+ chain: null
993
+ }));
994
+ const admin = await roleMember(ctx, vebo, DEFAULT_ADMIN_ROLE);
995
+ const submitRole = await ctx.client.readContract({
996
+ ...vebo,
997
+ functionName: "SUBMIT_DATA_ROLE"
998
+ });
999
+ const contractVersion = await ctx.client.readContract({
1000
+ ...vebo,
1001
+ functionName: "getContractVersion"
1002
+ });
1003
+ await actAs(ctx, admin, async (from) => {
1004
+ await ctx.client.writeContract({
1005
+ ...vebo,
1006
+ functionName: "grantRole",
1007
+ args: [submitRole, admin],
1008
+ account: from,
1009
+ chain: null
1010
+ });
1011
+ await ctx.client.writeContract({
1012
+ ...vebo,
1013
+ functionName: "submitReportData",
1014
+ args: [report, contractVersion],
1015
+ account: from,
1016
+ chain: null
1017
+ });
1018
+ });
1019
+ let clStatus;
1020
+ if (ctx.clMockUrl) {
1021
+ const effectiveBalanceGwei = await activeEffectiveBalanceGwei(ctx, opts);
1022
+ await setClValidator(ctx.clMockUrl, {
1023
+ pubkey,
1024
+ status: "active_exiting",
1025
+ effectiveBalanceGwei
1026
+ });
1027
+ clStatus = "active_exiting";
1028
+ }
1029
+ return {
1030
+ noId: opts.noId,
1031
+ keyIndex: opts.keyIndex,
1032
+ validatorIndex,
1033
+ moduleId,
1034
+ refSlot,
1035
+ reportHash,
1036
+ pubkey,
1037
+ clStatus
1038
+ };
1039
+ }
1040
+ /** Find the staking-module id whose registered address is `moduleAddress` (scans ALL ids). */
1041
+ async function resolveModuleId(ctx, moduleAddress) {
1042
+ const sr = {
1043
+ address: ctx.addresses.stakingRouter,
1044
+ abi: stakingRouterAbi
1045
+ };
1046
+ const ids = await ctx.client.readContract({
1047
+ ...sr,
1048
+ functionName: "getStakingModuleIds"
1049
+ });
1050
+ const idx = (await Promise.all(ids.map((id) => ctx.client.readContract({
1051
+ ...sr,
1052
+ functionName: "getStakingModule",
1053
+ args: [id]
1054
+ })))).findIndex((mod) => mod.stakingModuleAddress.toLowerCase() === moduleAddress.toLowerCase());
1055
+ if (idx === -1) throw new Error(`@sm-lab/recipes: module ${moduleAddress} not registered in the StakingRouter`);
1056
+ return ids[idx];
1057
+ }
1058
+ //#endregion
1059
+ export { snapshot as A, nodeOperatorIdBytes as C, proposeReward as D, proposeManager as E, warpBy as M, warpTo as N, setTargetLimit as O, operatorInfo as P, keyCountBytes as S, confirmReward as T, slash as _, setClValidator as a, removeKey as b, setGateAddrs as c, cancelPenalty as d, compensatePenalty as f, reportBalance as g, activateKeys as h, clActivate as i, topUpAccount as j, revert as k, addBond as l, settlePenalty as m, pause as n, makeRewards$1 as o, reportPenalty as p, resume as r, submitRewards as s, exitRequest as t, createBondDebt as u, withdraw as v, confirmManager as w, unvet as x, exit as y };
652
1060
 
653
- //# sourceMappingURL=cl-activate-CPqr6v_D.mjs.map
1061
+ //# sourceMappingURL=exit-request-c0CS5wKu.mjs.map