fluncle 0.245.0 → 0.246.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 +89 -7
  2. package/package.json +1 -1
package/bin/fluncle.mjs CHANGED
@@ -622,7 +622,7 @@ function parseVersion(version) {
622
622
  var currentVersion;
623
623
  var init_version = __esm(() => {
624
624
  init_output();
625
- currentVersion = "0.245.0".trim() ? "0.245.0".trim() : "0.1.0";
625
+ currentVersion = "0.246.0".trim() ? "0.246.0".trim() : "0.1.0";
626
626
  });
627
627
 
628
628
  // src/update-notifier.ts
@@ -2335,7 +2335,7 @@ function parseVersion2(version) {
2335
2335
  var currentVersion2, latestReleaseUrl = "https://api.github.com/repos/mauricekleine/fluncle/releases/latest";
2336
2336
  var init_version2 = __esm(() => {
2337
2337
  init_output();
2338
- currentVersion2 = "0.245.0".trim() ? "0.245.0".trim() : "0.1.0";
2338
+ currentVersion2 = "0.246.0".trim() ? "0.246.0".trim() : "0.1.0";
2339
2339
  });
2340
2340
 
2341
2341
  // ../../packages/registry/src/index.ts
@@ -12341,7 +12341,7 @@ var init_admin_prompts = __esm(() => {
12341
12341
  });
12342
12342
 
12343
12343
  // ../../packages/contracts/src/orpc/admin-projections.ts
12344
- var PROJECTION_STEP_LIMIT_MAX = 500, ProjectionTargetSchema, ProjectionCutoverSchema, ProjectionStepActionSchema, CountSchema, BoundedCountSchema, DigestSchema2, RebuildSchema, BacklogSchema, RepairSchema, OldestOutstandingMarkerAgeSchema, ConvergenceSchema, ProjectionFamilyStatusSchema, ProjectionStatusSchema, getProjectionStatus, advanceProjection, setProjectionCutover, adminProjectionsContract;
12344
+ var PROJECTION_STEP_LIMIT_MAX = 500, ProjectionTargetSchema, ProjectionCutoverSchema, ProjectionStepActionSchema, CountSchema, BoundedCountSchema, DigestSchema2, RebuildSchema, BacklogSchema, RepairSchema, OldestOutstandingMarkerAgeSchema, ConvergenceSchema, ProjectionFamilyStatusSchema, ProjectionStatusSchema, getProjectionStatus, advanceProjection, setProjectionCutover, DUE_WORK_REKEY_LIMIT_MAX = 500, rekeyDueWorkQueue, adminProjectionsContract;
12345
12345
  var init_admin_projections = __esm(() => {
12346
12346
  init_dist3();
12347
12347
  init_zod();
@@ -12433,6 +12433,8 @@ var init_admin_projections = __esm(() => {
12433
12433
  complete: boolean2(),
12434
12434
  ok: literal(true),
12435
12435
  processed: CountSchema,
12436
+ rebuildRowsWalked: CountSchema.optional(),
12437
+ rebuildStaleFamilies: CountSchema.optional(),
12436
12438
  scheduled: CountSchema,
12437
12439
  status: ProjectionStatusSchema.optional(),
12438
12440
  target: ProjectionTargetSchema,
@@ -12450,9 +12452,33 @@ var init_admin_projections = __esm(() => {
12450
12452
  status: ProjectionStatusSchema,
12451
12453
  target: ProjectionCutoverSchema
12452
12454
  }));
12455
+ rekeyDueWorkQueue = oc.route({
12456
+ method: "POST",
12457
+ operationId: "rekeyDueWorkQueue",
12458
+ path: "/admin/projections/due-work/{workKind}/rekey",
12459
+ summary: "Mark one due-work queue for re-keying under today's order definition",
12460
+ tags: ["Admin"]
12461
+ }).input(object({
12462
+ apply: boolean2().default(false),
12463
+ cursor: string2().max(200).nullable().default(null),
12464
+ limit: number2().int().min(1).max(DUE_WORK_REKEY_LIMIT_MAX).default(DUE_WORK_REKEY_LIMIT_MAX),
12465
+ workKind: string2().min(1).max(64)
12466
+ })).output(object({
12467
+ applied: boolean2(),
12468
+ cursor: string2().nullable(),
12469
+ definitionVersion: string2(),
12470
+ hasMore: boolean2(),
12471
+ marked: CountSchema,
12472
+ matched: CountSchema,
12473
+ ok: literal(true),
12474
+ remaining: BoundedCountSchema,
12475
+ subjectType: string2(),
12476
+ workKind: string2()
12477
+ }));
12453
12478
  adminProjectionsContract = {
12454
12479
  advance_projection: advanceProjection,
12455
12480
  get_projection_status: getProjectionStatus,
12481
+ rekey_due_work_queue: rekeyDueWorkQueue,
12456
12482
  set_projection_cutover: setProjectionCutover
12457
12483
  };
12458
12484
  });
@@ -16862,6 +16888,7 @@ async function advanceProjectionCommand(input) {
16862
16888
  let processed = response.processed;
16863
16889
  let scheduled = response.scheduled;
16864
16890
  let wallStopped = false;
16891
+ let rebuildRowsWalked = response.rebuildRowsWalked ?? 0;
16865
16892
  while (!response.complete && steps < maxSteps) {
16866
16893
  if (wallMs !== undefined && now() - startedAt >= wallMs) {
16867
16894
  wallStopped = true;
@@ -16871,18 +16898,56 @@ async function advanceProjectionCommand(input) {
16871
16898
  steps += 1;
16872
16899
  processed += response.processed;
16873
16900
  scheduled += response.scheduled;
16901
+ rebuildRowsWalked += response.rebuildRowsWalked ?? 0;
16874
16902
  }
16903
+ const rebuild = response.rebuildStaleFamilies === undefined ? {} : { rebuildRowsWalked, rebuildStaleFamilies: response.rebuildStaleFamilies };
16875
16904
  if (!includeTerminalStatus) {
16876
16905
  const { status: _status, ...withoutStatus } = response;
16877
- return { ...withoutStatus, processed, scheduled, steps, wallStopped };
16906
+ return { ...withoutStatus, ...rebuild, processed, scheduled, steps, wallStopped };
16878
16907
  }
16879
16908
  const status = response.status ?? (await getProjectionStatusCommand()).status;
16880
- return { ...response, processed, scheduled, status, steps, wallStopped };
16909
+ return { ...response, ...rebuild, processed, scheduled, status, steps, wallStopped };
16881
16910
  }
16882
16911
  async function setProjectionCutoverCommand(input) {
16883
16912
  const { enabled, target } = input;
16884
16913
  return adminApiPut(`/api/v1/admin/projections/${target}/cutover`, { enabled });
16885
16914
  }
16915
+ async function rekeyDueWorkQueueCommand(input) {
16916
+ const { apply, limit, maxPages, workKind } = input;
16917
+ let cursor = input.cursor;
16918
+ let response = await adminApiPost(`/api/v1/admin/projections/due-work/${encodeURIComponent(workKind)}/rekey`, { apply, cursor, limit });
16919
+ let pages = 1;
16920
+ let marked = response.marked;
16921
+ let matched = response.matched;
16922
+ cursor = response.cursor;
16923
+ while (apply && response.hasMore && response.cursor !== null && pages < maxPages) {
16924
+ response = await adminApiPost(`/api/v1/admin/projections/due-work/${encodeURIComponent(workKind)}/rekey`, { apply, cursor, limit });
16925
+ pages += 1;
16926
+ marked += response.marked;
16927
+ matched += response.matched;
16928
+ cursor = response.cursor;
16929
+ }
16930
+ return { ...response, cursor, marked, matched, pages };
16931
+ }
16932
+ function parseDueWorkRekeyLimit(value) {
16933
+ const limit = Number(value);
16934
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > DUE_WORK_REKEY_LIMIT_MAX) {
16935
+ throw new Error(`--limit must be a whole number from 1 through ${DUE_WORK_REKEY_LIMIT_MAX}`);
16936
+ }
16937
+ return limit;
16938
+ }
16939
+ function parseDueWorkRekeyMaxPages(value) {
16940
+ const pages = Number(value);
16941
+ if (!Number.isSafeInteger(pages) || pages < 1 || pages > DUE_WORK_REKEY_MAX_PAGES) {
16942
+ throw new Error(`--max-pages must be a whole number from 1 through ${DUE_WORK_REKEY_MAX_PAGES}`);
16943
+ }
16944
+ return pages;
16945
+ }
16946
+ function dueWorkRekeyLine(result) {
16947
+ const remaining = `${result.remaining.count}${result.remaining.truncated ? "+" : ""}`;
16948
+ const verb = result.applied ? `marked ${result.marked}` : `would mark ${result.matched}`;
16949
+ return `${result.workKind} re-key — ${verb} over ${result.pages} page(s); ${remaining} still on the old key; cursor ${result.cursor ?? "start"}; definition ${result.definitionVersion}.`;
16950
+ }
16886
16951
  function parseProjectionEnabled(value) {
16887
16952
  if (value !== "true" && value !== "false") {
16888
16953
  throw new Error("--enabled must be true or false");
@@ -16937,7 +17002,7 @@ function projectionStatusLines(status) {
16937
17002
  row("Artist qualification", status.projections.artistQualification, status.cutovers.publicProjections)
16938
17003
  ];
16939
17004
  }
16940
- var PROJECTION_MAX_STEPS = 100, PROJECTION_WALL_MS_MIN = 1000, PROJECTION_WALL_MS_MAX = 600000;
17005
+ var PROJECTION_MAX_STEPS = 100, DUE_WORK_REKEY_MAX_PAGES = 200, PROJECTION_WALL_MS_MIN = 1000, PROJECTION_WALL_MS_MAX = 600000;
16941
17006
  var init_admin_projections2 = __esm(() => {
16942
17007
  init_orpc();
16943
17008
  init_api();
@@ -21786,6 +21851,21 @@ JSON field reference:
21786
21851
  }
21787
21852
  console.log(`${result.target} ${result.action}: steps ${result.steps}, processed ${result.processed}, scheduled ${result.scheduled}, ${result.complete ? "complete" : result.wallStopped ? "wall budget spent, more work remains" : "more work remains"}.`);
21788
21853
  });
21854
+ adminProjections.command("rekey").description("Mark one due-work queue for re-keying under today's order definition").requiredOption("--work-kind <kind>", "Physical queue, e.g. capture-catalogue").option("--cursor <subjectId>", "Resume after this subject id").option("--limit <limit>", "Rows per page (1-500)", "500").option("--max-pages <pages>", "Maximum pages to mark in one run (1-200)", "1").option("--apply", "Write the repair markers; omit for a dry run", false).option("--json", "Print the page result as JSON", false).action(async (options) => {
21855
+ const projections = await Promise.resolve().then(() => (init_admin_projections2(), {}));
21856
+ const result = await rekeyDueWorkQueueCommand({
21857
+ apply: options.apply,
21858
+ cursor: options.cursor ?? null,
21859
+ limit: parseDueWorkRekeyLimit(options.limit),
21860
+ maxPages: parseDueWorkRekeyMaxPages(options.maxPages),
21861
+ workKind: options.workKind
21862
+ });
21863
+ if (options.json) {
21864
+ printJson(result);
21865
+ return;
21866
+ }
21867
+ console.log(dueWorkRekeyLine(result));
21868
+ });
21789
21869
  adminProjections.command("set").description("Open or close one readiness-gated projection cutover").requiredOption("--target <target>", "track_due_work, crawl_due_work, or public_projections").requiredOption("--enabled <boolean>", "true opens; false closes unconditionally").option("--json", "Print the stored flag and current readiness as JSON", false).action(async (options) => {
21790
21870
  const projections = await Promise.resolve().then(() => (init_admin_projections2(), {}));
21791
21871
  const result = await setProjectionCutoverCommand({
@@ -25785,6 +25865,7 @@ var stringOptions = new Set([
25785
25865
  "--lens",
25786
25866
  "--limit",
25787
25867
  "--max-hop",
25868
+ "--max-pages",
25788
25869
  "--max-steps",
25789
25870
  "--max-overlap",
25790
25871
  "--metrics",
@@ -25845,7 +25926,8 @@ var stringOptions = new Set([
25845
25926
  "--voice-id",
25846
25927
  "--wall-ms",
25847
25928
  "--window-since",
25848
- "--window-until"
25929
+ "--window-until",
25930
+ "--work-kind"
25849
25931
  ]);
25850
25932
  var rootHelpSections = `
25851
25933
 
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.245.0"
34
+ "version": "0.246.0"
35
35
  }