deepline 0.3.356 → 0.3.358

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 (103) hide show
  1. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  2. package/dist/bundling-sources/shared_libs/monitors/deactivation-reasons.ts +14 -1
  3. package/dist/bundling-sources/shared_libs/play-runtime/async-operation.ts +52 -19
  4. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +77 -25
  5. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +202 -44
  6. package/dist/cli/{auth-PFLCB6IL.mjs → auth-QSEB4OI6.mjs} +6 -4
  7. package/dist/cli/auth-VP5WIGFS.js +33 -0
  8. package/dist/cli/{billing-T3K2KS55.mjs → billing-KNJ6ZHSN.mjs} +5 -5
  9. package/dist/cli/{billing-TJOZMRIV.js → billing-UE2CP5O5.js} +74 -74
  10. package/dist/cli/{chunk-NAMT3YP5.mjs → chunk-3DP24EZA.mjs} +15 -15
  11. package/dist/cli/{chunk-35AZMPQV.mjs → chunk-4IUOBUNS.mjs} +1 -1
  12. package/dist/cli/{chunk-6GOZN6ZF.js → chunk-5PJ6XYRV.js} +64 -60
  13. package/dist/cli/{chunk-26FD35VW.js → chunk-5RWJSROL.js} +8 -8
  14. package/dist/cli/{chunk-HBN5ORV2.js → chunk-BVPN57AD.js} +6 -6
  15. package/dist/cli/{chunk-6S2HRJIV.mjs → chunk-EL62MLRD.mjs} +1 -1
  16. package/dist/cli/{chunk-AUQYSGGD.mjs → chunk-EVPWVNJV.mjs} +7 -7
  17. package/dist/cli/{chunk-OXNEO6OS.js → chunk-GYDSDOXB.js} +75 -50
  18. package/dist/cli/{chunk-X4PJURJH.mjs → chunk-HGLESMAC.mjs} +27 -2
  19. package/dist/cli/{chunk-447A2YBS.js → chunk-HKRJUIRL.js} +47 -47
  20. package/dist/cli/{chunk-MK3WFSJN.js → chunk-HNAFCPM4.js} +8 -8
  21. package/dist/cli/{chunk-UC27KYXC.js → chunk-KIRDHNX5.js} +11 -11
  22. package/dist/cli/{chunk-2EYFTDKU.js → chunk-LOSZZCER.js} +2 -2
  23. package/dist/cli/{chunk-GD4YCB5C.mjs → chunk-NMHQTEIQ.mjs} +2 -2
  24. package/dist/cli/{chunk-OIJR6SCZ.js → chunk-OO3MYL2Y.js} +26 -26
  25. package/dist/cli/{chunk-YILVDBYO.js → chunk-OVUDXZCK.js} +1 -1
  26. package/dist/cli/{chunk-YFLAUIJN.mjs → chunk-Q77PWYDF.mjs} +4 -4
  27. package/dist/cli/chunk-QFBHEQCQ.mjs +1421 -0
  28. package/dist/cli/{chunk-W3VTKDQK.mjs → chunk-QH6PV7IJ.mjs} +3 -3
  29. package/dist/cli/chunk-QILHWZFP.js +1421 -0
  30. package/dist/cli/{chunk-2CTZ4MRZ.mjs → chunk-SJY4SUCH.mjs} +1 -1
  31. package/dist/cli/{chunk-2RMJLL3R.mjs → chunk-SPJ3IDR4.mjs} +2 -2
  32. package/dist/cli/{chunk-A544Z3OR.js → chunk-UZQWPQ6V.js} +5 -5
  33. package/dist/cli/{chunk-HXL4ZESY.js → chunk-V4MVLHOW.js} +231 -231
  34. package/dist/cli/{chunk-WF5BHZWA.mjs → chunk-VZBNBCEB.mjs} +3 -3
  35. package/dist/cli/{chunk-LDOOR6AE.js → chunk-WVO6AJM7.js} +15 -15
  36. package/dist/cli/{chunk-RPALAI2R.mjs → chunk-WYVUMIEF.mjs} +8 -8
  37. package/dist/cli/{chunk-7LFNGGH6.mjs → chunk-YWGKGXSH.mjs} +6 -2
  38. package/dist/cli/client-I4RRFLPM.js +20 -0
  39. package/dist/cli/{client-XMFAODL2.mjs → client-M2TQV23S.mjs} +4 -4
  40. package/dist/cli/command-docs.d.mts +50 -0
  41. package/dist/cli/command-docs.d.ts +50 -0
  42. package/dist/cli/command-docs.js +13 -0
  43. package/dist/cli/command-docs.mjs +13 -0
  44. package/dist/cli/{csv-NLCVCEZ3.mjs → csv-OQUTHAMD.mjs} +3 -3
  45. package/dist/cli/{csv-4TMZI4RY.js → csv-VSVZWQ24.js} +12 -12
  46. package/dist/cli/{db-PWID5GLT.js → db-6QNWRH47.js} +30 -30
  47. package/dist/cli/{db-IMLYZF3N.mjs → db-QH56PKPT.mjs} +5 -5
  48. package/dist/cli/{describe-LTYF5NWH.js → describe-BKJNG2I5.js} +21 -21
  49. package/dist/cli/{describe-LFKBFDRQ.mjs → describe-NCUJW2JG.mjs} +16 -16
  50. package/dist/cli/{executions-RB4WIKFH.js → executions-63CSEYKE.js} +7 -7
  51. package/dist/cli/{executions-6UVFDX2O.mjs → executions-NOZELHEN.mjs} +5 -5
  52. package/dist/cli/{feedback-PH3WH5LE.mjs → feedback-GL7YHJAK.mjs} +3 -3
  53. package/dist/cli/{feedback-EOUSGLRS.js → feedback-T4FGM7DY.js} +7 -7
  54. package/dist/cli/git-4EBFGJAN.js +23 -0
  55. package/dist/cli/{git-BLVZPTBC.mjs → git-C3SPUEUB.mjs} +4 -4
  56. package/dist/cli/index.js +183 -83
  57. package/dist/cli/index.mjs +145 -45
  58. package/dist/cli/{legacy-noops-5JDDNT4H.mjs → legacy-noops-BBDNHMAW.mjs} +4 -4
  59. package/dist/cli/{legacy-noops-KQBQ4WMC.js → legacy-noops-W6UWORVY.js} +7 -7
  60. package/dist/cli/{monitors-JL7A5ZOX.mjs → monitors-LEGM63T3.mjs} +5 -5
  61. package/dist/cli/{monitors-IETMP6ER.js → monitors-R32SKFE3.js} +86 -86
  62. package/dist/cli/{org-L6TG5MRM.mjs → org-RBIBSVP3.mjs} +5 -5
  63. package/dist/cli/{org-HL2CWV6W.js → org-RYRHB22V.js} +61 -61
  64. package/dist/cli/{play-42RA7JRU.mjs → play-FMPNHLXU.mjs} +11 -11
  65. package/dist/cli/play-GDDOUU3I.js +153 -0
  66. package/dist/cli/{providers-RH5ZPZXO.mjs → providers-5JHHZWMF.mjs} +5 -5
  67. package/dist/cli/{providers-MASSERVB.js → providers-WAUWYRTK.js} +8 -8
  68. package/dist/cli/{quickstart-OMZY743O.mjs → quickstart-RYKNMAFN.mjs} +5 -5
  69. package/dist/cli/{quickstart-6AYK534A.js → quickstart-V5LHMW2X.js} +7 -7
  70. package/dist/cli/{search-TBOZ5R36.mjs → search-B2BB2MHO.mjs} +6 -6
  71. package/dist/cli/search-RQLY5D2A.js +26 -0
  72. package/dist/cli/{secrets-74CH44OT.js → secrets-BEAESK2H.js} +14 -14
  73. package/dist/cli/{secrets-IN4XCGBJ.mjs → secrets-XJOXWVUG.mjs} +5 -5
  74. package/dist/cli/{sessions-KK47BDGG.js → sessions-ELBTWKLS.js} +5 -5
  75. package/dist/cli/{sessions-BAMVNM3F.mjs → sessions-VRDJCPKE.mjs} +4 -4
  76. package/dist/cli/{settings-HZFVYTEW.mjs → settings-QEL2SD7N.mjs} +8 -8
  77. package/dist/cli/{settings-VSKWLX2B.js → settings-V5RI4UWE.js} +75 -75
  78. package/dist/cli/{setup-IYVMYYZW.js → setup-CS3IACGU.js} +43 -43
  79. package/dist/cli/{setup-3YOU6BBX.mjs → setup-FNVP5XQR.mjs} +8 -8
  80. package/dist/cli/{skills-DB3TE5LF.mjs → skills-73PM6I6F.mjs} +4 -4
  81. package/dist/cli/skills-OH3X3OUA.js +28 -0
  82. package/dist/cli/tools-BY6D7M4I.js +40 -0
  83. package/dist/cli/{tools-AMNLACHH.mjs → tools-N2H5HJYP.mjs} +8 -8
  84. package/dist/cli/{update-3PBHH5FL.mjs → update-MUMZ6L7J.mjs} +6 -6
  85. package/dist/cli/update-PEGDRQ3G.js +28 -0
  86. package/dist/cli/{workflow-C2KGKJJD.mjs → workflow-WY2CL73A.mjs} +9 -9
  87. package/dist/cli/{workflow-5YDAWSKH.js → workflow-X66V6L3H.js} +19 -19
  88. package/dist/index.js +13 -13
  89. package/dist/index.mjs +12 -12
  90. package/dist/install-integrity.json +80 -74
  91. package/dist/release.d.mts +1 -1
  92. package/dist/release.d.ts +1 -1
  93. package/dist/release.js +2 -2
  94. package/dist/release.mjs +1 -1
  95. package/package.json +6 -1
  96. package/dist/cli/auth-IHV3XXSN.js +0 -31
  97. package/dist/cli/client-TDH32IGR.js +0 -20
  98. package/dist/cli/git-V6HWB6JB.js +0 -23
  99. package/dist/cli/play-QQLZQILD.js +0 -153
  100. package/dist/cli/search-FR6FXEXN.js +0 -26
  101. package/dist/cli/skills-3HFZGYM7.js +0 -28
  102. package/dist/cli/tools-GJ7TH2T3.js +0 -40
  103. package/dist/cli/update-SUNCN4SV.js +0 -28
