shinjuku-shielded 0.3.68 → 0.3.70

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/manifest.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schema": "carbon-shielded-wallet/bundle-manifest/v1",
3
3
  "file": "shinjuku-wallet.mjs",
4
- "sha256": "3d64f9b47b1139c42d3a2ff22642951710beeb669bf633b934b31419e94cc843",
5
- "bytes": 12187129,
6
- "sourceCommit": "8fd3e9152a6ef43a73769ded07e2cfa23c03615b",
4
+ "sha256": "ae568c800e9c2e6ccaf4cad6958cf133aa07469a93428827e679d3a1be89505f",
5
+ "bytes": 12197454,
6
+ "sourceCommit": "dc07c3b2f68a0358fc8137b8ba3773c533856117",
7
7
  "sourceDirty": false,
8
8
  "installRecordMatchesLockfile": true,
9
9
  "releaseRule": "valid only when two fresh npm ci --ignore-scripts builds on different OSes give the same sha256; installRecordMatchesLockfile true means every entry npm installed equals its package-lock.json entry and every entry not marked optional, devOptional included, is installed: an optional entry (a package for another platform) may be absent",
@@ -1282,5 +1282,5 @@
1282
1282
  "version": "1.8.0"
1283
1283
  }
1284
1284
  ],
1285
- "publishedAt": "2026-10-22T13:57:14.597Z"
1285
+ "publishedAt": "2026-10-22T15:46:57.559Z"
1286
1286
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "shinjuku-shielded",
3
- "version": "0.3.68",
3
+ "version": "0.3.70",
4
4
  "mcpName": "io.github.ShinjukuStaition/shinjuku-mcp",
5
5
  "description": "Shinjuku Shielded, the private x402 facilitator on Solana: the self-custody wallet CLI and its MCP server. Shield, pay, and unshield USDC from any MCP agent, under caps you set.",
6
- "shinjukuRelease": "3d64f9b4",
7
- "shinjukuSha256": "3d64f9b47b1139c42d3a2ff22642951710beeb669bf633b934b31419e94cc843",
6
+ "shinjukuRelease": "ae568c80",
7
+ "shinjukuSha256": "ae568c800e9c2e6ccaf4cad6958cf133aa07469a93428827e679d3a1be89505f",
8
8
  "license": "SEE LICENSE IN LICENSE.txt",
9
9
  "author": "Shinjuku Shielded",
10
10
  "homepage": "https://github.com/ShinjukuStaition/shinjuku-mcp#readme",
@@ -13144,8 +13144,8 @@ var require_utils4 = __commonJS({
13144
13144
  module.exports.wrapperForImpl = function(impl) {
13145
13145
  return impl[module.exports.wrapperSymbol];
13146
13146
  };
13147
- module.exports.implForWrapper = function(wrapper) {
13148
- return wrapper[module.exports.implSymbol];
13147
+ module.exports.implForWrapper = function(wrapper2) {
13148
+ return wrapper2[module.exports.implSymbol];
13149
13149
  };
13150
13150
  }
13151
13151
  });
@@ -18026,9 +18026,9 @@ var require_event_target = __commonJS({
18026
18026
  return;
18027
18027
  }
18028
18028
  }
