fluncle 0.132.0 → 0.133.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.
Files changed (2) hide show
  1. package/bin/fluncle.mjs +106 -3
  2. package/package.json +1 -1
package/bin/fluncle.mjs CHANGED
@@ -561,7 +561,7 @@ function parseVersion(version) {
561
561
  var currentVersion;
562
562
  var init_version = __esm(() => {
563
563
  init_output();
564
- currentVersion = "0.132.0".trim() ? "0.132.0".trim() : "0.1.0";
564
+ currentVersion = "0.133.0".trim() ? "0.133.0".trim() : "0.1.0";
565
565
  });
566
566
 
567
567
  // src/update-notifier.ts
@@ -2189,7 +2189,7 @@ function parseVersion2(version) {
2189
2189
  var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
2190
2190
  var init_version2 = __esm(() => {
2191
2191
  init_output();
2192
- currentVersion2 = "0.132.0".trim() ? "0.132.0".trim() : "0.1.0";
2192
+ currentVersion2 = "0.133.0".trim() ? "0.133.0".trim() : "0.1.0";
2193
2193
  });
2194
2194
 
2195
2195
  // ../../packages/registry/src/index.ts
@@ -2651,14 +2651,25 @@ var init_src = __esm(() => {
2651
2651
  },
2652
2652
  {
2653
2653
  apiFormat: "application/xml",
2654
- exposedContent: ["the XML sitemap of every public page"],
2654
+ exposedContent: ["the XML sitemap index of every public page"],
2655
2655
  kind: "discovery",
2656
2656
  name: "discovery.sitemap",
2657
+ operatorNotes: "A sitemap INDEX, not a flat urlset: the URLs live in children at /sitemap/<kind>-<n>.xml (pages/findings/graph/logbook), each auto-paged under Google's 50,000-URL ceiling so a breach cannot happen rather than merely not having happened yet. robots.txt still names this one URL — a crawler discovers the children from here. Splitting by kind is also the diagnostic: Search Console reports coverage PER sitemap.",
2657
2658
  probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
2658
2659
  route: "/sitemap.xml",
2659
2660
  url: `${SITE}/sitemap.xml`,
2660
2661
  weights: { web: "secondary" }
2661
2662
  },
2663
+ {
2664
+ apiFormat: "application/xml",
2665
+ exposedContent: ["one child sitemap: the pages / findings / graph / logbook URLs, auto-paged"],
2666
+ kind: "discovery",
2667
+ name: "discovery.sitemap-shard",
2668
+ probeConfig: { cadenceMs: PROBE_CADENCE_MS, kind: "http", timeoutMs: PROBE_TIMEOUT_MS },
2669
+ route: "/sitemap/$shard",
2670
+ url: `${SITE}/sitemap/pages-1.xml`,
2671
+ weights: {}
2672
+ },
2662
2673
  {
2663
2674
  apiFormat: "text/plain",
2664
2675
  exposedContent: [
@@ -4217,6 +4228,22 @@ var init_publish = __esm(() => {
4217
4228
  init_api();
4218
4229
  });
4219
4230
 
4231
+ // src/commands/capture.ts
4232
+ var exports_capture = {};
4233
+ __export(exports_capture, {
4234
+ setCaptureBudgetCommand: () => setCaptureBudgetCommand,
4235
+ captureBudgetCommand: () => captureBudgetCommand
4236
+ });
4237
+ async function captureBudgetCommand() {
4238
+ return adminApiGet("/api/admin/catalogue/capture-budget");
4239
+ }
4240
+ async function setCaptureBudgetCommand(input) {
4241
+ return adminApiPut("/api/admin/catalogue/capture-budget", input);
4242
+ }
4243
+ var init_capture = __esm(() => {
4244
+ init_api();
4245
+ });
4246
+
4220
4247
  // ../../packages/contracts/src/util/multipart.ts
4221
4248
  function planMultipart(contentLength, partSize = DEFAULT_PART_SIZE) {
4222
4249
  if (!Number.isInteger(contentLength) || contentLength <= 0) {
@@ -8221,6 +8248,26 @@ function addAdminCommands(program2) {
8221
8248
  const { publishAdvancePauseCommand: publishAdvancePauseCommand2 } = await Promise.resolve().then(() => (init_publish(), exports_publish));
8222
8249
  await runPublishAdvancePause(false, options, publishAdvancePauseCommand2);
8223
8250
  });
8251
+ const adminCapture = configureCommand(admin.command("capture").description("The metered audio-capture budget and its kill switch"));
8252
+ adminCapture.action(() => {
8253
+ adminCapture.outputHelp();
8254
+ });
8255
+ adminCapture.command("budget").description("What catalogue capture spent in the last 24h, and how much budget is left").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
8256
+ const { captureBudgetCommand: captureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
8257
+ await runCaptureBudget(options, captureBudgetCommand2);
8258
+ });
8259
+ adminCapture.command("pause").description("Stop all catalogue audio capture \u2014 the kill switch (operator)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
8260
+ const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
8261
+ await runSetCaptureBudget({ paused: true }, options, setCaptureBudgetCommand2);
8262
+ });
8263
+ adminCapture.command("resume").description("Let catalogue audio capture spend again, up to its budget (operator)").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
8264
+ const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
8265
+ await runSetCaptureBudget({ paused: false }, options, setCaptureBudgetCommand2);
8266
+ });
8267
+ adminCapture.command("set").description("Set the rolling-24h capture caps (operator)").option("--tracks <n>", "Max catalogue downloads per rolling 24h").option("--gb <n>", "Max GB downloaded per rolling 24h").option("--json", "Print JSON", false).allowExcessArguments().action(async (options) => {
8268
+ const { setCaptureBudgetCommand: setCaptureBudgetCommand2 } = await Promise.resolve().then(() => (init_capture(), exports_capture));
8269
+ await runSetCaptureCaps(options, setCaptureBudgetCommand2);
8270
+ });
8224
8271
  const adminClips = configureCommand(admin.command("clips").description("Mixtape clip (Fluncle Studio) commands"));
8225
8272
  adminClips.action(() => {
8226
8273
  adminClips.outputHelp();
@@ -9373,6 +9420,60 @@ async function runPublishAdvance(options, publishAdvanceCommand2) {
9373
9420
  console.log(`Failed ${failure.platform} for ${failure.trackId} \u2014 left for the operator.`);
9374
9421
  }
9375
9422
  }
9423
+ var GB = 1073741824;
9424
+ function formatGb(bytes) {
9425
+ return `${(bytes / GB).toFixed(2)} GB`;
9426
+ }
9427
+ function printCaptureBudget(state) {
9428
+ const reason = state.closedReason === "paused" ? "paused \u2014 you stopped it" : state.closedReason === "tracks_spent" ? "the daily track cap is spent" : state.closedReason === "bytes_spent" ? "the daily GB cap is spent" : "";
9429
+ console.log(state.open ? "Catalogue capture is RUNNING \u2014 it may buy audio, up to the budget below." : `Catalogue capture is STOPPED (${reason}). Findings still capture as normal.`);
9430
+ console.log(` Last ${state.windowHours}h: ${state.spend.tracks} ${state.spend.tracks === 1 ? "track" : "tracks"} \xB7 ${formatGb(state.spend.bytes)}`);
9431
+ console.log(` Budget: ${state.budget.dailyTracks} tracks \xB7 ${formatGb(state.budget.dailyBytes)} per ${state.windowHours}h`);
9432
+ console.log(` Left: ${state.remainingTracks} ${state.remainingTracks === 1 ? "track" : "tracks"} \xB7 ${formatGb(state.remainingBytes)}`);
9433
+ }
9434
+ async function runCaptureBudget(options, captureBudgetCommand2) {
9435
+ const state = await captureBudgetCommand2();
9436
+ if (options.json) {
9437
+ printJson(state);
9438
+ return;
9439
+ }
9440
+ printCaptureBudget(state);
9441
+ }
9442
+ async function runSetCaptureBudget(input, options, setCaptureBudgetCommand2) {
9443
+ const state = await setCaptureBudgetCommand2(input);
9444
+ if (options.json) {
9445
+ printJson(state);
9446
+ return;
9447
+ }
9448
+ printCaptureBudget(state);
9449
+ }
9450
+ async function runSetCaptureCaps(options, setCaptureBudgetCommand2) {
9451
+ const input = {};
9452
+ if (options.tracks !== undefined) {
9453
+ const tracks = Number(options.tracks);
9454
+ if (!Number.isInteger(tracks) || tracks < 0) {
9455
+ console.error("--tracks must be a whole number of tracks (0 or more).");
9456
+ process.exitCode = 1;
9457
+ return;
9458
+ }
9459
+ input.dailyTracks = tracks;
9460
+ }
9461
+ if (options.gb !== undefined) {
9462
+ const gb = Number(options.gb);
9463
+ if (!Number.isFinite(gb) || gb < 0) {
9464
+ console.error("--gb must be a number of gigabytes (0 or more).");
9465
+ process.exitCode = 1;
9466
+ return;
9467
+ }
9468
+ input.dailyBytes = Math.round(gb * GB);
9469
+ }
9470
+ if (input.dailyTracks === undefined && input.dailyBytes === undefined) {
9471
+ console.error("Nothing to set \u2014 pass --tracks and/or --gb.");
9472
+ process.exitCode = 1;
9473
+ return;
9474
+ }
9475
+ await runSetCaptureBudget(input, options, setCaptureBudgetCommand2);
9476
+ }
9376
9477
  async function runPublishAdvancePause(paused, options, publishAdvancePauseCommand2) {
9377
9478
  const result = await publishAdvancePauseCommand2(paused);
9378
9479
  if (options.json) {
@@ -10243,6 +10344,7 @@ var stringOptions = new Set([
10243
10344
  "--footage-social",
10244
10345
  "--from",
10245
10346
  "--galaxy-id",
10347
+ "--gb",
10246
10348
  "--has-key",
10247
10349
  "--intent",
10248
10350
  "--key",
@@ -10281,6 +10383,7 @@ var stringOptions = new Set([
10281
10383
  "--title",
10282
10384
  "--token",
10283
10385
  "--tracklist-file",
10386
+ "--tracks",
10284
10387
  "--url",
10285
10388
  "--verdict",
10286
10389
  "--verdict-file",
package/package.json CHANGED
@@ -31,5 +31,5 @@
31
31
  "url": "git+https://github.com/mauricekleine/fluncle.git"
32
32
  },
33
33
  "type": "module",
34
- "version": "0.132.0"
34
+ "version": "0.133.0"
35
35
  }