deepline 0.3.470 → 0.3.472

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 (157) hide show
  1. package/dist/bundling-sources/sdk/src/client-core.ts +14 -0
  2. package/dist/bundling-sources/sdk/src/index.ts +2 -0
  3. package/dist/bundling-sources/sdk/src/plays/run-request.ts +1 -0
  4. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  5. package/dist/bundling-sources/sdk/src/types.ts +29 -0
  6. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +3 -1
  7. package/dist/bundling-sources/shared_libs/play-runtime/play-admission-outcome.ts +34 -8
  8. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +131 -22
  9. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +36 -1
  10. package/dist/cli/{auth-7J52UEWO.mjs → auth-35DAEPHC.mjs} +5 -5
  11. package/dist/cli/auth-Q5TM66UI.js +41 -0
  12. package/dist/cli/{billing-ASNWVDQG.js → billing-5ED5X2IO.js} +82 -81
  13. package/dist/cli/{billing-ORB3UZ73.mjs → billing-CXVBJEC4.mjs} +9 -8
  14. package/dist/cli/{chunk-4BQQ3Q3J.js → chunk-2DND7LLL.js} +8 -8
  15. package/dist/cli/{chunk-GDFO3ERN.js → chunk-2G4R4APL.js} +2 -2
  16. package/dist/cli/{chunk-RVQ333NB.mjs → chunk-2S36YV2K.mjs} +1 -1
  17. package/dist/cli/{chunk-EM2E7YIS.js → chunk-3L76SFGN.js} +53 -53
  18. package/dist/cli/{chunk-QG7UPPOK.mjs → chunk-4NFBYW7X.mjs} +3 -3
  19. package/dist/cli/{chunk-7WILY2XM.mjs → chunk-52VOORHM.mjs} +2 -2
  20. package/dist/cli/{chunk-CNQBCLQP.js → chunk-5FHU67AT.js} +3 -3
  21. package/dist/cli/{chunk-6B7XLHIE.mjs → chunk-6PKONIIP.mjs} +4 -4
  22. package/dist/cli/{chunk-HNP5V5BN.js → chunk-6ZTSHKJF.js} +25 -7
  23. package/dist/cli/{chunk-Y4OE46HH.js → chunk-7KAS4QOW.js} +112 -107
  24. package/dist/cli/{chunk-SHB7BUNQ.mjs → chunk-C5PY2PP6.mjs} +3 -3
  25. package/dist/cli/{chunk-CTDWQYBW.mjs → chunk-CFDQZQE2.mjs} +2 -2
  26. package/dist/cli/{chunk-262PYO4I.mjs → chunk-FHIO7WI2.mjs} +3 -3
  27. package/dist/cli/{chunk-6R5UKWRW.js → chunk-GJPRBELO.js} +16 -16
  28. package/dist/cli/{chunk-57F5VKHV.js → chunk-H7YFUC3J.js} +8 -8
  29. package/dist/cli/{chunk-F6OB5L74.js → chunk-HBVT4FW5.js} +6 -6
  30. package/dist/cli/{chunk-C7EA2VNR.js → chunk-IIQ6O5F3.js} +5 -5
  31. package/dist/cli/{chunk-3P4WOCRB.mjs → chunk-IPJ27SD2.mjs} +5 -5
  32. package/dist/cli/{chunk-JKVRBCZL.js → chunk-JDMR33HS.js} +1 -0
  33. package/dist/cli/{chunk-DSOTGAXS.mjs → chunk-JRZW4LWK.mjs} +1 -1
  34. package/dist/cli/{chunk-VL7OL7YR.mjs → chunk-KQJHIVCE.mjs} +1 -1
  35. package/dist/cli/{chunk-PWXHZPHK.js → chunk-L3AXQXNT.js} +10 -10
  36. package/dist/cli/{chunk-A7THVTRN.js → chunk-LQUOZGM6.js} +51 -51
  37. package/dist/cli/{chunk-YTFCKCII.js → chunk-M475BQ77.js} +3 -3
  38. package/dist/cli/{chunk-YBDQUVDE.mjs → chunk-MRZ7AO72.mjs} +10 -10
  39. package/dist/cli/{chunk-FAG4DFUC.mjs → chunk-NELMCOWK.mjs} +1 -0
  40. package/dist/cli/{chunk-SOME764Z.mjs → chunk-NZBZFEVA.mjs} +4 -4
  41. package/dist/cli/{chunk-ETTUFFBS.js → chunk-ODAARZSK.js} +36 -36
  42. package/dist/cli/{chunk-SETIOXN4.mjs → chunk-OMPW5ELS.mjs} +1 -1
  43. package/dist/cli/{chunk-NNCDHMCT.js → chunk-QLVYYDUI.js} +26 -26
  44. package/dist/cli/{chunk-SXQZYTUW.mjs → chunk-QSCLOPWR.mjs} +1 -1
  45. package/dist/cli/{chunk-PJX7BA7T.mjs → chunk-R6L6JRDR.mjs} +2 -2
  46. package/dist/cli/{chunk-3XLJPLXZ.mjs → chunk-R73LE2IM.mjs} +1 -1
  47. package/dist/cli/{chunk-F2XK4UN6.js → chunk-RDOPZK7A.js} +3 -3
  48. package/dist/cli/{chunk-44UR3BU2.js → chunk-RMQB72WW.js} +14 -14
  49. package/dist/cli/{chunk-D464JW3N.mjs → chunk-RZHUHL53.mjs} +19 -1
  50. package/dist/cli/{chunk-VBKN6ISP.js → chunk-SBPI7AEB.js} +93 -93
  51. package/dist/cli/{chunk-ORO2GFH4.js → chunk-SKVMC6K6.js} +5 -5
  52. package/dist/cli/{chunk-AGIEKE3L.js → chunk-SYWOSAW7.js} +4 -4
  53. package/dist/cli/{chunk-YFKOA4HW.mjs → chunk-T5H7ETIM.mjs} +4 -4
  54. package/dist/cli/{chunk-5ADROBCY.mjs → chunk-TMMODGPV.mjs} +2 -2
  55. package/dist/cli/{chunk-NSAKJQLX.js → chunk-UKKCS6Z4.js} +1 -1
  56. package/dist/cli/{chunk-KBNAI5BY.js → chunk-UPXGN62E.js} +21 -21
  57. package/dist/cli/{chunk-SV3B6KW4.mjs → chunk-UXFUD2MB.mjs} +5 -5
  58. package/dist/cli/{chunk-N72VIY7R.js → chunk-VDHDTXCK.js} +2 -2
  59. package/dist/cli/{chunk-MXAB4W6E.js → chunk-XSSIBO74.js} +8 -8
  60. package/dist/cli/{chunk-QW6HNDS7.mjs → chunk-YK64LQPQ.mjs} +7 -2
  61. package/dist/cli/{chunk-GLSFZYZB.mjs → chunk-YMB2CD55.mjs} +1 -1
  62. package/dist/cli/{chunk-F4L7WMLK.mjs → chunk-YNW47NOJ.mjs} +2 -2
  63. package/dist/cli/{chunk-FVYAEBGO.mjs → chunk-YUNPYX5T.mjs} +25 -7
  64. package/dist/cli/{chunk-WG3KGAII.js → chunk-Z52WEIBR.js} +19 -1
  65. package/dist/cli/{chunk-BWLXHUKH.mjs → chunk-ZZQIS3TH.mjs} +3 -3
  66. package/dist/cli/command-docs.js +2 -2
  67. package/dist/cli/command-docs.mjs +1 -1
  68. package/dist/cli/{csv-D3JPZVUN.mjs → csv-OSDYY3QW.mjs} +4 -4
  69. package/dist/cli/{csv-FSXDIWBP.js → csv-SQJQM3B2.js} +13 -13
  70. package/dist/cli/{db-3UWDQXLF.mjs → db-2M6BU6G5.mjs} +7 -7
  71. package/dist/cli/{db-DZQUPWI3.js → db-ATDYXAD5.js} +28 -28
  72. package/dist/cli/describe-37QXXDCF.js +48 -0
  73. package/dist/cli/{describe-APG2GVFG.mjs → describe-WIAJCWF3.mjs} +18 -18
  74. package/dist/cli/describe-core.d.mts +3 -3
  75. package/dist/cli/describe-core.d.ts +3 -3
  76. package/dist/cli/{executions-TDUX3575.mjs → executions-2J6CCJL2.mjs} +7 -7
  77. package/dist/cli/{executions-BFAPMPG2.js → executions-Y32LMYH6.js} +9 -9
  78. package/dist/cli/{feedback-BMV7PUDL.mjs → feedback-L4AVIMGI.mjs} +4 -4
  79. package/dist/cli/{feedback-2KNPCYTH.js → feedback-RXQLS6QU.js} +8 -8
  80. package/dist/cli/git-JGUR335T.js +25 -0
  81. package/dist/cli/{git-KBVONNE5.mjs → git-V3K77AWH.mjs} +5 -5
  82. package/dist/cli/index.js +139 -139
  83. package/dist/cli/index.mjs +41 -41
  84. package/dist/cli/{legacy-noops-LE6LJO7F.js → legacy-noops-B2KJT4CZ.js} +8 -8
  85. package/dist/cli/{legacy-noops-GZDRRUFE.mjs → legacy-noops-LOGMYOY5.mjs} +5 -5
  86. package/dist/cli/{monitors-CW22L3VL.mjs → monitors-5ETSB7S7.mjs} +8 -8
  87. package/dist/cli/{monitors-PGBHMKOU.js → monitors-A5WYUCGD.js} +92 -92
  88. package/dist/cli/{org-3V2VAH5D.js → org-7EZDWYKK.js} +73 -73
  89. package/dist/cli/{org-K5C23LAV.mjs → org-BJOAUSXL.mjs} +7 -7
  90. package/dist/cli/{pages-7V2C7GWU.mjs → pages-3BYGBTVK.mjs} +7 -7
  91. package/dist/cli/{pages-2F73VVWC.js → pages-45VNTEQU.js} +18 -18
  92. package/dist/cli/{play-62KSZGJQ.js → play-5KER3JFU.js} +586 -518
  93. package/dist/cli/{play-VT7TPJUH.mjs → play-R7JQV533.mjs} +93 -25
  94. package/dist/cli/{providers-3SI3QBT3.js → providers-OHMZ6QIF.js} +10 -10
  95. package/dist/cli/{providers-LX562YG7.mjs → providers-RMFCE6MM.mjs} +7 -7
  96. package/dist/cli/{quickstart-5HA5IFTB.js → quickstart-GNRE4SAT.js} +6 -6
  97. package/dist/cli/{quickstart-ADE7FV26.mjs → quickstart-IHR4VC5K.mjs} +4 -4
  98. package/dist/cli/{run-4ZV4UDKP.js → run-77QIMUUV.js} +37 -37
  99. package/dist/cli/{run-OITZJ6QZ.mjs → run-Y4MIRFJY.mjs} +23 -23
  100. package/dist/cli/{search-BI5VZQMD.mjs → search-24YKTHMK.mjs} +8 -8
  101. package/dist/cli/search-S3VO2UKV.js +32 -0
  102. package/dist/cli/{secrets-A2R36AZ6.mjs → secrets-KHX62AWC.mjs} +7 -7
  103. package/dist/cli/{secrets-UAKNTMYB.js → secrets-SSEBT3IS.js} +16 -16
  104. package/dist/cli/{sessions-3JM3OXME.js → sessions-E6KNWYEH.js} +6 -6
  105. package/dist/cli/{sessions-PPOFUFBW.mjs → sessions-H7T25HGE.mjs} +5 -5
  106. package/dist/cli/{settings-C4M5HOD4.js → settings-GXUYF5G7.js} +79 -79
  107. package/dist/cli/{settings-PZA6TBOL.mjs → settings-XSJG6M32.mjs} +12 -12
  108. package/dist/cli/{setup-245XVTBR.mjs → setup-GD7IOD4U.mjs} +9 -9
  109. package/dist/cli/{setup-TY2OSI6D.js → setup-JP5YPIA4.js} +44 -44
  110. package/dist/cli/skills-C4KTW3US.js +31 -0
  111. package/dist/cli/{skills-ZAN23KLR.mjs → skills-HLHE3ENN.mjs} +7 -7
  112. package/dist/cli/tools-KS7JMRK6.js +55 -0
  113. package/dist/cli/{tools-GG4KDQBM.mjs → tools-Q4XIQX7W.mjs} +17 -17
  114. package/dist/cli/{update-XKXIL6DU.mjs → update-3KRMR2QJ.mjs} +9 -9
  115. package/dist/cli/update-GYTQYK2W.js +33 -0
  116. package/dist/cli/{workflow-VN7M3D2U.js → workflow-NMUESL3O.js} +18 -18
  117. package/dist/cli/{workflow-LVQVTFUJ.mjs → workflow-NOZ7WFEY.mjs} +8 -8
  118. package/dist/{client-CdJR18SJ.d.mts → client-C9bJ0QXu.d.mts} +1 -1
  119. package/dist/{client-B3tlWsw7.d.ts → client-CuNH54w3.d.ts} +1 -1
  120. package/dist/{client-core-CxHBKfE5.d.ts → client-core-C8Q6DKga.d.ts} +38 -2
  121. package/dist/{client-core-ByJD7QXj.d.mts → client-core-CSiXbe2n.d.mts} +38 -2
  122. package/dist/{compiler-manifest-D5dARg3M.d.ts → compiler-manifest-Zwm9yqOA.d.mts} +39 -0
  123. package/dist/{compiler-manifest-D5dARg3M.d.mts → compiler-manifest-Zwm9yqOA.d.ts} +39 -0
  124. package/dist/{errors-BtHHzWL8.d.ts → errors-CsYwlpn4.d.ts} +1 -1
  125. package/dist/{errors-BveMVPwA.d.mts → errors-nEsqNLL8.d.mts} +1 -1
  126. package/dist/{index-C6sovoYP.d.ts → index-9pUZqkPH.d.ts} +1 -1
  127. package/dist/{index-BboApDGD.d.mts → index-CXF2jtza.d.mts} +1 -1
  128. package/dist/index.d.mts +7 -7
  129. package/dist/index.d.ts +7 -7
  130. package/dist/index.js +10 -10
  131. package/dist/index.mjs +7 -7
  132. package/dist/install-integrity.json +112 -112
  133. package/dist/plays/bundle-play-file.d.mts +3 -3
  134. package/dist/plays/bundle-play-file.d.ts +3 -3
  135. package/dist/plays/bundle-play-file.mjs +1 -1
  136. package/dist/plays/play-description.d.mts +2 -2
  137. package/dist/plays/play-description.d.ts +2 -2
  138. package/dist/plays/run-request.d.mts +2 -2
  139. package/dist/plays/run-request.d.ts +2 -2
  140. package/dist/plays/run-request.js +2 -2
  141. package/dist/plays/run-request.mjs +1 -1
  142. package/dist/release.d.mts +1 -1
  143. package/dist/release.d.ts +1 -1
  144. package/dist/release.js +2 -2
  145. package/dist/release.mjs +1 -1
  146. package/dist/server.d.mts +4 -4
  147. package/dist/server.d.ts +4 -4
  148. package/dist/server.js +6 -6
  149. package/dist/server.mjs +4 -4
  150. package/package.json +1 -1
  151. package/dist/cli/auth-4DBOZZDX.js +0 -41
  152. package/dist/cli/describe-2ENX4O3U.js +0 -48
  153. package/dist/cli/git-LUW3GBSD.js +0 -25
  154. package/dist/cli/search-PXFM3MGW.js +0 -32
  155. package/dist/cli/skills-UYNRYDDI.js +0 -31
  156. package/dist/cli/tools-OBESOBG7.js +0 -55
  157. package/dist/cli/update-2VMXTKBN.js +0 -33
