deepline 0.3.461 → 0.3.462

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 (296) hide show
  1. package/dist/bundling-sources/sdk/src/client-core.ts +7593 -0
  2. package/dist/bundling-sources/sdk/src/client.ts +8 -7366
  3. package/dist/bundling-sources/sdk/src/http-core.ts +1239 -0
  4. package/dist/bundling-sources/sdk/src/http.ts +6 -1231
  5. package/dist/bundling-sources/sdk/src/index.ts +4 -1
  6. package/dist/bundling-sources/sdk/src/play.ts +5 -5
  7. package/dist/bundling-sources/sdk/src/plays/client-core.ts +437 -0
  8. package/dist/bundling-sources/sdk/src/plays/client.ts +4 -421
  9. package/dist/bundling-sources/sdk/src/plays/input-example.ts +3 -4
  10. package/dist/bundling-sources/sdk/src/plays/play-description.ts +1 -1
  11. package/dist/bundling-sources/sdk/src/plays/run-request.ts +1 -1
  12. package/dist/bundling-sources/sdk/src/release.ts +1 -1
  13. package/dist/bundling-sources/sdk/src/server.ts +43 -0
  14. package/dist/bundling-sources/sdk/src/types.ts +15 -5
  15. package/dist/bundling-sources/shared_libs/integration-contracts/billing-entitlements.ts +15 -0
  16. package/dist/bundling-sources/shared_libs/monitors/callback-security.ts +0 -307
  17. package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +3 -0
  18. package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +3 -2
  19. package/dist/bundling-sources/shared_libs/monitors/package.json +2 -0
  20. package/dist/bundling-sources/shared_libs/monitors/provider-callback-verification.ts +34 -0
  21. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +59 -0
  22. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-upstream-identity.ts +94 -1
  23. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-dead-letter.ts +11 -1
  24. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-failure-codes.ts +24 -0
  25. package/dist/bundling-sources/shared_libs/observability/dlq.ts +32 -0
  26. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +57 -3
  27. package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +1 -0
  28. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +66 -1
  29. package/dist/bundling-sources/shared_libs/play-data-plane/sheet-column-storage.ts +36 -7
  30. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +250 -11
  31. package/dist/bundling-sources/shared_libs/play-runtime/array-input-store.ts +319 -0
  32. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +991 -359
  33. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +17 -0
  34. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +13 -0
  35. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-reaper.ts +110 -0
  36. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-machines.ts +155 -6
  37. package/dist/bundling-sources/shared_libs/play-runtime/deployment/fly-registry.ts +110 -6
  38. package/dist/bundling-sources/shared_libs/play-runtime/durable-receipt-execution.ts +127 -13
  39. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +14 -1
  40. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +57 -1
  41. package/dist/bundling-sources/shared_libs/play-runtime/free-company-lookup-batching.ts +218 -0
  42. package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +42 -5
  43. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-budget-state-backend.ts +6 -1
  44. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +92 -31
  45. package/dist/bundling-sources/shared_libs/play-runtime/governor/block-reserving-budget-state-backend.ts +69 -14
  46. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +93 -23
  47. package/dist/bundling-sources/shared_libs/play-runtime/governor/in-memory-rate-state-backend.ts +15 -4
  48. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +22 -18
  49. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +5 -0
  50. package/dist/bundling-sources/shared_libs/play-runtime/launch-identity.ts +2 -0
  51. package/dist/bundling-sources/shared_libs/play-runtime/map-memory-limits.ts +190 -14
  52. package/dist/bundling-sources/shared_libs/play-runtime/memory-ledger.ts +131 -0
  53. package/dist/bundling-sources/shared_libs/play-runtime/modal-runtime-config.ts +77 -2
  54. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +271 -2
  55. package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +51 -0
  56. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/contracts.ts +2 -0
  57. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/job.ts +27 -1
  58. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +2 -0
  59. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +3 -0
  60. package/dist/bundling-sources/shared_libs/play-runtime/provider-text-for-log.ts +63 -0
  61. package/dist/bundling-sources/shared_libs/play-runtime/resource-governor.ts +19 -0
  62. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger-event-transport.ts +112 -16
  63. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +104 -2
  64. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +265 -151
  65. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-gateway-transport.ts +17 -0
  66. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-progress-push.ts +35 -14
  67. package/dist/bundling-sources/shared_libs/play-runtime/runner-app/runtime-sheet-persistence-retry.ts +12 -1
  68. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-control-transport.ts +4 -0
  69. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-labels.ts +36 -0
  70. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-launch-transport.ts +136 -70
  71. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +237 -36
  72. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-runtime-watchdog.ts +148 -4
  73. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-session-execution.ts +6 -0
  74. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +285 -32
  75. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/modal.ts +251 -56
  76. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +29 -4
  77. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/sandbox-create-outcome.ts +27 -0
  78. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/types.ts +22 -1
  79. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +1397 -382
  80. package/dist/bundling-sources/shared_libs/play-runtime/runtime-array-input-receipts.ts +920 -0
  81. package/dist/bundling-sources/shared_libs/play-runtime/runtime-constants.ts +16 -0
  82. package/dist/bundling-sources/shared_libs/play-runtime/runtime-environment.ts +38 -0
  83. package/dist/bundling-sources/shared_libs/play-runtime/runtime-flow.ts +6 -0
  84. package/dist/bundling-sources/shared_libs/play-runtime/runtime-incident-drills.ts +26 -1
  85. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +30 -0
  86. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +14 -3
  87. package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +31 -4
  88. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sheet-row-transition.ts +47 -0
  89. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-compute-usage.ts +20 -7
  90. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +12 -0
  91. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/index.ts +9 -0
  92. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +10 -0
  93. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +4 -0
  94. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +1496 -320
  95. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +31 -1
  96. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +1389 -129
  97. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +36 -0
  98. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-dispatch-authority.ts +4 -0
  99. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +162 -23
  100. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-event-search.ts +499 -115
  101. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +377 -9
  102. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-ledger-reconciliation.ts +117 -8
  103. package/dist/bundling-sources/shared_libs/play-runtime/secret-resolution-retry-policy.ts +25 -0
  104. package/dist/bundling-sources/shared_libs/play-runtime/terminal-runtime-performance.ts +391 -0
  105. package/dist/bundling-sources/shared_libs/play-runtime/test-runtime-seams.ts +40 -0
  106. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/index.ts +6 -0
  107. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/mapped-calls.ts +171 -0
  108. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/receipt-cohort.ts +16 -1
  109. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +26 -3
  110. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +16 -2
  111. package/dist/bundling-sources/shared_libs/play-runtime/transport-error-diagnostics.ts +28 -0
  112. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-storage-contract.ts +55 -5
  113. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +41 -1
  114. package/dist/bundling-sources/shared_libs/plays/contracts.ts +4 -0
  115. package/dist/bundling-sources/shared_libs/plays/dataset.ts +9 -3
  116. package/dist/bundling-sources/shared_libs/plays/deploy/manifest-contract.ts +2 -0
  117. package/dist/bundling-sources/shared_libs/plays/deploy/manifest.ts +3 -2
  118. package/dist/bundling-sources/shared_libs/plays/deploy/project-serializer.ts +2 -2
  119. package/dist/bundling-sources/shared_libs/plays/run-output-summary.ts +66 -0
  120. package/dist/bundling-sources/shared_libs/plays/script-entry.ts +1 -1
  121. package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +43 -1
  122. package/dist/bundling-sources/shared_libs/product-notifications/content.ts +9 -0
  123. package/dist/bundling-sources/shared_libs/product-notifications/email.ts +91 -13
  124. package/dist/bundling-sources/shared_libs/product-notifications/events.ts +3 -0
  125. package/dist/bundling-sources/shared_libs/product-notifications/slack-delivery.ts +41 -24
  126. package/dist/bundling-sources/shared_libs/security/attested-client-ip.ts +91 -0
  127. package/dist/bundling-sources/shared_libs/security/internal-actor.ts +0 -11
  128. package/dist/cli/{auth-6HJXNWUG.mjs → auth-JDLEY7VU.mjs} +5 -4
  129. package/dist/cli/auth-UXKY6TCC.js +41 -0
  130. package/dist/cli/{billing-6P5HO6QG.js → billing-HXAXB3XZ.js} +152 -78
  131. package/dist/cli/{billing-MJ42N7YF.mjs → billing-SDHLBLMV.mjs} +84 -10
  132. package/dist/cli/{chunk-5MDIZX7M.js → chunk-3ACMRZRV.js} +8 -6
  133. package/dist/cli/{chunk-FGLKOWSC.mjs → chunk-3KZCFOZ6.mjs} +1 -1
  134. package/dist/cli/chunk-4KQ6SIBC.mjs +1038 -0
  135. package/dist/cli/{chunk-Z2GUFYT6.js → chunk-5LEAXRHV.js} +11 -11
  136. package/dist/cli/{chunk-MEAIOXJL.mjs → chunk-6NNVJDVR.mjs} +7 -5
  137. package/dist/cli/{chunk-NMJ4D2WO.js → chunk-6PMCRYDA.js} +216 -91
  138. package/dist/cli/{chunk-RY4IVOU3.mjs → chunk-6RNQGWFD.mjs} +16 -806
  139. package/dist/cli/{chunk-EBU7LQ64.js → chunk-6V7KVRR5.js} +3 -3
  140. package/dist/cli/{chunk-OZBWRICM.js → chunk-7LFIMWMW.js} +2 -2
  141. package/dist/cli/chunk-7MJ6VI2T.mjs +19 -0
  142. package/dist/cli/chunk-7SWNPNML.js +1039 -0
  143. package/dist/cli/{chunk-IHHLTHE7.mjs → chunk-7U3XNPOA.mjs} +267 -38
  144. package/dist/cli/{chunk-5FDKJQZE.js → chunk-7VZHXVOQ.js} +1 -1
  145. package/dist/cli/{chunk-R64BGGRQ.mjs → chunk-AT636LLU.mjs} +2 -2
  146. package/dist/cli/{chunk-MDJPEGVN.js → chunk-BGTPIMSM.js} +392 -261
  147. package/dist/cli/{chunk-KVJ5VHW5.mjs → chunk-CKSOY47X.mjs} +2 -2
  148. package/dist/cli/{chunk-7DH2FD7Y.mjs → chunk-D464JW3N.mjs} +5 -85
  149. package/dist/cli/chunk-D6DXOUTO.mjs +827 -0
  150. package/dist/cli/{describe-2WQY7ZCY.js → chunk-EM4TXCCI.js} +27 -44
  151. package/dist/cli/chunk-F6QV42MC.mjs +91 -0
  152. package/dist/cli/chunk-FKVYR3QA.mjs +1039 -0
  153. package/dist/cli/{chunk-FGMX4HUZ.js → chunk-GEGW5HPZ.js} +29 -27
  154. package/dist/cli/{chunk-TNMBPMMC.js → chunk-HUB3CCM2.js} +13 -4
  155. package/dist/cli/{chunk-ACCR7POB.js → chunk-I6VHOU5O.js} +27 -27
  156. package/dist/cli/{chunk-Z2XUZC34.js → chunk-IAYSWZDJ.js} +188 -76
  157. package/dist/cli/chunk-JF3TLIMQ.js +19 -0
  158. package/dist/cli/{chunk-HDFRJ4IT.mjs → chunk-JVHOS3K3.mjs} +177 -65
  159. package/dist/cli/{chunk-V7REJRDZ.mjs → chunk-LFXLQEZN.mjs} +1 -1
  160. package/dist/cli/{chunk-CRYOUPEB.js → chunk-LROWFPGN.js} +16 -16
  161. package/dist/cli/{chunk-SLEUWLJE.mjs → chunk-MSY22NQW.mjs} +5 -5
  162. package/dist/cli/{chunk-BGY2PLP7.mjs → chunk-MUUQZIOF.mjs} +23 -49
  163. package/dist/cli/{chunk-FCAZQ7WV.js → chunk-NBLSCHKK.js} +52 -50
  164. package/dist/cli/{chunk-QAJAJPKK.mjs → chunk-NHRWZPWZ.mjs} +4 -2
  165. package/dist/cli/{chunk-KXMNM4AQ.js → chunk-NMU3VR5U.js} +4 -5
  166. package/dist/cli/{chunk-QIW7TVV6.mjs → chunk-O2RX5A66.mjs} +14 -12
  167. package/dist/cli/{chunk-SAZFZQRI.js → chunk-OMQ23IXL.js} +2 -2
  168. package/dist/cli/{chunk-5IYOUBFZ.js → chunk-OPJAJBD4.js} +28 -54
  169. package/dist/cli/{chunk-FJZILBL7.mjs → chunk-PHSEINNH.mjs} +5 -5
  170. package/dist/cli/{chunk-3DNKFH2G.mjs → chunk-PKHVSIJG.mjs} +19 -1
  171. package/dist/cli/{chunk-WIYWSYDS.mjs → chunk-Q2EIZKVX.mjs} +3 -3
  172. package/dist/cli/{chunk-5FY72YOV.js → chunk-QJZ6WNWD.js} +8 -8
  173. package/dist/cli/{chunk-EIMG75BT.mjs → chunk-S3A4IXBQ.mjs} +4 -5
  174. package/dist/cli/{chunk-3BMLICF7.mjs → chunk-S42YIQNE.mjs} +13 -8
  175. package/dist/cli/{chunk-RFONC4WJ.mjs → chunk-S6UAJR6V.mjs} +3 -3
  176. package/dist/cli/{chunk-G7L27KZB.mjs → chunk-TKAQR3IB.mjs} +31 -21
  177. package/dist/cli/{chunk-QWRHGGUH.js → chunk-UAJFWWZE.js} +20 -2
  178. package/dist/cli/{chunk-VZBCEA5S.mjs → chunk-UDRPEZ5F.mjs} +223 -92
  179. package/dist/cli/{chunk-KCCOQ5G5.js → chunk-ULK7JGGI.js} +511 -282
  180. package/dist/cli/chunk-V335HGX5.js +1038 -0
  181. package/dist/cli/{chunk-MGXEUZHL.mjs → chunk-V3MEA7NB.mjs} +7 -5
  182. package/dist/cli/{chunk-O6QOMHCH.js → chunk-VFGVXXZP.js} +37 -35
  183. package/dist/cli/chunk-VLEVVDWG.js +91 -0
  184. package/dist/cli/{chunk-R2GLGLDR.mjs → chunk-VPHN2HAL.mjs} +216 -91
  185. package/dist/cli/{chunk-CFUTOWE4.js → chunk-WG3KGAII.js} +8 -88
  186. package/dist/cli/{describe-FRAVCY5F.mjs → chunk-WIY6U6GD.mjs} +19 -36
  187. package/dist/cli/{chunk-PNATXKLP.js → chunk-XANRM3QA.js} +6 -6
  188. package/dist/cli/{chunk-KGQNIA37.js → chunk-XQCTG5OO.js} +44 -34
  189. package/dist/cli/{chunk-T3MVIPHG.mjs → chunk-XZAFIOUQ.mjs} +1 -1
  190. package/dist/cli/chunk-Y4DPU4OM.js +827 -0
  191. package/dist/cli/chunk-YT5EODJO.js +920 -0
  192. package/dist/cli/{chunk-SCIR5JXW.js → chunk-ZGQSFYD2.js} +56 -51
  193. package/dist/cli/{chunk-QEYHTIV4.mjs → chunk-ZUK6LIJB.mjs} +10 -1
  194. package/dist/cli/command-docs.d.mts +5 -0
  195. package/dist/cli/command-docs.d.ts +5 -0
  196. package/dist/cli/command-docs.js +2 -2
  197. package/dist/cli/command-docs.mjs +1 -1
  198. package/dist/cli/{csv-NX7NO3O6.js → csv-C56GSCEU.js} +13 -12
  199. package/dist/cli/{csv-DQ6GW5B5.mjs → csv-L54JS7TF.mjs} +4 -3
  200. package/dist/cli/{db-R72DFMP6.js → db-MOGRMZTA.js} +30 -27
  201. package/dist/cli/{db-2YP33M4K.mjs → db-YVBUW2DX.mjs} +10 -7
  202. package/dist/cli/describe-KYEULWPG.js +48 -0
  203. package/dist/cli/describe-NLZKKT7C.mjs +48 -0
  204. package/dist/cli/describe-core.d.mts +153 -5
  205. package/dist/cli/describe-core.d.ts +153 -5
  206. package/dist/cli/describe-core.js +9 -5
  207. package/dist/cli/describe-core.mjs +10 -6
  208. package/dist/cli/{executions-ZLHD4QIT.js → executions-A7L4ULPP.js} +9 -7
  209. package/dist/cli/{executions-WFBU7L2Q.mjs → executions-ZBGSTT37.mjs} +7 -5
  210. package/dist/cli/{feedback-CN3HJFVF.mjs → feedback-G6GU37FD.mjs} +6 -5
  211. package/dist/cli/{feedback-NDV6TPHG.js → feedback-OHLY7RYD.js} +10 -9
  212. package/dist/cli/getting-started.d.mts +6 -6
  213. package/dist/cli/getting-started.d.ts +6 -6
  214. package/dist/cli/getting-started.js +2 -2
  215. package/dist/cli/getting-started.mjs +1 -1
  216. package/dist/cli/git-P76N4NDQ.js +25 -0
  217. package/dist/cli/{git-QAD6E3HW.mjs → git-PKZW3QD5.mjs} +5 -4
  218. package/dist/cli/index.js +152 -142
  219. package/dist/cli/index.mjs +56 -46
  220. package/dist/cli/{legacy-noops-KVC5QJ74.js → legacy-noops-5LM3D724.js} +8 -7
  221. package/dist/cli/{legacy-noops-TPTKNBI2.mjs → legacy-noops-LJJYG6YA.mjs} +5 -4
  222. package/dist/cli/{monitors-SV57JFLO.mjs → monitors-72QV4ALO.mjs} +19 -6
  223. package/dist/cli/{monitors-KCROV6PJ.js → monitors-UX3H5DC2.js} +103 -90
  224. package/dist/cli/{org-KX6QIR7A.mjs → org-6RRRKOCP.mjs} +9 -6
  225. package/dist/cli/{org-NJYX5743.js → org-IF7ISUVB.js} +70 -67
  226. package/dist/cli/pages-3SU3HKL7.js +252 -0
  227. package/dist/cli/pages-DXDYYKEK.mjs +252 -0
  228. package/dist/cli/{play-IQQ57L7Z.mjs → play-AHASKRLA.mjs} +512 -1508
  229. package/dist/cli/{play-32L7EQN4.js → play-EUIUVLUH.js} +1090 -2086
  230. package/dist/cli/{providers-4WEC2EQN.mjs → providers-GWGE3WY3.mjs} +7 -5
  231. package/dist/cli/{providers-ZQV6QLVQ.js → providers-V5WU4VXJ.js} +10 -8
  232. package/dist/cli/{quickstart-RQ76RIUE.mjs → quickstart-OXKQ5ZST.mjs} +5 -4
  233. package/dist/cli/{quickstart-HKUSFADF.js → quickstart-QP65I5PF.js} +13 -12
  234. package/dist/cli/run-6MM72IGL.mjs +443 -0
  235. package/dist/cli/run-F3FTYS56.js +443 -0
  236. package/dist/cli/search-OYKOOI7A.js +32 -0
  237. package/dist/cli/{search-ZRAVFBZC.mjs → search-ZMEBVJZB.mjs} +8 -6
  238. package/dist/cli/{secrets-J3G5Y43U.js → secrets-ACND5N6A.js} +16 -14
  239. package/dist/cli/{secrets-CMJOVNVH.mjs → secrets-XRCJFF3L.mjs} +7 -5
  240. package/dist/cli/{sessions-MDQYY5CB.mjs → sessions-RTK3CEW6.mjs} +5 -4
  241. package/dist/cli/{sessions-WY7VN4AE.js → sessions-ZGRJPCFF.js} +6 -5
  242. package/dist/cli/{settings-HTNTFKCE.js → settings-PD5KWQQZ.js} +80 -77
  243. package/dist/cli/{settings-4RWZPCT5.mjs → settings-XDRBPRDE.mjs} +14 -11
  244. package/dist/cli/{setup-P3GYYZWG.mjs → setup-3HPYAOCC.mjs} +12 -10
  245. package/dist/cli/{setup-QGCAP62X.js → setup-E2Q6PXHC.js} +53 -51
  246. package/dist/cli/{skills-7NAE4ICL.mjs → skills-OOQFMPOV.mjs} +7 -6
  247. package/dist/cli/skills-XYWV52KB.js +31 -0
  248. package/dist/cli/tools-ASCDZJCK.js +55 -0
  249. package/dist/cli/tools-C5ZT3UIC.mjs +55 -0
  250. package/dist/cli/update-5RQSEIFM.js +33 -0
  251. package/dist/cli/{update-GODLRKNB.mjs → update-ZWJTADIW.mjs} +9 -8
  252. package/dist/cli/{workflow-4BXOUVEO.mjs → workflow-23NMPAJ7.mjs} +10 -8
  253. package/dist/cli/{workflow-AO3A6LXN.js → workflow-TCXU5YJV.js} +20 -18
  254. package/dist/client-DS2IWYZF.d.ts +10 -0
  255. package/dist/client-DTwnz_AW.d.mts +10 -0
  256. package/dist/{client-CYqG23K1.d.ts → client-core-B_6HAIBy.d.ts} +385 -12
  257. package/dist/{client-BbU5_j7n.d.mts → client-core-DzBSlY1U.d.mts} +385 -12
  258. package/dist/{compiler-manifest-CWz_sNOQ.d.ts → compiler-manifest-Dcyd3-Zd.d.mts} +43 -1
  259. package/dist/{compiler-manifest-CWz_sNOQ.d.mts → compiler-manifest-Dcyd3-Zd.d.ts} +43 -1
  260. package/dist/errors-d-sTrZhe.d.mts +142 -0
  261. package/dist/errors-yQwfgrcX.d.ts +142 -0
  262. package/dist/{index-BF2JB_Ug.d.mts → index-C6oXchjN.d.mts} +1 -1
  263. package/dist/{index-4NPXDzlD.d.ts → index-P56zy_z5.d.ts} +1 -1
  264. package/dist/index.d.mts +11 -147
  265. package/dist/index.d.ts +11 -147
  266. package/dist/index.js +15 -11
  267. package/dist/index.mjs +14 -10
  268. package/dist/install-integrity.json +141 -104
  269. package/dist/plays/bundle-play-file.d.mts +3 -3
  270. package/dist/plays/bundle-play-file.d.ts +3 -3
  271. package/dist/plays/bundle-play-file.mjs +2 -1
  272. package/dist/plays/play-description.d.mts +2 -2
  273. package/dist/plays/play-description.d.ts +2 -2
  274. package/dist/plays/play-description.js +2 -2
  275. package/dist/plays/play-description.mjs +1 -1
  276. package/dist/plays/run-request.d.mts +2 -2
  277. package/dist/plays/run-request.d.ts +2 -2
  278. package/dist/release.d.mts +1 -1
  279. package/dist/release.d.ts +1 -1
  280. package/dist/release.js +2 -2
  281. package/dist/release.mjs +1 -1
  282. package/dist/server.d.mts +17 -0
  283. package/dist/server.d.ts +17 -0
  284. package/dist/server.js +76 -0
  285. package/dist/server.mjs +76 -0
  286. package/package.json +6 -1
  287. package/dist/cli/auth-IACERYQH.js +0 -40
  288. package/dist/cli/chunk-PQUUWFXY.js +0 -95
  289. package/dist/cli/chunk-YBWAG72P.mjs +0 -95
  290. package/dist/cli/chunk-YQDUODZW.js +0 -1710
  291. package/dist/cli/git-JVI36ZFV.js +0 -24
  292. package/dist/cli/search-75X5LTDE.js +0 -30
  293. package/dist/cli/skills-BKJ53JOQ.js +0 -30
  294. package/dist/cli/tools-COWMIEJ6.mjs +0 -45
  295. package/dist/cli/tools-TASOCE7I.js +0 -45
  296. package/dist/cli/update-SJIKVME6.js +0 -32