18029
- let wrapper;
18029
+ let wrapper2;
18030
18030
  if (type === "message") {
18031
- wrapper = function onMessage(data, isBinary) {
18031
+ wrapper2 = function onMessage(data, isBinary) {
18032
18032
  const event = new MessageEvent("message", {
18033
18033
  data: isBinary ? data : data.toString()
18034
18034
  });
@@ -18036,7 +18036,7 @@ var require_event_target = __commonJS({
18036
18036
  callListener(handler, this, event);
18037
18037
  };
18038
18038
  } else if (type === "close") {
18039
- wrapper = function onClose(code2, message) {
18039
+ wrapper2 = function onClose(code2, message) {
18040
18040
  const event = new CloseEvent("close", {
18041
18041
  code: code2,
18042
18042
  reason: message.toString(),
@@ -18046,7 +18046,7 @@ var require_event_target = __commonJS({
18046
18046
  callListener(handler, this, event);
18047
18047
  };
18048
18048
  } else if (type === "error") {
18049
- wrapper = function onError(error) {
18049
+ wrapper2 = function onError(error) {
18050
18050
  const event = new ErrorEvent("error", {
18051
18051
  error,
18052
18052
  message: error.message
@@ -18055,7 +18055,7 @@ var require_event_target = __commonJS({
18055
18055
  callListener(handler, this, event);
18056
18056
  };
18057
18057
  } else if (type === "open") {
18058
- wrapper = function onOpen() {
18058
+ wrapper2 = function onOpen() {
18059
18059
  const event = new Event("open");
18060
18060
  event[kTarget] = this;
18061
18061
  callListener(handler, this, event);
@@ -18063,12 +18063,12 @@ var require_event_target = __commonJS({
18063
18063
  } else {
18064
18064
  return;
18065
18065
  }
18066
- wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];
18067
- wrapper[kListener] = handler;
18066
+ wrapper2[kForOnEventAttribute] = !!options[kForOnEventAttribute];
18067
+ wrapper2[kListener] = handler;
18068
18068
  if (options.once) {
18069
- this.once(type, wrapper);
18069
+ this.once(type, wrapper2);
18070
18070
  } else {
18071
- this.on(type, wrapper);
18071
+ this.on(type, wrapper2);
18072
18072
  }
18073
18073
  },
18074
18074
  /**
@@ -42800,7 +42800,10 @@ async function routeFacilitatorsOverOnion(argv2, {
42800
42800
  onNone?.();
42801
42801
  }
42802
42802
  });
42803
+ const first = firstRaces.has(group.label) ? void 0 : { startedAt: Date.now() };
42804
+ if (first) firstRaces.set(group.label, first);
42803
42805
  group.pending = raced.winner.then((onion) => {
42806
+ if (first) Object.assign(first, { endedAt: Date.now(), answered: !unanswered2 });
42804
42807
  group.winner = onion;
42805
42808
  group.pending = void 0;
42806
42809
  if (!unanswered2 && !raced.stopped) err(`tor: the onion ${hostOf(onion)} of ${group.label} answered first; it serves this run's requests to it
@@ -42901,7 +42904,7 @@ async function routeFacilitatorsOverOnion(argv2, {
42901
42904
  }
42902
42905
  };
42903
42906
  }
42904
- var SITE_ONIONS, SITE_SPARE_ONIONS, PINNED_FACILITATOR_ONIONS, PINNED_SPARE_ONIONS, HISTORY_ONIONS, PINNED_HISTORY_ONIONS, HISTORY_PROBE_PATH, FACILITATOR_FLAGS, V3_ONION, DISCOVERY_TIMEOUT_MS, WARM_TIMEOUT_MS, RACE_TIMEOUT_MS, ROUTE_WAIT_MS, SPARE_AFTER_MS, SPARE_CAUSE, routedGroups, liveOnions, hostOf, noAnswer, routedOnions, routedOrigins, onionsOfOrigin, routesOverOnion, GLOBAL_DISPATCHER, onionDispatchers;
42907
+ var SITE_ONIONS, SITE_SPARE_ONIONS, PINNED_FACILITATOR_ONIONS, PINNED_SPARE_ONIONS, HISTORY_ONIONS, PINNED_HISTORY_ONIONS, HISTORY_PROBE_PATH, FACILITATOR_FLAGS, V3_ONION, DISCOVERY_TIMEOUT_MS, WARM_TIMEOUT_MS, RACE_TIMEOUT_MS, ROUTE_WAIT_MS, SPARE_AFTER_MS, SPARE_CAUSE, routedGroups, liveOnions, hostOf, noAnswer, routedOnions, routedOrigins, onionsOfOrigin, routesOverOnion, firstRaces, firstOnionRace, GLOBAL_DISPATCHER, onionDispatchers;
42905
42908
  var init_facilitatorOnion = __esm({
42906
42909
  "wallet/src/net/facilitatorOnion.mjs"() {
42907
42910
  "use strict";
@@ -42951,6 +42954,11 @@ var init_facilitatorOnion = __esm({
42951
42954
  routedOrigins = /* @__PURE__ */ new Map();
42952
42955
  onionsOfOrigin = (origin) => routedOrigins.get(origin) ?? PINNED_FACILITATOR_ONIONS[origin] ?? [];
42953
42956
  routesOverOnion = (origin) => routedOrigins.has(origin);
42957
+ firstRaces = /* @__PURE__ */ new Map();
42958
+ firstOnionRace = (origin) => {
42959
+ const race = firstRaces.get(origin);
42960
+ return race === void 0 ? void 0 : { ...race };
42961
+ };
42954
42962
  GLOBAL_DISPATCHER = /* @__PURE__ */ Symbol.for("undici.globalDispatcher.1");
42955
42963
  onionDispatchers = /* @__PURE__ */ new Map();
42956
42964
  }
@@ -53654,6 +53662,11 @@ function finalizedPoolStateOf(report, { programId, pool: pool2 }) {
53654
53662
  if (entry === void 0 || entry.programId !== String(programId) || entry.pool !== String(pool2)) return void 0;
53655
53663
  return entry.state;
53656
53664
  }
53665
+ function poolReadAtOf(report) {
53666
+ if (!report || !AUTHENTICATED_HISTORY_REPORTS.has(report)) return void 0;
53667
+ const readAt = REPORT_POOL_STATES.get(report)?.readAt;
53668
+ return Number.isFinite(readAt) ? readAt : void 0;
53669
+ }
53657
53670
  function p03SettlementConsumesBuffer(tag2) {
53658
53671
  return P03_SETTLEMENT_TAGS.includes(tag2) && !P03_INLINE_SETTLEMENT_TAGS.includes(tag2);
53659
53672
  }
@@ -53835,13 +53848,34 @@ async function refreshFinalizedP03HistorySnapshot({
53835
53848
  history,
53836
53849
  paymentSettler
53837
53850
  }) {
53851
+ const { authenticated, program, poolKey } = refreshBinding(history, programId, pool2);
53852
+ const snapshot = await readFinalizedPoolForRefresh(connection, program, poolKey);
53853
+ return refreshedFromSnapshot({ connection, program, poolKey, authenticated, snapshot, paymentSettler });
53854
+ }
53855
+ async function refreshFinalizedP03HistoryFromSliced({ connection, programId, pool: pool2, history, snapshot }) {
53856
+ const { authenticated, program, poolKey } = refreshBinding(history, programId, pool2);
53857
+ if (snapshot === null || typeof snapshot !== "object" || snapshot.programDataReuse === void 0) return void 0;
53858
+ let view2 = snapshot;
53859
+ if (snapshot.replayStore === REPLAY_STORE_INDEXED) {
53860
+ const slices = snapshot.e1TreeSlices;
53861
+ if (!slices || slices.slot !== snapshot.slot || !(slices.header instanceof Uint8Array)) return void 0;
53862
+ view2 = withPoolStateOf(snapshot, Object.freeze({
53863
+ ...snapshot,
53864
+ e1TreeHeader: Object.freeze({ address: slices.address, ownerProgramId: slices.ownerProgramId, data: Buffer.from(slices.header) })
53865
+ }));
53866
+ }
53867
+ return refreshedFromSnapshot({ connection, program, poolKey, authenticated, snapshot: view2, reuseAnswer: snapshot.programDataReuse });
53868
+ }
53869
+ function refreshBinding(history, programId, pool2) {
53838
53870
  const authenticated = assertAuthenticatedFinalizedP03History(history);
53839
53871
  const program = canonicalKey(programId, "program_id");
53840
53872
  const poolKey = canonicalKey(pool2, "pool");
53841
53873
  if (authenticated.programId !== b58(program) || authenticated.pool !== poolKey.toBase58()) {
53842
53874
  throw new Error("p03_history_refresh_binding_invalid");
53843
53875
  }
53844
- const snapshot = await readFinalizedPoolForRefresh(connection, program, poolKey);
53876
+ return { authenticated, program, poolKey };
53877
+ }
53878
+ async function refreshedFromSnapshot({ connection, program, poolKey, authenticated, snapshot, paymentSettler, reuseAnswer }) {
53845
53879
  if (snapshot.terminal !== authenticated.finalizedPoolSnapshot.terminal || snapshot.currentIndex !== authenticated.finalizedPoolSnapshot.currentIndex || snapshot.currentRoot !== authenticated.finalizedPoolSnapshot.currentRoot || !sameP03PoolPolicy(snapshot, authenticated.finalizedPoolSnapshot.policy) || !sameE1TreeHeader(snapshot, authenticated.finalizedPoolSnapshot.e1Tree, program, poolKey) || paymentSettler !== void 0 && snapshot.paymentSettler?.toBase58() !== paymentSettler) {
53846
53880
  throw Object.assign(
53847
53881
  new Error("p03_history_refresh_transition_detected"),
@@ -53861,7 +53895,8 @@ async function refreshFinalizedP03HistorySnapshot({
53861
53895
  programDataSha256: priorCoverage.programDataSha256,
53862
53896
  ...priorCoverage.programHistory ? { programHistory: priorCoverage.programHistory } : {}
53863
53897
  },
53864
- prior: HISTORY_ATTESTATIONS.get(authenticated)
53898
+ prior: HISTORY_ATTESTATIONS.get(authenticated),
53899
+ ...reuseAnswer !== void 0 ? { reuseAnswer } : {}
53865
53900
  });
53866
53901
  const deploymentCoverage = refreshedCoverage.coverage;
53867
53902
  if (!hasExecutableEvidence(deploymentCoverage)) throw new Error("p03_history_executable_evidence_required");
@@ -54154,7 +54189,8 @@ function parseFinalizedPool(response, program, pool2) {
54154
54189
  SNAPSHOT_POOL_STATES.set(snapshot, Object.freeze({
54155
54190
  programId: b58(program),
54156
54191
  pool: pool2.toBase58(),
54157
- state: Object.freeze({ ...state, owner })
54192
+ state: Object.freeze({ ...state, owner }),
54193
+ readAt: Date.now()
54158
54194
  }));
54159
54195
  }
54160
54196
  return snapshot;
@@ -57444,8 +57480,15 @@ async function readPages(history, pool2, needed, first, { wakeSlot } = {}) {
57444
57480
  }
57445
57481
  return { records: records.slice(0, needed), imports, initialization, syncedSlot };
57446
57482
  }
57447
- async function readCompactPoolSnapshot({ connection, programId, pool: pool2 }) {
57448
- return readFinalizedPool(withBoundedOwnReads(connection), new import_web397.PublicKey(programId), new import_web397.PublicKey(pool2), { treeSlices: true });
57483
+ function startCompactPoolSnapshot({ connection, programId, pool: pool2 }) {
57484
+ const own = withBoundedOwnReads(connection);
57485
+ const program = new import_web397.PublicKey(programId);
57486
+ const poolKey = new import_web397.PublicKey(pool2);
57487
+ const sliced = readFinalizedPoolSliced(own, program, poolKey).catch(() => void 0);
57488
+ const full = sliced.then((snapshot) => snapshot ?? readFinalizedPool(own, program, poolKey));
57489
+ full.catch(() => {
57490
+ });
57491
+ return { sliced, full };
57449
57492
  }
57450
57493
  function requestCompactFirstPage({ history, pool: pool2 }) {
57451
57494
  try {
@@ -58471,7 +58514,8 @@ async function loadOrExtendFinalizedP03History({
58471
58514
  fallbacks += 1;
58472
58515
  }
58473
58516
  let laggingRetries = 0;
58474
- for (let laggingTry = 0; cached; laggingTry += 1) {
58517
+ let cursorRetry;
58518
+ for (let attempt = 0; cached; attempt += 1) {
58475
58519
  try {
58476
58520
  const extended = await extendFromCache({
58477
58521
  connection,
@@ -58484,11 +58528,12 @@ async function loadOrExtendFinalizedP03History({
58484
58528
  historySource,
58485
58529
  forceRead,
58486
58530
  // A retry reads the pool again: the first read may be the one that lagged (stamp review).
58487
- liveRead: laggingTry === 0 ? liveRead : void 0
58531
+ liveRead: attempt === 0 ? liveRead : void 0
58488
58532
  });
58489
58533
  await beforePersist?.(extended);
58490
58534
  await persistCache(cache, extended, programIdBase58, poolBase58);
58491
58535
  remember(extended);
58536
+ if (cursorRetry === "running") markPhase("extension-retry-ok");
58492
58537
  return {
58493
58538
  report: extended.report,
58494
58539
  mode: extended.mode,
@@ -58498,11 +58543,22 @@ async function loadOrExtendFinalizedP03History({
58498
58543
  ...extended.window ? { window: extended.window } : {}
58499
58544
  };
58500
58545
  } catch (error) {
58546
+ if (cursorRetry === void 0 && /^p03_history_cursor_exhausted/.test(String(error?.message))) {
58547
+ cursorRetry = "running";
58548
+ onEvent("extension_retry", error);
58549
+ markPhase("extension-retry-start");
58550
+ await new Promise((resolve38) => setTimeout(resolve38, EXTENSION_CURSOR_RETRY_MS));
58551
+ continue;
58552
+ }
58553
+ if (cursorRetry === "running") {
58554
+ cursorRetry = "done";
58555
+ markPhase("extension-retry-failed");
58556
+ }
58501
58557
  onEvent("extension_failed", error);
58502
58558
  if (isProgramDataIdentityError(error)) throw error;
58503
- if (isLaggingNodeRpcError(error) && laggingTry < EXTENSION_LAGGING_RETRY_MS.length) {
58559
+ if (isLaggingNodeRpcError(error) && laggingRetries < EXTENSION_LAGGING_RETRY_MS.length) {
58504
58560
  laggingRetries += 1;
58505
- await new Promise((resolve38) => setTimeout(resolve38, EXTENSION_LAGGING_RETRY_MS[laggingTry]));
58561
+ await new Promise((resolve38) => setTimeout(resolve38, EXTENSION_LAGGING_RETRY_MS[laggingRetries - 1]));
58506
58562
  continue;
58507
58563
  }
58508
58564
  fallbacks += 1;
@@ -58888,7 +58944,7 @@ async function persistCache(cache, { report, entries: walked, attestation, marks
58888
58944
  ...attestation ? { attestation } : {}
58889
58945
  });
58890
58946
  }
58891
- var import_web398, EXTENSION_LAGGING_RETRY_MS, PAGE_SIZE2, LAST_REPORTS, sameMark, HISTORY_ROUND_BUCKET, HISTORY_WARM_FRESH_MS, runBufferLists;
58947
+ var import_web398, EXTENSION_LAGGING_RETRY_MS, EXTENSION_CURSOR_RETRY_MS, PAGE_SIZE2, LAST_REPORTS, sameMark, HISTORY_ROUND_BUCKET, HISTORY_WARM_FRESH_MS, runBufferLists;
58892
58948
  var init_incremental = __esm({
58893
58949
  "wallet/src/history/incremental.mjs"() {
58894
58950
  "use strict";
@@ -58897,6 +58953,7 @@ var init_incremental = __esm({
58897
58953
  init_walk();
58898
58954
  init_phaseTiming();
58899
58955
  EXTENSION_LAGGING_RETRY_MS = [1e3, 2e3];
58956
+ EXTENSION_CURSOR_RETRY_MS = 2e3;
58900
58957
  PAGE_SIZE2 = 1e3;
58901
58958
  LAST_REPORTS = /* @__PURE__ */ new WeakMap();
58902
58959
  sameMark = (cached, live) => cached === void 0 || cached === live;
@@ -58966,7 +59023,7 @@ async function loadWalletP03History(args) {
58966
59023
  }
58967
59024
  if (runKey !== void 0 && recentScope.getStore() !== void 0 && strictScope.getStore() !== true && args.forceRead !== true) {
58968
59025
  const recent = recentLoads.get(runKey);
58969
- if (recent !== void 0 && Date.now() - recent.startedAt <= HISTORY_PREWARM_JOIN_MS) {
59026
+ if (recent !== void 0 && Date.now() - recentAgeStart(recent) <= HISTORY_PREWARM_JOIN_MS) {
58970
59027
  PREWARMED_REPORTS.add(recent.report);
58971
59028
  PAYMENT_TAKEN_REPORTS.add(recent.report);
58972
59029
  markPhase("walk-recent");
@@ -59000,7 +59057,7 @@ function recentBeforePrewarm(runKey, prewarm) {
59000
59057
  const accept = recentScope.getStore()?.accept;
59001
59058
  if (typeof accept !== "function" || prewarm.settled) return void 0;
59002
59059
  const recent = recentLoads.get(runKey);
59003
- if (recent === void 0 || Date.now() - recent.startedAt > HISTORY_PREWARM_JOIN_MS) return void 0;
59060
+ if (recent === void 0 || Date.now() - recentAgeStart(recent) > HISTORY_PREWARM_JOIN_MS) return void 0;
59004
59061
  let accepted = false;
59005
59062
  try {
59006
59063
  accepted = accept(recent.report) === true;
@@ -59145,11 +59202,11 @@ async function walkWalletP03HistoryNow({ store, connection: given, programId, po
59145
59202
  if (typeof index === "bigint") movedIndex = index + SUBTREE_LEAVES4;
59146
59203
  } else if (earlier !== void 0) {
59147
59204
  markPhase("refresh-start");
59148
- const refreshing = refreshFinalizedP03HistorySnapshot({ connection, programId, pool: pool2, history: earlier });
59205
+ let slicedPreRead;
59149
59206
  if (compactNext) {
59150
- poolPreRead = readCompactPoolSnapshot({ connection, programId, pool: pool2 });
59151
- poolPreRead.catch(() => {
59152
- });
59207
+ const started = startCompactPoolSnapshot({ connection, programId, pool: pool2 });
59208
+ slicedPreRead = started.sliced;
59209
+ poolPreRead = started.full;
59153
59210
  markPhase("compact-pool-prestarted");
59154
59211
  if (!inTorRun() && Date.now() - remembered.at > PAGE0_PREREAD_AFTER_MS) {
59155
59212
  firstPreRead = requestCompactFirstPage({ history: connection.historyRpcSource, pool: pool2 });
@@ -59162,11 +59219,24 @@ async function walkWalletP03HistoryNow({ store, connection: given, programId, po
59162
59219
  } catch {
59163
59220
  }
59164
59221
  }
59222
+ let fromSliced = false;
59223
+ const refreshing = (async () => {
59224
+ if (slicedPreRead !== void 0) {
59225
+ const decided = await refreshFinalizedP03HistoryFromSliced({ connection, programId, pool: pool2, history: earlier, snapshot: await slicedPreRead });
59226
+ if (decided !== void 0) {
59227
+ fromSliced = true;
59228
+ markPhase("refresh-from-sliced");
59229
+ return decided;
59230
+ }
59231
+ markPhase("refresh-sliced-undecided");
59232
+ }
59233
+ return refreshFinalizedP03HistorySnapshot({ connection, programId, pool: pool2, history: earlier });
59234
+ })();
59165
59235
  try {
59166
59236
  const refreshed = await refreshing;
59167
59237
  markPhase("walk-refreshed");
59168
59238
  rememberRunReport(runKey, refreshed);
59169
- writeStderr("history: the pool made no transition since this run's last walk; that history was moved to the current pool account (your own RPC read the pool account and the program's deployment account; the history source answered one signature read)\n");
59239
+ writeStderr("history: the pool made no transition since this run's last walk; that history was moved to the current pool account " + (fromSliced ? "(your own RPC read the pool account and the program's deployment account in one request)\n" : "(your own RPC read the pool account and the program's deployment account; the history source answered one signature read)\n"));
59170
59240
  return refreshed;
59171
59241
  } catch (error) {
59172
59242
  markPhase("refresh-missed");
@@ -59389,7 +59459,7 @@ function reportHistoryRpc(split5, source, result, crossChecked) {
59389
59459
  writeStderr(`history: ${who} answered ${list(split5.history)}; your own RPC answered ${list(split5.own)} (the pool account the history must match, and the cross-check)${window2}${integrity}
59390
59460
  `);
59391
59461
  }
59392
- var prepareReport, strictScope, withStrictHistorySource, recentScope, withRecentWalletHistory, recentLoads, forgetRecentWalletHistory, proofBuiltAt, historyCacheKey, latestPrewarm, HOME_MARKS_SETTLED_MS, HISTORY_PREWARM_JOIN_MS, SHARED_WALK_WAIT_MS, PAGE0_PREREAD_AFTER_MS, SUBTREE_LEAVES4, prewarmedWalks, sharedWalks, PREWARMED_REPORTS, PAYMENT_TAKEN_REPORTS, isPrewarmedWalletHistory, REPORT_STARTED_AT, walkStartedAtOf, COMPACT_BEHIND_POLL_MS, COMPACT_BEHIND_READ_MS, COMPACT_BEHIND_TOR_READ_MS, COMPACT_BEHIND_REFUSAL_MAX_BYTES, COMPACT_BEHIND_PAGE_BODY_MS, COMPACT_BEHIND_RETRY_MS, lastRunReports, writeStderr, announcedSources;
59462
+ var prepareReport, strictScope, withStrictHistorySource, recentScope, withRecentWalletHistory, recentLoads, recentAgeStart, forgetRecentWalletHistory, proofBuiltAt, historyCacheKey, latestPrewarm, HOME_MARKS_SETTLED_MS, HISTORY_PREWARM_JOIN_MS, SHARED_WALK_WAIT_MS, PAGE0_PREREAD_AFTER_MS, SUBTREE_LEAVES4, prewarmedWalks, sharedWalks, PREWARMED_REPORTS, PAYMENT_TAKEN_REPORTS, isPrewarmedWalletHistory, REPORT_STARTED_AT, walkStartedAtOf, COMPACT_BEHIND_POLL_MS, COMPACT_BEHIND_READ_MS, COMPACT_BEHIND_TOR_READ_MS, COMPACT_BEHIND_REFUSAL_MAX_BYTES, COMPACT_BEHIND_PAGE_BODY_MS, COMPACT_BEHIND_RETRY_MS, lastRunReports, writeStderr, announcedSources;
59393
59463
  var init_walletHistory = __esm({
59394
59464
  "wallet/src/history/walletHistory.mjs"() {
59395
59465
  "use strict";
@@ -59411,6 +59481,7 @@ var init_walletHistory = __esm({
59411
59481
  recentScope = new AsyncLocalStorage2();
59412
59482
  withRecentWalletHistory = (fn, { accept } = {}) => recentScope.run({ accept }, fn);
59413
59483
  recentLoads = /* @__PURE__ */ new Map();
59484
+ recentAgeStart = (recent) => poolReadAtOf(recent.report) ?? recent.startedAt;
59414
59485
  forgetRecentWalletHistory = () => {
59415
59486
  recentLoads.clear();
59416
59487
  proofBuiltAt = Date.now();
@@ -64273,6 +64344,7 @@ var init_errorCodes = __esm({
64273
64344
  "exit_policy_values_invalid",
64274
64345
  "exit_proof_tools_invalid",
64275
64346
  "extension_failed",
64347
+ "extension_retry",
64276
64348
  "max_delay_invalid",
64277
64349
  "max_delay_minutes",
64278
64350
  "no_anchor",
@@ -95977,7 +96049,7 @@ function withSellerResource(xPayment, record) {
95977
96049
  return patched;
95978
96050
  }
95979
96051
  function floatFetch(base, seen) {
95980
- const wrapper = async (target, init = {}) => {
96052
+ const wrapper2 = async (target, init = {}) => {
95981
96053
  const response = await base(target, floatInit(init));
95982
96054
  const paid = Object.keys(init.headers ?? {}).some((name) => name.toLowerCase() === "payment-signature");
95983
96055
  if (paid || response.status === 402 || response.status < 400) return response;
@@ -95999,7 +96071,7 @@ function floatFetch(base, seen) {
95999
96071
  };
96000
96072
  return new Response(null, { status: 400 });
96001
96073
  };
96002
- return Object.defineProperty(wrapper, "baseFetch", { value: base });
96074
+ return Object.defineProperty(wrapper2, "baseFetch", { value: base });
96003
96075
  }
96004
96076
  function floatRefusalError(refusal3, record) {
96005
96077
  const extra = {
@@ -105384,7 +105456,8 @@ async function downloadSet({ fetchImpl, base, entries, budget, onFile, onBytes =
105384
105456
  } }) {
105385
105457
  const stop3 = new AbortController();
105386
105458
  const files = entries.map((entry) => ({ entry, url: new URL(entry.path, base).href, label: `the proof-tool file ${entry.path}`, buffer: void 0, left: 0 }));
105387
- const queue = files.map((file) => ({ file, start: 0, end: RANGE_BYTES - 1, head: true, attempts: 0 })).sort((x, y) => Number(y.file.entry.path.endsWith(".params")) - Number(x.file.entry.path.endsWith(".params")));
105459
+ const rank = (file) => file.entry.path === "proof-tools.json" ? 2 : file.entry.path.endsWith(".params") ? 1 : 0;
105460
+ const queue = files.map((file) => ({ file, start: 0, end: RANGE_BYTES - 1, head: true, attempts: 0 })).sort((x, y) => rank(y.file) - rank(x.file));
105388
105461
  const inFlight = /* @__PURE__ */ new Set();
105389
105462
  let firstError;
105390
105463
  let filesLeft = files.length;
@@ -105581,12 +105654,17 @@ async function installProofTools({
105581
105654
  onProgress = () => {
105582
105655
  },
105583
105656
  progressLine = (text3) => process.stderr.write(text3),
105584
- progressEveryMs = PROGRESS_EVERY_MS
105657
+ progressEveryMs = PROGRESS_EVERY_MS,
105658
+ onFileWritten = () => {
105659
+ },
105660
+ mark = () => {
105661
+ }
105585
105662
  }) {
105586
105663
  const { dir, sumsSha256 } = expected;
105587
105664
  if (!HEX643.test(String(sumsSha256)) || dir !== sumsSha256.slice(0, 8)) throw fail26("setup_release_invalid", "the expected proof-tool set is not a 64-hex list hash");
105588
105665
  const folder = join21(toolsRoot, dir);
105589
105666
  if (existsSync(folder) && verifyToolsFolder(folder, sumsSha256)) {
105667
+ mark("present");
105590
105668
  return Object.freeze({ dir, sumsSha256, folder, downloaded: 0, ...toolPaths(folder) });
105591
105669
  }
105592
105670
  const base = new URL(`/proof-tools/${dir}/`, facilitator);
@@ -105594,6 +105672,7 @@ async function installProofTools({
105594
105672
  if (sha2569(sums) !== sumsSha256) {
105595
105673
  throw fail26("setup_sums_mismatch", "the downloaded SHA256SUMS does not have the pinned SHA-256, so no proof tool was downloaded");
105596
105674
  }
105675
+ mark("sums");
105597
105676
  const entries = parseSums(sums.toString("utf8"));
105598
105677
  const partial = `${folder}.partial`;
105599
105678
  for (const entry of entries) {
@@ -105627,14 +105706,22 @@ async function installProofTools({
105627
105706
  let bytesDone = 0;
105628
105707
  let downloaded = 0;
105629
105708
  const budget = { left: LIMITS.total };
105709
+ let hashMs = 0;
105630
105710
  const write = (entry, bytes2) => {
105631
105711
  const target = localPath(partial, entry.path);
105632
- if (sha2569(bytes2) !== entry.sha256) {
105712
+ const hashStart = Date.now();
105713
+ const hash12 = sha2569(bytes2);
105714
+ hashMs += Date.now() - hashStart;
105715
+ if (hash12 !== entry.sha256) {
105633
105716
  throw fail26("setup_file_hash_mismatch", `the proof-tool file ${entry.path} does not have the SHA-256 that SHA256SUMS lists, so it was not kept; rerun setup`);
105634
105717
  }
105635
105718
  mkdirSync(dirname20(target), { recursive: true, mode: 448 });
105636
105719
  writeFileSync(target, bytes2, { flag: "wx", mode: 384 });
105637
105720
  if (executable(entry.path)) chmodSync(target, 493);
105721
+ try {
105722
+ onFileWritten({ path: entry.path, file: target });
105723
+ } catch {
105724
+ }
105638
105725
  };
105639
105726
  for (const { entry, bytes: bytes2 } of kept) {
105640
105727
  write(entry, bytes2);
@@ -105668,20 +105755,35 @@ async function installProofTools({
105668
105755
  }, progressEveryMs);
105669
105756
  ticker.unref?.();
105670
105757
  }
105758
+ let quarter = 0;
105759
+ const markQuarters = () => {
105760
+ const share = totalBytes !== void 0 && totalBytes > 0 ? (keptBytes + arrived) / totalBytes : (kept.length + downloaded) / entries.length;
105761
+ while (quarter < 4 && share >= (quarter + 1) / 4) {
105762
+ quarter += 1;
105763
+ mark(`download-${quarter * 25}`);
105764
+ }
105765
+ };
105766
+ mark("download-start", `f${missing.length}_of_${entries.length}`);
105671
105767
  try {
105672
105768
  await downloadSet({ fetchImpl, base, entries: missing, budget, onBytes: (count2) => {
105673
105769
  arrived += count2;
105770
+ markQuarters();
105674
105771
  }, onFile: (entry, bytes2) => {
105675
105772
  write(entry, bytes2);
105676
105773
  bytesDone += bytes2.length;
105677
105774
  downloaded += 1;
105775
+ mark("file", `f${kept.length + downloaded}_of_${entries.length}`);
105678
105776
  onProgress({ filesDone: kept.length + downloaded, filesTotal: entries.length, bytesDone });
105679
105777
  } });
105680
105778
  } finally {
105681
105779
  clearInterval(ticker);
105682
105780
  }
105781
+ if (quarter < 4) mark("download-100");
105782
+ mark("file-hashes", `ms${hashMs}`);
105683
105783
  writeFileSync(join21(partial, "SHA256SUMS"), sums, { flag: "wx", mode: 384 });
105784
+ mark("hash-check-start");
105684
105785
  if (!verifyToolsFolder(partial, sumsSha256)) throw fail26("setup_file_hash_mismatch", "the downloaded proof-tools folder did not check out on disk; rerun setup");
105786
+ mark("hash-check-end");
105685
105787
  if (existsSync(folder)) rmSync(folder, { recursive: true, force: true });
105686
105788
  renameSync(partial, folder);
105687
105789
  return Object.freeze({ dir, sumsSha256, folder, downloaded, ...toolPaths(folder) });
@@ -106231,6 +106333,18 @@ function facilitatorAnchor(origin, fetchImpl = fetch) {
106231
106333
  fail29(`anchor_refused_${response.status}`);
106232
106334
  };
106233
106335
  }
106336
+ function markedAnchorRequest(requestAnchor) {
106337
+ return async () => {
106338
+ markPhase("anchor-request-start");
106339
+ try {
106340
+ await requestAnchor();
106341
+ markPhase("anchor-request-done");
106342
+ } catch (error) {
106343
+ markPhase("anchor-request-done", "refused");
106344
+ throw error;
106345
+ }
106346
+ };
106347
+ }
106234
106348
  async function exitWhenAnchored(run5, { now = Date.now, sleep: sleep6 = (ms) => new Promise((resolve38) => setTimeout(resolve38, ms)), ring } = {}) {
106235
106349
  const deadline = now() + EXIT_ANCHOR_WAIT_MS;
106236
106350
  for (; ; ) {
@@ -106245,7 +106359,9 @@ async function exitWhenAnchored(run5, { now = Date.now, sleep: sleep6 = (ms) =>
106245
106359
  if (start + waitMs > deadline) throw error;
106246
106360
  const before = subAnchors ? await readRingBefore(ring, start) : void 0;
106247
106361
  progress(`your self-payment's note is spendable after the next pool anchor at ${new Date(anchorAt).toISOString().slice(11, 19)}Z; waiting ${Math.ceil(waitMs / 1e3)} s (nothing was signed for the exit): ${anchorWaitText(start)}; the exit then runs by itself`);
106362
+ markPhase("anchor-wait-start");
106248
106363
  await sleepForAnchor(waitMs, { ring, before, now, sleep: sleep6 });
106364
+ markPhase("anchor-wait-done");
106249
106365
  }
106250
106366
  }
106251
106367
  }
@@ -106452,6 +106568,7 @@ var init_cli2 = __esm({
106452
106568
  init_privateSend();
106453
106569
  init_promised();
106454
106570
  init_usdcWords();
106571
+ init_phaseTiming();
106455
106572
  USAGE2 = "node --import tsx wallet/src/unshield/cli.mjs --wallet <encrypted-file> --passphrase-file <file> [--rpc-file <file>] --payer-proof-tools <manifest> --exit-proof-tools <manifest> --profile <public-profile.json> --program <address> --facilitator <https-origin> --unshield-id <id> --amount <atomic> --to <token-account> --recipient-owner <pubkey> [--history-rpc <own|url>] [--parts <1-8>] [--max-delay-minutes <0-60>]";
106456
106573
  REQUIRED2 = [
106457
106574
  "wallet",
@@ -117330,7 +117447,7 @@ async function runUnshield({
117330
117447
  recipientOwner: owner.toBase58(),
117331
117448
  allowForeignRecipient: true,
117332
117449
  relaySubmit: facilitatorExitRelay(facilitatorOrigin2),
117333
- requestAnchor: facilitatorAnchor(facilitatorOrigin2),
117450
+ requestAnchor: markedAnchorRequest(facilitatorAnchor(facilitatorOrigin2)),
117334
117451
  deps: { walkHistory: walk(exitProofTools.deploymentIdentity) }
117335
117452
  }), { ring: { connection: session.connection, pool: store.state.pool } }));
117336
117453
  mark("unshield-exited");
@@ -117390,7 +117507,7 @@ async function runDirectExit({
117390
117507
  recipientOwner: owner.toBase58(),
117391
117508
  allowForeignRecipient: true,
117392
117509
  relaySubmit: facilitatorExitRelay(facilitatorOrigin2),
117393
- requestAnchor: facilitatorAnchor(facilitatorOrigin2),
117510
+ requestAnchor: markedAnchorRequest(facilitatorAnchor(facilitatorOrigin2)),
117394
117511
  deps: { walkHistory: walk(exitProofTools.deploymentIdentity), proveExit }
117395
117512
  }), { ring: { connection: session.connection, pool: store.state.pool } }));
117396
117513
  } catch (error) {
@@ -146364,7 +146481,7 @@ init_cli();
146364
146481
  init_floatPay();
146365
146482
  import { randomBytes as randomBytes33 } from "node:crypto";
146366
146483
  import { dirname as dirname29, join as join36, resolve as resolve37 } from "node:path";
146367
- import { spawn as spawn6 } from "node:child_process";
146484
+ import { spawn as spawn7 } from "node:child_process";
146368
146485
  import { fileURLToPath as fileURLToPath22 } from "node:url";
146369
146486
 
146370
146487
  // wallet/src/fetch/index.mjs
@@ -146387,6 +146504,8 @@ init_recoveryFile();
146387
146504
  init_config2();
146388
146505
  init_proofTools();
146389
146506
  init_proxy();
146507
+ init_facilitatorOnion();
146508
+ init_timing();
146390
146509
  init_migration();
146391
146510
  init_successions();
146392
146511
  init_chain2();
@@ -146512,10 +146631,23 @@ function readPassphrase(path, access) {
146512
146631
  }
146513
146632
  async function runSetup(options, deps = {}) {
146514
146633
  const home = resolve26(options.home);
146515
- const onStage = options.onStage ?? (() => {
146516
- });
146517
146634
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
146518
146635
  const warnings = [];
146636
+ const setupStartedAt = Date.now();
146637
+ const heldMarks = [];
146638
+ let writeMark;
146639
+ const mark = (phase, outcome, at = Date.now()) => {
146640
+ try {
146641
+ if (writeMark) writeMark(phase, outcome, at);
146642
+ else heldMarks.push([phase, outcome, at]);
146643
+ } catch {
146644
+ }
146645
+ };
146646
+ const onStage = (stage, detail) => {
146647
+ if (stage !== "proof-tools" || detail === void 0) mark(`stage-${stage}`);
146648
+ (options.onStage ?? (() => {
146649
+ }))(stage, detail);
146650
+ };
146519
146651
  onStage("platform");
146520
146652
  const platform = proverPlatform({ platform: deps.platform, hasWsl: deps.hasWsl });
146521
146653
  if (!platform.ok) throw fail40(platform.code, platform.detail);
@@ -146539,6 +146671,10 @@ async function runSetup(options, deps = {}) {
146539
146671
  } catch (error) {
146540
146672
  releaseError = error;
146541
146673
  }
146674
+ mark("release-read", release ? void 0 : "failed");
146675
+ const race = firstOnionRace(facilitator);
146676
+ if (race !== void 0) mark("onion-race-start", void 0, race.startedAt);
146677
+ if (race?.endedAt !== void 0) mark("onion-race-end", race.answered ? "answered" : "none", race.endedAt);
146542
146678
  let identity;
146543
146679
  if (release) {
146544
146680
  expected = await trustServedSet({ home, facilitator, release, expected, fetchImpl: deps.fetchImpl ?? fetch });
@@ -146708,19 +146844,56 @@ async function runSetup(options, deps = {}) {
146708
146844
  }
146709
146845
  const keep = old?.proofToolsRelease && old.pool === identity.pool ? { proofTools: old.proofTools, exitProofTools: old.exitProofTools, profile: old.profile, proofToolsRelease: old.proofToolsRelease } : {};
146710
146846
  writeSetupConfig(home, { ...base, ...keep });
146847
+ try {
146848
+ writeMark = (deps.timingLog ?? createTimingLog)(`${walletFile}.timing.log`, { component: "setup" }).start({ startedAt: setupStartedAt });
146849
+ for (const [phase, outcome, at] of heldMarks.splice(0)) writeMark(phase, outcome, at);
146850
+ } catch {
146851
+ }
146711
146852
  onStage("proof-tools");
146712
146853
  let tools;
146713
- if (release) {
146714
- tools = await installProofTools({
146715
- facilitator,
146716
- toolsRoot: join30(home, "proof-tools"),
146717
- expected,
146718
- fetchImpl: deps.fetchImpl,
146719
- onProgress: (progress3) => onStage("proof-tools", progress3)
146854
+ let warm;
146855
+ let warmCode;
146856
+ const warmAllowed = typeof deps.startWarm === "function" && !(tor && !inTorRun());
146857
+ const startWarm = (proofToolsPath) => {
146858
+ if (warm !== void 0 || !warmAllowed) return;
146859
+ try {
146860
+ warm = deps.startWarm({ walletFile, passphrase: passphrase2, proofToolsPath, program: identity.program, facilitator }) ?? null;
146861
+ } catch {
146862
+ warm = null;
146863
+ }
146864
+ if (!warm) return;
146865
+ mark("attest-start");
146866
+ warm.exited.then((code2) => {
146867
+ if (warmCode !== void 0) return;
146868
+ warmCode = code2;
146869
+ mark("attest-end", code2 === 0 ? "ok" : `exit${code2}`);
146870
+ }, () => {
146720
146871
  });
146721
- } else {
146722
- const folder = join30(home, "proof-tools", old.proofToolsRelease.dir);
146723
- tools = { ...old.proofToolsRelease, folder, downloaded: 0, ...toolPaths(folder) };
146872
+ };
146873
+ try {
146874
+ if (release) {
146875
+ tools = await installProofTools({
146876
+ facilitator,
146877
+ toolsRoot: join30(home, "proof-tools"),
146878
+ expected,
146879
+ fetchImpl: deps.fetchImpl,
146880
+ onProgress: (progress3) => onStage("proof-tools", progress3),
146881
+ mark: (phase, outcome) => mark(`tools-${phase}`, outcome),
146882
+ onFileWritten: ({ path, file }) => {
146883
+ if (path === "proof-tools.json") startWarm(file);
146884
+ }
146885
+ });
146886
+ } else {
146887
+ const folder = join30(home, "proof-tools", old.proofToolsRelease.dir);
146888
+ tools = { ...old.proofToolsRelease, folder, downloaded: 0, ...toolPaths(folder) };
146889
+ }
146890
+ } finally {
146891
+ if (warm && warmCode === void 0) {
146892
+ warmCode = "stopped";
146893
+ mark("attest-end", "stopped");
146894
+ await Promise.resolve().then(() => warm.stop()).catch(() => {
146895
+ });
146896
+ }
146724
146897
  }
146725
146898
  onStage("config");
146726
146899
  const config = {
@@ -146744,10 +146917,200 @@ async function runSetup(options, deps = {}) {
146744
146917
  passphraseGenerated,
146745
146918
  proofTools: { dir: tools.dir, downloaded: tools.downloaded, folder: tools.folder },
146746
146919
  platform: platform.wsl ? "windows+wsl" : "linux",
146747
- warnings
146920
+ warnings,
146921
+ ...warmCode === 0 ? { firstBalanceReady: true } : {}
146748
146922
  });
146749
146923
  }
146750
146924
 
146925
+ // wallet/src/setup/setupWarm.mjs
146926
+ import { spawn as spawn5 } from "node:child_process";
146927
+
146928
+ // wallet/src/history/keepWarm.mjs
146929
+ init_fs();
146930
+ init_chain2();
146931
+ init_proxy();
146932
+ init_recoveredPayment();
146933
+ init_rpcDefault();
146934
+ init_store();
146935
+ init_incremental();
146936
+ init_walletHistory();
146937
+ import { spawn as spawn4 } from "node:child_process";
146938
+ import { randomInt as randomInt7 } from "node:crypto";
146939
+ import { resolve as resolve27 } from "node:path";
146940
+ var KEEP_WARM_PARENT_ENV = "SHINJUKU_KEEP_WARM_PARENT";
146941
+ var KEEP_WARM_ONCE_PARENT_ENV = "SHINJUKU_KEEP_WARM_ONCE_PARENT";
146942
+ function watchSetupParentPipe({ stdin = process.stdin, exit = (code2) => process.exit(code2) } = {}) {
146943
+ const parentGone = () => exit(1);
146944
+ for (const event of ["end", "close", "error"]) stdin.on(event, parentGone);
146945
+ stdin.resume();
146946
+ return () => {
146947
+ for (const event of ["end", "close", "error"]) stdin.off(event, parentGone);
146948
+ stdin.destroy();
146949
+ };
146950
+ }
146951
+ var KEEP_WARM_MIN_MS = 18e4;
146952
+ var KEEP_WARM_MAX_MS = 3e5;
146953
+ async function keepWarmOnce(values, { io, env = process.env }) {
146954
+ const started = Date.now();
146955
+ const walletPath2 = resolve27(values.get("--wallet"));
146956
+ const passphrase2 = assertPassphrase(values.has("--passphrase-file") ? readFileSync(resolve27(values.get("--passphrase-file")), "utf8").trim() : String(env.SHIELDED_WALLET_PASSPHRASE ?? ""));
146957
+ const store = openWalletStore(walletPath2, passphrase2);
146958
+ const connection = connect2(resolveRpcUrl2({
146959
+ rpcFile: values.get("--rpc-file"),
146960
+ origin: values.get("--memo-service"),
146961
+ readFile: (path) => readFileSync(resolve27(path), "utf8").trim()
146962
+ }).url, "finalized");
146963
+ const proofTools = loadP03PublicPaymentProofTools(resolve27(values.get("--proof-tools")));
146964
+ await loadWalletP03History({
146965
+ store,
146966
+ connection: connectSplit(connection, historyRpcUrl(values.get("--history-rpc"))),
146967
+ programId: values.get("--program"),
146968
+ pool: store.state.pool,
146969
+ deploymentIdentity: proofTools.deploymentIdentity,
146970
+ forceRead: true
146971
+ });
146972
+ io.err(`keep-warm: the pool history is current (${((Date.now() - started) / 1e3).toFixed(1)} s); a payment in the next ${HISTORY_WARM_FRESH_MS / 6e4} minutes reads no pool history while the pool does not move
146973
+ `);
146974
+ }
146975
+ async function keepWarmMain(args, values, { io, env = process.env, entry } = {}) {
146976
+ if (values.has("--once")) {
146977
+ await keepWarmOnce(values, { io, env });
146978
+ return 0;
146979
+ }
146980
+ if (typeof entry !== "string" || !entry) throw new Error("keep_warm_entry_missing");
146981
+ const proxy = childRunProxy(env);
146982
+ let stopped = false;
146983
+ let child;
146984
+ let wake;
146985
+ const stop3 = () => {
146986
+ stopped = true;
146987
+ child?.kill("SIGTERM");
146988
+ wake?.();
146989
+ };
146990
+ process.on("SIGINT", stop3);
146991
+ process.on("SIGTERM", stop3);
146992
+ if (env[KEEP_WARM_PARENT_ENV] === "1") {
146993
+ process.stdin.on("end", stop3);
146994
+ process.stdin.on("close", stop3);
146995
+ process.stdin.on("error", stop3);
146996
+ process.stdin.resume();
146997
+ }
146998
+ try {
146999
+ while (!stopped) {
147000
+ const code2 = await new Promise((done) => {
147001
+ child = spawn4(process.execPath, [...process.execArgv, entry, ...proxy.args, "keep-warm", ...args, "--once"], {
147002
+ env: proxy.env,
147003
+ stdio: ["ignore", "ignore", "inherit"],
147004
+ windowsHide: true
147005
+ });
147006
+ child.on("error", () => done(1));
147007
+ child.on("exit", (exitCode) => done(exitCode ?? 1));
147008
+ });
147009
+ child = void 0;
147010
+ if (stopped) break;
147011
+ if (code2 !== 0) io.err(`keep-warm: this refresh failed (exit ${code2}); the next one runs at its usual time
147012
+ `);
147013
+ const gap = randomInt7(KEEP_WARM_MIN_MS, KEEP_WARM_MAX_MS + 1);
147014
+ io.err(`keep-warm: next refresh in ${Math.round(gap / 1e3)} s (stop with Ctrl-C)
147015
+ `);
147016
+ await new Promise((done) => {
147017
+ const timer = setTimeout(done, gap);
147018
+ wake = () => {
147019
+ clearTimeout(timer);
147020
+ done();
147021
+ };
147022
+ });
147023
+ wake = void 0;
147024
+ }
147025
+ } finally {
147026
+ process.off("SIGINT", stop3);
147027
+ process.off("SIGTERM", stop3);
147028
+ }
147029
+ return 0;
147030
+ }
147031
+
147032
+ // wallet/src/setup/setupWarm.mjs
147033
+ init_proxy();
147034
+ var SETUP_WARM_STOP_WAIT_MS = 5e3;
147035
+ function killProcessTree(child, { platform = process.platform, run: run5 = spawn5 } = {}) {
147036
+ if (!Number.isSafeInteger(child?.pid)) return;
147037
+ if (platform === "win32") {
147038
+ try {
147039
+ const killer = run5("taskkill", ["/T", "/F", "/PID", String(child.pid)], { windowsHide: true, stdio: "ignore" });
147040
+ killer?.on?.("error", () => {
147041
+ });
147042
+ killer?.unref?.();
147043
+ } catch {
147044
+ }
147045
+ return;
147046
+ }
147047
+ try {
147048
+ child.kill("SIGTERM");
147049
+ } catch {
147050
+ }
147051
+ }
147052
+ function startSetupWarm({
147053
+ entry,
147054
+ walletFile,
147055
+ passphrase: passphrase2,
147056
+ passphraseEnv,
147057
+ proofToolsPath,
147058
+ program,
147059
+ facilitator,
147060
+ env = process.env,
147061
+ spawnImpl = spawn5,
147062
+ killTree = killProcessTree
147063
+ }) {
147064
+ const proxy = childRunProxy(env);
147065
+ const child = spawnImpl(process.execPath, [
147066
+ ...process.execArgv,
147067
+ entry,
147068
+ ...proxy.args,
147069
+ "keep-warm",
147070
+ "--once",
147071
+ "--wallet",
147072
+ walletFile,
147073
+ "--proof-tools",
147074
+ proofToolsPath,
147075
+ "--program",
147076
+ program,
147077
+ "--memo-service",
147078
+ facilitator
147079
+ ], {
147080
+ env: { ...proxy.env, [passphraseEnv]: passphrase2, [KEEP_WARM_ONCE_PARENT_ENV]: "1" },
147081
+ stdio: ["pipe", "ignore", "ignore"],
147082
+ windowsHide: true
147083
+ });
147084
+ let ended = false;
147085
+ const exited = new Promise((resolve38) => {
147086
+ child.on("error", () => {
147087
+ ended = true;
147088
+ resolve38(1);
147089
+ });
147090
+ child.on("exit", (code2) => {
147091
+ ended = true;
147092
+ resolve38(code2 ?? 1);
147093
+ });
147094
+ });
147095
+ child.stdin?.on?.("error", () => {
147096
+ });
147097
+ return {
147098
+ exited,
147099
+ async stop() {
147100
+ try {
147101
+ child.stdin?.end?.();
147102
+ } catch {
147103
+ }
147104
+ if (!ended) killTree(child);
147105
+ let timer;
147106
+ await Promise.race([exited, new Promise((resolve38) => {
147107
+ timer = setTimeout(resolve38, SETUP_WARM_STOP_WAIT_MS);
147108
+ })]);
147109
+ clearTimeout(timer);
147110
+ }
147111
+ };
147112
+ }
147113
+
146751
147114
  // wallet/src/cli/shinjukuWallet.mjs
146752
147115
  init_channel();
146753
147116
  init_family();
@@ -146777,7 +147140,7 @@ init_proxy();
146777
147140
  init_rpcDefault();
146778
147141
  init_secretFile();
146779
147142
  init_serviceUrl();
146780
- import { resolve as resolve27 } from "node:path";
147143
+ import { resolve as resolve28 } from "node:path";
146781
147144
  import { fileURLToPath as fileURLToPath19 } from "node:url";
146782
147145
  var USAGE3 = "shinjuku-wallet merge --wallet <encrypted-file> --passphrase-file <file> --program <address> [--dry-run] [--rpc-file <file>] --proof-tools <manifest> --profile <public-profile.json> --facilitator <https-origin> [--history-rpc <own|url>]";
146783
147146
  var VALUED = ["wallet", "passphrase-file", "program", "rpc-file", "proof-tools", "profile", "facilitator", "history-rpc"];
@@ -146820,8 +147183,8 @@ async function main5(args = process.argv.slice(2)) {
146820
147183
  const origin = dryRun ? void 0 : new URL(options.facilitator);
146821
147184
  if (origin && (origin.protocol !== "https:" && !isOnionOrigin(origin) || origin.pathname !== "/" || origin.search)) fail41("facilitator_origin_invalid");
146822
147185
  const historyUrl = historyRpcUrl(options["history-rpc"]);
146823
- const walletPath2 = resolve27(options.wallet);
146824
- const passphrase2 = assertPassphrase(readSecretText(resolve27(options["passphrase-file"]), "--passphrase-file"));
147186
+ const walletPath2 = resolve28(options.wallet);
147187
+ const passphrase2 = assertPassphrase(readSecretText(resolve28(options["passphrase-file"]), "--passphrase-file"));
146825
147188
  let release;
146826
147189
  try {
146827
147190
  release = await acquireWalletProcessLease(walletLockPath(walletPath2));
@@ -146840,13 +147203,13 @@ async function main5(args = process.argv.slice(2)) {
146840
147203
  const connection = connect2(resolveRpcUrl2({
146841
147204
  rpcFile: options["rpc-file"],
146842
147205
  origin: origin.origin,
146843
- readFile: (path) => readFileSync(resolve27(path), "utf8").trim()
147206
+ readFile: (path) => readFileSync(resolve28(path), "utf8").trim()
146844
147207
  }).url, "finalized");
146845
- const proofTools = loadP03PublicPaymentProofTools(resolve27(options["proof-tools"]));
147208
+ const proofTools = loadP03PublicPaymentProofTools(resolve28(options["proof-tools"]));
146846
147209
  steps = {
146847
147210
  connection,
146848
147211
  proofTools,
146849
- profile: JSON.parse(readFileSync(resolve27(options.profile), "utf8")),
147212
+ profile: JSON.parse(readFileSync(resolve28(options.profile), "utf8")),
146850
147213
  timing: createTimingLog(`${walletPath2}.timing.log`, { component: "payer" })
146851
147214
  };
146852
147215
  }
@@ -146944,7 +147307,7 @@ async function main5(args = process.argv.slice(2)) {
146944
147307
  await release();
146945
147308
  }
146946
147309
  }
146947
- if (process.argv[1] && resolve27(process.argv[1]) === fileURLToPath19(new URL("__bundled_source__/wallet/src/merge/cli.mjs", import.meta.url).href)) {
147310
+ if (process.argv[1] && resolve28(process.argv[1]) === fileURLToPath19(new URL("__bundled_source__/wallet/src/merge/cli.mjs", import.meta.url).href)) {
146948
147311
  main5().catch((error) => {
146949
147312
  console.error(describeCliErrorWithHint(error));
146950
147313
  process.exitCode = 1;
@@ -146953,7 +147316,7 @@ if (process.argv[1] && resolve27(process.argv[1]) === fileURLToPath19(new URL("_
146953
147316
 
146954
147317
  // wallet/src/item/buyItem.mjs
146955
147318
  init_fs();
146956
- import { resolve as resolve28 } from "node:path";
147319
+ import { resolve as resolve29 } from "node:path";
146957
147320
 
146958
147321
  // src/shared/blindVoucher.ts
146959
147322
  init_sha256();
@@ -147445,8 +147808,8 @@ async function main6(args = process.argv.slice(2)) {
147445
147808
  }
147446
147809
  if (REQUIRED3.some((key) => !options[key])) throw new Error("p03_item_cli_arguments_missing");
147447
147810
  const historyUrl = historyRpcUrl(options["history-rpc"]);
147448
- const walletPath2 = resolve28(options.wallet);
147449
- const passphrase2 = assertPassphrase(readSecretText(resolve28(options["passphrase-file"]), "--passphrase-file"));
147811
+ const walletPath2 = resolve29(options.wallet);
147812
+ const passphrase2 = assertPassphrase(readSecretText(resolve29(options["passphrase-file"]), "--passphrase-file"));
147450
147813
  const timing = createTimingLog(`${walletPath2}.timing.log`, { component: "payer" }).start({ startedAt: performance.timeOrigin });
147451
147814
  timing("process-start", void 0, performance.timeOrigin);
147452
147815
  if (proxyProvenAt() !== void 0) timing("proxy-proven", void 0, proxyProvenAt());
@@ -147463,15 +147826,15 @@ async function main6(args = process.argv.slice(2)) {
147463
147826
  const connection = connect2(resolveRpcUrl2({
147464
147827
  rpcFile: options["rpc-file"],
147465
147828
  origin: options["memo-service"],
147466
- readFile: (path) => readFileSync(resolve28(path), "utf8").trim()
147829
+ readFile: (path) => readFileSync(resolve29(path), "utf8").trim()
147467
147830
  }).url, "finalized");
147468
147831
  const earlySource = resolveHistorySource(connectSplit(connection, historyUrl), store.state.pool);
147469
147832
  if (earlySource.source === "pinned") earlySource.connection.historyRpcWarm?.();
147470
147833
  connection.getSlot("finalized").catch(() => {
147471
147834
  });
147472
- const proofTools = loadP03PublicPaymentProofTools(resolve28(options["proof-tools"]));
147835
+ const proofTools = loadP03PublicPaymentProofTools(resolve29(options["proof-tools"]));
147473
147836
  timing("proof-tools");
147474
- const playToken = options["play-token-file"] ? readFileSync(resolve28(options["play-token-file"]), "utf8").trim() : void 0;
147837
+ const playToken = options["play-token-file"] ? readFileSync(resolve29(options["play-token-file"]), "utf8").trim() : void 0;
147475
147838
  if (playToken !== void 0 && !/^sjp_[A-Za-z0-9_-]{16,200}$/.test(playToken)) throw new Error("p03_item_play_token_invalid");
147476
147839
  const walkHistory = async () => {
147477
147840
  const history = await loadWalletP03History({
@@ -147518,100 +147881,6 @@ async function main6(args = process.argv.slice(2)) {
147518
147881
  }
147519
147882
  }
147520
147883
 
147521
- // wallet/src/history/keepWarm.mjs
147522
- init_fs();
147523
- init_chain2();
147524
- init_proxy();
147525
- init_recoveredPayment();
147526
- init_rpcDefault();
147527
- init_store();
147528
- init_incremental();
147529
- init_walletHistory();
147530
- import { spawn as spawn4 } from "node:child_process";
147531
- import { randomInt as randomInt7 } from "node:crypto";
147532
- import { resolve as resolve29 } from "node:path";
147533
- var KEEP_WARM_PARENT_ENV = "SHINJUKU_KEEP_WARM_PARENT";
147534
- var KEEP_WARM_MIN_MS = 18e4;
147535
- var KEEP_WARM_MAX_MS = 3e5;
147536
- async function keepWarmOnce(values, { io, env = process.env }) {
147537
- const started = Date.now();
147538
- const walletPath2 = resolve29(values.get("--wallet"));
147539
- const passphrase2 = assertPassphrase(values.has("--passphrase-file") ? readFileSync(resolve29(values.get("--passphrase-file")), "utf8").trim() : String(env.SHIELDED_WALLET_PASSPHRASE ?? ""));
147540
- const store = openWalletStore(walletPath2, passphrase2);
147541
- const connection = connect2(resolveRpcUrl2({
147542
- rpcFile: values.get("--rpc-file"),
147543
- origin: values.get("--memo-service"),
147544
- readFile: (path) => readFileSync(resolve29(path), "utf8").trim()
147545
- }).url, "finalized");
147546
- const proofTools = loadP03PublicPaymentProofTools(resolve29(values.get("--proof-tools")));
147547
- await loadWalletP03History({
147548
- store,
147549
- connection: connectSplit(connection, historyRpcUrl(values.get("--history-rpc"))),
147550
- programId: values.get("--program"),
147551
- pool: store.state.pool,
147552
- deploymentIdentity: proofTools.deploymentIdentity,
147553
- forceRead: true
147554
- });
147555
- io.err(`keep-warm: the pool history is current (${((Date.now() - started) / 1e3).toFixed(1)} s); a payment in the next ${HISTORY_WARM_FRESH_MS / 6e4} minutes reads no pool history while the pool does not move
147556
- `);
147557
- }
147558
- async function keepWarmMain(args, values, { io, env = process.env, entry } = {}) {
147559
- if (values.has("--once")) {
147560
- await keepWarmOnce(values, { io, env });
147561
- return 0;
147562
- }
147563
- if (typeof entry !== "string" || !entry) throw new Error("keep_warm_entry_missing");
147564
- const proxy = childRunProxy(env);
147565
- let stopped = false;
147566
- let child;
147567
- let wake;
147568
- const stop3 = () => {
147569
- stopped = true;
147570
- child?.kill("SIGTERM");
147571
- wake?.();
147572
- };
147573
- process.on("SIGINT", stop3);
147574
- process.on("SIGTERM", stop3);
147575
- if (env[KEEP_WARM_PARENT_ENV] === "1") {
147576
- process.stdin.on("end", stop3);
147577
- process.stdin.on("close", stop3);
147578
- process.stdin.on("error", stop3);
147579
- process.stdin.resume();
147580
- }
147581
- try {
147582
- while (!stopped) {
147583
- const code2 = await new Promise((done) => {
147584
- child = spawn4(process.execPath, [...process.execArgv, entry, ...proxy.args, "keep-warm", ...args, "--once"], {
147585
- env: proxy.env,
147586
- stdio: ["ignore", "ignore", "inherit"],
147587
- windowsHide: true
147588
- });
147589
- child.on("error", () => done(1));
147590
- child.on("exit", (exitCode) => done(exitCode ?? 1));
147591
- });
147592
- child = void 0;
147593
- if (stopped) break;
147594
- if (code2 !== 0) io.err(`keep-warm: this refresh failed (exit ${code2}); the next one runs at its usual time
147595
- `);
147596
- const gap = randomInt7(KEEP_WARM_MIN_MS, KEEP_WARM_MAX_MS + 1);
147597
- io.err(`keep-warm: next refresh in ${Math.round(gap / 1e3)} s (stop with Ctrl-C)
147598
- `);
147599
- await new Promise((done) => {
147600
- const timer = setTimeout(done, gap);
147601
- wake = () => {
147602
- clearTimeout(timer);
147603
- done();
147604
- };
147605
- });
147606
- wake = void 0;
147607
- }
147608
- } finally {
147609
- process.off("SIGINT", stop3);
147610
- process.off("SIGTERM", stop3);
147611
- }
147612
- return 0;
147613
- }
147614
-
147615
147884
  // wallet/src/cli/shinjukuWallet.mjs
147616
147885
  init_cli3();
147617
147886
 
@@ -149809,7 +150078,7 @@ init_deposit();
149809
150078
  init_fs();
149810
150079
  init_balance();
149811
150080
  init_deposit();
149812
- import { spawn as spawn5 } from "node:child_process";
150081
+ import { spawn as spawn6 } from "node:child_process";
149813
150082
  import { randomBytes as randomBytes25, randomInt as randomInt9 } from "node:crypto";
149814
150083
  import { tmpdir as tmpdir4 } from "node:os";
149815
150084
  import { join as join33, resolve as resolve31 } from "node:path";
@@ -150064,7 +150333,7 @@ async function runStep(ctx, argv2) {
150064
150333
  const file = join33(ctx.tempDir, `step-${randomBytes25(8).toString("hex")}.json`);
150065
150334
  const held = [];
150066
150335
  let last;
150067
- const proc = spawn5(process.execPath, [...process.execArgv, ctx.entry, ...ctx.proxyArgs, ...argv2], {
150336
+ const proc = spawn6(process.execPath, [...process.execArgv, ctx.entry, ...ctx.proxyArgs, ...argv2], {
150068
150337
  env: { ...ctx.childEnv, [RESULT_FILE_ENV]: file },
150069
150338
  stdio: ["ignore", "ignore", "pipe"],
150070
150339
  windowsHide: true
@@ -151557,7 +151826,7 @@ function startKeepWarm(options, env = process.env) {
151557
151826
  options.memoServiceUrl,
151558
151827
  ...options.historyRpc ? ["--history-rpc", options.historyRpc] : []
151559
151828
  ];
151560
- const child = spawn6(process.execPath, [...process.execArgv, CLI_FILE, ...proxy.args, ...warmArgs], {
151829
+ const child = spawn7(process.execPath, [...process.execArgv, CLI_FILE, ...proxy.args, ...warmArgs], {
151561
151830
  env: {
151562
151831
  ...proxy.env,
151563
151832
  [PASSPHRASE_ENV2]: options.passphrase,
@@ -151577,6 +151846,11 @@ function startKeepWarm(options, env = process.env) {
151577
151846
  });
151578
151847
  return child;
151579
151848
  }
151849
+ function setupWarmStarter(deps) {
151850
+ if (deps.startSetupWarm) return deps.startSetupWarm;
151851
+ if (!process.argv[1] || resolve37(process.argv[1]) !== CLI_FILE) return void 0;
151852
+ return (options) => startSetupWarm({ ...options, entry: CLI_FILE, passphraseEnv: PASSPHRASE_ENV2, env: deps.env ?? process.env });
151853
+ }
151580
151854
  function mcpServerOptions(values, deps) {
151581
151855
  const options = payerSessionOptions(values, deps);
151582
151856
  let pool2;
@@ -152143,7 +152417,7 @@ Copy it to two offline places now; it is the only way to restore this wallet.
152143
152417
  lastStage = stage;
152144
152418
  io.err(`${STAGE_TEXT[stage]}...
152145
152419
  `);
152146
- } }, setupDependencies(deps), inference);
152420
+ } }, { ...setupDependencies(deps), startWarm: setupWarmStarter(deps) }, inference);
152147
152421
  } catch (error) {
152148
152422
  if (/^(setup_[a-z_]+|secret_file_utf16): /.test(String(error?.message))) throw new PublicFailure(error.message);
152149
152423
  throw error;
@@ -152154,7 +152428,9 @@ Copy it to two offline places now; it is the only way to restore this wallet.
152154
152428
  ` limits ${capText(summary.caps.maxPayment, usdcText3)} per payment, ${capText(summary.caps.maxSession, usdcText3)} in any 24 hours, ${capText(summary.caps.maxTotal, usdcText3)} for the life of the wallet${summary.tor ? "; Tor on" : ""}`,
152155
152429
  ` config ${summary.configPath}`,
152156
152430
  ` passphrase ${summary.passphraseFile}${summary.passphraseGenerated ? " (a new random passphrase; only you can read the file; it is never printed)" : ""}`,
152157
- ` proof tools ${summary.proofTools.folder} (${summary.proofTools.downloaded ? `${summary.proofTools.downloaded} files downloaded, every hash checked` : "already here, every hash checked"})`
152431
+ ` proof tools ${summary.proofTools.folder} (${summary.proofTools.downloaded ? `${summary.proofTools.downloaded} files downloaded, every hash checked` : "already here, every hash checked"})`,
152432
+ // The setup warm ended well (setup/setupWarm.mjs); nothing is said when it did not.
152433
+ ...summary.firstBalanceReady ? [" balance prepared during setup: your first balance after a deposit shows sooner"] : []
152158
152434
  ];
152159
152435
  if (summary.wallet.status === "created") {
152160
152436
  lines.push(
@@ -155254,8 +155530,11 @@ ${sellerLine}${landedLine}${whyLine}${ambiguousLine}${blockingLine}${hint ? `hin
155254
155530
  // wallet/bin/shinjuku-wallet.mjs
155255
155531
  init_proxy();
155256
155532
  var argv = process.argv.slice(2);
155533
+ var wrapper = runNetworkMode() === null && (argv.includes("--tor") || argv.includes("--proxy"));
155534
+ var stopSetupWatch = process.env[KEEP_WARM_ONCE_PARENT_ENV] === "1" && !wrapper ? watchSetupParentPipe() : void 0;
155257
155535
  var mcpRefused = async (options) => (await Promise.resolve().then(() => (init_torMissingMcp(), torMissingMcp_exports))).serveTorMissingMcp(options);
155258
155536
  var code = isHelpRequest(argv) ? await runShinjukuWallet(argv) : await proxyEntry(argv, runShinjukuWallet, { mcpRefused });
155537
+ stopSetupWatch?.();
155259
155538
  process.exitCode = code;
155260
155539
  if (code !== 0) setTimeout(() => process.exit(code), 2e3).unref();
155261
155540
  else if (mcpServerEndedHere()) setTimeout(() => process.exit(code), 0).unref();