fluncle 0.262.0 → 0.264.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 +215 -25
  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.262.0".trim() ? "0.262.0".trim() : "0.1.0";
625
+ currentVersion = "0.264.0".trim() ? "0.264.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.262.0".trim() ? "0.262.0".trim() : "0.1.0";
2338
+ currentVersion2 = "0.264.0".trim() ? "0.264.0".trim() : "0.1.0";
2339
2339
  });
2340
2340
 
2341
2341
  // ../../packages/registry/src/index.ts
@@ -4476,6 +4476,7 @@ var init_admin_attention = __esm(() => {
4476
4476
  "attach-cues": "cues",
4477
4477
  "bio-review": "bio gate",
4478
4478
  "capture-suspect": "capture check",
4479
+ "crawl-hold": "held release",
4479
4480
  distribute: "distribute",
4480
4481
  "drip-empty": "clip drip",
4481
4482
  "label-review": "label",
@@ -10193,7 +10194,7 @@ var init_zod = __esm(() => {
10193
10194
  });
10194
10195
 
10195
10196
  // ../../packages/contracts/src/orpc/admin-catalogue.ts
10196
- var CatalogueLensSchema, CapturePriorityReasonSchema, CatalogueMatchSchema, CatalogueTrackItemSchema, CatalogueSummarySchema, listCatalogueTracks, rankCatalogue, recordDemand, clearWrongAudio, requeueUnmatchedCaptures, requeueAnchor, requeueIsrcRecovery, flagWrongAudio, forceCapture, certifyTrack, setTrackDismissed, CaptureVerifyItemSchema, listUnverifiedCaptures, verifyCapture, CrawlPassSchema, CrawlPhaseInitializationSchema, MAX_CRAWL_PREPARE_LIMIT = 6, CrawlFetchPlanSchema, SuppliedCrawlBodySchema, MAX_CRAWL_COMMIT_BATCH, CRAWL_COMMIT_TOKEN_MAX_BYTES, CRAWL_COMMIT_BATCH_MAX_TOTAL_BYTES, CrawlCommitItemSchema, CrawlCommitReceiptSchema, CrawlPhaseCapabilitiesSchema, CrawlPhaseInputSchema, CrawlPhaseOutputSchema, CrawlStatusSchema, CrawlPipelineSummarySchema, PipelineWatchBoundedCountSchema, getPipeline, crawlCatalogue, commitCrawlNodes, getCrawlStatus, ANCHOR_CANDIDATE_LIMIT = 100, ANCHOR_ARTIST_LIMIT = 20, ANCHOR_TEXT_MAX = 300, ANCHOR_ISRC_MAX = 64, ANCHOR_ID_MAX = 64, ANCHOR_URL_MAX = 2048, AnchorCandidateSchema, anchorTrack, recordAnchorFailure, DEEZER_CANDIDATE_LIMIT = 5, DEEZER_TEXT_MAX = 300, DEEZER_ISRC_MAX = 64, DEEZER_TRACK_ID_MAX = 32, DeezerIsrcCandidateSchema, resolveAnchor, resolveAnchorReview, setAnchorSearch, setAnchorApify, CaptureBudgetStateSchema, getCaptureBudget, setCaptureBudget, AnchorApifyBudgetSchema, getAnchorApifyBudget, setAnchorApifyBudget, SpotifyAnchorBreakerStateSchema, AnchorRungFlagsSchema, getSpotifyAnchorBreaker, LabelReleasesBudgetSchema, getLabelReleasesBudget, setLabelReleasesBudget, resetSpotifyAnchorBreaker, AppleBreakerStateSchema, resetAppleBreaker, adminCatalogueContract;
10197
+ var CatalogueLensSchema, CapturePriorityReasonSchema, CatalogueMatchSchema, CatalogueTrackItemSchema, CatalogueSummarySchema, listCatalogueTracks, rankCatalogue, recordDemand, clearWrongAudio, requeueUnmatchedCaptures, requeueAnchor, requeueIsrcRecovery, flagWrongAudio, forceCapture, certifyTrack, setTrackDismissed, CaptureVerifyItemSchema, listUnverifiedCaptures, verifyCapture, CrawlPassSchema, CrawlPhaseInitializationSchema, MAX_CRAWL_PREPARE_LIMIT = 6, CrawlFetchPlanSchema, SuppliedCrawlBodySchema, MAX_CRAWL_COMMIT_BATCH, CRAWL_COMMIT_TOKEN_MAX_BYTES, CRAWL_COMMIT_BATCH_MAX_TOTAL_BYTES, CrawlCommitItemSchema, CrawlCommitReceiptSchema, CrawlPhaseCapabilitiesSchema, CrawlPhaseInputSchema, CrawlPhaseOutputSchema, CrawlStatusSchema, CrawlPipelineSummarySchema, PipelineWatchBoundedCountSchema, getPipeline, crawlCatalogue, commitCrawlNodes, getCrawlStatus, ANCHOR_CANDIDATE_LIMIT = 100, ANCHOR_ARTIST_LIMIT = 20, ANCHOR_TEXT_MAX = 300, ANCHOR_ISRC_MAX = 64, ANCHOR_ID_MAX = 64, ANCHOR_URL_MAX = 2048, AnchorCandidateSchema, anchorTrack, recordAnchorFailure, DEEZER_CANDIDATE_LIMIT = 5, DEEZER_TEXT_MAX = 300, DEEZER_ISRC_MAX = 64, DEEZER_TRACK_ID_MAX = 32, DeezerIsrcCandidateSchema, AnchorResolveResultSchema, AnchorCommitResultSchema, prepareAnchor, AnchorPhaseBatchItemFailureSchema, prepareAnchorBatch, resolveAnchorCandidate, commitAnchor, commitAnchorBatch, getAnchorReceipt, getAnchorPaidToken, cancelAnchorPaidResult, resolveAnchorPaidResult, resolveAnchor, resolveAnchorReview, CrawlHoldReasonSchema, CrawlHoldStateSchema, CrawlHoldSchema, listCrawlHolds, resolveCrawlHold, setAnchorSearch, setAnchorApify, CaptureBudgetStateSchema, getCaptureBudget, setCaptureBudget, AnchorApifyBudgetSchema, getAnchorApifyBudget, setAnchorApifyBudget, SpotifyAnchorBreakerStateSchema, AnchorRungFlagsSchema, getSpotifyAnchorBreaker, LabelReleasesBudgetSchema, getLabelReleasesBudget, setLabelReleasesBudget, resetSpotifyAnchorBreaker, AppleBreakerStateSchema, resetAppleBreaker, adminCatalogueContract;
10197
10198
  var init_admin_catalogue = __esm(() => {
10198
10199
  init_dist3();
10199
10200
  init_zod();
@@ -10222,6 +10223,7 @@ var init_admin_catalogue = __esm(() => {
10222
10223
  hasCapturedAudio: boolean2(),
10223
10224
  hasPreview: boolean2(),
10224
10225
  hiddenFromPublic: boolean2(),
10226
+ hiddenReason: _enum(["long_form", "spoken_word"]).nullable(),
10225
10227
  isrc: string2().nullable(),
10226
10228
  key: string2().nullable(),
10227
10229
  label: string2().nullable(),
@@ -10320,9 +10322,12 @@ var init_admin_catalogue = __esm(() => {
10320
10322
  method: "POST",
10321
10323
  operationId: "requeueAnchor",
10322
10324
  path: "/admin/catalogue/anchor/requeue",
10323
- summary: "Clear named rows' anchor re-ask backoff or terminal validation error (operator)",
10325
+ summary: "Requeue named anchor rows and optionally reconcile pending paid receipts (operator)",
10324
10326
  tags: ["Admin"]
10325
- }).input(object({ trackIds: array(string2().min(1)).min(1).max(250) })).output(object({ ok: literal(true), requeued: number2() }));
10327
+ }).input(object({
10328
+ clearPaid: boolean2().optional(),
10329
+ trackIds: array(string2().min(1)).min(1).max(250)
10330
+ })).output(object({ ok: literal(true), paidCleared: number2(), requeued: number2() }));
10326
10331
  requeueIsrcRecovery = oc.route({
10327
10332
  method: "POST",
10328
10333
  operationId: "requeueIsrcRecovery",
@@ -10426,6 +10431,7 @@ var init_admin_catalogue = __esm(() => {
10426
10431
  seedsRearmed: number2(),
10427
10432
  tracksAllowedIn: number2().optional(),
10428
10433
  tracksFound: number2(),
10434
+ tracksHeldImplausible: number2().optional(),
10429
10435
  tracksSkipped: number2(),
10430
10436
  tracksSkippedArtistRule: number2().optional(),
10431
10437
  tracksSkippedHeld: number2().optional(),
@@ -10660,6 +10666,7 @@ var init_admin_catalogue = __esm(() => {
10660
10666
  tags: ["Admin"]
10661
10667
  }).input(object({
10662
10668
  candidates: array(AnchorCandidateSchema).max(ANCHOR_CANDIDATE_LIMIT).default([]),
10669
+ paidResultToken: string2().max(32 * 1024).optional(),
10663
10670
  trackId: string2().min(1)
10664
10671
  })).output(object({
10665
10672
  anchored: boolean2(),
@@ -10680,22 +10687,12 @@ var init_admin_catalogue = __esm(() => {
10680
10687
  isrc: string2().max(DEEZER_ISRC_MAX),
10681
10688
  title: string2().max(DEEZER_TEXT_MAX)
10682
10689
  }).meta({ id: "DeezerIsrcCandidate" });
10683
- resolveAnchor = oc.route({
10684
- method: "POST",
10685
- operationId: "resolveAnchor",
10686
- path: "/admin/catalogue/anchor/resolve",
10687
- summary: "Resolve a catalogue row's Spotify anchor from the free rungs (ListenBrainz + dark Spotify search)",
10688
- tags: ["Admin"]
10689
- }).input(object({
10690
- deezerCandidates: array(DeezerIsrcCandidateSchema).max(DEEZER_CANDIDATE_LIMIT).optional(),
10691
- spotifySearch: boolean2().optional(),
10692
- trackId: string2().min(1)
10693
- })).output(object({
10690
+ AnchorResolveResultSchema = object({
10694
10691
  anchored: boolean2(),
10695
10692
  apifyBudgetRemaining: number2().int().nonnegative(),
10696
10693
  apifyEligible: boolean2(),
10697
10694
  apifyEnabled: boolean2(),
10698
- apifyIneligibleReason: _enum(["apify_budget_spent", "awaiting_free_ask"]).nullable(),
10695
+ apifyIneligibleReason: _enum(["apify_budget_spent", "awaiting_free_ask", "awaiting_paid_result"]).nullable(),
10699
10696
  freeDurationMsOmitted: number2().int().nonnegative(),
10700
10697
  isrcRecoveredByDeezer: boolean2(),
10701
10698
  listenbrainzOutcome: _enum([
@@ -10710,6 +10707,7 @@ var init_admin_catalogue = __esm(() => {
10710
10707
  "yielded-on-breaker"
10711
10708
  ]),
10712
10709
  ok: literal(true),
10710
+ paidResultToken: string2().optional(),
10713
10711
  source: _enum(["listenbrainz", "spotify-isrc", "spotify-search"]).nullable(),
10714
10712
  spotifyIsrcAsked: boolean2(),
10715
10713
  spotifySearchDone: boolean2(),
@@ -10717,7 +10715,140 @@ var init_admin_catalogue = __esm(() => {
10717
10715
  spotifyThrottled: boolean2(),
10718
10716
  stamped: boolean2(),
10719
10717
  verifiedBy: _enum(["isrc", "search", "search-subset"]).nullable()
10718
+ });
10719
+ AnchorCommitResultSchema = AnchorResolveResultSchema.extend({
10720
+ paidReceiptPending: boolean2()
10721
+ });
10722
+ prepareAnchor = oc.route({
10723
+ method: "POST",
10724
+ operationId: "prepareAnchor",
10725
+ path: "/admin/catalogue/anchor/prepare",
10726
+ summary: "Prepare one anchor row for provider lookup",
10727
+ tags: ["Admin"]
10728
+ }).input(object({
10729
+ deezerCandidates: array(DeezerIsrcCandidateSchema).max(DEEZER_CANDIDATE_LIMIT).optional(),
10730
+ trackId: string2().min(1)
10731
+ })).output(object({ ok: literal(true), prepared: string2(), receiptAt: string2() }));
10732
+ AnchorPhaseBatchItemFailureSchema = object({
10733
+ elapsedMs: number2().nonnegative(),
10734
+ error: string2().optional(),
10735
+ httpStatus: number2().int().optional(),
10736
+ status: _enum(["deferred", "error"]),
10737
+ trackId: string2()
10738
+ });
10739
+ prepareAnchorBatch = oc.route({
10740
+ method: "POST",
10741
+ operationId: "prepareAnchorBatch",
10742
+ path: "/admin/catalogue/anchor/prepares",
10743
+ summary: "Prepare a bounded batch of anchor rows",
10744
+ tags: ["Admin"]
10745
+ }).input(object({
10746
+ items: array(object({
10747
+ deezerCandidates: array(DeezerIsrcCandidateSchema).max(DEEZER_CANDIDATE_LIMIT).optional(),
10748
+ trackId: string2().min(1)
10749
+ })).min(1).max(15)
10750
+ })).output(object({
10751
+ items: array(union([
10752
+ object({
10753
+ elapsedMs: number2().nonnegative(),
10754
+ prepared: string2(),
10755
+ receiptAt: string2(),
10756
+ status: literal("done"),
10757
+ trackId: string2()
10758
+ }),
10759
+ AnchorPhaseBatchItemFailureSchema
10760
+ ])),
10761
+ ok: literal(true)
10762
+ }));
10763
+ resolveAnchorCandidate = oc.route({
10764
+ method: "POST",
10765
+ operationId: "resolveAnchorCandidate",
10766
+ path: "/admin/catalogue/anchor/candidates/resolve",
10767
+ summary: "Look up free anchor candidates from providers",
10768
+ tags: ["Admin"]
10769
+ }).input(object({ prepared: string2().max(32 * 1024), spotifySearch: boolean2().optional() })).output(object({ evidence: string2(), ok: literal(true) }));
10770
+ commitAnchor = oc.route({
10771
+ method: "POST",
10772
+ operationId: "commitAnchor",
10773
+ path: "/admin/catalogue/anchor/commit",
10774
+ summary: "Verify provider evidence and settle one anchor row",
10775
+ tags: ["Admin"]
10776
+ }).input(object({
10777
+ allowPaid: boolean2().optional(),
10778
+ evidence: string2().max(32 * 1024),
10779
+ prepared: string2().max(32 * 1024)
10780
+ })).output(AnchorCommitResultSchema);
10781
+ commitAnchorBatch = oc.route({
10782
+ method: "POST",
10783
+ operationId: "commitAnchorBatch",
10784
+ path: "/admin/catalogue/anchor/commits",
10785
+ summary: "Settle a bounded batch of anchor rows",
10786
+ tags: ["Admin"]
10787
+ }).input(object({
10788
+ items: array(object({
10789
+ allowPaid: boolean2().optional(),
10790
+ evidence: string2().max(32 * 1024),
10791
+ prepared: string2().max(32 * 1024),
10792
+ trackId: string2().min(1)
10793
+ })).min(1).max(15)
10794
+ })).output(object({
10795
+ items: array(union([
10796
+ AnchorCommitResultSchema.extend({
10797
+ elapsedMs: number2().nonnegative(),
10798
+ status: literal("done"),
10799
+ trackId: string2()
10800
+ }),
10801
+ AnchorPhaseBatchItemFailureSchema
10802
+ ])),
10803
+ ok: literal(true)
10720
10804
  }));
10805
+ getAnchorReceipt = oc.route({
10806
+ method: "POST",
10807
+ operationId: "getAnchorReceipt",
10808
+ path: "/admin/catalogue/anchor/receipt",
10809
+ summary: "Read exact paid admission receipt status",
10810
+ tags: ["Admin"]
10811
+ }).input(object({ receiptAt: string2().min(1), trackId: string2().min(1) })).output(object({
10812
+ admitted: boolean2(),
10813
+ ok: literal(true),
10814
+ paidState: string2().nullable()
10815
+ }));
10816
+ getAnchorPaidToken = oc.route({
10817
+ method: "POST",
10818
+ operationId: "getAnchorPaidToken",
10819
+ path: "/admin/catalogue/anchor/paid-result/token",
10820
+ summary: "Read a fresh token for an exact pending paid anchor receipt",
10821
+ tags: ["Admin"]
10822
+ }).input(object({ receiptAt: string2().min(1), trackId: string2().min(1) })).output(object({ ok: literal(true), paidResultToken: string2() }));
10823
+ cancelAnchorPaidResult = oc.route({
10824
+ method: "POST",
10825
+ operationId: "cancelAnchorPaidResult",
10826
+ path: "/admin/catalogue/anchor/paid-result/cancel",
10827
+ summary: "Settle a paid admission when its actor never started",
10828
+ tags: ["Admin"]
10829
+ }).input(object({
10830
+ paidResultToken: string2().max(32 * 1024),
10831
+ refundCap: boolean2().optional(),
10832
+ trackId: string2().min(1)
10833
+ })).output(object({ ok: literal(true), settled: literal(true) }));
10834
+ resolveAnchorPaidResult = oc.route({
10835
+ method: "POST",
10836
+ operationId: "resolveAnchorPaidResult",
10837
+ path: "/admin/catalogue/anchor/paid-result/resolve",
10838
+ summary: "Settle a paid receipt for a track no longer available to anchor",
10839
+ tags: ["Admin"]
10840
+ }).input(object({ receiptAt: string2().min(1), trackId: string2().min(1) })).output(object({ ok: literal(true), reason: _enum(["missing", "settled", "unavailable"]) }));
10841
+ resolveAnchor = oc.route({
10842
+ method: "POST",
10843
+ operationId: "resolveAnchor",
10844
+ path: "/admin/catalogue/anchor/resolve",
10845
+ summary: "Resolve a catalogue row's Spotify anchor from the free rungs (ListenBrainz + dark Spotify search)",
10846
+ tags: ["Admin"]
10847
+ }).input(object({
10848
+ deezerCandidates: array(DeezerIsrcCandidateSchema).max(DEEZER_CANDIDATE_LIMIT).optional(),
10849
+ spotifySearch: boolean2().optional(),
10850
+ trackId: string2().min(1)
10851
+ })).output(AnchorResolveResultSchema);
10721
10852
  resolveAnchorReview = oc.route({
10722
10853
  method: "POST",
10723
10854
  operationId: "resolveAnchorReview",
@@ -10735,6 +10866,48 @@ var init_admin_catalogue = __esm(() => {
10735
10866
  spotifyTrackId: string2().optional()
10736
10867
  })
10737
10868
  }));
10869
+ CrawlHoldReasonSchema = _enum(["before_founding", "before_label_era"]).meta({ id: "CrawlHoldReason" });
10870
+ CrawlHoldStateSchema = _enum(["held", "kept_out", "released"]).meta({ id: "CrawlHoldState" });
10871
+ CrawlHoldSchema = object({
10872
+ artists: array(string2()),
10873
+ createdAt: string2(),
10874
+ labelId: string2(),
10875
+ labelName: string2().nullable(),
10876
+ labelSlug: string2().nullable(),
10877
+ reason: CrawlHoldReasonSchema,
10878
+ releaseDate: string2().nullable(),
10879
+ releaseMbid: string2(),
10880
+ releaseTitle: string2().nullable(),
10881
+ state: CrawlHoldStateSchema,
10882
+ thresholdYear: number2().int(),
10883
+ trackCount: number2().int()
10884
+ }).meta({ id: "CrawlHold" });
10885
+ listCrawlHolds = oc.route({
10886
+ method: "GET",
10887
+ operationId: "listCrawlHolds",
10888
+ path: "/admin/catalogue/holds",
10889
+ summary: "Releases the crawl held back because their label credit looks implausible",
10890
+ tags: ["Admin"]
10891
+ }).input(object({
10892
+ cursor: string2().min(1).max(512).optional(),
10893
+ limit: number3().int().min(1).max(100).optional(),
10894
+ state: CrawlHoldStateSchema.optional()
10895
+ })).output(object({
10896
+ holds: array(CrawlHoldSchema),
10897
+ nextCursor: string2().optional(),
10898
+ ok: literal(true),
10899
+ total: number2().int()
10900
+ }));
10901
+ resolveCrawlHold = oc.route({
10902
+ method: "POST",
10903
+ operationId: "resolveCrawlHold",
10904
+ path: "/admin/catalogue/holds/{releaseMbid}/resolve",
10905
+ summary: "Rule on a held release: store it on the next crawl tick, or keep it out (operator)",
10906
+ tags: ["Admin"]
10907
+ }).input(object({
10908
+ decision: _enum(["keep_out", "store"]),
10909
+ releaseMbid: string2().min(1)
10910
+ })).output(object({ ok: literal(true), state: CrawlHoldStateSchema }));
10738
10911
  setAnchorSearch = oc.route({
10739
10912
  method: "PUT",
10740
10913
  operationId: "setAnchorSearch",
@@ -10872,20 +11045,28 @@ var init_admin_catalogue = __esm(() => {
10872
11045
  }).input(object({})).output(AppleBreakerStateSchema.extend({ ok: literal(true) }));
10873
11046
  adminCatalogueContract = {
10874
11047
  anchor_track: anchorTrack,
11048
+ cancel_anchor_paid_result: cancelAnchorPaidResult,
10875
11049
  certify_track: certifyTrack,
10876
11050
  clear_wrong_audio: clearWrongAudio,
11051
+ commit_anchor: commitAnchor,
11052
+ commit_anchor_batch: commitAnchorBatch,
10877
11053
  commit_crawl_nodes: commitCrawlNodes,
10878
11054
  crawl_catalogue: crawlCatalogue,
10879
11055
  flag_wrong_audio: flagWrongAudio,
10880
11056
  force_capture: forceCapture,
10881
11057
  get_anchor_apify_budget: getAnchorApifyBudget,
11058
+ get_anchor_paid_token: getAnchorPaidToken,
11059
+ get_anchor_receipt: getAnchorReceipt,
10882
11060
  get_capture_budget: getCaptureBudget,
10883
11061
  get_crawl_status: getCrawlStatus,
10884
11062
  get_label_releases_budget: getLabelReleasesBudget,
10885
11063
  get_pipeline: getPipeline,
10886
11064
  get_spotify_anchor_breaker: getSpotifyAnchorBreaker,
10887
11065
  list_catalogue_tracks: listCatalogueTracks,
11066
+ list_crawl_holds: listCrawlHolds,
10888
11067
  list_unverified_captures: listUnverifiedCaptures,
11068
+ prepare_anchor: prepareAnchor,
11069
+ prepare_anchor_batch: prepareAnchorBatch,
10889
11070
  rank_catalogue: rankCatalogue,
10890
11071
  record_anchor_failure: recordAnchorFailure,
10891
11072
  record_demand: recordDemand,
@@ -10895,7 +11076,10 @@ var init_admin_catalogue = __esm(() => {
10895
11076
  reset_apple_breaker: resetAppleBreaker,
10896
11077
  reset_spotify_anchor_breaker: resetSpotifyAnchorBreaker,
10897
11078
  resolve_anchor: resolveAnchor,
11079
+ resolve_anchor_candidate: resolveAnchorCandidate,
11080
+ resolve_anchor_paid_result: resolveAnchorPaidResult,
10898
11081
  resolve_anchor_review: resolveAnchorReview,
11082
+ resolve_crawl_hold: resolveCrawlHold,
10899
11083
  set_anchor_apify: setAnchorApify,
10900
11084
  set_anchor_apify_budget: setAnchorApifyBudget,
10901
11085
  set_anchor_search: setAnchorSearch,
@@ -11527,6 +11711,7 @@ var init_admin_attention2 = __esm(() => {
11527
11711
  "attach-cues",
11528
11712
  "bio-review",
11529
11713
  "capture-suspect",
11714
+ "crawl-hold",
11530
11715
  "distribute",
11531
11716
  "drip-empty",
11532
11717
  "label-review",
@@ -16145,6 +16330,7 @@ var init_me_recs = __esm(() => {
16145
16330
  label: string2().optional(),
16146
16331
  logId: string2(),
16147
16332
  note: string2().optional(),
16333
+ previewable: boolean2(),
16148
16334
  similarity: number2(),
16149
16335
  spotifyUri: string2().optional(),
16150
16336
  spotifyUrl: string2().optional(),
@@ -16230,6 +16416,7 @@ var init_me_saved = __esm(() => {
16230
16416
  imageUrl: string2().optional(),
16231
16417
  logId: string2().optional(),
16232
16418
  note: string2().optional(),
16419
+ previewable: boolean2(),
16233
16420
  savedAt: string2(),
16234
16421
  title: string2(),
16235
16422
  trackId: string2()
@@ -17353,6 +17540,7 @@ async function advanceProjectionCommand(input) {
17353
17540
  let scheduled = response.scheduled;
17354
17541
  let wallStopped = false;
17355
17542
  let rebuildRowsWalked = response.rebuildRowsWalked ?? 0;
17543
+ let rebuildReported = response.rebuildStaleFamilies !== undefined;
17356
17544
  while (!response.complete && steps < maxSteps) {
17357
17545
  if (wallMs !== undefined && now() - startedAt >= wallMs) {
17358
17546
  wallStopped = true;
@@ -17363,8 +17551,9 @@ async function advanceProjectionCommand(input) {
17363
17551
  processed += response.processed;
17364
17552
  scheduled += response.scheduled;
17365
17553
  rebuildRowsWalked += response.rebuildRowsWalked ?? 0;
17554
+ rebuildReported ||= response.rebuildStaleFamilies !== undefined;
17366
17555
  }
17367
- const rebuild = response.rebuildStaleFamilies === undefined ? {} : { rebuildRowsWalked, rebuildStaleFamilies: response.rebuildStaleFamilies };
17556
+ const rebuild = rebuildReported ? { rebuildRowsWalked, rebuildStaleFamilies: response.rebuildStaleFamilies ?? 0 } : {};
17368
17557
  if (!includeTerminalStatus) {
17369
17558
  const { status: _status, ...withoutStatus } = response;
17370
17559
  return { ...withoutStatus, ...rebuild, processed, scheduled, steps, wallStopped };
@@ -19328,10 +19517,8 @@ async function clearWrongAudioCommand(trackId) {
19328
19517
  async function requeueUnmatchedCommand() {
19329
19518
  return adminApiPost("/api/v1/admin/catalogue/captures/requeue-unmatched", {});
19330
19519
  }
19331
- async function requeueAnchorCommand(trackIds) {
19332
- return adminApiPost("/api/v1/admin/catalogue/anchor/requeue", {
19333
- trackIds
19334
- });
19520
+ async function requeueAnchorCommand(trackIds, clearPaid = false) {
19521
+ return adminApiPost("/api/v1/admin/catalogue/anchor/requeue", { clearPaid, trackIds });
19335
19522
  }
19336
19523
  async function requeueIsrcRecoveryCommand(input) {
19337
19524
  return adminApiPost("/api/v1/admin/catalogue/isrc-recovery/requeue", input);
@@ -23124,14 +23311,17 @@ JSON field reference:
23124
23311
  }
23125
23312
  console.log(cleared ? `Kept ${trackId}. Its audio re-embeds and rejoins the ranking on the next sweep.` : `${trackId} was not quarantined \u2014 nothing to clear.`);
23126
23313
  });
23127
- catalogue.command("requeue-anchor").description("Clear rows' anchor re-ask backoff so the next tick retries them (operator)").argument("<trackIds...>", "The catalogue track id(s) to requeue (up to 250)").option("--json", "Print JSON", false).action(async (trackIds, options) => {
23314
+ catalogue.command("requeue-anchor").description("Clear rows' anchor re-ask backoff so the next tick retries them (operator)").argument("<trackIds...>", "The catalogue track id(s) to requeue (up to 250)").option("--clear-paid", "Settle a reconciled pending paid receipt; keeps its spend (operator)", false).option("--json", "Print JSON", false).action(async (trackIds, options) => {
23128
23315
  await Promise.resolve().then(() => init_admin_catalogue2());
23129
- const { requeued } = await requeueAnchorCommand(trackIds);
23316
+ const { paidCleared, requeued } = await requeueAnchorCommand(trackIds, options.clearPaid);
23130
23317
  if (options.json) {
23131
- printJson({ ok: true, requeued });
23318
+ printJson({ ok: true, paidCleared, requeued });
23132
23319
  return;
23133
23320
  }
23134
23321
  console.log(`Re-queued ${requeued} of ${trackIds.length} row(s) \u2014 the next anchor tick picks them up at their real priority.`);
23322
+ if (options.clearPaid) {
23323
+ console.log(`Settled ${paidCleared} pending paid receipt(s); recorded spend remains charged.`);
23324
+ }
23135
23325
  });
23136
23326
  const labelReleasesBudget = catalogue.command("label-releases-budget").description("Read or set the label releases tap daily Spotify call budget");
23137
23327
  labelReleasesBudget.option("--json", "Print JSON", false).action(async (options) => {
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.262.0"
34
+ "version": "0.264.0"
35
35
  }