@@ -200,7 +200,7 @@ export const SDK_RELEASE = {
200
200
  // getters keep their established compatibility behavior.
201
201
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
202
202
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
203
- version: '0.3.356',
203
+ version: '0.3.358',
204
204
  updateSummary:
205
205
  'Play grep now returns concise results with the matched fields and terms. Automatic CLI updates are enabled by default; use `deepline settings autoupdate off` to opt out, `deepline settings autoupdate on` to re-enable updates, or `deepline settings autoupdate pin <version>` to hold an exact release.',
206
206
  packageCapabilities: {
@@ -20,7 +20,7 @@ import { monitorBillingRequiresExplicitReactivation } from './billing/state';
20
20
  * this off" and "we did, and here is why" must not be the same state.
21
21
  */
22
22
 
23
- export type MonitorDeactivationOwner = 'policy' | 'fleet';
23
+ export type MonitorDeactivationOwner = 'policy' | 'fleet' | 'admin';
24
24
 
25
25
  /**
26
26
  * The delivery window, in days, that `monitors health` reports against.
@@ -43,6 +43,13 @@ export type MonitorDeactivationReasonDefinition = {
43
43
 
44
44
  export const MONITOR_DEACTIVATION_REASONS: readonly MonitorDeactivationReasonDefinition[] =
45
45
  [
46
+ {
47
+ id: 'workspace_archived',
48
+ owner: 'admin',
49
+ summary: 'Deactivated because the workspace is archived.',
50
+ resolution:
51
+ 'Contact a platform administrator. Credit changes never reactivate an archived workspace.',
52
+ },
46
53
  {
47
54
  id: 'insufficient_balance',
48
55
  owner: 'policy',
@@ -122,6 +129,12 @@ export function isPolicyDeactivation(id: string | undefined | null): boolean {
122
129
  return monitorDeactivationReason(id)?.owner === 'policy';
123
130
  }
124
131
 
132
+ /** Both policy and admin shutdown retain the definition; only policy owns recovery. */
133
+ export function isMonitorSuspension(id: string | undefined | null): boolean {
134
+ const owner = monitorDeactivationReason(id)?.owner;
135
+ return owner === 'policy' || owner === 'admin';
136
+ }
137
+
125
138
  // ---------------------------------------------------------------------------
126
139
  // The balance policy
127
140
  // ---------------------------------------------------------------------------
@@ -954,6 +954,17 @@ function asyncOperationRateLimitPollDelayMs(input: {
954
954
  return Math.max(input.retryAfterMs ?? 0, localBackoffMs);
955
955
  }
956
956
 
957
+ /** A paced read of an already accepted job must never restart its launch. */
958
+ export class AsyncOperationCompanionPacingError extends Error {
959
+ constructor(
960
+ message: string,
961
+ readonly retryAfterMs: number,
962
+ ) {
963
+ super(message);
964
+ this.name = 'AsyncOperationCompanionPacingError';
965
+ }
966
+ }
967
+
957
968
  /**
958
969
  * Runtime-neutral executor for a declared async lifecycle.
959
970
  *
@@ -1074,25 +1085,47 @@ export async function executeAsyncOperationLifecycle<Response>(input: {
1074
1085
  }): Promise<
1075
1086
  { kind: 'response'; response: Response } | { kind: 'timed_out' }
1076
1087
  > => {
1077
- const remainingTimeoutMs = Math.max(
1078
- 0,
1079
- polling.timeoutMs - (now() - startedAt),
1080
- );
1081
- if (remainingTimeoutMs <= 0) return { kind: 'timed_out' };
1082
- const abortSignal = AbortSignal.timeout(Math.ceil(remainingTimeoutMs));
1083
- try {
1084
- const response = await input.executeAction({
1085
- ...request,
1086
- jobId,
1087
- timeoutMs: Math.ceil(remainingTimeoutMs),
1088
- abortSignal,
1089
- });
1090
- return now() - startedAt >= polling.timeoutMs || abortSignal.aborted
1091
- ? { kind: 'timed_out' }
1092
- : { kind: 'response', response };
1093
- } catch (error) {
1094
- if (abortSignal.aborted) return { kind: 'timed_out' };
1095
- throw error;
1088
+ let pacingAttempt = 0;
1089
+ while (true) {
1090
+ const remainingTimeoutMs = Math.max(
1091
+ 0,
1092
+ polling.timeoutMs - (now() - startedAt),
1093
+ );
1094
+ if (remainingTimeoutMs <= 0) return { kind: 'timed_out' };
1095
+ const abortSignal = AbortSignal.timeout(Math.ceil(remainingTimeoutMs));
1096
+ try {
1097
+ const response = await input.executeAction({
1098
+ ...request,
1099
+ jobId,
1100
+ timeoutMs: Math.ceil(remainingTimeoutMs),
1101
+ abortSignal,
1102
+ });
1103
+ return now() - startedAt >= polling.timeoutMs || abortSignal.aborted
1104
+ ? { kind: 'timed_out' }
1105
+ : { kind: 'response', response };
1106
+ } catch (error) {
1107
+ if (abortSignal.aborted) return { kind: 'timed_out' };
1108
+ if (!(error instanceof AsyncOperationCompanionPacingError)) throw error;
1109
+ // This refusal applies only to the current companion read. The launch
1110
+ // already owns its job and hold. Stay inside their original deadline
1111
+ // and repeat this exact action/page, never the enclosing start request.
1112
+ pacingAttempt += 1;
1113
+ const delayMs = Math.max(
1114
+ 1,
1115
+ asyncOperationRateLimitPollDelayMs({
1116
+ contract: effectiveContract,
1117
+ pollAttempt: request.pollAttempt,
1118
+ rateLimitAttempt: pacingAttempt,
1119
+ retryAfterMs: error.retryAfterMs,
1120
+ }),
1121
+ );
1122
+ const remainingAfterRefusal = Math.max(
1123
+ 0,
1124
+ polling.timeoutMs - (now() - startedAt),
1125
+ );
1126
+ if (remainingAfterRefusal <= 0) return { kind: 'timed_out' };
1127
+ await sleep(Math.min(delayMs, remainingAfterRefusal));
1128
+ }
1096
1129
  }
1097
1130
  };
1098
1131
  while (true) {
@@ -17609,6 +17609,22 @@ export async function readPostgresSchedulerObservationAdmissions(
17609
17609
  }));
17610
17610
  }
17611
17611
 
17612
+ /** Admission authority: includes live runs whose Convex projection has not landed. */
17613
+ export async function listPostgresSchedulerActiveRunsForOrg(
17614
+ client: PostgresSchedulerQueryClient,
17615
+ orgId: string,
17616
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
17617
+ ): Promise<string[]> {
17618
+ if (!orgId.trim()) throw new Error('Workspace ID is required.');
17619
+ const result = await client.query<{ run_id: string }>(
17620
+ `SELECT run_id FROM ${tableName('runs', options)}
17621
+ WHERE org_id = $1 AND status IN ('queued', 'running', 'waiting')
17622
+ ORDER BY created_at, run_id LIMIT 5`,
17623
+ [orgId],
17624
+ );
17625
+ return result.rows.map((row) => row.run_id);
17626
+ }
17627
+
17612
17628
  export async function readPostgresSchedulerRunStatus(
17613
17629
  client: PostgresSchedulerQueryClient,
17614
17630
  runId: string,
@@ -18338,6 +18354,11 @@ async function claimPostgresSchedulerOutboxPrefix(
18338
18354
  ? `(head.event_type = ${RUN_SCHEDULER_OUTBOX_EVENT_TYPE_SQL_LITERAL.runEvents})`
18339
18355
  : 'false';
18340
18356
  const findSearchBlockersOnce = seekRunHead && input.searchOnly === true;
18357
+ const searchFactColumnsSql = (alias: string) =>
18358
+ `${alias}.event_id, ${alias}.run_id, ${alias}.event_type,
18359
+ ${alias}.created_at, ${alias}.failed_at, ${alias}.next_attempt_at,
18360
+ ${alias}.lease_owner, ${alias}.lease_expires_at,
18361
+ ${supportsTerminalBatchMarker ? `${alias}.delivery_batch_started_at` : 'NULL::timestamptz AS delivery_batch_started_at'}`;
18341
18362
  const blockingPredecessorSql = (alias: string) => `(
18342
18363
  (${alias}.event_type = ${RUN_SCHEDULER_OUTBOX_EVENT_TYPE_SQL_LITERAL.runEvents}
18343
18364
  AND NOT (${ingressPrefixSql}))
@@ -18477,13 +18498,44 @@ async function claimPostgresSchedulerOutboxPrefix(
18477
18498
  LIMIT 1
18478
18499
  ), ${
18479
18500
  findSearchBlockersOnce
18480
- ? `first_blocker AS MATERIALIZED (
18501
+ ? `search_prefix AS MATERIALIZED (
18502
+ SELECT ${searchFactColumnsSql('pending')}
18503
+ FROM ${tableName('outbox', options)} AS pending
18504
+ JOIN head ON head.run_id = pending.run_id
18505
+ WHERE pending.run_id = $2::text
18506
+ AND ${pending('pending')}
18507
+ AND ${searchLaneSql('pending')} = true
18508
+ ORDER BY ${runLedgerOrderSql('pending')}
18509
+ LIMIT $1
18510
+ ), frozen_search_prefix AS MATERIALIZED (
18511
+ SELECT EXISTS (
18512
+ SELECT 1 FROM search_prefix AS fact
18513
+ WHERE fact.delivery_batch_started_at IS NOT NULL
18514
+ AND fact.event_type IN (
18515
+ ${RUN_EVENT_KIND_SQL_LITERAL.runCompleted}, ${RUN_EVENT_KIND_SQL_LITERAL.runFailed}, ${RUN_EVENT_KIND_SQL_LITERAL.runCancelled}
18516
+ )
18517
+ ) AS has_terminal
18518
+ ), search_facts AS MATERIALIZED (
18519
+ -- Ordinary search claims examine only the existing batch's causal
18520
+ -- window, including ineligible rows so a blocker cannot be skipped.
18521
+ SELECT prefix.* FROM search_prefix AS prefix
18522
+ WHERE NOT (SELECT has_terminal FROM frozen_search_prefix)
18523
+ UNION ALL
18524
+ -- A frozen terminal receipt can contain marked facts beyond newer
18525
+ -- unmarked rows. Retain that full membership scan only for this case;
18526
+ -- limiting its raw window would strand an already attempted receipt.
18527
+ SELECT ${searchFactColumnsSql('pending')}
18528
+ FROM ${tableName('outbox', options)} AS pending
18529
+ JOIN head ON head.run_id = pending.run_id
18530
+ WHERE (SELECT has_terminal FROM frozen_search_prefix)
18531
+ AND pending.run_id = $2::text
18532
+ AND ${pending('pending')}
18533
+ AND ${searchLaneSql('pending')} = true
18534
+ ), first_blocker AS MATERIALIZED (
18481
18535
  SELECT predecessor.event_type, predecessor.created_at, predecessor.event_id
18482
- FROM ${tableName('outbox', options)} AS predecessor
18536
+ FROM search_facts AS predecessor
18483
18537
  JOIN head ON head.run_id = predecessor.run_id
18484
18538
  WHERE predecessor.run_id = $2::text
18485
- AND ${pending('predecessor')}
18486
- AND ${searchLaneSql('predecessor')} = true
18487
18539
  -- The oldest pending head passed eligibility above. Only later
18488
18540
  -- facts can introduce an ordinary blocker for this prefix.
18489
18541
  AND ${runLedgerPositionSql('predecessor')} > (
@@ -18496,11 +18548,9 @@ async function claimPostgresSchedulerOutboxPrefix(
18496
18548
  LIMIT 1
18497
18549
  ), first_started_terminal AS MATERIALIZED (
18498
18550
  SELECT terminal_predecessor.event_type, terminal_predecessor.created_at, terminal_predecessor.event_id
18499
- FROM ${tableName('outbox', options)} AS terminal_predecessor
18551
+ FROM search_facts AS terminal_predecessor
18500
18552
  JOIN head ON head.run_id = terminal_predecessor.run_id
18501
18553
  WHERE terminal_predecessor.run_id = $2::text
18502
- AND ${pending('terminal_predecessor')}
18503
- AND ${searchLaneSql('terminal_predecessor')} = true
18504
18554
  AND ${supportsTerminalBatchMarker ? 'terminal_predecessor.delivery_batch_started_at IS NOT NULL' : 'false'}
18505
18555
  AND terminal_predecessor.event_type IN (
18506
18556
  ${RUN_EVENT_KIND_SQL_LITERAL.runCompleted}, ${RUN_EVENT_KIND_SQL_LITERAL.runFailed}, ${RUN_EVENT_KIND_SQL_LITERAL.runCancelled}
@@ -18515,6 +18565,7 @@ async function claimPostgresSchedulerOutboxPrefix(
18515
18565
  JOIN head ON head.run_id = outbox.run_id
18516
18566
  WHERE ${pending('outbox')}
18517
18567
  ${runId !== null ? 'AND outbox.run_id = $2::text' : ''}
18568
+ ${findSearchBlockersOnce ? 'AND outbox.event_id = ANY(ARRAY(SELECT event_id FROM search_facts))' : ''}
18518
18569
  AND ${searchLaneSql('outbox')} = ${input.searchOnly === true ? 'true' : 'false'}
18519
18570
  AND outbox.failed_at IS NULL
18520
18571
  -- Admission is causally first and must be projected alone. A later
@@ -18735,26 +18786,25 @@ async function claimPostgresSchedulerOutboxPrefix(
18735
18786
  */
18736
18787
  export async function readPostgresSchedulerOutboxNextDueAt(
18737
18788
  client: PostgresSchedulerQueryClient,
18738
- options?: Pick<PostgresSchedulerOptions, 'schema'>,
18789
+ options?: Pick<PostgresSchedulerOptions, 'schema'> & {
18790
+ lane?: 'lifecycle' | 'observability';
18791
+ },
18739
18792
  ): Promise<Date | null> {
18793
+ const lanes =
18794
+ options?.lane === 'lifecycle'
18795
+ ? [false]
18796
+ : options?.lane === 'observability'
18797
+ ? [true]
18798
+ : [false, true];
18740
18799
  const result = await client.query<{ due_at: Date | string | null }>(
18741
18800
  `
18742
18801
  -- Seek distinct run identities without reading their pending fact tails.
18743
- WITH RECURSIVE ${runLedgerPendingRunsSql(options)}, heads AS MATERIALIZED (
18744
- SELECT pending_run.run_id, false AS search_only, head.*
18745
- FROM pending_runs AS pending_run
18746
- CROSS JOIN LATERAL (
18747
- SELECT pending.created_at, pending.next_attempt_at,
18748
- pending.failed_at, pending.lease_expires_at
18749
- FROM ${tableName('outbox', options)} AS pending
18750
- WHERE pending.run_id = pending_run.run_id
18751
- AND pending.delivered_at IS NULL
18752
- AND ${searchLaneSql('pending')} = false
18753
- ORDER BY ${runLedgerOrderSql('pending')}
18754
- LIMIT 1
18755
- ) AS head
18756
- UNION ALL
18757
- SELECT pending_run.run_id, true AS search_only, head.*
18802
+ WITH RECURSIVE ${runLedgerPendingRunsSql(options, options?.lane === undefined ? undefined : lanes[0])}, heads AS MATERIALIZED (
18803
+ ${lanes
18804
+ .map(
18805
+ (
18806
+ searchOnly,
18807
+ ) => ` SELECT pending_run.run_id, ${searchOnly} AS search_only, head.*
18758
18808
  FROM pending_runs AS pending_run
18759
18809
  CROSS JOIN LATERAL (
18760
18810
  SELECT pending.created_at, pending.next_attempt_at,
@@ -18762,10 +18812,12 @@ export async function readPostgresSchedulerOutboxNextDueAt(
18762
18812
  FROM ${tableName('outbox', options)} AS pending
18763
18813
  WHERE pending.run_id = pending_run.run_id
18764
18814
  AND pending.delivered_at IS NULL
18765
- AND ${searchLaneSql('pending')} = true
18815
+ AND ${searchLaneSql('pending')} = ${searchOnly}
18766
18816
  ORDER BY ${runLedgerOrderSql('pending')}
18767
18817
  LIMIT 1
18768
- ) AS head
18818
+ ) AS head`,
18819
+ )
18820
+ .join('\n UNION ALL\n')}
18769
18821
  )
18770
18822
  SELECT min(greatest(
18771
18823
  CASE