@ipv9/tokentracker-cli 0.39.46 → 0.39.47
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/dashboard/dist/assets/{Card-Bk5BMQ2P.js → Card-BMWFZ5k5.js} +1 -1
- package/dashboard/dist/assets/{DashboardPage-DPP44kwE.js → DashboardPage-HjWNRKq7.js} +1 -1
- package/dashboard/dist/assets/{FadeIn-CWvnEI0O.js → FadeIn-BgLVBi0I.js} +1 -1
- package/dashboard/dist/assets/{IpCheckPage-BmSn2zKd.js → IpCheckPage-CsS9rEbM.js} +1 -1
- package/dashboard/dist/assets/{LimitsPage-CDCccsH_.js → LimitsPage-BifpRDJ6.js} +1 -1
- package/dashboard/dist/assets/{LocalOnlyNotice-D19MhLRF.js → LocalOnlyNotice-D7tdrheS.js} +1 -1
- package/dashboard/dist/assets/{PopoverPopup-D78fYtAs.js → PopoverPopup-DjMB9uLV.js} +1 -1
- package/dashboard/dist/assets/{Select-CKV1Rvl0.js → Select-DeCgT4YH.js} +1 -1
- package/dashboard/dist/assets/{SelectItemText-5eDkx616.js → SelectItemText-DwZRVpPE.js} +1 -1
- package/dashboard/dist/assets/{SettingsPage-DIwe50pL.js → SettingsPage-B1l6jasL.js} +1 -1
- package/dashboard/dist/assets/{SkillsPage-zUzRrWak.js → SkillsPage-DP5bdeUE.js} +1 -1
- package/dashboard/dist/assets/{WidgetsPage-3yOTNqKD.js → WidgetsPage-BVOQlozx.js} +1 -1
- package/dashboard/dist/assets/{WrappedPage-DPAnbLdi.js → WrappedPage-ixZYG73C.js} +1 -1
- package/dashboard/dist/assets/{arrow-up-right-BGg2lx0L.js → arrow-up-right-D74FAyJC.js} +1 -1
- package/dashboard/dist/assets/{download-BU4HPPvG.js → download-sKFNy5AQ.js} +1 -1
- package/dashboard/dist/assets/{format-vw28c71d.js → format-Bl1W1y2T.js} +1 -1
- package/dashboard/dist/assets/{limitDisplay-CY5Qlw5s.js → limitDisplay-C2rw2OOb.js} +1 -1
- package/dashboard/dist/assets/{main-D9Jo7Pt-.js → main-NjvOmlYA.js} +3 -3
- package/dashboard/dist/assets/{mock-data-B0oPPFnn.js → mock-data-DJ2XGAUP.js} +1 -1
- package/dashboard/dist/assets/{use-limits-display-prefs-BAGMxrq7.js → use-limits-display-prefs-C7BBDoNV.js} +1 -1
- package/dashboard/dist/assets/{use-native-settings-C4lSH6qA.js → use-native-settings-BYIme-b6.js} +1 -1
- package/dashboard/dist/assets/{useCurrency-Dvz0184_.js → useCurrency-CJzAqnSI.js} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/lib/pricing/seed-snapshot.json +1 -1
- package/src/lib/rollout.js +48 -7
package/src/lib/rollout.js
CHANGED
|
@@ -3237,21 +3237,48 @@ function isUncPath(p) {
|
|
|
3237
3237
|
return typeof p === "string" && (p.startsWith("\\\\") || p.startsWith("//"));
|
|
3238
3238
|
}
|
|
3239
3239
|
|
|
3240
|
+
function sqliteDbChangeFingerprint(dbPath) {
|
|
3241
|
+
const parts = [];
|
|
3242
|
+
for (const suffix of ["", "-wal", "-shm", "-journal"]) {
|
|
3243
|
+
const filePath = dbPath + suffix;
|
|
3244
|
+
const label = suffix || "main";
|
|
3245
|
+
try {
|
|
3246
|
+
const stat = fssync.statSync(filePath, { bigint: true });
|
|
3247
|
+
parts.push(`${label}:${stat.size}:${stat.mtimeNs}`);
|
|
3248
|
+
} catch (error) {
|
|
3249
|
+
if (error && error.code === "ENOENT") {
|
|
3250
|
+
parts.push(`${label}:missing`);
|
|
3251
|
+
continue;
|
|
3252
|
+
}
|
|
3253
|
+
// A partial fingerprint must never authorize the no-change fast path.
|
|
3254
|
+
// Retry the read instead of treating repeated stat failures as stable.
|
|
3255
|
+
return null;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
return parts.join("|");
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3240
3261
|
function snapshotSqliteDb(dbPath) {
|
|
3241
3262
|
const tmpRoot = fssync.mkdtempSync(
|
|
3242
3263
|
path.join(require("node:os").tmpdir(), "tokentracker-hermes-snap-"),
|
|
3243
3264
|
);
|
|
3244
3265
|
const target = path.join(tmpRoot, path.basename(dbPath));
|
|
3245
3266
|
fssync.copyFileSync(dbPath, target);
|
|
3246
|
-
//
|
|
3267
|
+
// Copy SQLite sidecars as one logical snapshot. A missing sidecar is normal,
|
|
3268
|
+
// but any other copy failure makes the snapshot incomplete and must prevent
|
|
3269
|
+
// callers from advancing a change fingerprint based on stale main-DB data.
|
|
3270
|
+
let sidecarsComplete = true;
|
|
3247
3271
|
for (const suffix of ["-wal", "-shm", "-journal"]) {
|
|
3248
3272
|
const src = dbPath + suffix;
|
|
3249
3273
|
try {
|
|
3250
|
-
|
|
3251
|
-
} catch (
|
|
3274
|
+
fssync.copyFileSync(src, target + suffix);
|
|
3275
|
+
} catch (error) {
|
|
3276
|
+
if (!error || error.code !== "ENOENT") sidecarsComplete = false;
|
|
3277
|
+
}
|
|
3252
3278
|
}
|
|
3253
3279
|
return {
|
|
3254
3280
|
path: target,
|
|
3281
|
+
sidecarsComplete,
|
|
3255
3282
|
cleanup() {
|
|
3256
3283
|
try { fssync.rmSync(tmpRoot, { recursive: true, force: true }); } catch (_e) { }
|
|
3257
3284
|
},
|
|
@@ -6128,7 +6155,8 @@ async function parseGooseIncremental({
|
|
|
6128
6155
|
? { ...gooseState.sessionTotals }
|
|
6129
6156
|
: {};
|
|
6130
6157
|
|
|
6131
|
-
const
|
|
6158
|
+
const cursorDbFingerprint =
|
|
6159
|
+
typeof gooseState.lastDbFingerprint === "string" ? gooseState.lastDbFingerprint : null;
|
|
6132
6160
|
let currentMtime = 0;
|
|
6133
6161
|
try {
|
|
6134
6162
|
currentMtime = fssync.statSync(resolvedDb).mtimeMs;
|
|
@@ -6139,9 +6167,12 @@ async function parseGooseIncremental({
|
|
|
6139
6167
|
}
|
|
6140
6168
|
throw e;
|
|
6141
6169
|
}
|
|
6142
|
-
|
|
6143
|
-
//
|
|
6144
|
-
|
|
6170
|
+
const currentDbFingerprint = sqliteDbChangeFingerprint(resolvedDb);
|
|
6171
|
+
// Goose commonly commits active-session writes only to SQLite's WAL. Skip
|
|
6172
|
+
// the table scan only when the main DB and every sidecar are unchanged.
|
|
6173
|
+
// Legacy cursors without a fingerprint intentionally perform one read to
|
|
6174
|
+
// establish the sidecar-aware baseline.
|
|
6175
|
+
if (cursorDbFingerprint && currentDbFingerprint === cursorDbFingerprint) {
|
|
6145
6176
|
cursors.goose = { ...gooseState, sessionTotals, updatedAt: observedAt };
|
|
6146
6177
|
return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
6147
6178
|
}
|
|
@@ -6151,6 +6182,15 @@ async function parseGooseIncremental({
|
|
|
6151
6182
|
const snap = snapshotSqliteDb(resolvedDb);
|
|
6152
6183
|
let rows = [];
|
|
6153
6184
|
try {
|
|
6185
|
+
if (!snap.sidecarsComplete) {
|
|
6186
|
+
cursors.goose = {
|
|
6187
|
+
...gooseState,
|
|
6188
|
+
sessionTotals,
|
|
6189
|
+
lastDbFingerprint: null,
|
|
6190
|
+
updatedAt: observedAt,
|
|
6191
|
+
};
|
|
6192
|
+
return { recordsProcessed: 0, eventsAggregated: 0, bucketsQueued: 0 };
|
|
6193
|
+
}
|
|
6154
6194
|
rows = readGooseSessionsFromSqlite(snap.path, sqliteOptions);
|
|
6155
6195
|
} finally {
|
|
6156
6196
|
snap.cleanup();
|
|
@@ -6271,6 +6311,7 @@ async function parseGooseIncremental({
|
|
|
6271
6311
|
...gooseState,
|
|
6272
6312
|
sessionTotals,
|
|
6273
6313
|
lastDbMtimeMs: currentMtime,
|
|
6314
|
+
lastDbFingerprint: currentDbFingerprint,
|
|
6274
6315
|
updatedAt: observedAt,
|
|
6275
6316
|
};
|
|
6276
6317
|
|