@smthrs/control 0.0.0-stage → 1.0.0-rc.4

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 (418) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/LICENSE +21 -0
  3. package/README.md +168 -2
  4. package/dist/cjs/ApprovalAuthority.d.ts +73 -0
  5. package/dist/cjs/ApprovalAuthority.d.ts.map +1 -0
  6. package/dist/cjs/ApprovalAuthority.js +62 -0
  7. package/dist/cjs/ApprovalAuthority.js.map +7 -0
  8. package/dist/cjs/Cancellation.d.ts +107 -0
  9. package/dist/cjs/Cancellation.d.ts.map +1 -0
  10. package/dist/cjs/Cancellation.js +72 -0
  11. package/dist/cjs/Cancellation.js.map +7 -0
  12. package/dist/cjs/Channels.d.ts +170 -0
  13. package/dist/cjs/Channels.d.ts.map +1 -0
  14. package/dist/cjs/Channels.js +278 -0
  15. package/dist/cjs/Channels.js.map +7 -0
  16. package/dist/cjs/Control.d.ts +202 -0
  17. package/dist/cjs/Control.d.ts.map +1 -0
  18. package/dist/cjs/Control.js +47 -0
  19. package/dist/cjs/Control.js.map +7 -0
  20. package/dist/cjs/ControlClient.d.ts +52 -0
  21. package/dist/cjs/ControlClient.d.ts.map +1 -0
  22. package/dist/cjs/ControlClient.js +191 -0
  23. package/dist/cjs/ControlClient.js.map +7 -0
  24. package/dist/cjs/ControlError.d.ts +318 -0
  25. package/dist/cjs/ControlError.d.ts.map +1 -0
  26. package/dist/cjs/ControlError.js +249 -0
  27. package/dist/cjs/ControlError.js.map +7 -0
  28. package/dist/cjs/ControlExecutor.d.ts +372 -0
  29. package/dist/cjs/ControlExecutor.d.ts.map +1 -0
  30. package/dist/cjs/ControlExecutor.js +123 -0
  31. package/dist/cjs/ControlExecutor.js.map +7 -0
  32. package/dist/cjs/ControlFacts.d.ts +454 -0
  33. package/dist/cjs/ControlFacts.d.ts.map +1 -0
  34. package/dist/cjs/ControlFacts.js +261 -0
  35. package/dist/cjs/ControlFacts.js.map +7 -0
  36. package/dist/cjs/ControlLive.d.ts +23 -0
  37. package/dist/cjs/ControlLive.d.ts.map +1 -0
  38. package/dist/cjs/ControlLive.js +1293 -0
  39. package/dist/cjs/ControlLive.js.map +7 -0
  40. package/dist/cjs/ControlRpcs.d.ts +1204 -0
  41. package/dist/cjs/ControlRpcs.d.ts.map +1 -0
  42. package/dist/cjs/ControlRpcs.js +247 -0
  43. package/dist/cjs/ControlRpcs.js.map +7 -0
  44. package/dist/cjs/ControlRuntime.d.ts +635 -0
  45. package/dist/cjs/ControlRuntime.d.ts.map +1 -0
  46. package/dist/cjs/ControlRuntime.js +744 -0
  47. package/dist/cjs/ControlRuntime.js.map +7 -0
  48. package/dist/cjs/ControlSchema.d.ts +2642 -0
  49. package/dist/cjs/ControlSchema.d.ts.map +1 -0
  50. package/dist/cjs/ControlSchema.js +634 -0
  51. package/dist/cjs/ControlSchema.js.map +7 -0
  52. package/dist/cjs/ControlServer.d.ts +51 -0
  53. package/dist/cjs/ControlServer.d.ts.map +1 -0
  54. package/dist/cjs/ControlServer.js +121 -0
  55. package/dist/cjs/ControlServer.js.map +7 -0
  56. package/dist/cjs/Credential.d.ts +136 -0
  57. package/dist/cjs/Credential.d.ts.map +1 -0
  58. package/dist/cjs/Credential.js +168 -0
  59. package/dist/cjs/Credential.js.map +7 -0
  60. package/dist/cjs/CredentialCipher.d.ts +90 -0
  61. package/dist/cjs/CredentialCipher.d.ts.map +1 -0
  62. package/dist/cjs/CredentialCipher.js +45 -0
  63. package/dist/cjs/CredentialCipher.js.map +7 -0
  64. package/dist/cjs/CredentialStore.d.ts +97 -0
  65. package/dist/cjs/CredentialStore.d.ts.map +1 -0
  66. package/dist/cjs/CredentialStore.js +81 -0
  67. package/dist/cjs/CredentialStore.js.map +7 -0
  68. package/dist/cjs/DispatchReader.d.ts +112 -0
  69. package/dist/cjs/DispatchReader.d.ts.map +1 -0
  70. package/dist/cjs/DispatchReader.js +45 -0
  71. package/dist/cjs/DispatchReader.js.map +7 -0
  72. package/dist/cjs/Health.d.ts +333 -0
  73. package/dist/cjs/Health.d.ts.map +1 -0
  74. package/dist/cjs/Health.js +311 -0
  75. package/dist/cjs/Health.js.map +7 -0
  76. package/dist/cjs/JevSessionChecker.d.ts +57 -0
  77. package/dist/cjs/JevSessionChecker.d.ts.map +1 -0
  78. package/dist/cjs/JevSessionChecker.js +113 -0
  79. package/dist/cjs/JevSessionChecker.js.map +7 -0
  80. package/dist/cjs/Lineage.d.ts +131 -0
  81. package/dist/cjs/Lineage.d.ts.map +1 -0
  82. package/dist/cjs/Lineage.js +81 -0
  83. package/dist/cjs/Lineage.js.map +7 -0
  84. package/dist/cjs/Migrations.d.ts +34 -0
  85. package/dist/cjs/Migrations.d.ts.map +1 -0
  86. package/dist/cjs/Migrations.js +60 -0
  87. package/dist/cjs/Migrations.js.map +7 -0
  88. package/dist/cjs/Monitor.d.ts +282 -0
  89. package/dist/cjs/Monitor.d.ts.map +1 -0
  90. package/dist/cjs/Monitor.js +283 -0
  91. package/dist/cjs/Monitor.js.map +7 -0
  92. package/dist/cjs/ScopedToken.d.ts +193 -0
  93. package/dist/cjs/ScopedToken.d.ts.map +1 -0
  94. package/dist/cjs/ScopedToken.js +135 -0
  95. package/dist/cjs/ScopedToken.js.map +7 -0
  96. package/dist/cjs/SqlControlRuntime.d.ts +161 -0
  97. package/dist/cjs/SqlControlRuntime.d.ts.map +1 -0
  98. package/dist/cjs/SqlControlRuntime.js +1522 -0
  99. package/dist/cjs/SqlControlRuntime.js.map +7 -0
  100. package/dist/cjs/SqlCredentialStore.d.ts +43 -0
  101. package/dist/cjs/SqlCredentialStore.d.ts.map +1 -0
  102. package/dist/cjs/SqlCredentialStore.js +113 -0
  103. package/dist/cjs/SqlCredentialStore.js.map +7 -0
  104. package/dist/cjs/Steering.d.ts +69 -0
  105. package/dist/cjs/Steering.d.ts.map +1 -0
  106. package/dist/cjs/Steering.js +49 -0
  107. package/dist/cjs/Steering.js.map +7 -0
  108. package/dist/cjs/SystemFlows.d.ts +223 -0
  109. package/dist/cjs/SystemFlows.d.ts.map +1 -0
  110. package/dist/cjs/SystemFlows.js +195 -0
  111. package/dist/cjs/SystemFlows.js.map +7 -0
  112. package/dist/cjs/WebCryptoCipher.d.ts +49 -0
  113. package/dist/cjs/WebCryptoCipher.d.ts.map +1 -0
  114. package/dist/cjs/WebCryptoCipher.js +129 -0
  115. package/dist/cjs/WebCryptoCipher.js.map +7 -0
  116. package/dist/cjs/WebhookChannel.d.ts +113 -0
  117. package/dist/cjs/WebhookChannel.d.ts.map +1 -0
  118. package/dist/cjs/WebhookChannel.js +98 -0
  119. package/dist/cjs/WebhookChannel.js.map +7 -0
  120. package/dist/cjs/index.d.ts +160 -0
  121. package/dist/cjs/index.d.ts.map +1 -0
  122. package/dist/cjs/index.js +91 -0
  123. package/dist/cjs/index.js.map +7 -0
  124. package/dist/cjs/internal/MutationBoundary.d.ts +27 -0
  125. package/dist/cjs/internal/MutationBoundary.d.ts.map +1 -0
  126. package/dist/cjs/internal/MutationBoundary.js +50 -0
  127. package/dist/cjs/internal/MutationBoundary.js.map +7 -0
  128. package/dist/cjs/internal/activeFibers.d.ts +12 -0
  129. package/dist/cjs/internal/activeFibers.d.ts.map +1 -0
  130. package/dist/cjs/internal/activeFibers.js +30 -0
  131. package/dist/cjs/internal/activeFibers.js.map +7 -0
  132. package/dist/cjs/internal/issues.d.ts +28 -0
  133. package/dist/cjs/internal/issues.d.ts.map +1 -0
  134. package/dist/cjs/internal/issues.js +34 -0
  135. package/dist/cjs/internal/issues.js.map +7 -0
  136. package/dist/cjs/internal/planning.d.ts +347 -0
  137. package/dist/cjs/internal/planning.d.ts.map +1 -0
  138. package/dist/cjs/internal/planning.js +137 -0
  139. package/dist/cjs/internal/planning.js.map +7 -0
  140. package/dist/cjs/internal/sqlSchemaErrors.d.ts +18 -0
  141. package/dist/cjs/internal/sqlSchemaErrors.d.ts.map +1 -0
  142. package/dist/cjs/internal/sqlSchemaErrors.js +40 -0
  143. package/dist/cjs/internal/sqlSchemaErrors.js.map +7 -0
  144. package/dist/cjs/migrations/0001_control_tables.d.ts +18 -0
  145. package/dist/cjs/migrations/0001_control_tables.d.ts.map +1 -0
  146. package/dist/cjs/migrations/0001_control_tables.js +115 -0
  147. package/dist/cjs/migrations/0001_control_tables.js.map +7 -0
  148. package/dist/cjs/migrations/0002_run_keys.d.ts +15 -0
  149. package/dist/cjs/migrations/0002_run_keys.d.ts.map +1 -0
  150. package/dist/cjs/migrations/0002_run_keys.js +44 -0
  151. package/dist/cjs/migrations/0002_run_keys.js.map +7 -0
  152. package/dist/cjs/migrations/0003_signal_commands.d.ts +13 -0
  153. package/dist/cjs/migrations/0003_signal_commands.d.ts.map +1 -0
  154. package/dist/cjs/migrations/0003_signal_commands.js +50 -0
  155. package/dist/cjs/migrations/0003_signal_commands.js.map +7 -0
  156. package/dist/cjs/migrations/0004_approval_decisions.d.ts +13 -0
  157. package/dist/cjs/migrations/0004_approval_decisions.d.ts.map +1 -0
  158. package/dist/cjs/migrations/0004_approval_decisions.js +45 -0
  159. package/dist/cjs/migrations/0004_approval_decisions.js.map +7 -0
  160. package/dist/cjs/migrations/0005_signal_principals.d.ts +18 -0
  161. package/dist/cjs/migrations/0005_signal_principals.d.ts.map +1 -0
  162. package/dist/cjs/migrations/0005_signal_principals.js +45 -0
  163. package/dist/cjs/migrations/0005_signal_principals.js.map +7 -0
  164. package/dist/cjs/migrations/0006_run_principals.d.ts +18 -0
  165. package/dist/cjs/migrations/0006_run_principals.d.ts.map +1 -0
  166. package/dist/cjs/migrations/0006_run_principals.js +49 -0
  167. package/dist/cjs/migrations/0006_run_principals.js.map +7 -0
  168. package/dist/cjs/migrations/0007_resume_consent.d.ts +18 -0
  169. package/dist/cjs/migrations/0007_resume_consent.d.ts.map +1 -0
  170. package/dist/cjs/migrations/0007_resume_consent.js +46 -0
  171. package/dist/cjs/migrations/0007_resume_consent.js.map +7 -0
  172. package/dist/cjs/package.json +1 -0
  173. package/dist/cjs/test/TestControl.d.ts +19 -0
  174. package/dist/cjs/test/TestControl.d.ts.map +1 -0
  175. package/dist/cjs/test/TestControl.js +62 -0
  176. package/dist/cjs/test/TestControl.js.map +7 -0
  177. package/dist/esm/ApprovalAuthority.d.ts +73 -0
  178. package/dist/esm/ApprovalAuthority.d.ts.map +1 -0
  179. package/dist/esm/ApprovalAuthority.js +72 -0
  180. package/dist/esm/ApprovalAuthority.js.map +1 -0
  181. package/dist/esm/Cancellation.d.ts +107 -0
  182. package/dist/esm/Cancellation.d.ts.map +1 -0
  183. package/dist/esm/Cancellation.js +116 -0
  184. package/dist/esm/Cancellation.js.map +1 -0
  185. package/dist/esm/Channels.d.ts +170 -0
  186. package/dist/esm/Channels.d.ts.map +1 -0
  187. package/dist/esm/Channels.js +312 -0
  188. package/dist/esm/Channels.js.map +1 -0
  189. package/dist/esm/Control.d.ts +202 -0
  190. package/dist/esm/Control.d.ts.map +1 -0
  191. package/dist/esm/Control.js +42 -0
  192. package/dist/esm/Control.js.map +1 -0
  193. package/dist/esm/ControlClient.d.ts +52 -0
  194. package/dist/esm/ControlClient.d.ts.map +1 -0
  195. package/dist/esm/ControlClient.js +217 -0
  196. package/dist/esm/ControlClient.js.map +1 -0
  197. package/dist/esm/ControlError.d.ts +318 -0
  198. package/dist/esm/ControlError.d.ts.map +1 -0
  199. package/dist/esm/ControlError.js +359 -0
  200. package/dist/esm/ControlError.js.map +1 -0
  201. package/dist/esm/ControlExecutor.d.ts +372 -0
  202. package/dist/esm/ControlExecutor.d.ts.map +1 -0
  203. package/dist/esm/ControlExecutor.js +212 -0
  204. package/dist/esm/ControlExecutor.js.map +1 -0
  205. package/dist/esm/ControlFacts.d.ts +454 -0
  206. package/dist/esm/ControlFacts.d.ts.map +1 -0
  207. package/dist/esm/ControlFacts.js +324 -0
  208. package/dist/esm/ControlFacts.js.map +1 -0
  209. package/dist/esm/ControlLive.d.ts +23 -0
  210. package/dist/esm/ControlLive.d.ts.map +1 -0
  211. package/dist/esm/ControlLive.js +1589 -0
  212. package/dist/esm/ControlLive.js.map +1 -0
  213. package/dist/esm/ControlRpcs.d.ts +1204 -0
  214. package/dist/esm/ControlRpcs.d.ts.map +1 -0
  215. package/dist/esm/ControlRpcs.js +299 -0
  216. package/dist/esm/ControlRpcs.js.map +1 -0
  217. package/dist/esm/ControlRuntime.d.ts +635 -0
  218. package/dist/esm/ControlRuntime.d.ts.map +1 -0
  219. package/dist/esm/ControlRuntime.js +808 -0
  220. package/dist/esm/ControlRuntime.js.map +1 -0
  221. package/dist/esm/ControlSchema.d.ts +2642 -0
  222. package/dist/esm/ControlSchema.d.ts.map +1 -0
  223. package/dist/esm/ControlSchema.js +1030 -0
  224. package/dist/esm/ControlSchema.js.map +1 -0
  225. package/dist/esm/ControlServer.d.ts +51 -0
  226. package/dist/esm/ControlServer.d.ts.map +1 -0
  227. package/dist/esm/ControlServer.js +145 -0
  228. package/dist/esm/ControlServer.js.map +1 -0
  229. package/dist/esm/Credential.d.ts +136 -0
  230. package/dist/esm/Credential.d.ts.map +1 -0
  231. package/dist/esm/Credential.js +190 -0
  232. package/dist/esm/Credential.js.map +1 -0
  233. package/dist/esm/CredentialCipher.d.ts +90 -0
  234. package/dist/esm/CredentialCipher.d.ts.map +1 -0
  235. package/dist/esm/CredentialCipher.js +56 -0
  236. package/dist/esm/CredentialCipher.js.map +1 -0
  237. package/dist/esm/CredentialStore.d.ts +97 -0
  238. package/dist/esm/CredentialStore.d.ts.map +1 -0
  239. package/dist/esm/CredentialStore.js +101 -0
  240. package/dist/esm/CredentialStore.js.map +1 -0
  241. package/dist/esm/DispatchReader.d.ts +112 -0
  242. package/dist/esm/DispatchReader.d.ts.map +1 -0
  243. package/dist/esm/DispatchReader.js +76 -0
  244. package/dist/esm/DispatchReader.js.map +1 -0
  245. package/dist/esm/Health.d.ts +333 -0
  246. package/dist/esm/Health.d.ts.map +1 -0
  247. package/dist/esm/Health.js +400 -0
  248. package/dist/esm/Health.js.map +1 -0
  249. package/dist/esm/JevSessionChecker.d.ts +57 -0
  250. package/dist/esm/JevSessionChecker.d.ts.map +1 -0
  251. package/dist/esm/JevSessionChecker.js +108 -0
  252. package/dist/esm/JevSessionChecker.js.map +1 -0
  253. package/dist/esm/Lineage.d.ts +131 -0
  254. package/dist/esm/Lineage.d.ts.map +1 -0
  255. package/dist/esm/Lineage.js +174 -0
  256. package/dist/esm/Lineage.js.map +1 -0
  257. package/dist/esm/Migrations.d.ts +34 -0
  258. package/dist/esm/Migrations.d.ts.map +1 -0
  259. package/dist/esm/Migrations.js +53 -0
  260. package/dist/esm/Migrations.js.map +1 -0
  261. package/dist/esm/Monitor.d.ts +282 -0
  262. package/dist/esm/Monitor.d.ts.map +1 -0
  263. package/dist/esm/Monitor.js +415 -0
  264. package/dist/esm/Monitor.js.map +1 -0
  265. package/dist/esm/ScopedToken.d.ts +193 -0
  266. package/dist/esm/ScopedToken.d.ts.map +1 -0
  267. package/dist/esm/ScopedToken.js +224 -0
  268. package/dist/esm/ScopedToken.js.map +1 -0
  269. package/dist/esm/SqlControlRuntime.d.ts +161 -0
  270. package/dist/esm/SqlControlRuntime.d.ts.map +1 -0
  271. package/dist/esm/SqlControlRuntime.js +1756 -0
  272. package/dist/esm/SqlControlRuntime.js.map +1 -0
  273. package/dist/esm/SqlCredentialStore.d.ts +43 -0
  274. package/dist/esm/SqlCredentialStore.d.ts.map +1 -0
  275. package/dist/esm/SqlCredentialStore.js +97 -0
  276. package/dist/esm/SqlCredentialStore.js.map +1 -0
  277. package/dist/esm/Steering.d.ts +69 -0
  278. package/dist/esm/Steering.d.ts.map +1 -0
  279. package/dist/esm/Steering.js +89 -0
  280. package/dist/esm/Steering.js.map +1 -0
  281. package/dist/esm/SystemFlows.d.ts +223 -0
  282. package/dist/esm/SystemFlows.d.ts.map +1 -0
  283. package/dist/esm/SystemFlows.js +198 -0
  284. package/dist/esm/SystemFlows.js.map +1 -0
  285. package/dist/esm/WebCryptoCipher.d.ts +49 -0
  286. package/dist/esm/WebCryptoCipher.d.ts.map +1 -0
  287. package/dist/esm/WebCryptoCipher.js +123 -0
  288. package/dist/esm/WebCryptoCipher.js.map +1 -0
  289. package/dist/esm/WebhookChannel.d.ts +113 -0
  290. package/dist/esm/WebhookChannel.d.ts.map +1 -0
  291. package/dist/esm/WebhookChannel.js +109 -0
  292. package/dist/esm/WebhookChannel.js.map +1 -0
  293. package/dist/esm/index.d.ts +160 -0
  294. package/dist/esm/index.d.ts.map +1 -0
  295. package/dist/esm/index.js +160 -0
  296. package/dist/esm/index.js.map +1 -0
  297. package/dist/esm/internal/MutationBoundary.d.ts +27 -0
  298. package/dist/esm/internal/MutationBoundary.d.ts.map +1 -0
  299. package/dist/esm/internal/MutationBoundary.js +40 -0
  300. package/dist/esm/internal/MutationBoundary.js.map +1 -0
  301. package/dist/esm/internal/activeFibers.d.ts +12 -0
  302. package/dist/esm/internal/activeFibers.d.ts.map +1 -0
  303. package/dist/esm/internal/activeFibers.js +17 -0
  304. package/dist/esm/internal/activeFibers.js.map +1 -0
  305. package/dist/esm/internal/issues.d.ts +28 -0
  306. package/dist/esm/internal/issues.d.ts.map +1 -0
  307. package/dist/esm/internal/issues.js +35 -0
  308. package/dist/esm/internal/issues.js.map +1 -0
  309. package/dist/esm/internal/planning.d.ts +347 -0
  310. package/dist/esm/internal/planning.d.ts.map +1 -0
  311. package/dist/esm/internal/planning.js +199 -0
  312. package/dist/esm/internal/planning.js.map +1 -0
  313. package/dist/esm/internal/sqlSchemaErrors.d.ts +18 -0
  314. package/dist/esm/internal/sqlSchemaErrors.d.ts.map +1 -0
  315. package/dist/esm/internal/sqlSchemaErrors.js +38 -0
  316. package/dist/esm/internal/sqlSchemaErrors.js.map +1 -0
  317. package/dist/esm/migrations/0001_control_tables.d.ts +18 -0
  318. package/dist/esm/migrations/0001_control_tables.d.ts.map +1 -0
  319. package/dist/esm/migrations/0001_control_tables.js +96 -0
  320. package/dist/esm/migrations/0001_control_tables.js.map +1 -0
  321. package/dist/esm/migrations/0002_run_keys.d.ts +15 -0
  322. package/dist/esm/migrations/0002_run_keys.d.ts.map +1 -0
  323. package/dist/esm/migrations/0002_run_keys.js +22 -0
  324. package/dist/esm/migrations/0002_run_keys.js.map +1 -0
  325. package/dist/esm/migrations/0003_signal_commands.d.ts +13 -0
  326. package/dist/esm/migrations/0003_signal_commands.d.ts.map +1 -0
  327. package/dist/esm/migrations/0003_signal_commands.js +26 -0
  328. package/dist/esm/migrations/0003_signal_commands.js.map +1 -0
  329. package/dist/esm/migrations/0004_approval_decisions.d.ts +13 -0
  330. package/dist/esm/migrations/0004_approval_decisions.d.ts.map +1 -0
  331. package/dist/esm/migrations/0004_approval_decisions.js +25 -0
  332. package/dist/esm/migrations/0004_approval_decisions.js.map +1 -0
  333. package/dist/esm/migrations/0005_signal_principals.d.ts +18 -0
  334. package/dist/esm/migrations/0005_signal_principals.d.ts.map +1 -0
  335. package/dist/esm/migrations/0005_signal_principals.js +27 -0
  336. package/dist/esm/migrations/0005_signal_principals.js.map +1 -0
  337. package/dist/esm/migrations/0006_run_principals.d.ts +18 -0
  338. package/dist/esm/migrations/0006_run_principals.d.ts.map +1 -0
  339. package/dist/esm/migrations/0006_run_principals.js +30 -0
  340. package/dist/esm/migrations/0006_run_principals.js.map +1 -0
  341. package/dist/esm/migrations/0007_resume_consent.d.ts +18 -0
  342. package/dist/esm/migrations/0007_resume_consent.d.ts.map +1 -0
  343. package/dist/esm/migrations/0007_resume_consent.js +27 -0
  344. package/dist/esm/migrations/0007_resume_consent.js.map +1 -0
  345. package/dist/esm/test/TestControl.d.ts +19 -0
  346. package/dist/esm/test/TestControl.d.ts.map +1 -0
  347. package/dist/esm/test/TestControl.js +30 -0
  348. package/dist/esm/test/TestControl.js.map +1 -0
  349. package/docs/README.md +189 -0
  350. package/docs/api.md +982 -0
  351. package/docs/concepts/authority.md +109 -0
  352. package/docs/concepts/cancellation.md +129 -0
  353. package/docs/concepts/lineage.md +132 -0
  354. package/docs/concepts/ownership.md +139 -0
  355. package/docs/concepts/projections.md +203 -0
  356. package/docs/concepts/receipts.md +128 -0
  357. package/docs/guides/approvals.md +284 -0
  358. package/docs/guides/cancel-and-resume.md +162 -0
  359. package/docs/guides/durable-storage.md +147 -0
  360. package/docs/guides/implement-an-executor.md +173 -0
  361. package/docs/guides/ingest-a-webhook.md +177 -0
  362. package/docs/guides/list-runs.md +160 -0
  363. package/docs/guides/monitor-runs.md +176 -0
  364. package/docs/guides/observe-health.md +147 -0
  365. package/docs/guides/postgres-tests.md +7 -0
  366. package/docs/guides/serve-over-rpc.md +220 -0
  367. package/docs/guides/signal-a-run.md +53 -0
  368. package/docs/guides/steer-a-run.md +138 -0
  369. package/docs/guides/store-credentials.md +164 -0
  370. package/docs/guides/testing.md +139 -0
  371. package/docs/guides/watch-a-run.md +154 -0
  372. package/docs/installation.md +106 -0
  373. package/docs/quickstart.md +163 -0
  374. package/docs/troubleshooting.md +208 -0
  375. package/package.json +405 -3
  376. package/src/ApprovalAuthority.ts +114 -0
  377. package/src/Cancellation.ts +172 -0
  378. package/src/Channels.ts +493 -0
  379. package/src/Control.ts +337 -0
  380. package/src/ControlClient.ts +319 -0
  381. package/src/ControlError.ts +378 -0
  382. package/src/ControlExecutor.ts +490 -0
  383. package/src/ControlFacts.ts +383 -0
  384. package/src/ControlLive.ts +2127 -0
  385. package/src/ControlRpcs.ts +443 -0
  386. package/src/ControlRuntime.ts +1601 -0
  387. package/src/ControlSchema.ts +1380 -0
  388. package/src/ControlServer.ts +182 -0
  389. package/src/Credential.ts +310 -0
  390. package/src/CredentialCipher.ts +110 -0
  391. package/src/CredentialStore.ts +152 -0
  392. package/src/DispatchReader.ts +122 -0
  393. package/src/Health.ts +591 -0
  394. package/src/JevSessionChecker.ts +127 -0
  395. package/src/Lineage.ts +203 -0
  396. package/src/Migrations.ts +56 -0
  397. package/src/Monitor.ts +600 -0
  398. package/src/ScopedToken.ts +306 -0
  399. package/src/SqlControlRuntime.ts +2478 -0
  400. package/src/SqlCredentialStore.ts +148 -0
  401. package/src/Steering.ts +96 -0
  402. package/src/SystemFlows.ts +225 -0
  403. package/src/WebCryptoCipher.ts +169 -0
  404. package/src/WebhookChannel.ts +166 -0
  405. package/src/index.ts +188 -0
  406. package/src/internal/MutationBoundary.ts +46 -0
  407. package/src/internal/activeFibers.ts +22 -0
  408. package/src/internal/issues.ts +40 -0
  409. package/src/internal/planning.ts +262 -0
  410. package/src/internal/sqlSchemaErrors.ts +37 -0
  411. package/src/migrations/0001_control_tables.ts +99 -0
  412. package/src/migrations/0002_run_keys.ts +23 -0
  413. package/src/migrations/0003_signal_commands.ts +27 -0
  414. package/src/migrations/0004_approval_decisions.ts +25 -0
  415. package/src/migrations/0005_signal_principals.ts +27 -0
  416. package/src/migrations/0006_run_principals.ts +31 -0
  417. package/src/migrations/0007_resume_consent.ts +28 -0
  418. package/src/test/TestControl.ts +47 -0