@@ -126,6 +126,7 @@ import type {
126
126
  PlayRunListItem,
127
127
  PlaysActivityResponse,
128
128
  PlayDetail,
129
+ PlayCostEstimateResult,
129
130
  PlayCheckResult,
130
131
  PlayRunResult,
131
132
  PlayRunStart,
@@ -593,6 +594,8 @@ export type RunsHistoryPage = {
593
594
  };
594
595
 
595
596
  export type PlaysListOptions = {
597
+ /** Load compact inventory metadata without authored source or revisions. */
598
+ summaryOnly?: boolean;
596
599
  origin?: 'prebuilt' | 'owned';
597
600
  grep?: string;
598
601
  /**
@@ -2072,6 +2075,11 @@ export type TargetBillingPlan = {
2072
2075
  | 'legacy-growth-v1';
2073
2076
  name: string;
2074
2077
  recurring_price_usd: number;
2078
+ /**
2079
+ * The first month's fee for switching to this plan when a first-month
2080
+ * discount is offered; null or absent means the list price.
2081
+ */
2082
+ first_month_price_usd?: number | null;
2075
2083
  interval: 'month' | 'year';
2076
2084
  included_credits: number;
2077
2085
  /** Offered benefit terms; omitted by older API deployments. */
@@ -5338,6 +5346,7 @@ export class DeeplineClient {
5338
5346
  if (paginateInventory && !options?.grep?.trim())
5339
5347
  params.set('inventory_paginated', '1');
5340
5348
  if (options?.origin) params.set('origin', options.origin);
5349
+ if (options?.summaryOnly) params.set('summary_only', '1');
5341
5350
  if (options?.categories) {
5342
5351
  params.set(
5343
5352
  'categories',
@@ -5922,6 +5931,11 @@ export class DeeplineClient {
5922
5931
  return this.playClient.getPlay(name, options);
5923
5932
  }
5924
5933
 
5934
+ /** Estimate one Play without reading the rest of the workspace catalog. */
5935
+ async getPlayCostEstimate(name: string): Promise<PlayCostEstimateResult> {
5936
+ return this.http.get(`/api/v2/plays/${encodeURIComponent(name)}/cost`);
5937
+ }
5938
+
5925
5939
  /** Read one trigger inventory page without loading run histories. */
5926
5940
  async listPlayTriggerInventory(options?: { cursor?: string }): Promise<{
5927
5941
  page: Array<{
@@ -331,6 +331,7 @@ export type {
331
331
  PlayRunActionPackage,
332
332
  PlayRunDatasetActions,
333
333
  PlayRunPackage,
334
+ PlayRunRateLimited,
334
335
  PlayActivityObservation,
335
336
  PlayActivityState,
336
337
  PlayActivityTarget,
@@ -343,6 +344,7 @@ export type {
343
344
  PublishPlayVersionResult,
344
345
  StartPlayRunRequest,
345
346
  PlayCostEstimate,
347
+ PlayCostEstimateResult,
346
348
  PlayListItem,
347
349
  PlaysActivityResponse,
348
350
  CustomerDbQueryResult,
@@ -453,6 +453,7 @@ export function normalizePlayRunStart(
453
453
  ...(runPackage.run.dashboardUrl
454
454
  ? { dashboardUrl: runPackage.run.dashboardUrl }
455
455
  : {}),
456
+ ...(runPackage.rateLimited ? { rateLimited: runPackage.rateLimited } : {}),
456
457
  ...(isTerminalPlayRunLifecycleStatus(status)
457
458
  ? raw.finalStatusView === 'full' && raw.runId === runPackage.run.id
458
459
  ? { finalStatus: raw, finalStatusView: 'full' as const }
@@ -205,7 +205,7 @@ export const SDK_RELEASE = {
205
205
  // getters keep their established compatibility behavior.
206
206
  // 0.3.1 deprecated the legacy `deepline enrich` command in favor of Plays.
207
207
  // 0.3.90 is the first deliberately versioned SDK release for API v3.
208
- version: '0.3.470',
208
+ version: '0.3.472',
209
209
  updateSummary: {
210
210
  introducedIn: '0.3.90',
211
211
  summary:
@@ -847,6 +847,22 @@ export type PlayRunDatasetActions = {
847
847
  };
848
848
  };
849
849
 
850
+ /**
851
+ * Present when no run started because the Play's `rateLimit` window is held.
852
+ * The response then describes `latestRunId`, an earlier run, not a new one.
853
+ */
854
+ export interface PlayRunRateLimited {
855
+ code: 'PLAY_RUN_RATE_LIMITED';
856
+ latestRunId: string;
857
+ /** ISO time the latest run started its window. */
858
+ latestRunStartedAt: string;
859
+ /** ISO time the next run can start. */
860
+ nextAllowedAt: string;
861
+ everySeconds: number;
862
+ /** One-line explanation to show the caller. */
863
+ message: string;
864
+ }
865
+
850
866
  /**
851
867
  * Compact canonical run package for SDK/CLI consumers: stable metadata,
852
868
  * output handles and follow-up actions without dashboard internals.
@@ -856,6 +872,8 @@ export interface PlayRunPackage {
856
872
  schemaVersion: 1;
857
873
  /** Package discriminator. */
858
874
  kind: 'play_run';
875
+ /** Set when this package is the latest run returned instead of a new one. */
876
+ rateLimited?: PlayRunRateLimited;
859
877
  /** Retained return structure with dataset references, not flattened output previews. */
860
878
  result?: unknown;
861
879
  /** Full-only values are omitted as a whole, never replaced with partial authored data. */
@@ -1266,6 +1284,8 @@ export interface RerunPlayRunResult {
1266
1284
  * servers.
1267
1285
  */
1268
1286
  deduplicated?: boolean;
1287
+ /** Set when no rerun started; `runId` is then the Play's latest run. */
1288
+ rateLimited?: PlayRunRateLimited;
1269
1289
  next: { inspect: string; input: string };
1270
1290
  }
1271
1291
 
@@ -1612,6 +1632,13 @@ export interface PlayDefinitionDetail {
1612
1632
  currentPublishedVersion?: number | null;
1613
1633
  }
1614
1634
 
1635
+ /** Advisory pricing for one saved or prebuilt Play in the current workspace. */
1636
+ export type PlayCostEstimateResult = {
1637
+ reference: string;
1638
+ costEstimate: PlayCostEstimate;
1639
+ observedCost?: PrebuiltPlayObservedCost;
1640
+ };
1641
+
1615
1642
  export type PlayCostEstimate =
1616
1643
  | {
1617
1644
  status: 'available';
@@ -1902,6 +1929,8 @@ export interface PlayRunStart {
1902
1929
  finalStatusView?: 'full';
1903
1930
  /** Canonical compact run package returned by current SDK/API responses. */
1904
1931
  package?: PlayRunPackage;
1932
+ /** Set when no run started; `workflowId` is then the Play's latest run. */
1933
+ rateLimited?: PlayRunRateLimited;
1905
1934
  }
1906
1935
 
1907
1936
  /**
@@ -15565,7 +15565,9 @@ export class PlayContextImpl implements ScalarPlayAuthoringRuntimeContext {
15565
15565
  this.steps.push(step);
15566
15566
  }
15567
15567
  this.log(
15568
- `ctx.runPlayAsync(${normalizedKey}): admitted ${resolvedName} as ${launched.runId}`,
15568
+ launched.rateLimited
15569
+ ? `ctx.runPlayAsync(${normalizedKey}): ${launched.rateLimited.message}`
15570
+ : `ctx.runPlayAsync(${normalizedKey}): admitted ${resolvedName} as ${launched.runId}`,
15569
15571
  );
15570
15572
  return launched;
15571
15573
  }
@@ -40,6 +40,14 @@ export const PLAY_RUN_LAUNCH_CONFLICT = 'PLAY_RUN_LAUNCH_CONFLICT' as const;
40
40
  export const PLAY_RUNTIME_CALLBACK_UNCONFIGURED =
41
41
  'PLAY_RUNTIME_CALLBACK_UNCONFIGURED' as const;
42
42
 
43
+ /**
44
+ * The Play's declared `rateLimit` already started a run in the current
45
+ * window. The source is settled as skipped: no Run, no retry, not a DLQ item.
46
+ */
47
+ export const PLAY_RUN_RATE_LIMITED = 'PLAY_RUN_RATE_LIMITED' as const;
48
+
49
+ export type PlayAdmissionSkippedCode = typeof PLAY_RUN_RATE_LIMITED;
50
+
43
51
  export type PlayAdmissionBlockedCode =
44
52
  | typeof PLAY_ADMISSION_PAYLOAD_UNREADABLE
45
53
  | typeof PLAY_SECRET_UNAVAILABLE
@@ -63,6 +71,12 @@ export type PlayAdmissionFailure =
63
71
  disposition: 'blocked';
64
72
  code: PlayAdmissionBlockedCode;
65
73
  message: string;
74
+ }
75
+ | {
76
+ /** Settle the source terminally without a Run; nothing to repair or retry. */
77
+ disposition: 'skipped';
78
+ code: PlayAdmissionSkippedCode;
79
+ message: string;
66
80
  };
67
81
 
68
82
  const TERMINAL_PRE_ADMISSION_CODES = new Set<PlayAdmissionBlockedCode>([
@@ -87,18 +101,23 @@ function blocked(code: PlayAdmissionBlockedCode): PlayAdmissionFailure {
87
101
  };
88
102
  }
89
103
 
104
+ const PLAY_RUN_RATE_LIMITED_MESSAGE =
105
+ "Rate limited: this Play's rateLimit already started a run in the current window, so this delivery started no run. It is not retried.";
106
+
90
107
  /**
91
- * The customer-facing reason for a blocked source. A deferred batch settles by
108
+ * The customer-facing reason for a blocked or skipped source. A deferred batch settles by
92
109
  * code alone, so the reason must be derivable from the stable code.
93
110
  */
94
111
  export function playAdmissionBlockedMessage(code: string): string {
95
- return code === PLAY_SECRET_UNAVAILABLE
96
- ? 'The Play configuration is unavailable. Repair it, then retry this delivery.'
97
- : code === PLAY_RUN_LAUNCH_CONFLICT
98
- ? 'This run identity is already bound to a different launch. Repair the trigger identity before retrying this delivery.'
99
- : code === PLAY_RUNTIME_CALLBACK_UNCONFIGURED
100
- ? 'This deployment has no public runtime callback URL, so Play workers cannot report progress. Configure the callback (local dev: start the dev tunnel), then retry this delivery.'
101
- : 'This delivery needs attention before it can be retried.';
112
+ return code === PLAY_RUN_RATE_LIMITED
113
+ ? PLAY_RUN_RATE_LIMITED_MESSAGE
114
+ : code === PLAY_SECRET_UNAVAILABLE
115
+ ? 'The Play configuration is unavailable. Repair it, then retry this delivery.'
116
+ : code === PLAY_RUN_LAUNCH_CONFLICT
117
+ ? 'This run identity is already bound to a different launch. Repair the trigger identity before retrying this delivery.'
118
+ : code === PLAY_RUNTIME_CALLBACK_UNCONFIGURED
119
+ ? 'This deployment has no public runtime callback URL, so Play workers cannot report progress. Configure the callback (local dev: start the dev tunnel), then retry this delivery.'
120
+ : 'This delivery needs attention before it can be retried.';
102
121
  }
103
122
 
104
123
  /**
@@ -135,6 +154,13 @@ export function classifyPlayAdmissionFailure(
135
154
  return blocked(PLAY_SECRET_UNAVAILABLE);
136
155
  }
137
156
  const code = stableErrorCode(error);
157
+ if (code === PLAY_RUN_RATE_LIMITED) {
158
+ return {
159
+ disposition: 'skipped',
160
+ code,
161
+ message: PLAY_RUN_RATE_LIMITED_MESSAGE,
162
+ };
163
+ }
138
164
  if (
139
165
  code !== null &&
140
166
  TERMINAL_PRE_ADMISSION_CODES.has(code as PlayAdmissionBlockedCode)
@@ -6330,6 +6330,32 @@ function cronOccurrenceLaunch(input: {
6330
6330
  });
6331
6331
  }
6332
6332
 
6333
+ function cronSuccessorDueAtMs(schedule: PostgresSchedulerCronSchedule): number {
6334
+ let successorDueAtMs: number;
6335
+ try {
6336
+ successorDueAtMs = advanceWorkflowCronSchedule(
6337
+ schedule.cron,
6338
+ Math.max(Date.now(), schedule.dueAtMs),
6339
+ schedule.timezone,
6340
+ );
6341
+ } catch (error) {
6342
+ throw new PostgresSchedulerCronScheduleConfigurationError(
6343
+ `Cron schedule "${schedule.scheduleId}" has an invalid pinned expression or timezone: ${
6344
+ error instanceof Error ? error.message : String(error)
6345
+ }`,
6346
+ );
6347
+ }
6348
+ if (
6349
+ !Number.isSafeInteger(successorDueAtMs) ||
6350
+ successorDueAtMs <= schedule.dueAtMs
6351
+ ) {
6352
+ throw new PostgresSchedulerCronScheduleConfigurationError(
6353
+ `Cron schedule "${schedule.scheduleId}" did not produce a future successor occurrence.`,
6354
+ );
6355
+ }
6356
+ return successorDueAtMs;
6357
+ }
6358
+
6333
6359
  export type FirePostgresSchedulerCronScheduleInput = {
6334
6360
  scheduleId: string;
6335
6361
  generation: number;
@@ -6388,28 +6414,7 @@ export async function firePostgresSchedulerCronSchedule(
6388
6414
  ) {
6389
6415
  return { status: 'superseded' };
6390
6416
  }
6391
- let successorDueAtMs: number;
6392
- try {
6393
- successorDueAtMs = advanceWorkflowCronSchedule(
6394
- schedule.cron,
6395
- Math.max(Date.now(), schedule.dueAtMs),
6396
- schedule.timezone,
6397
- );
6398
- } catch (error) {
6399
- throw new PostgresSchedulerCronScheduleConfigurationError(
6400
- `Cron schedule "${schedule.scheduleId}" has an invalid pinned expression or timezone: ${
6401
- error instanceof Error ? error.message : String(error)
6402
- }`,
6403
- );
6404
- }
6405
- if (
6406
- !Number.isSafeInteger(successorDueAtMs) ||
6407
- successorDueAtMs <= schedule.dueAtMs
6408
- ) {
6409
- throw new PostgresSchedulerCronScheduleConfigurationError(
6410
- `Cron schedule "${schedule.scheduleId}" did not produce a future successor occurrence.`,
6411
- );
6412
- }
6417
+ const successorDueAtMs = cronSuccessorDueAtMs(schedule);
6413
6418
  const launch = cronOccurrenceLaunch({
6414
6419
  schedule,
6415
6420
  launch: input.launch,
@@ -6724,6 +6729,110 @@ export async function firePostgresSchedulerCronSchedule(
6724
6729
  return { status: 'superseded' };
6725
6730
  }
6726
6731
 
6732
+ /**
6733
+ * Advance a cron cursor past an occurrence that deliberately starts no Run (a
6734
+ * Play's `rateLimit` window is held). Under the same schedule lock and fences
6735
+ * as `firePostgresSchedulerCronSchedule`, it spawns only the successor timer,
6736
+ * so the schedule keeps ticking. A replay after commit is `superseded`.
6737
+ */
6738
+ export async function skipPostgresSchedulerCronOccurrence(
6739
+ client: PostgresSchedulerQueryClient,
6740
+ input: Pick<
6741
+ FirePostgresSchedulerCronScheduleInput,
6742
+ 'scheduleId' | 'generation' | 'fireGeneration' | 'dueAtMs' | 'queueName'
6743
+ >,
6744
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
6745
+ ): Promise<
6746
+ { status: 'skipped'; successorDueAtMs: number } | { status: 'superseded' }
6747
+ > {
6748
+ assertPostgresSchedulerCronScheduleInput(input);
6749
+ const schedule = await readPostgresSchedulerCronSchedule(
6750
+ client,
6751
+ input.scheduleId,
6752
+ options,
6753
+ );
6754
+ if (
6755
+ !schedule ||
6756
+ schedule.state !== 'active' ||
6757
+ schedule.generation !== input.generation ||
6758
+ schedule.dueAtMs !== input.dueAtMs ||
6759
+ schedule.currentFireGeneration !== input.fireGeneration
6760
+ ) {
6761
+ return { status: 'superseded' };
6762
+ }
6763
+ const successorDueAtMs = cronSuccessorDueAtMs(schedule);
6764
+ const successorTask = buildAbsurdCronFireTask({
6765
+ scheduleId: schedule.scheduleId,
6766
+ generation: schedule.generation,
6767
+ fireGeneration: 1,
6768
+ dueAtMs: successorDueAtMs,
6769
+ schedulerSchema:
6770
+ options?.schema ?? schedule.sourcePin.schedulerSchema ?? null,
6771
+ orgId: schedule.sourcePin.orgId,
6772
+ });
6773
+ const result = await client.query<{ advanced: boolean }>(
6774
+ `
6775
+ WITH schedule_lock AS MATERIALIZED (
6776
+ SELECT pg_advisory_xact_lock(
6777
+ ${POSTGRES_SCHEDULER_RELEASE_ADMISSION_LOCK_NAMESPACE},
6778
+ ${quoteIdent(schemaName(options))}.runtime_release_admission_lock_id(
6779
+ 'cron-schedule:' || $1::text
6780
+ )
6781
+ )
6782
+ ), matching_schedule AS MATERIALIZED (
6783
+ SELECT schedule.schedule_id
6784
+ FROM schedule_lock
6785
+ JOIN ${tableName(POSTGRES_SCHEDULER_CRON_SCHEDULES_TABLE, options)} AS schedule
6786
+ ON schedule.schedule_id = $1::text
6787
+ WHERE schedule.generation = $2::bigint
6788
+ AND schedule.state = 'active'
6789
+ AND schedule.current_due_at = to_timestamp($3::double precision / 1000.0)
6790
+ AND schedule.current_fire_generation = $4::bigint
6791
+ FOR UPDATE
6792
+ ), successor_task_spawn AS MATERIALIZED (
6793
+ SELECT spawned.task_id::text AS task_id
6794
+ FROM matching_schedule
6795
+ CROSS JOIN LATERAL absurd.spawn_task(
6796
+ $6::text,
6797
+ $7::text,
6798
+ $8::jsonb,
6799
+ $9::jsonb
6800
+ ) AS spawned
6801
+ ), schedule_advance AS (
6802
+ UPDATE ${tableName(POSTGRES_SCHEDULER_CRON_SCHEDULES_TABLE, options)} AS schedule
6803
+ SET current_due_at = to_timestamp($5::double precision / 1000.0),
6804
+ current_fire_task_id = (SELECT task_id FROM successor_task_spawn),
6805
+ current_fire_generation = 1,
6806
+ current_fire_queue_name = $6::text,
6807
+ last_fired_at = clock_timestamp(),
6808
+ updated_at = now()
6809
+ WHERE schedule.schedule_id = $1::text
6810
+ AND schedule.generation = $2::bigint
6811
+ AND schedule.state = 'active'
6812
+ AND schedule.current_due_at = to_timestamp($3::double precision / 1000.0)
6813
+ AND schedule.current_fire_generation = $4::bigint
6814
+ AND EXISTS (SELECT 1 FROM successor_task_spawn)
6815
+ RETURNING schedule.schedule_id
6816
+ )
6817
+ SELECT EXISTS (SELECT 1 FROM schedule_advance) AS advanced
6818
+ `,
6819
+ [
6820
+ schedule.scheduleId,
6821
+ schedule.generation,
6822
+ schedule.dueAtMs,
6823
+ schedule.currentFireGeneration,
6824
+ successorDueAtMs,
6825
+ input.queueName,
6826
+ successorTask.taskName,
6827
+ stringifyPostgresJson(successorTask.params),
6828
+ stringifyPostgresJson(successorTask.options),
6829
+ ],
6830
+ );
6831
+ return result.rows[0]?.advanced === true
6832
+ ? { status: 'skipped', successorDueAtMs }
6833
+ : { status: 'superseded' };
6834
+ }
6835
+
6727
6836
  /** Fence a malformed/invalid timer so it cannot repeatedly consume workers. */
6728
6837
  export async function blockPostgresSchedulerCronSchedule(
6729
6838
  client: PostgresSchedulerQueryClient,
@@ -795,6 +795,7 @@ export const PLAY_AUTHORING_BINDING_FIELDS = {
795
795
  'compatibility',
796
796
  'cron',
797
797
  'inline',
798
+ 'rateLimit',
798
799
  'runtime',
799
800
  'secrets',
800
801
  'sqlListeners',
@@ -864,6 +865,14 @@ export type PlayAuthoringBindings<TInput = Record<string, unknown>> = {
864
865
  timeout?: string;
865
866
  size?: 'standard';
866
867
  };
868
+ /**
869
+ * Start at most one run of this Play per window, whatever started it.
870
+ * Inside the window a caller gets the latest run, marked rate limited;
871
+ * webhook, cron, and listener starts are skipped and never retried.
872
+ */
873
+ rateLimit?: {
874
+ every: string;
875
+ };
867
876
  webhook?: {
868
877
  hmac?: {
869
878
  algorithm?: 'sha256';
@@ -1291,6 +1300,11 @@ export type PlayRunId = string & {
1291
1300
  */
1292
1301
  export type AsyncPlayRunRef = Readonly<{
1293
1302
  runId: PlayRunId;
1303
+ /**
1304
+ * Set when the child's `rateLimit` window was held: no child started and
1305
+ * `runId` is that Play's latest run.
1306
+ */
1307
+ rateLimited?: { latestRunId: string; nextAllowedAt: string; message: string };
1294
1308
  }>;
1295
1309
 
1296
1310
  export type PlayAuthoringAsyncCallOptions = Readonly<{
@@ -2934,6 +2948,24 @@ export const PLAY_AUTHORING_FIELD_REGISTRY = {
2934
2948
  errorMessage:
2935
2949
  'runtime.timeout must be a static duration such as "90m" or "2h".',
2936
2950
  },
2951
+ 'rateLimit.every': {
2952
+ schema: Type.String({ pattern: '^\\d+\\s*[smh]$' }),
2953
+ fixtures: {
2954
+ valid: '5m',
2955
+ invalid: '5 minutes',
2956
+ absent: undefined,
2957
+ unresolved: { expression: 'every' },
2958
+ edition1: '5m',
2959
+ },
2960
+ referenceType: 'string',
2961
+ required: false,
2962
+ resolution: 'static-required',
2963
+ issueCode: 'play_authoring_binding_invalid',
2964
+ description:
2965
+ 'Start at most one run per window, such as 30s, 5m, or 1h (10s to 24h).',
2966
+ errorMessage:
2967
+ 'rateLimit.every must be a static duration from "10s" to "24h", such as "5m".',
2968
+ },
2937
2969
  'runtime.size': {
2938
2970
  schema: Type.Literal('standard'),
2939
2971
  fixtures: {
@@ -3251,6 +3283,8 @@ export type AdmittedPlayAuthoringContract = {
3251
3283
  bindings: PlayAuthoringBindingsSnapshot | null;
3252
3284
  billingLimit: { maxCreditsPerRun: number } | null;
3253
3285
  runtimeLimit: PlaySandboxRuntimeLimits;
3286
+ /** Absent on artifacts admitted before `rateLimit` existed: unlimited. */
3287
+ rateLimit?: { everySeconds: number };
3254
3288
  allowedSecrets: string[];
3255
3289
  };
3256
3290
 
@@ -3396,6 +3430,7 @@ export const PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
3396
3430
  ` inline?: ${cloudReferenceType('inline')};`,
3397
3431
  ` billing?: { maxCreditsPerRun?: ${cloudReferenceType('billing.maxCreditsPerRun')} };`,
3398
3432
  ` runtime?: { timeout?: ${cloudReferenceType('runtime.timeout')}; size?: ${cloudReferenceType('runtime.size')} };`,
3433
+ ` rateLimit?: { every: ${cloudReferenceType('rateLimit.every')} };`,
3399
3434
  ` webhook?: { hmac?: { algorithm?: ${cloudReferenceType('bindings.webhook.hmac.algorithm')}; header?: ${cloudReferenceType('bindings.webhook.hmac.header')}; signaturePrefix?: ${cloudReferenceType('bindings.webhook.hmac.signaturePrefix')}; secretEnv: ${cloudReferenceType('bindings.webhook.hmac.secretEnv')} }; auth?: { type: ${cloudReferenceType('bindings.webhook.auth.type')}; headerFamily: ${cloudReferenceType('bindings.webhook.auth.headerFamily')}; signingSecrets: readonly ${cloudReferenceType('bindings.webhook.auth.signingSecrets[]')}[]; toleranceSeconds?: ${cloudReferenceType('bindings.webhook.auth.toleranceSeconds')} } };`,
3400
3435
  ` cron?: { schedule: ${cloudReferenceType('bindings.cron.schedule')}; timezone?: ${cloudReferenceType('bindings.cron.timezone')}; input?: PlayCronInput<TInput> };`,
3401
3436
  ' sqlListeners?: readonly SqlListenerDeclaration[];',
@@ -3420,7 +3455,7 @@ export const PLAY_AUTHORING_CLOUD_TYPE_DECLARATIONS = [
3420
3455
  `export type PlayAsyncCallOptions = { description: ${cloudReferenceType('ctx.runPlayAsync.options.description')} };`,
3421
3456
  'declare const PLAY_RUN_ID_BRAND: unique symbol;',
3422
3457
  "export type PlayRunId = string & { readonly [PLAY_RUN_ID_BRAND]: 'PlayRunId' };",
3423
- 'export type AsyncPlayRunRef = Readonly<{ runId: PlayRunId }>;',
3458
+ 'export type AsyncPlayRunRef = Readonly<{ runId: PlayRunId; rateLimited?: { latestRunId: string; nextAllowedAt: string; message: string } }>;',
3424
3459
  `export type RuntimeStepOptions = { semanticKey?: ${cloudReferenceType('ctx.step.semanticKey')}; staleAfterSeconds?: ${cloudReferenceType('ctx.step.staleAfterSeconds')} };`,
3425
3460
  `export type FetchOptions = { staleAfterSeconds?: ${cloudReferenceType('ctx.fetch.staleAfterSeconds')}; transient?: boolean };`,
3426
3461
  "export type CallFreshnessMetadata = { requestedStaleAfterSeconds: number | null; effectiveStaleAfterSeconds: number | null; source: 'executed' | 'operation_recovery' | 'reusable_result' | 'live_observation'; resultAgeMs: number; completedAt: number; operationReceiptKey?: string; unavailableReason?: string };",
@@ -13,14 +13,14 @@ import {
13
13
  reportSetupCompleted,
14
14
  resolvePendingAuthClaimForResume,
15
15
  statusBannerLine
16
- } from "./chunk-BWLXHUKH.mjs";
17
- import "./chunk-QG7UPPOK.mjs";
18
- import "./chunk-VL7OL7YR.mjs";
19
- import "./chunk-SETIOXN4.mjs";
16
+ } from "./chunk-ZZQIS3TH.mjs";
17
+ import "./chunk-4NFBYW7X.mjs";
18
+ import "./chunk-KQJHIVCE.mjs";
19
+ import "./chunk-OMPW5ELS.mjs";
20
20
  import "./chunk-4QF2K7TM.mjs";
21
21
  import "./chunk-DLIRSHV6.mjs";
22
22
  import "./chunk-HBL4PM5Q.mjs";
23
- import "./chunk-DSOTGAXS.mjs";
23
+ import "./chunk-JRZW4LWK.mjs";
24
24
  import "./chunk-WZYKRD7T.mjs";
25
25
  import "./chunk-KRD6H754.mjs";
26
26
  export {
@@ -0,0 +1,41 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+ var _chunkLQUOZGM6js = require('./chunk-LQUOZGM6.js');
17
+ require('./chunk-H7YFUC3J.js');
18
+ require('./chunk-5FHU67AT.js');
19
+ require('./chunk-SYWOSAW7.js');
20
+ require('./chunk-ALJJRZNJ.js');
21
+ require('./chunk-XNYIZMNQ.js');
22
+ require('./chunk-DIAWYWT5.js');
23
+ require('./chunk-UKKCS6Z4.js');
24
+ require('./chunk-OG64RBAC.js');
25
+ require('./chunk-COGTRVWW.js');
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+ exports.EXIT_WORKSPACE_MISMATCH = _chunkLQUOZGM6js.EXIT_WORKSPACE_MISMATCH; exports.authStatusLine = _chunkLQUOZGM6js.authStatusLine; exports.clearPendingClaim = _chunkLQUOZGM6js.clearPendingClaim; exports.clearSatisfiedPendingClaim = _chunkLQUOZGM6js.clearSatisfiedPendingClaim; exports.handleRegister = _chunkLQUOZGM6js.handleRegister; exports.handleStatus = _chunkLQUOZGM6js.handleStatus; exports.handleWait = _chunkLQUOZGM6js.handleWait; exports.httpJson = _chunkLQUOZGM6js.httpJson; exports.readPendingAuthClaim = _chunkLQUOZGM6js.readPendingAuthClaim; exports.readStatusBanner = _chunkLQUOZGM6js.readStatusBanner; exports.registerAuthCommands = _chunkLQUOZGM6js.registerAuthCommands; exports.reportSetupCompleted = _chunkLQUOZGM6js.reportSetupCompleted; exports.resolvePendingAuthClaimForResume = _chunkLQUOZGM6js.resolvePendingAuthClaimForResume; exports.statusBannerLine = _chunkLQUOZGM6js.statusBannerLine;