@@ -0,0 +1,218 @@
1
+ import {
2
+ defineBatchStrategyMap,
3
+ type BatchOperationStrategy,
4
+ } from './batching-types';
5
+
6
+ export const FREE_COMPANY_LOOKUP_KEY_TYPES = [
7
+ 'domain',
8
+ 'linkedin_url',
9
+ 'company_name',
10
+ ] as const;
11
+ export type FreeCompanyLookupKeyType =
12
+ (typeof FREE_COMPANY_LOOKUP_KEY_TYPES)[number];
13
+
14
+ /** Snowflake bind count stays well inside one statement's limits. */
15
+ export const FREE_COMPANY_BULK_LOOKUP_MAX_KEYS = 1_000;
16
+ /** One SQL statement per batch keeps a row's wait under the query timeout. */
17
+ export const FREE_COMPANY_LOOKUP_MAX_BATCH_SIZE = 100;
18
+
19
+ /**
20
+ * The same steps the loader applies to PDL's `website` column, so a lookup
21
+ * matches `normalized_domain` exactly. Subdomains are kept, as they are there.
22
+ */
23
+ export function normalizeFreeCompanyDomain(value: string): string {
24
+ return value
25
+ .trim()
26
+ .toLowerCase()
27
+ .replace(/^https?:\/\//, '')
28
+ .replace(/^www\./, '')
29
+ .replace(/[/?#].*$/, '')
30
+ .replace(/\.$/, '');
31
+ }
32
+
33
+ /** Stored as `linkedin.com/company/<slug>`; LinkedIn slugs ignore case. */
34
+ export function normalizeFreeCompanyLinkedinUrl(value: string): string {
35
+ return value
36
+ .trim()
37
+ .toLowerCase()
38
+ .replace(/^https?:\/\//, '')
39
+ .replace(/^www\./, '')
40
+ .replace(/[?#].*$/, '')
41
+ .replace(/\/+$/, '');
42
+ }
43
+
44
+ /** Stored names are trimmed and lowercase, so this is case-insensitive equality. */
45
+ export function normalizeFreeCompanyName(value: string): string {
46
+ return value.trim().toLowerCase();
47
+ }
48
+
49
+ export function normalizeFreeCompanyLookupKey(
50
+ keyType: FreeCompanyLookupKeyType,
51
+ value: string,
52
+ ): string {
53
+ switch (keyType) {
54
+ case 'domain':
55
+ return normalizeFreeCompanyDomain(value);
56
+ case 'linkedin_url':
57
+ return normalizeFreeCompanyLinkedinUrl(value);
58
+ case 'company_name':
59
+ return normalizeFreeCompanyName(value);
60
+ }
61
+ }
62
+
63
+ type LookupPayload = Record<string, unknown> & {
64
+ domain?: string;
65
+ linkedin_url?: string;
66
+ company_name?: string;
67
+ };
68
+
69
+ type BulkLookupPayload = Record<string, unknown> & {
70
+ domains?: string[];
71
+ linkedin_urls?: string[];
72
+ company_names?: string[];
73
+ };
74
+
75
+ export type FreeCompanyLookupResult = Record<string, unknown> & {
76
+ key_type: FreeCompanyLookupKeyType;
77
+ key: string;
78
+ matches: Record<string, unknown>[];
79
+ };
80
+
81
+ type BulkLookupResult = Record<string, unknown> & {
82
+ results?: unknown;
83
+ };
84
+
85
+ const BULK_FIELD: Record<FreeCompanyLookupKeyType, keyof BulkLookupPayload> = {
86
+ domain: 'domains',
87
+ linkedin_url: 'linkedin_urls',
88
+ company_name: 'company_names',
89
+ };
90
+
91
+ /** The one usable key a lookup names, or null when it does not name exactly one. */
92
+ function usableFreeCompanyLookupKey(payload: LookupPayload): {
93
+ keyType: FreeCompanyLookupKeyType;
94
+ key: string;
95
+ } | null {
96
+ const present = FREE_COMPANY_LOOKUP_KEY_TYPES.filter(
97
+ (keyType) => typeof payload[keyType] === 'string',
98
+ );
99
+ if (present.length !== 1) return null;
100
+ const keyType = present[0]!;
101
+ const key = normalizeFreeCompanyLookupKey(
102
+ keyType,
103
+ payload[keyType] as string,
104
+ );
105
+ return key ? { keyType, key } : null;
106
+ }
107
+
108
+ /** The single key a lookup names. Callers validate the payload first. */
109
+ export function freeCompanyLookupKey(payload: LookupPayload): {
110
+ keyType: FreeCompanyLookupKeyType;
111
+ key: string;
112
+ } {
113
+ const lookupKey = usableFreeCompanyLookupKey(payload);
114
+ if (!lookupKey) {
115
+ throw new Error(
116
+ 'free_company_lookup needs exactly one usable domain, linkedin_url or company_name.',
117
+ );
118
+ }
119
+ return lookupKey;
120
+ }
121
+
122
+ function isLookupResult(value: unknown): value is FreeCompanyLookupResult {
123
+ const row = value as FreeCompanyLookupResult | null;
124
+ return Boolean(
125
+ row &&
126
+ typeof row === 'object' &&
127
+ FREE_COMPANY_LOOKUP_KEY_TYPES.includes(row.key_type) &&
128
+ typeof row.key === 'string' &&
129
+ Array.isArray(row.matches),
130
+ );
131
+ }
132
+
133
+ export const freeCompanyLookupBatchStrategy: BatchOperationStrategy<
134
+ LookupPayload,
135
+ BulkLookupPayload | LookupPayload,
136
+ BulkLookupResult | FreeCompanyLookupResult,
137
+ FreeCompanyLookupResult
138
+ > = {
139
+ sourceOperation: 'free_company_lookup',
140
+ batchOperation: 'free_company_bulk_lookup',
141
+ kind: 'identifier_batch',
142
+ maxBatchSize: FREE_COMPANY_LOOKUP_MAX_BATCH_SIZE,
143
+ // Rows looking up by different keys share a batch; the bulk lookup takes all
144
+ // three lists in one statement.
145
+ canBatchWith() {
146
+ return true;
147
+ },
148
+ // The runtime batches before the app validates anything. A row without one
149
+ // usable key gets a bucket and item key of its own, so it never joins a
150
+ // batch of valid rows. compile sends it to free_company_lookup alone, which
151
+ // refuses it with a 422 for that row only.
152
+ toBucketKey(payload) {
153
+ return usableFreeCompanyLookupKey(payload)
154
+ ? 'free_company_bulk_lookup'
155
+ : `invalid:${JSON.stringify(payload)}`;
156
+ },
157
+ toItemKey(payload) {
158
+ const lookupKey = usableFreeCompanyLookupKey(payload);
159
+ return lookupKey
160
+ ? JSON.stringify([lookupKey.keyType, lookupKey.key])
161
+ : JSON.stringify(['invalid', payload]);
162
+ },
163
+ compile(payloads) {
164
+ const [only] = payloads;
165
+ if (payloads.length === 1 && only && !usableFreeCompanyLookupKey(only)) {
166
+ return {
167
+ batchOperation: 'free_company_lookup',
168
+ batchPayload: only,
169
+ items: [{ itemKey: JSON.stringify(['invalid', only]), payload: only }],
170
+ };
171
+ }
172
+ const batchPayload: BulkLookupPayload = {};
173
+ const items = payloads.map((payload) => {
174
+ const { keyType, key } = freeCompanyLookupKey(payload);
175
+ const field = BULK_FIELD[keyType];
176
+ const list = (batchPayload[field] ??= []) as string[];
177
+ if (!list.includes(key)) list.push(key);
178
+ return { itemKey: JSON.stringify([keyType, key]), payload };
179
+ });
180
+ return {
181
+ batchOperation: 'free_company_bulk_lookup',
182
+ batchPayload,
183
+ items,
184
+ };
185
+ },
186
+ splitResult(fullResult, compiled) {
187
+ if (compiled.batchOperation === 'free_company_lookup') {
188
+ throw new Error(
189
+ 'free_company_lookup answered a payload without one usable key; it must refuse it.',
190
+ );
191
+ }
192
+ const result = ((fullResult as { data?: unknown }).data ??
193
+ fullResult) as BulkLookupResult;
194
+ if (!Array.isArray(result.results)) {
195
+ throw new Error('free_company_bulk_lookup returned no results list.');
196
+ }
197
+ const byKey = new Map<string, FreeCompanyLookupResult>();
198
+ for (const row of result.results) {
199
+ if (!isLookupResult(row)) {
200
+ throw new Error('free_company_bulk_lookup returned a malformed result.');
201
+ }
202
+ byKey.set(JSON.stringify([row.key_type, row.key]), row);
203
+ }
204
+ return compiled.items.map((item) => {
205
+ const row = byKey.get(item.itemKey);
206
+ if (!row) {
207
+ throw new Error(
208
+ `free_company_bulk_lookup omitted the result for ${item.itemKey}.`,
209
+ );
210
+ }
211
+ return { itemKey: item.itemKey, result: row, rawResult: row };
212
+ });
213
+ },
214
+ };
215
+
216
+ export const freeCompanyLookupBatchStrategies = defineBatchStrategyMap({
217
+ free_company_lookup: freeCompanyLookupBatchStrategy,
218
+ });
@@ -1,4 +1,4 @@
1
- export type GatewayPostgresLane = 'ordinary' | 'commit';
1
+ export type GatewayPostgresLane = 'ordinary' | 'commit' | 'heartbeat';
2
2
 
3
3
  export type GatewayPostgresAdmissionTenant = string | null;
4
4
  export const GATEWAY_POSTGRES_MACHINE_TENANT: GatewayPostgresAdmissionTenant =
@@ -89,6 +89,7 @@ export class GatewayPostgresAdmission {
89
89
  readonly #waiting: Record<GatewayPostgresLane, LaneQueue> = {
90
90
  ordinary: { ring: new Map(), size: 0 },
91
91
  commit: { ring: new Map(), size: 0 },
92
+ heartbeat: { ring: new Map(), size: 0 },
92
93
  };
93
94
  readonly #activeByTenant: Record<
94
95
  GatewayPostgresLane,
@@ -96,9 +97,11 @@ export class GatewayPostgresAdmission {
96
97
  > = {
97
98
  ordinary: new Map(),
98
99
  commit: new Map(),
100
+ heartbeat: new Map(),
99
101
  };
100
102
  #ordinaryActive = 0;
101
103
  #commitActive = 0;
104
+ #heartbeatActive = 0;
102
105
  #cancelled = 0;
103
106
  #overloaded = 0;
104
107
  #fairShareEvictions = 0;
@@ -110,8 +113,21 @@ export class GatewayPostgresAdmission {
110
113
  maxOrdinaryActive?: number;
111
114
  maxTotalActive?: number;
112
115
  maxWaitingPerLane?: number;
116
+ /** Capacity withheld from bulk work, within maxTotalActive. */
117
+ reservedHeartbeatActive?: number;
113
118
  } = {},
114
119
  ) {
120
+ const reserved = limits.reservedHeartbeatActive ?? 0;
121
+ if (
122
+ !Number.isSafeInteger(reserved) ||
123
+ reserved < 0 ||
124
+ reserved > 1 ||
125
+ reserved >= this.#maxTotalActive()
126
+ ) {
127
+ throw new Error(
128
+ 'Gateway Postgres heartbeat reservation must be zero or one and leave bulk capacity.',
129
+ );
130
+ }
115
131
  if (
116
132
  limits.maxWaitingPerLane !== undefined &&
117
133
  (!Number.isSafeInteger(limits.maxWaitingPerLane) ||
@@ -135,7 +151,12 @@ export class GatewayPostgresAdmission {
135
151
  this.#cancelled += 1;
136
152
  throw new GatewayPostgresAdmissionCancelledError();
137
153
  }
138
- if (this.#canGrant(lane) && this.#waiting.commit.size === 0) {
154
+ if (
155
+ this.#canGrant(lane) &&
156
+ (lane === 'heartbeat'
157
+ ? this.#waiting.heartbeat.size === 0
158
+ : this.#waiting.commit.size === 0)
159
+ ) {
139
160
  return this.#grant(lane, tenant);
140
161
  }
141
162
  if (this.#waiting[lane].size >= this.#maxWaitingPerLane()) {
@@ -172,15 +193,18 @@ export class GatewayPostgresAdmission {
172
193
  active: {
173
194
  ordinary: this.#ordinaryActive,
174
195
  commit: this.#commitActive,
196
+ heartbeat: this.#heartbeatActive,
175
197
  total: this.#activeTotal(),
176
198
  },
177
199
  waiting: {
178
200
  ordinary: this.#waiting.ordinary.size,
179
201
  commit: this.#waiting.commit.size,
202
+ heartbeat: this.#waiting.heartbeat.size,
180
203
  },
181
204
  waitingTenants: {
182
205
  ordinary: this.#waiting.ordinary.ring.size,
183
206
  commit: this.#waiting.commit.ring.size,
207
+ heartbeat: this.#waiting.heartbeat.ring.size,
184
208
  },
185
209
  cancelled: this.#cancelled,
186
210
  overloaded: this.#overloaded,
@@ -190,11 +214,17 @@ export class GatewayPostgresAdmission {
190
214
  }
191
215
 
192
216
  #activeTotal(): number {
193
- return this.#ordinaryActive + this.#commitActive;
217
+ return this.#ordinaryActive + this.#commitActive + this.#heartbeatActive;
194
218
  }
195
219
 
196
220
  #canGrant(lane: GatewayPostgresLane): boolean {
197
221
  if (this.#activeTotal() >= this.#maxTotalActive()) return false;
222
+ if (lane === 'heartbeat') return this.#heartbeatActive < 1;
223
+ if (
224
+ this.#ordinaryActive + this.#commitActive >=
225
+ this.#maxTotalActive() - (this.limits.reservedHeartbeatActive ?? 0)
226
+ )
227
+ return false;
198
228
  return (
199
229
  lane === 'commit' || this.#ordinaryActive < this.#maxOrdinaryActive()
200
230
  );
@@ -221,7 +251,8 @@ export class GatewayPostgresAdmission {
221
251
  tenant: GatewayPostgresAdmissionTenant,
222
252
  ): () => void {
223
253
  if (lane === 'ordinary') this.#ordinaryActive += 1;
224
- else this.#commitActive += 1;
254
+ else if (lane === 'commit') this.#commitActive += 1;
255
+ else this.#heartbeatActive += 1;
225
256
  const activeByTenant = this.#activeByTenant[lane];
226
257
  activeByTenant.set(tenant, (activeByTenant.get(tenant) ?? 0) + 1);
227
258
  let released = false;
@@ -229,7 +260,8 @@ export class GatewayPostgresAdmission {
229
260
  if (released) return;
230
261
  released = true;
231
262
  if (lane === 'ordinary') this.#ordinaryActive -= 1;
232
- else this.#commitActive -= 1;
263
+ else if (lane === 'commit') this.#commitActive -= 1;
264
+ else this.#heartbeatActive -= 1;
233
265
  const remaining = (activeByTenant.get(tenant) ?? 1) - 1;
234
266
  if (remaining > 0) activeByTenant.set(tenant, remaining);
235
267
  else activeByTenant.delete(tenant);
@@ -239,6 +271,11 @@ export class GatewayPostgresAdmission {
239
271
 
240
272
  #drain(): void {
241
273
  while (this.#activeTotal() < this.#maxTotalActive()) {
274
+ if (this.#waiting.heartbeat.size > 0 && this.#canGrant('heartbeat')) {
275
+ this.#resolve(this.#dequeueLeastActiveTenant('heartbeat')!);
276
+ continue;
277
+ }
278
+ if (!this.#canGrant('commit')) return;
242
279
  const ordinaryCanRun =
243
280
  this.#waiting.ordinary.size > 0 &&
244
281
  this.#ordinaryActive < this.#maxOrdinaryActive();
@@ -2,12 +2,16 @@ import {
2
2
  chargeGovernorBudgetViaAppRuntime,
3
3
  type WorkerRuntimeApiContext,
4
4
  } from '../app-runtime-api';
5
- import { BlockReservingBudgetStateBackend } from './block-reserving-budget-state-backend';
5
+ import {
6
+ BlockReservingBudgetStateBackend,
7
+ type BlockReservingBudgetStateOptions,
8
+ } from './block-reserving-budget-state-backend';
6
9
 
7
10
  export class AppRuntimeBudgetStateBackend extends BlockReservingBudgetStateBackend {
8
11
  constructor(
9
12
  context: WorkerRuntimeApiContext,
10
13
  schedulerSchema?: string | null,
14
+ options?: BlockReservingBudgetStateOptions,
11
15
  ) {
12
16
  super(
13
17
  async (input) =>
@@ -17,6 +21,7 @@ export class AppRuntimeBudgetStateBackend extends BlockReservingBudgetStateBacke
17
21
  charges: [...input.charges],
18
22
  schedulerSchema: schedulerSchema ?? null,
19
23
  }),
24
+ options,
20
25
  );
21
26
  }
22
27
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  acquireRateStateViaAppRuntime,
3
- AppRuntimeApiResponseError,
4
- isAppRuntimeApiCapacityError,
3
+ AppRuntimeApiTransportError,
4
+ capacityShedRetryAfterMs,
5
5
  penalizeRateStateViaAppRuntime,
6
6
  releaseRateStateViaAppRuntime,
7
7
  RateStateValidationUnavailableError,
@@ -143,20 +143,15 @@ function sleepWithAbort(
143
143
  */
144
144
  const RATE_BLOCK_HORIZON_MS = 1_000;
145
145
  const STORE_FAILURE_RETRY_DELAYS_MS = [100, 250] as const;
146
- const CAPACITY_SHED_DEFAULT_RETRY_AFTER_MS = 1_000;
147
-
148
- function capacityShedRetryAfterMs(error: unknown): number | null {
149
- const shed =
150
- isAppRuntimeApiCapacityError(error) ||
151
- (error instanceof AppRuntimeApiResponseError &&
152
- error.retryable &&
153
- error.status === 429);
154
- if (!shed) return null;
155
- const retryAfterMs = (error as AppRuntimeApiResponseError).retryAfterMs;
156
- return retryAfterMs && retryAfterMs > 0
157
- ? retryAfterMs
158
- : CAPACITY_SHED_DEFAULT_RETRY_AFTER_MS;
159
- }
146
+ const RELEASE_SHED_BACKOFF_BASE_MS = 1_000;
147
+ const RELEASE_SHED_BACKOFF_MAX_MS = 16_000;
148
+ /**
149
+ * Longest one batch of leases keeps retrying a shed release. The store expires
150
+ * an unreleased lease after five minutes, so retrying only frees its slot
151
+ * sooner. Past this window the lease is left to that TTL.
152
+ */
153
+ export const RELEASE_SHED_RETRY_WINDOW_MS = 120_000;
154
+
160
155
  /**
161
156
  * Jitter fraction applied to a server-supplied `waitMs` so a synchronized wave
162
157
  * of buckets that all hit granted=0 at the same instant re-probe at slightly
@@ -316,10 +311,18 @@ export class AppRuntimeRateStateBackend implements RateStateBackend {
316
311
  string,
317
312
  number
318
313
  >();
319
- private pendingReleaseFailure: Error | null = null;
314
+
315
+ /**
316
+ * The sandbox runner's transport already retries a request that gets no
317
+ * response through a whole network cut, so one more round here would only
318
+ * repeat that wait.
319
+ */
320
+ private readonly transportRetriesOutages: boolean;
320
321
 
321
322
  constructor(context: WorkerRuntimeApiContext, options: Options = {}) {
322
323
  this.port = options.port ?? contextRatePort(context);
324
+ this.transportRetriesOutages =
325
+ context.connectionRetryBudgetMs !== undefined;
323
326
  this.schedulerSchema = options.schedulerSchema?.trim() || null;
324
327
  this.now = options.now ?? (() => Date.now());
325
328
  this.sleep = options.sleep ?? sleepWithAbort;
@@ -437,9 +440,9 @@ export class AppRuntimeRateStateBackend implements RateStateBackend {
437
440
  }): PacingPermit | null {
438
441
  const { bucketId, rules } = input;
439
442
  if (rules.length === 0) return noopPacingPermit();
440
- // A probe reports nothing and repairs nothing: a pending release failure
441
- // or an exhausted pacer surfaces from the next blocking acquire instead.
442
- if (this.pendingReleaseFailure || this.pacerExhaustion(bucketId)) {
443
+ // A probe reports nothing and repairs nothing: an exhausted pacer surfaces
444
+ // from the next blocking acquire instead.
445
+ if (this.pacerExhaustion(bucketId)) {
443
446
  return null;
444
447
  }
445
448
  const laneKey = rateLaneKey(
@@ -535,7 +538,6 @@ export class AppRuntimeRateStateBackend implements RateStateBackend {
535
538
  }): Promise<PacingPermit> {
536
539
  const { bucketId, rules, signal } = input;
537
540
  if (rules.length === 0) return noopPacingPermit();
538
- this.throwPendingReleaseFailure();
539
541
  // Pre-check: zero round trips when the pacer is already holding past the
540
542
  // threshold. Fails fast with a typed PROVIDER_EXHAUSTED before touching the
541
543
  // store.
@@ -1177,9 +1179,14 @@ export class AppRuntimeRateStateBackend implements RateStateBackend {
1177
1179
  consecutiveFailures += 1;
1178
1180
  const normalized = normalizeError(error);
1179
1181
  this.onStoreFailure({ bucketId, error: normalized.message });
1180
- if (consecutiveFailures > STORE_FAILURE_RETRY_DELAYS_MS.length) {
1182
+ if (
1183
+ consecutiveFailures > STORE_FAILURE_RETRY_DELAYS_MS.length ||
1184
+ (this.transportRetriesOutages &&
1185
+ error instanceof AppRuntimeApiTransportError)
1186
+ ) {
1181
1187
  throw new Error(
1182
1188
  `Rate-state store unavailable for ${bucketId}; failing closed after ${consecutiveFailures} acquire attempts: ${normalized.message}`,
1189
+ { cause: error },
1183
1190
  );
1184
1191
  }
1185
1192
  await this.sleep(
@@ -1983,10 +1990,31 @@ export class AppRuntimeRateStateBackend implements RateStateBackend {
1983
1990
  queueMicrotask(() => void this.flushReleases(key, pending));
1984
1991
  }
1985
1992
 
1993
+ /**
1994
+ * Background write: `permit.release()` has already returned, so a failure
1995
+ * here has no caller, and the next acquire belongs to an unrelated row. An
1996
+ * unreleased lease holds its slot until the store's TTL, which errs toward
1997
+ * fewer provider calls, and the store still owns every grant. That is why a
1998
+ * failed acquire fails closed and a failed release does not.
1999
+ *
2000
+ * A shed comes from a working store, and DELETE by lease id is idempotent, so
2001
+ * it is retried inside a window. Anything else has spent the transport's
2002
+ * retries already. A contract 4xx would only repeat: acquire passes the same
2003
+ * auth and scope checks and fails closed on its own row, while a release-only
2004
+ * bug surfaces as provider admission timeouts once slots pin. Report it and
2005
+ * let the TTL reclaim the slot.
2006
+ *
2007
+ * Unreleased leases keep counting against the store's concurrency cap, so a
2008
+ * shed lane cannot be granted more than that cap per TTL, and the window
2009
+ * drops whatever the batch holds. The batch stays bounded, and this loop ends
2010
+ * once the lane stops releasing.
2011
+ */
1986
2012
  private async flushReleases(
1987
2013
  key: string,
1988
2014
  pending: PendingRelease,
1989
2015
  ): Promise<void> {
2016
+ let shedStartedAtMs: number | null = null;
2017
+ let consecutiveSheds = 0;
1990
2018
  while (pending.leaseIds.length > 0) {
1991
2019
  const leaseIds = pending.leaseIds.splice(0);
1992
2020
  try {
@@ -1997,15 +2025,37 @@ export class AppRuntimeRateStateBackend implements RateStateBackend {
1997
2025
  leaseIds,
1998
2026
  schedulerSchema: this.schedulerSchema,
1999
2027
  });
2028
+ shedStartedAtMs = null;
2029
+ consecutiveSheds = 0;
2000
2030
  this.signalLeaseRelease(pending.bucketId);
2001
2031
  } catch (error) {
2002
2032
  const normalized = normalizeError(error);
2003
- this.pendingReleaseFailure = new Error(
2004
- `Rate-state release failed for ${pending.bucketId}: ${normalized.message}`,
2005
- );
2033
+ const shedRetryAfterMs = capacityShedRetryAfterMs(error);
2034
+ if (shedRetryAfterMs !== null) {
2035
+ consecutiveSheds += 1;
2036
+ shedStartedAtMs ??= this.now();
2037
+ const delayMs = this.releaseShedDelayMs(
2038
+ shedRetryAfterMs,
2039
+ consecutiveSheds,
2040
+ );
2041
+ if (
2042
+ this.now() - shedStartedAtMs + delayMs <
2043
+ RELEASE_SHED_RETRY_WINDOW_MS
2044
+ ) {
2045
+ this.onStoreFailure({
2046
+ bucketId: pending.bucketId,
2047
+ error: `Rate-state release shed for ${pending.bucketId}; retrying in ${delayMs}ms: ${normalized.message}`,
2048
+ });
2049
+ pending.leaseIds.unshift(...leaseIds);
2050
+ await this.sleep(delayMs);
2051
+ continue;
2052
+ }
2053
+ }
2054
+ shedStartedAtMs = null;
2055
+ consecutiveSheds = 0;
2006
2056
  this.onStoreFailure({
2007
2057
  bucketId: pending.bucketId,
2008
- error: normalized.message,
2058
+ error: `Rate-state release failed for ${pending.bucketId}; leases held until their TTL (${leaseIds.length}): ${normalized.message}`,
2009
2059
  });
2010
2060
  }
2011
2061
  }
@@ -2020,11 +2070,22 @@ export class AppRuntimeRateStateBackend implements RateStateBackend {
2020
2070
  }
2021
2071
  }
2022
2072
 
2023
- private throwPendingReleaseFailure(): void {
2024
- if (!this.pendingReleaseFailure) return;
2025
- const error = this.pendingReleaseFailure;
2026
- this.pendingReleaseFailure = null;
2027
- throw error;
2073
+ /**
2074
+ * Capped doubling, never under the shed's Retry-After. Jitter only adds, so a
2075
+ * wave of runners shed together spreads out above the deadline they were given.
2076
+ */
2077
+ private releaseShedDelayMs(
2078
+ retryAfterMs: number,
2079
+ consecutiveSheds: number,
2080
+ ): number {
2081
+ const floorMs = Math.max(
2082
+ retryAfterMs,
2083
+ Math.min(
2084
+ RELEASE_SHED_BACKOFF_BASE_MS * 2 ** (consecutiveSheds - 1),
2085
+ RELEASE_SHED_BACKOFF_MAX_MS,
2086
+ ),
2087
+ );
2088
+ return floorMs + Math.round(this.jitter() * floorMs);
2028
2089
  }
2029
2090
 
2030
2091
  private signalLeaseRelease(bucketId: string): void {