@@ -0,0 +1,744 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var ControlRuntime_exports = {};
30
+ __export(ControlRuntime_exports, {
31
+ ApprovalDecision: () => ApprovalDecision,
32
+ ApprovalDenied: () => ApprovalDenied,
33
+ ApprovalPending: () => ApprovalPending,
34
+ ControlRuntime: () => ControlRuntime,
35
+ idPageLimit: () => idPageLimit,
36
+ launchedByMatches: () => launchedByMatches,
37
+ layerMemory: () => layerMemory,
38
+ make: () => make,
39
+ requireApproved: () => requireApproved
40
+ });
41
+ module.exports = __toCommonJS(ControlRuntime_exports);
42
+ var Fault = __toESM(require("@smthrs/flow/Fault"), 1);
43
+ var import_effect = require("effect");
44
+ var ApprovalAuthority = __toESM(require("./ApprovalAuthority.js"), 1);
45
+ var import_ControlError = require("./ControlError.js");
46
+ var import_ControlSchema = require("./ControlSchema.js");
47
+ var import_issues = require("./internal/issues.js");
48
+ var import_planning = require("./internal/planning.js");
49
+ var import_SystemFlows = require("./SystemFlows.js");
50
+ const launchedByMatches = (run, launcher) => run.launchedBy !== void 0 && run.launchedBy.id === launcher.id && (launcher.kind === void 0 || run.launchedBy.kind === launcher.kind);
51
+ const ApprovalDecision = import_effect.Schema.Union([
52
+ import_effect.Schema.Struct({ _tag: import_effect.Schema.Literal("Pending") }),
53
+ import_effect.Schema.Struct({
54
+ _tag: import_effect.Schema.Literal("Approved"),
55
+ decisionPrincipal: import_ControlSchema.Principal,
56
+ decidedAt: import_effect.Schema.Number.check(import_effect.Schema.isInt(), import_effect.Schema.isGreaterThanOrEqualTo(0)),
57
+ scope: import_ControlSchema.GrantScope
58
+ }),
59
+ import_effect.Schema.Struct({
60
+ _tag: import_effect.Schema.Literal("Denied"),
61
+ decisionPrincipal: import_ControlSchema.Principal,
62
+ decidedAt: import_effect.Schema.Number.check(import_effect.Schema.isInt(), import_effect.Schema.isGreaterThanOrEqualTo(0))
63
+ })
64
+ ]);
65
+ class ApprovalPending extends import_effect.Schema.TaggedError()("/control/ApprovalPending", {
66
+ tokenId: import_effect.Schema.String
67
+ }) {
68
+ get message() {
69
+ return "Approval is still pending. Wait for a decision before proceeding.";
70
+ }
71
+ }
72
+ class ApprovalDenied extends import_effect.Schema.TaggedError()("/control/ApprovalDenied", {
73
+ tokenId: import_effect.Schema.String,
74
+ decisionPrincipal: import_ControlSchema.Principal
75
+ }) {
76
+ get message() {
77
+ return "Approval was denied. This request cannot authorize the gated work.";
78
+ }
79
+ }
80
+ const requireApproved = (token) => token._tag === "Approved" ? import_effect.Effect.succeed(token) : token._tag === "Pending" ? import_effect.Effect.fail(new ApprovalPending({ tokenId: token.tokenId })) : import_effect.Effect.fail(new ApprovalDenied({ tokenId: token.tokenId, decisionPrincipal: token.decisionPrincipal }));
81
+ class ControlRuntime extends import_effect.Context.Service()(
82
+ "/control/ControlRuntime"
83
+ ) {
84
+ }
85
+ const make = (implementation) => ControlRuntime.of(implementation);
86
+ const idPageLimit = (limit) => Number.isSafeInteger(limit) && limit >= 1 && limit <= 500 ? import_effect.Effect.void : import_effect.Effect.fail(new import_ControlError.InvalidInput({ issue: "limit: must be an integer between 1 and 500" }));
87
+ const pageByPosition = (request, newest, idAt) => {
88
+ const through = request.through ?? newest;
89
+ const ids = [];
90
+ let position = request.after ?? 0;
91
+ let visited = 0;
92
+ while (position < through && visited < request.limit) {
93
+ position += 1;
94
+ visited += 1;
95
+ const id = idAt(position);
96
+ if (id !== void 0) ids.push(id);
97
+ }
98
+ return position < through ? { ids, next: position, through } : { ids, through };
99
+ };
100
+ const snapshot = (value) => structuredClone(value);
101
+ const asStored = (plan) => ({
102
+ card: snapshot(plan.card),
103
+ decodedInput: snapshot(plan.decodedInput),
104
+ decision: plan.decision
105
+ });
106
+ const approvalKey = (target) => target._tag === "Plan" ? JSON.stringify([target._tag, target.planId]) : JSON.stringify([target._tag, target.runId, target.requestId]);
107
+ const sameApprovalIdentity = (left, right) => left._tag === "Plan" ? right._tag === "Plan" && left.planId === right.planId : right._tag === "Node" && left.runId === right.runId && left.requestId === right.requestId;
108
+ const approvalToken = (token) => ({
109
+ tokenId: token.tokenId,
110
+ target: snapshot(token.target),
111
+ ...snapshot(token.decision)
112
+ });
113
+ const layerMemory = (options = {}) => import_effect.Layer.effect(
114
+ ControlRuntime,
115
+ import_effect.Effect.gen(function* () {
116
+ const crypto = yield* import_effect.Crypto.Crypto;
117
+ const now = options.now ?? Date.now;
118
+ const approvalAuthority = options.approvalAuthority ?? (yield* ApprovalAuthority.make([
119
+ {
120
+ principal: { id: "local", kind: "operator" },
121
+ scopes: ["once", "run", "remembered"],
122
+ targets: ["Plan", "Node"]
123
+ },
124
+ { principal: { id: "memory", kind: "test" }, scopes: ["once", "run", "remembered"], targets: ["Plan", "Node"] }
125
+ ]).pipe(import_effect.Effect.orDie));
126
+ const authorizeApproval = approvalAuthority.authorize.bind(approvalAuthority);
127
+ const configuredFlows = options.flows ?? import_SystemFlows.plannable.map((entry) => ({
128
+ flowId: entry.flowId,
129
+ description: `Reserved ${entry.verb} system flow`,
130
+ deployClass: entry.deployClass,
131
+ envelope: import_planning.emptyEnvelope
132
+ }));
133
+ const flows = new Map(configuredFlows.map(
134
+ (flow) => [
135
+ flow.flowId,
136
+ { ...flow, envelope: snapshot(flow.envelope) }
137
+ ]
138
+ ));
139
+ const plans = /* @__PURE__ */ new Map();
140
+ const planKeys = /* @__PURE__ */ new Map();
141
+ const tokens = /* @__PURE__ */ new Map();
142
+ const runs = /* @__PURE__ */ new Map();
143
+ const mutations = /* @__PURE__ */ new Map();
144
+ const runKeys = /* @__PURE__ */ new Map();
145
+ const installedGrants = [];
146
+ const installedGrantKeys = /* @__PURE__ */ new Set();
147
+ let planSequence = 0;
148
+ const signalCommands = /* @__PURE__ */ new Map();
149
+ let pendingSignalOffset = 0;
150
+ let runSequence = 0;
151
+ let fenceSequence = 0;
152
+ let resumeSequence = 0;
153
+ const requireRun = (runId) => import_effect.Effect.fromOption(import_effect.Option.fromNullishOr(runs.get(runId)), () => new import_ControlError.RunNotFound({ runId }));
154
+ const updateSummary = (run, fields) => {
155
+ run.summary = snapshot({ ...run.summary, ...fields, updatedAt: now() });
156
+ return snapshot(run.summary);
157
+ };
158
+ const checkFence = (runId, run, fence) => run.fence === void 0 || run.fence !== fence ? import_effect.Effect.fail(new import_ControlError.ClaimLost({ runId })) : import_effect.Effect.void;
159
+ const resumeRun = (runId, adopt) => import_effect.Effect.gen(function* () {
160
+ const run = yield* requireRun(runId);
161
+ if (run.summary.status === "cancelled" || run.summary.status === "completed" || run.summary.status === "failed") return snapshot(run.summary);
162
+ if (run.fence !== void 0) {
163
+ if (run.localFence === void 0 || run.fence !== run.localFence) {
164
+ return yield* new import_ControlError.ClaimLost({ runId });
165
+ }
166
+ return snapshot(run.summary);
167
+ }
168
+ const adopted = adopt === void 0 ? void 0 : yield* adopt(run);
169
+ const fence = `fence-${++fenceSequence}`;
170
+ run.fence = fence;
171
+ run.localFence = fence;
172
+ return updateSummary(run, {
173
+ ...adopted,
174
+ status: "accepted",
175
+ ownerId: "memory-owner",
176
+ parkedBy: void 0
177
+ });
178
+ });
179
+ const service = make({
180
+ authorizeApproval,
181
+ plan: import_effect.Effect.fn("ControlRuntime.plan")(function* (input) {
182
+ const flow = flows.get(input.flowId);
183
+ if (flow === void 0) return yield* new import_ControlError.FlowNotFound({ flowId: input.flowId });
184
+ const requestFingerprint = yield* import_effect.Effect.try({
185
+ // Validate before cloning. Canonicalization reports a throwing
186
+ // getter at its stable path, while `structuredClone` would invoke
187
+ // the getter first and erase that safe diagnostic.
188
+ try: () => (0, import_planning.planFingerprint)(input),
189
+ catch: (cause) => new import_ControlError.InvalidInput({ issue: (0, import_issues.canonicalIssue)(cause) })
190
+ });
191
+ const submitted = yield* import_effect.Effect.try({
192
+ try: () => snapshot(input),
193
+ catch: (cause) => new import_ControlError.InvalidInput({ issue: (0, import_issues.canonicalIssue)(cause) })
194
+ });
195
+ if (submitted.idempotencyKey !== void 0) {
196
+ const prior = planKeys.get(submitted.idempotencyKey);
197
+ if (prior !== void 0) {
198
+ if (prior.fingerprint !== requestFingerprint) {
199
+ return yield* new import_ControlError.InvalidInput({
200
+ issue: `idempotency key ${submitted.idempotencyKey} was used for another plan`
201
+ });
202
+ }
203
+ const stored = plans.get(prior.planId);
204
+ if (stored !== void 0) return { card: snapshot(stored.card), created: false };
205
+ }
206
+ }
207
+ const decoded = yield* flow.decode?.(submitted.input) ?? import_effect.Effect.try({
208
+ try: () => {
209
+ (0, import_planning.canonical)(submitted.input);
210
+ return submitted.input;
211
+ },
212
+ catch: (cause) => new import_ControlError.InvalidInput({ issue: (0, import_issues.canonicalIssue)(cause) })
213
+ });
214
+ const planId = `plan-${++planSequence}`;
215
+ const handoff = flow.plan === void 0 ? void 0 : yield* flow.plan(decoded, planId);
216
+ const card = snapshot(
217
+ yield* (0, import_planning.planCard)({
218
+ planId,
219
+ flowId: submitted.flowId,
220
+ decodedInput: decoded,
221
+ envelope: (0, import_planning.budgeted)(flow.envelope, submitted.budget),
222
+ deployClass: flow.deployClass,
223
+ executionDigest: flow.executionDigest,
224
+ handoff,
225
+ idempotencyKey: submitted.idempotencyKey
226
+ }).pipe(import_effect.Effect.provideService(import_effect.Crypto.Crypto, crypto))
227
+ );
228
+ if (submitted.idempotencyKey !== void 0) {
229
+ const prior = planKeys.get(submitted.idempotencyKey);
230
+ if (prior !== void 0) {
231
+ if (prior.fingerprint !== requestFingerprint) {
232
+ return yield* new import_ControlError.InvalidInput({
233
+ issue: `idempotency key ${submitted.idempotencyKey} was used for another plan`
234
+ });
235
+ }
236
+ const stored = plans.get(prior.planId);
237
+ if (stored !== void 0) return { card: snapshot(stored.card), created: false };
238
+ }
239
+ }
240
+ plans.set(planId, { card, decodedInput: snapshot(decoded), decision: "pending" });
241
+ tokens.set(approvalKey(card.approval.target), {
242
+ tokenId: planId,
243
+ target: snapshot(card.approval.target),
244
+ decision: { _tag: "Pending" }
245
+ });
246
+ if (submitted.idempotencyKey !== void 0) {
247
+ planKeys.set(submitted.idempotencyKey, {
248
+ fingerprint: requestFingerprint,
249
+ planId
250
+ });
251
+ }
252
+ return { card: snapshot(card), created: true };
253
+ }),
254
+ getPlan: import_effect.Effect.fn("ControlRuntime.getPlan")(
255
+ (planId) => import_effect.Effect.fromOption(import_effect.Option.fromNullishOr(plans.get(planId)), () => new import_ControlError.PlanNotFound({ planId })).pipe(
256
+ import_effect.Effect.map(asStored)
257
+ )
258
+ ),
259
+ pagePlanIds: import_effect.Effect.fn("ControlRuntime.pagePlanIds")(function* (request) {
260
+ yield* idPageLimit(request.limit);
261
+ return pageByPosition(
262
+ request,
263
+ planSequence,
264
+ (position) => plans.has(`plan-${position}`) ? `plan-${position}` : void 0
265
+ );
266
+ }),
267
+ queryPlans: import_effect.Effect.fn("ControlRuntime.queryPlans")(function* (request) {
268
+ yield* idPageLimit(request.limit);
269
+ const matched = [];
270
+ let position = request.after ?? 0;
271
+ while (position < planSequence && matched.length < request.limit) {
272
+ position += 1;
273
+ const plan = plans.get(`plan-${position}`);
274
+ if (plan !== void 0 && (request.flowId === void 0 || plan.card.flowId === request.flowId) && (request.decision === void 0 || plan.decision === request.decision)) matched.push(asStored(plan));
275
+ }
276
+ return position < planSequence ? { plans: matched, next: position } : { plans: matched };
277
+ }),
278
+ lookupApproval: import_effect.Effect.fn("ControlRuntime.lookupApproval")(function* (target) {
279
+ const requested = snapshot(target);
280
+ const tokenId = requested._tag === "Plan" ? requested.planId : requested.requestId;
281
+ const token = yield* import_effect.Effect.fromOption(
282
+ import_effect.Option.fromNullishOr(tokens.get(approvalKey(requested))),
283
+ () => requested._tag === "Node" ? new import_ControlError.RunNotFound({ runId: requested.runId }) : new import_ControlError.PlanNotFound({ planId: requested.planId })
284
+ );
285
+ if (!sameApprovalIdentity(token.target, requested)) {
286
+ return yield* new import_ControlError.PersistenceError({
287
+ operation: "validate an approval token",
288
+ message: "The stored approval target does not match its identity"
289
+ });
290
+ }
291
+ if (token.target.digest !== requested.digest) {
292
+ return yield* new import_ControlError.PlanDigestMismatch({
293
+ planId: tokenId,
294
+ expected: token.target.digest,
295
+ actual: requested.digest
296
+ });
297
+ }
298
+ if (!(0, import_planning.sameEnvelope)(token.target.envelope, requested.envelope)) {
299
+ return yield* new import_ControlError.EnvelopeMismatch({
300
+ planId: tokenId,
301
+ expected: (0, import_planning.canonical)(token.target.envelope),
302
+ actual: (0, import_planning.canonical)(requested.envelope)
303
+ });
304
+ }
305
+ if (token.decision._tag !== "Pending") return yield* new import_ControlError.AlreadyResolved({ requestId: tokenId });
306
+ return approvalToken(token);
307
+ }),
308
+ registerApproval: import_effect.Effect.fn("ControlRuntime.registerApproval")(function* (target) {
309
+ const requested = snapshot(target);
310
+ yield* requireRun(requested.runId);
311
+ const key = approvalKey(requested);
312
+ const existing = tokens.get(key);
313
+ if (existing === void 0) {
314
+ const stored = {
315
+ tokenId: requested.requestId,
316
+ target: requested,
317
+ decision: { _tag: "Pending" }
318
+ };
319
+ tokens.set(key, stored);
320
+ return approvalToken(stored);
321
+ }
322
+ if (!sameApprovalIdentity(existing.target, requested)) {
323
+ return yield* new import_ControlError.PersistenceError({
324
+ operation: "validate an approval token",
325
+ message: "The stored approval target does not match its identity"
326
+ });
327
+ }
328
+ if (existing.target.digest !== requested.digest) {
329
+ return yield* new import_ControlError.PlanDigestMismatch({
330
+ planId: requested.requestId,
331
+ expected: existing.target.digest,
332
+ actual: requested.digest
333
+ });
334
+ }
335
+ if (!(0, import_planning.sameEnvelope)(existing.target.envelope, requested.envelope)) {
336
+ return yield* new import_ControlError.EnvelopeMismatch({
337
+ planId: requested.requestId,
338
+ expected: (0, import_planning.canonical)(existing.target.envelope),
339
+ actual: (0, import_planning.canonical)(requested.envelope)
340
+ });
341
+ }
342
+ return approvalToken(existing);
343
+ }),
344
+ installBulkGrant: import_effect.Effect.fn("ControlRuntime.installBulkGrant")(
345
+ (token, envelope, scope) => import_effect.Effect.sync(() => {
346
+ const storedToken = snapshot(token);
347
+ const key = approvalKey(storedToken.target);
348
+ if (installedGrantKeys.has(key)) return;
349
+ installedGrantKeys.add(key);
350
+ installedGrants.push({
351
+ tokenId: storedToken.tokenId,
352
+ envelope: snapshot(envelope),
353
+ scope,
354
+ installedAt: now()
355
+ });
356
+ })
357
+ ),
358
+ resolveApproval: import_effect.Effect.fn("ControlRuntime.resolveApproval")(
359
+ function* (token, decision, principal, scope = "once") {
360
+ const requested = snapshot(token);
361
+ const requestedPrincipal = snapshot(principal);
362
+ const answer = yield* import_effect.Schema.decodeUnknownEffect(ApprovalDecision)(
363
+ decision === "approved" ? { _tag: "Approved", decisionPrincipal: requestedPrincipal, decidedAt: now(), scope } : { _tag: "Denied", decisionPrincipal: requestedPrincipal, decidedAt: now() }
364
+ ).pipe(
365
+ import_effect.Effect.mapError(
366
+ () => new import_ControlError.PersistenceError({
367
+ operation: "record an approval decision",
368
+ message: "The approval decision metadata is invalid"
369
+ })
370
+ )
371
+ );
372
+ yield* authorizeApproval({ principal: requestedPrincipal, target: requested.target, decision, scope });
373
+ const mutable = tokens.get(approvalKey(requested.target));
374
+ if (mutable === void 0 || mutable.decision._tag !== "Pending") {
375
+ return yield* new import_ControlError.AlreadyResolved({ requestId: requested.tokenId });
376
+ }
377
+ mutable.decision = answer;
378
+ if (requested.target._tag === "Plan") {
379
+ const plan = plans.get(requested.target.planId);
380
+ if (plan !== void 0) plan.decision = decision;
381
+ }
382
+ }
383
+ ),
384
+ launch: import_effect.Effect.fn("ControlRuntime.launch")(
385
+ function* (planId, requestedDigest, envelope, principal, reservedRunId) {
386
+ const plan = yield* import_effect.Effect.fromOption(
387
+ import_effect.Option.fromNullishOr(plans.get(planId)),
388
+ () => new import_ControlError.PlanNotFound({ planId })
389
+ );
390
+ if (plan.card.digest !== requestedDigest) {
391
+ return yield* new import_ControlError.PlanDigestMismatch({
392
+ planId,
393
+ expected: plan.card.digest,
394
+ actual: requestedDigest
395
+ });
396
+ }
397
+ if (!(0, import_planning.sameEnvelope)(plan.card.envelope, envelope)) {
398
+ return yield* new import_ControlError.EnvelopeMismatch({
399
+ planId,
400
+ expected: (0, import_planning.canonical)(plan.card.envelope),
401
+ actual: (0, import_planning.canonical)(envelope)
402
+ });
403
+ }
404
+ if (plan.decision === "pending") {
405
+ return {
406
+ _tag: "Parked",
407
+ receipt: {
408
+ _tag: "Parked",
409
+ receiptId: `launch:${planId}`,
410
+ planId,
411
+ status: "waiting-approval"
412
+ }
413
+ };
414
+ }
415
+ if (plan.decision !== "approved") {
416
+ return yield* new import_ControlError.PlanDenied({ planId });
417
+ }
418
+ const sequence = ++runSequence;
419
+ const runId = reservedRunId ?? `run-${sequence}`;
420
+ if (runs.has(runId)) {
421
+ return yield* new import_ControlError.PersistenceError({ operation: "reserve a run", message: "Run identity already exists" });
422
+ }
423
+ const fence = `fence-${++fenceSequence}`;
424
+ const timestamp = now();
425
+ const summary = {
426
+ runId,
427
+ flowId: plan.card.flowId,
428
+ status: "accepted",
429
+ planId,
430
+ planDigest: plan.card.digest,
431
+ ...plan.card.executionDigest === void 0 ? {} : { executionDigest: plan.card.executionDigest },
432
+ ...options.engineVersion === void 0 ? {} : { engineVersion: options.engineVersion },
433
+ ownerId: "memory-owner",
434
+ ...principal === void 0 ? {} : { launchedBy: { id: principal.id, kind: principal.kind } },
435
+ ...plan.card.envelope.budget.deadline === void 0 ? {} : { deadlineAt: timestamp + plan.card.envelope.budget.deadline },
436
+ createdAt: timestamp,
437
+ updatedAt: timestamp
438
+ };
439
+ runs.set(runId, {
440
+ summary: snapshot(summary),
441
+ fence,
442
+ localFence: fence,
443
+ sequence: runSequence,
444
+ signals: []
445
+ });
446
+ return {
447
+ _tag: "Started",
448
+ receipt: (0, import_planning.accepted)(`launch:${planId}:${runId}`, runId),
449
+ run: snapshot(summary)
450
+ };
451
+ }
452
+ ),
453
+ getRun: import_effect.Effect.fn("ControlRuntime.getRun")(
454
+ (runId) => import_effect.Effect.map(requireRun(runId), (run) => snapshot(run.summary))
455
+ ),
456
+ pageRunIds: import_effect.Effect.fn("ControlRuntime.pageRunIds")(function* (request) {
457
+ yield* idPageLimit(request.limit);
458
+ return pageByPosition(
459
+ request,
460
+ runSequence,
461
+ (position) => runs.has(`run-${position}`) ? `run-${position}` : void 0
462
+ );
463
+ }),
464
+ queryRuns: import_effect.Effect.fn("ControlRuntime.queryRuns")(function* (request) {
465
+ if (!Number.isSafeInteger(request.limit) || request.limit < 1 || request.limit > 500) {
466
+ return yield* new import_ControlError.InvalidInput({ issue: "limit: must be an integer between 1 and 500" });
467
+ }
468
+ const selected = [];
469
+ const filters = request.filters;
470
+ const newest = request.order === "newest";
471
+ const oldest = request.order === "oldest";
472
+ const candidates = newest ? Array.from(runs.values()).sort(
473
+ (a, b) => b.summary.createdAt - a.summary.createdAt || b.sequence - a.sequence
474
+ ) : oldest ? Array.from(runs.values()).sort(
475
+ (a, b) => a.summary.createdAt - b.summary.createdAt || a.sequence - b.sequence
476
+ ) : runs.values();
477
+ for (const run of candidates) {
478
+ const after = request.cursor;
479
+ if (after !== void 0 && (after.source !== 0 || (newest ? run.summary.createdAt > after.createdAt || run.summary.createdAt === after.createdAt && run.sequence >= after.sequence : oldest ? run.summary.createdAt < after.createdAt || run.summary.createdAt === after.createdAt && run.sequence <= after.sequence : run.sequence <= after.sequence))) continue;
480
+ const summary = run.summary;
481
+ if (filters?.since !== void 0 && summary.createdAt < filters.since) continue;
482
+ if (filters?.until !== void 0 && summary.createdAt >= filters.until) continue;
483
+ if (filters?.runIds !== void 0 && !filters.runIds.includes(summary.runId)) continue;
484
+ if (filters?.flowId !== void 0 && summary.flowId !== filters.flowId) continue;
485
+ if (filters?.status !== void 0 && summary.status !== filters.status) continue;
486
+ if (filters?.terminal !== void 0 && ["completed", "failed", "cancelled"].includes(summary.status) !== filters.terminal) continue;
487
+ if (filters?.parentRunId !== void 0 && summary.parentRunId !== filters.parentRunId) continue;
488
+ if (filters?.lineageId !== void 0 && summary.lineageId !== filters.lineageId) continue;
489
+ if (filters?.launchedBy !== void 0 && !launchedByMatches(summary, filters.launchedBy)) continue;
490
+ selected.push(run);
491
+ if (selected.length > request.limit) break;
492
+ }
493
+ const page = selected.slice(0, request.limit);
494
+ const last = page.at(-1);
495
+ return {
496
+ items: page.map((run) => snapshot(run.summary)),
497
+ ...selected.length <= request.limit || last === void 0 ? {} : {
498
+ nextCursor: {
499
+ source: 0,
500
+ sequence: last.sequence,
501
+ createdAt: last.summary.createdAt,
502
+ runId: last.summary.runId
503
+ }
504
+ }
505
+ };
506
+ }),
507
+ listFlows: import_effect.Effect.fn("ControlRuntime.listFlows")(
508
+ () => import_effect.Effect.sync(
509
+ () => Array.from(flows.values(), (flow) => ({
510
+ flowId: flow.flowId,
511
+ description: flow.description
512
+ }))
513
+ )
514
+ )(),
515
+ deliverSignal: import_effect.Effect.fn("ControlRuntime.deliverSignal")(
516
+ (runId, signal) => import_effect.Effect.tap(requireRun(runId), (run) => import_effect.Effect.sync(() => void run.signals.push(snapshot(signal))))
517
+ ),
518
+ admitSignal: import_effect.Effect.fn("ControlRuntime.admitSignal")(function* (commandId, runId, signal, principal) {
519
+ yield* requireRun(runId);
520
+ if (!signalCommands.has(commandId)) {
521
+ signalCommands.set(
522
+ commandId,
523
+ snapshot({
524
+ commandId,
525
+ runId,
526
+ signal,
527
+ token: null,
528
+ state: "pending",
529
+ ...principal === void 0 ? {} : { principal }
530
+ })
531
+ );
532
+ }
533
+ }),
534
+ signalCommand: (commandId) => import_effect.Effect.sync(() => snapshot(signalCommands.get(commandId))),
535
+ pendingSignals: import_effect.Effect.sync(() => {
536
+ const pending = Array.from(signalCommands.values()).filter((command) => command.state === "pending");
537
+ if (pendingSignalOffset >= pending.length) pendingSignalOffset = 0;
538
+ const page = pending.slice(pendingSignalOffset, pendingSignalOffset + 100);
539
+ pendingSignalOffset += page.length;
540
+ return snapshot(page);
541
+ }),
542
+ bindSignal: (commandId, token) => import_effect.Effect.gen(function* () {
543
+ const command = signalCommands.get(commandId);
544
+ if (command === void 0) {
545
+ return yield* new import_ControlError.PersistenceError({
546
+ operation: "bind signal",
547
+ message: `No pending signal command ${commandId}`
548
+ });
549
+ }
550
+ if (command.state !== "pending") return command.token;
551
+ if (command.token === null && Array.from(signalCommands.values()).some(
552
+ (other) => other.commandId !== commandId && other.token === token
553
+ )) return null;
554
+ const bound = command.token ?? token;
555
+ signalCommands.set(commandId, { ...command, token: bound });
556
+ return bound;
557
+ }),
558
+ settleSignal: (commandId, state) => import_effect.Effect.sync(() => {
559
+ const command = signalCommands.get(commandId);
560
+ if (command !== void 0 && command.state === "pending") {
561
+ signalCommands.set(commandId, { ...command, state });
562
+ }
563
+ }),
564
+ deliveredSignals: import_effect.Effect.fn("ControlRuntime.deliveredSignals")(
565
+ (runId) => import_effect.Effect.map(
566
+ requireRun(runId),
567
+ (run) => snapshot([
568
+ ...run.signals,
569
+ ...Array.from(signalCommands.values()).filter(
570
+ (command) => command.runId === runId && command.state !== "rejected"
571
+ ).map((command) => command.signal)
572
+ ])
573
+ )
574
+ ),
575
+ requestResume: import_effect.Effect.fn("ControlRuntime.requestResume")(function* (runId, options2) {
576
+ const run = yield* requireRun(runId);
577
+ if (run.summary.status === "cancelled" || run.summary.status === "completed" || run.summary.status === "failed") {
578
+ return yield* new import_ControlError.InvalidInput({
579
+ issue: `run ${runId} is ${run.summary.status} and cannot take a resume`
580
+ });
581
+ }
582
+ const sequence = ++resumeSequence;
583
+ run.pendingResume = sequence;
584
+ run.pendingResumeAtMs = now();
585
+ run.pendingConsent = options2?.consent ?? run.pendingConsent;
586
+ updateSummary(run, { pendingResume: sequence });
587
+ return sequence;
588
+ }),
589
+ pendingResumes: import_effect.Effect.sync(
590
+ () => Array.from(runs.entries()).flatMap(
591
+ ([runId, run]) => run.pendingResume === void 0 || run.pendingResumeAtMs === void 0 || run.summary.status === "cancelled" || run.summary.status === "completed" || run.summary.status === "failed" ? [] : [{
592
+ runId,
593
+ sequence: run.pendingResume,
594
+ requestedAtMs: run.pendingResumeAtMs,
595
+ ...run.pendingConsent === void 0 ? {} : { consent: run.pendingConsent }
596
+ }]
597
+ )
598
+ ),
599
+ clearResume: import_effect.Effect.fn("ControlRuntime.clearResume")(
600
+ (runId, sequence) => import_effect.Effect.sync(() => {
601
+ const run = runs.get(runId);
602
+ if (run === void 0 || run.pendingResume !== sequence) return;
603
+ run.pendingResume = void 0;
604
+ run.pendingResumeAtMs = void 0;
605
+ run.pendingConsent = void 0;
606
+ updateSummary(run, { pendingResume: void 0 });
607
+ })
608
+ ),
609
+ registerFiber: import_effect.Effect.fn("ControlRuntime.registerFiber")(
610
+ (runId, fiber) => import_effect.Effect.tap(requireRun(runId), (run) => import_effect.Effect.sync(() => {
611
+ run.fiber = fiber;
612
+ fiber.addObserver(() => {
613
+ if (run.fiber === fiber) run.fiber = void 0;
614
+ });
615
+ }))
616
+ ),
617
+ interrupt: import_effect.Effect.fn("ControlRuntime.interrupt")(function* (runId, settle = (effect) => effect) {
618
+ const run = yield* requireRun(runId);
619
+ if (run.summary.status === "cancelled" || run.summary.status === "completed" || run.summary.status === "failed") return snapshot(run.summary);
620
+ if (run.localFence === void 0) return yield* new import_ControlError.ClaimLost({ runId });
621
+ const fence = run.localFence;
622
+ yield* checkFence(runId, run, fence);
623
+ if (run.fiber !== void 0) yield* import_effect.Fiber.interrupt(run.fiber);
624
+ return yield* settle(import_effect.Effect.gen(function* () {
625
+ if (run.summary.status === "cancelled" || run.summary.status === "completed" || run.summary.status === "failed") return snapshot(run.summary);
626
+ yield* checkFence(runId, run, fence);
627
+ run.fence = void 0;
628
+ run.localFence = void 0;
629
+ return updateSummary(run, { status: "cancelled", ownerId: void 0, parkedBy: void 0 });
630
+ }));
631
+ }),
632
+ codeDrift: import_effect.Effect.fn("ControlRuntime.codeDrift")(function* (runId) {
633
+ const run = yield* requireRun(runId);
634
+ return (0, import_planning.codeDriftOf)(run.summary, flows.get(run.summary.flowId), options.engineVersion);
635
+ }),
636
+ recordedCode: import_effect.Effect.fn("ControlRuntime.recordedCode")(function* (runId) {
637
+ const { executionDigest, engineVersion } = (yield* requireRun(runId)).summary;
638
+ return { executionDigest, engineVersion };
639
+ }),
640
+ resume: import_effect.Effect.fn("ControlRuntime.resume")((runId) => resumeRun(runId)),
641
+ // `plan` refuses a flow this catalog does not hold, and the catalog is
642
+ // fixed at construction, so a run's flow is never gone here and there
643
+ // is always code to adopt. `SqlControlRuntime` reads a catalog that can
644
+ // lose a flow, and refuses that case before the claim.
645
+ resumeAdopting: import_effect.Effect.fn("ControlRuntime.resumeAdopting")(
646
+ (runId) => resumeRun(
647
+ runId,
648
+ (run) => import_effect.Effect.succeed((0, import_planning.adoptedCode)(run.summary, flows.get(run.summary.flowId), options.engineVersion))
649
+ )
650
+ ),
651
+ claimFence: import_effect.Effect.fn("ControlRuntime.claimFence")(function* (runId) {
652
+ const run = yield* requireRun(runId);
653
+ if (run.localFence === void 0) return yield* new import_ControlError.ClaimLost({ runId });
654
+ return run.localFence;
655
+ }),
656
+ releasePending: import_effect.Effect.fn("ControlRuntime.releasePending")(function* (runId, fence) {
657
+ const run = yield* requireRun(runId);
658
+ yield* checkFence(runId, run, fence);
659
+ run.fence = void 0;
660
+ run.localFence = void 0;
661
+ return updateSummary(run, {
662
+ status: "accepted",
663
+ ownerId: void 0,
664
+ parkedBy: void 0
665
+ });
666
+ }),
667
+ writeStatus: import_effect.Effect.fn("ControlRuntime.writeStatus")(function* (runId, fence, status) {
668
+ const run = yield* requireRun(runId);
669
+ yield* checkFence(runId, run, fence);
670
+ if (status === "accepted" || status === "running") {
671
+ return updateSummary(run, { status, parkedBy: void 0 });
672
+ }
673
+ run.fence = void 0;
674
+ run.localFence = void 0;
675
+ return updateSummary(run, {
676
+ status,
677
+ ownerId: void 0,
678
+ parkedBy: status === "parked" || status === "waiting-approval" ? fence : void 0
679
+ });
680
+ }),
681
+ // Precedence matches `SqlControlRuntime`: the submitted identity is
682
+ // the one a server authenticated, and the configured one is this
683
+ // composition's fallback for a caller that named none.
684
+ stampPrincipal: import_effect.Effect.fn("ControlRuntime.stampPrincipal")(
685
+ (submitted) => import_effect.Effect.sync(() => ({
686
+ id: submitted?.id ?? options.principal?.id ?? "memory",
687
+ kind: submitted?.kind ?? options.principal?.kind ?? "test",
688
+ stampedAt: now()
689
+ }))
690
+ ),
691
+ lookupMutation: import_effect.Effect.fn("ControlRuntime.lookupMutation")(
692
+ (key, fingerprint) => import_effect.Effect.sync(() => {
693
+ const record = mutations.get(key);
694
+ if (record === void 0) return void 0;
695
+ return record.fingerprint === fingerprint ? (0, import_planning.alreadyApplied)(key, record.receipt) : { _tag: "Conflict", message: `idempotency key ${key} was used for another mutation` };
696
+ })
697
+ ),
698
+ recordMutation: import_effect.Effect.fn("ControlRuntime.recordMutation")(
699
+ (key, fingerprint, receipt) => import_effect.Effect.gen(function* () {
700
+ const prior = mutations.get(key);
701
+ if (prior !== void 0 && (prior.fingerprint !== fingerprint || (0, import_planning.canonical)(prior.receipt) !== (0, import_planning.canonical)(receipt))) {
702
+ return yield* import_effect.Effect.fail(
703
+ new import_ControlError.PersistenceError({
704
+ operation: "record a mutation",
705
+ message: `Idempotency key ${key} was already settled by another mutation`
706
+ })
707
+ );
708
+ }
709
+ mutations.set(key, { fingerprint, receipt: snapshot(receipt) });
710
+ })
711
+ ),
712
+ claimRunKey: import_effect.Effect.fn("ControlRuntime.claimRunKey")(function* (key, fingerprint) {
713
+ const holder = runKeys.get(key);
714
+ if (holder !== void 0) {
715
+ if (holder.fingerprint !== fingerprint) {
716
+ return yield* new import_ControlError.InvalidInput({
717
+ issue: `idempotency key ${key} was used for another run`
718
+ });
719
+ }
720
+ const record = mutations.get(key);
721
+ if (record === void 0) {
722
+ return yield* new import_ControlError.PersistenceError({
723
+ operation: "read a mutation",
724
+ message: `run key ${key} was claimed by a mutation that recorded no receipt`
725
+ });
726
+ }
727
+ return { _tag: "Raced", receipt: snapshot(record.receipt) };
728
+ }
729
+ runKeys.set(key, { fingerprint });
730
+ return { _tag: "Claimed" };
731
+ }),
732
+ releaseRunKey: import_effect.Effect.fn("ControlRuntime.releaseRunKey")(
733
+ (key) => import_effect.Effect.sync(() => {
734
+ runKeys.delete(key);
735
+ })
736
+ ),
737
+ grants: import_effect.Effect.fn("ControlRuntime.grants")(() => import_effect.Effect.sync(() => snapshot(installedGrants)))()
738
+ });
739
+ return service;
740
+ })
741
+ );
742
+ Fault.register("/control/ApprovalPending", "wait");
743
+ Fault.register("/control/ApprovalDenied", "user");
744
+ //# sourceMappingURL=ControlRuntime.js.map