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

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 +1280 -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 +740 -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 +1521 -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 +1585 -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 +807 -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 +5 -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 +2113 -0
  385. package/src/ControlRpcs.ts +443 -0
  386. package/src/ControlRuntime.ts +1597 -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 +2476 -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,262 @@
1
+ /**
2
+ * Plan construction shared by every `ControlRuntime` implementation.
3
+ *
4
+ * The plan digest is what an approval is bound to, so the memory runtime and
5
+ * the durable runtime must compute it the same way or an approval taken on one
6
+ * would not validate on the other. Keeping the construction here is what makes
7
+ * that a compile-time fact rather than a convention.
8
+ *
9
+ * @since 0.1.0
10
+ */
11
+
12
+ import { canonicalize } from "@smthrs/canonical"
13
+ import { Sha256 } from "@smthrs/crypto"
14
+ import * as Sha256Digest from "@smthrs/crypto/Sha256"
15
+ import type * as PersistedPlan from "@smthrs/plan/Plan"
16
+ import { Effect, Schema } from "effect"
17
+ import type { ApprovalTarget, PlanInput } from "../Control.ts"
18
+ import { CodeDrift } from "../ControlError.ts"
19
+ import type {
20
+ Envelope,
21
+ FlowId,
22
+ IdempotencyKey,
23
+ PlanCard,
24
+ PlanGraph,
25
+ PlanNode,
26
+ Principal,
27
+ Receipt,
28
+ RunId,
29
+ RunSummary
30
+ } from "../ControlSchema.ts"
31
+
32
+ /**
33
+ * The drift between the code a run recorded and the code that would resume
34
+ * it, or `undefined` when there is none. A run that recorded no digest (a flow
35
+ * without one, or a row older than the field) is not checked for flow drift,
36
+ * and one that recorded no engine version is not checked for engine drift.
37
+ *
38
+ * @since 1.0.0
39
+ * @private
40
+ */
41
+ export const codeDriftOf = (
42
+ run: RunSummary,
43
+ flow: { readonly executionDigest?: string | undefined } | undefined,
44
+ engineVersion: string | undefined
45
+ ): CodeDrift | undefined => {
46
+ const flowDrift = run.executionDigest !== undefined && flow?.executionDigest !== run.executionDigest
47
+ const engineDrift = run.engineVersion !== undefined && engineVersion !== undefined &&
48
+ engineVersion !== run.engineVersion
49
+ if (!flowDrift && !engineDrift) return undefined
50
+ return new CodeDrift({
51
+ runId: run.runId,
52
+ flowId: run.flowId,
53
+ ...(flowDrift ? { recorded: run.executionDigest } : {}),
54
+ ...(flowDrift && flow?.executionDigest !== undefined ? { current: flow.executionDigest } : {}),
55
+ ...(engineDrift ? { recordedEngine: run.engineVersion, currentEngine: engineVersion } : {})
56
+ })
57
+ }
58
+
59
+ /**
60
+ * The code identity a resume the operator allowed to drift records on the run,
61
+ * so later checks compare against the code it now runs.
62
+ *
63
+ * @since 1.0.0
64
+ * @private
65
+ */
66
+ export const adoptedCode = (
67
+ run: RunSummary,
68
+ flow: { readonly executionDigest?: string | undefined } | undefined,
69
+ engineVersion: string | undefined
70
+ ): Pick<RunSummary, "executionDigest" | "engineVersion"> => ({
71
+ executionDigest: flow?.executionDigest,
72
+ engineVersion: engineVersion ?? run.engineVersion
73
+ })
74
+
75
+ /**
76
+ * The envelope a flow with no declared capabilities carries.
77
+ *
78
+ * @since 0.1.0
79
+ * @private
80
+ */
81
+ export const emptyEnvelope: Envelope = {
82
+ capabilities: [],
83
+ flows: [],
84
+ budget: {}
85
+ }
86
+
87
+ /**
88
+ * Canonical bytes for a value.
89
+ * Throws on a non-serializable value; every caller either wraps it in
90
+ * `Effect.try` or has already validated the value.
91
+ *
92
+ * @since 0.1.0
93
+ * @private
94
+ */
95
+ export const canonical = (value: unknown): string => canonicalize(value)
96
+
97
+ /**
98
+ * The durable key a caller's idempotency key is stored under.
99
+ *
100
+ * Namespaced by the effective actor: the submitted principal, or the runtime's
101
+ * configured fallback when the caller named none. The principal's clock is
102
+ * omitted, so an equal retry lands on the same key.
103
+ *
104
+ * @since 0.1.0
105
+ * @private
106
+ */
107
+ export const mutationKey = (
108
+ operation: string,
109
+ key: IdempotencyKey,
110
+ principal: Pick<Principal, "id" | "kind">
111
+ ): string =>
112
+ `${operation}:actor:${Sha256Digest.digestSync(canonical({ id: principal.id, kind: principal.kind }))}:${key}`
113
+
114
+ /**
115
+ * The content digest of a value's canonical bytes.
116
+ *
117
+ * @since 0.1.0
118
+ * @private
119
+ */
120
+ export const digest = (value: unknown) => Schema.decodeUnknownEffect(Sha256)(canonical(value)).pipe(Effect.orDie)
121
+
122
+ /**
123
+ * Envelope equality by canonical bytes, not by reference or key order.
124
+ *
125
+ * @since 0.1.0
126
+ * @private
127
+ */
128
+ export const sameEnvelope = (left: Envelope, right: Envelope): boolean => canonical(left) === canonical(right)
129
+
130
+ /**
131
+ * A flow's envelope with a planner's budget fields laid over its declared ones.
132
+ *
133
+ * @since 1.0.0-rc.1
134
+ * @private
135
+ */
136
+ export const budgeted = (envelope: Envelope, budget: Envelope["budget"] | undefined): Envelope =>
137
+ budget === undefined ? envelope : { ...envelope, budget: { ...envelope.budget, ...budget } }
138
+
139
+ /**
140
+ * What one plan request asks for, for idempotency: a key replayed with another
141
+ * budget is another plan.
142
+ *
143
+ * @since 1.0.0-rc.1
144
+ * @private
145
+ */
146
+ export const planFingerprint = (input: PlanInput): string =>
147
+ canonical({
148
+ flowId: input.flowId,
149
+ input: input.input,
150
+ ...(input.budget === undefined ? {} : { budget: input.budget })
151
+ })
152
+
153
+ /**
154
+ * An accepted receipt, carrying a run id when one exists.
155
+ *
156
+ * @since 0.1.0
157
+ * @private
158
+ */
159
+ export const accepted = (receiptId: string, runId?: RunId): Receipt => {
160
+ /* v8 ignore next 3 -- both runtimes call this from `launch`, which has the run it just started; the parameter stays optional for the receipt's shape rather than for a caller */
161
+ return runId === undefined
162
+ ? { _tag: "Accepted", receiptId }
163
+ : { _tag: "Accepted", receiptId, runId }
164
+ }
165
+
166
+ /**
167
+ * The receipt a replayed mutation returns, derived from the recorded one.
168
+ *
169
+ * @since 0.1.0
170
+ * @private
171
+ */
172
+ export const alreadyApplied = (key: IdempotencyKey, receipt: Receipt): Receipt => {
173
+ const receiptId = receipt._tag === "Accepted" || receipt._tag === "AlreadyApplied" ? receipt.receiptId : key
174
+ const runId = receipt._tag === "Accepted" || receipt._tag === "AlreadyApplied" || receipt._tag === "Terminal"
175
+ ? receipt.runId
176
+ : undefined
177
+ const input = receipt._tag === "Accepted" || receipt._tag === "AlreadyApplied"
178
+ ? {
179
+ ...(receipt.inputConsumed === undefined ? {} : { inputConsumed: receipt.inputConsumed }),
180
+ ...(receipt.inputBody === undefined ? {} : { inputBody: receipt.inputBody })
181
+ }
182
+ : {}
183
+ return runId === undefined
184
+ ? { _tag: "AlreadyApplied", receiptId, ...input }
185
+ : { _tag: "AlreadyApplied", receiptId, runId, ...input }
186
+ }
187
+
188
+ /**
189
+ * The plan inputs a card is derived from.
190
+ *
191
+ * @since 0.1.0
192
+ * @private
193
+ */
194
+ export interface PlanSource {
195
+ readonly planId: string
196
+ readonly flowId: FlowId
197
+ readonly decodedInput: unknown
198
+ readonly envelope: Envelope
199
+ readonly deployClass: boolean
200
+ readonly executionDigest?: string | undefined
201
+ /** The persisted plan value and cache verdicts produced by the host. */
202
+ readonly handoff?: {
203
+ readonly plan: PersistedPlan.Plan
204
+ readonly statuses?: Readonly<Record<string, PlanNode["status"]>> | undefined
205
+ readonly graph?: PlanGraph | undefined
206
+ } | undefined
207
+ readonly idempotencyKey?: IdempotencyKey | undefined
208
+ }
209
+
210
+ /**
211
+ * Builds the immutable plan card and the approval target bound to its digest.
212
+ *
213
+ * @since 0.1.0
214
+ * @private
215
+ */
216
+ export const planCard = (source: PlanSource) =>
217
+ Effect.gen(function*() {
218
+ const plan = source.handoff?.plan
219
+ const nodes: ReadonlyArray<PlanNode> = plan === undefined
220
+ ? []
221
+ : plan.nodes.map((node) => ({
222
+ ...node,
223
+ status: source.handoff?.statuses?.[node.id] ?? "run"
224
+ }))
225
+ const planDigest = yield* digest({
226
+ flowId: source.flowId,
227
+ input: source.decodedInput,
228
+ envelope: source.envelope,
229
+ deployClass: source.deployClass,
230
+ ...(source.executionDigest === undefined ? {} : { executionDigest: source.executionDigest }),
231
+ // The persisted plan digest covers keys, edges, effects, conflicts,
232
+ // priorities, and generations. Hashing only node keys loses executable
233
+ // graph changes whose content keys legitimately stay stable.
234
+ persistedPlan: plan?.digest ?? null
235
+ })
236
+ const target: ApprovalTarget = {
237
+ _tag: "Plan",
238
+ planId: source.planId,
239
+ digest: planDigest,
240
+ envelope: source.envelope
241
+ }
242
+ return {
243
+ planId: source.planId,
244
+ flowId: source.flowId,
245
+ digest: planDigest,
246
+ inputSummary: canonical(source.decodedInput),
247
+ envelope: source.envelope,
248
+ deployClass: source.deployClass,
249
+ ...(source.executionDigest === undefined ? {} : { executionDigest: source.executionDigest }),
250
+ ...(plan === undefined ? {} : { plan }),
251
+ nodes,
252
+ // Outside `digest` above on purpose: the edges are how a reader draws
253
+ // the plan, not what the plan will do, so gaining them must not
254
+ // invalidate an approval taken before the host reported them.
255
+ ...(source.handoff?.graph === undefined ? {} : { graph: source.handoff.graph }),
256
+ approval: {
257
+ target,
258
+ scope: "run" as const,
259
+ idempotencyKey: source.idempotencyKey ?? `approve:${source.planId}`
260
+ }
261
+ } satisfies PlanCard
262
+ })
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Exact optional-schema failure classification across SQL driver wrappers.
3
+ * @since 1.0.0
4
+ */
5
+
6
+ /**
7
+ * Driver messages stay separate so wrapper context cannot identify a different failure.
8
+ * The depth bound terminates cyclic driver causes.
9
+ * @since 1.0.0
10
+ * @private
11
+ */
12
+ export const causeMessages = (value: unknown, depth = 4): ReadonlyArray<string> => {
13
+ if (typeof value === "string") return [value]
14
+ if (depth === 0 || typeof value !== "object" || value === null) return []
15
+ const fields = value as { readonly message?: unknown; readonly cause?: unknown; readonly reason?: unknown }
16
+ return [
17
+ ...(typeof fields.message === "string" ? [fields.message] : []),
18
+ ...causeMessages(fields.reason, depth - 1),
19
+ ...causeMessages(fields.cause, depth - 1)
20
+ ]
21
+ }
22
+
23
+ /**
24
+ * Only the relation named by a driver's missing-table diagnostic may be absent.
25
+ * @since 1.0.0
26
+ * @private
27
+ */
28
+ export const missingTable = (table: string) => (cause: unknown): boolean =>
29
+ causeMessages(cause).some((message) => {
30
+ const relation = /^no such table: (\S+)$/.exec(message)?.[1]
31
+ ?? /^relation "([^"]+)" does not exist$/.exec(message)?.[1]
32
+ // These queries name unqualified relations. A qualified name can refer
33
+ // to a different schema's dependency, so do not discard its qualifier.
34
+ if (relation !== undefined) return relation === table
35
+ // MySQL always names the database in its table diagnostic.
36
+ return /^Table '[^.']+\.([^']+)' doesn't exist$/.exec(message)?.[1] === table
37
+ })
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Initial durable control-plane schema.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+
7
+ import * as Dialect from "@smthrs/database/Dialect"
8
+ import * as Effect from "effect/Effect"
9
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
10
+
11
+ const statements = (sql: SqlClient.SqlClient) =>
12
+ [
13
+ sql`CREATE TABLE IF NOT EXISTS control_plans (
14
+ ${Dialect.rowId(sql)}
15
+ plan_id TEXT PRIMARY KEY,
16
+ card_json TEXT NOT NULL,
17
+ decoded_input_json TEXT NOT NULL,
18
+ decision TEXT NOT NULL
19
+ )`,
20
+ sql`CREATE TABLE IF NOT EXISTS control_plan_keys (
21
+ idempotency_key TEXT PRIMARY KEY,
22
+ fingerprint TEXT NOT NULL,
23
+ plan_id TEXT NOT NULL
24
+ )`,
25
+ sql`CREATE TABLE IF NOT EXISTS control_tokens (
26
+ target_tag TEXT NOT NULL,
27
+ run_id TEXT NOT NULL,
28
+ target_id TEXT NOT NULL,
29
+ token_id TEXT NOT NULL,
30
+ target_json TEXT NOT NULL,
31
+ resolved ${Dialect.integer(sql)} NOT NULL,
32
+ decision_principal_json TEXT,
33
+ PRIMARY KEY (target_tag, run_id, target_id),
34
+ CHECK (target_tag IN ('Plan', 'Node')),
35
+ CHECK ((target_tag = 'Plan' AND run_id = '') OR (target_tag = 'Node' AND length(run_id) > 0)),
36
+ CHECK (length(target_id) > 0 AND token_id = target_id)
37
+ )`,
38
+ sql`CREATE TABLE IF NOT EXISTS control_grants (
39
+ target_tag TEXT NOT NULL,
40
+ run_id TEXT NOT NULL,
41
+ target_id TEXT NOT NULL,
42
+ token_id TEXT NOT NULL,
43
+ envelope_json TEXT NOT NULL,
44
+ scope TEXT NOT NULL,
45
+ installed_at_ms ${Dialect.integer(sql)} NOT NULL,
46
+ PRIMARY KEY (target_tag, run_id, target_id),
47
+ CHECK (target_tag IN ('Plan', 'Node')),
48
+ CHECK ((target_tag = 'Plan' AND run_id = '') OR (target_tag = 'Node' AND length(run_id) > 0)),
49
+ CHECK (length(target_id) > 0 AND token_id = target_id)
50
+ )`,
51
+ sql`CREATE TABLE IF NOT EXISTS control_mutations (
52
+ mutation_key TEXT PRIMARY KEY,
53
+ fingerprint TEXT NOT NULL,
54
+ receipt_json TEXT NOT NULL
55
+ )`,
56
+ sql`CREATE TABLE IF NOT EXISTS control_runs (
57
+ run_id TEXT PRIMARY KEY,
58
+ created_seq ${Dialect.integer(sql)} NOT NULL
59
+ )`,
60
+ sql`CREATE TABLE IF NOT EXISTS control_run_resumes (
61
+ run_id TEXT PRIMARY KEY,
62
+ requested_seq ${Dialect.integer(sql)} NOT NULL,
63
+ requested_at_ms ${Dialect.integer(sql)} NOT NULL
64
+ )`,
65
+ sql`CREATE TABLE IF NOT EXISTS control_run_messages (
66
+ seq ${Dialect.identity(sql)},
67
+ run_id TEXT NOT NULL,
68
+ kind TEXT NOT NULL,
69
+ payload_json TEXT NOT NULL
70
+ )`,
71
+ sql`CREATE TABLE IF NOT EXISTS control_sequences (
72
+ name TEXT PRIMARY KEY,
73
+ value ${Dialect.integer(sql)} NOT NULL
74
+ )`,
75
+ sql`CREATE TABLE IF NOT EXISTS control_credentials (
76
+ id TEXT PRIMARY KEY,
77
+ name TEXT NOT NULL,
78
+ ciphertext TEXT NOT NULL,
79
+ nonce TEXT NOT NULL,
80
+ version ${Dialect.integer(sql)} NOT NULL,
81
+ updated_at_ms ${Dialect.integer(sql)} NOT NULL
82
+ )`
83
+ ] as const
84
+
85
+ /**
86
+ * Creates every table owned by `@smthrs/control`.
87
+ *
88
+ * `IF NOT EXISTS` lets the recorded migration and each standalone adapter's
89
+ * bootstrap share this exact schema without competing over table creation.
90
+ *
91
+ * @category migrations
92
+ * @since 0.1.0
93
+ */
94
+ export const initial: Effect.Effect<void, unknown, SqlClient.SqlClient> = Effect.gen(function*() {
95
+ const sql = yield* SqlClient.SqlClient
96
+ for (const statement of statements(sql)) {
97
+ yield* statement
98
+ }
99
+ })
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Durable run idempotency claims, including upgrades of existing databases.
3
+ *
4
+ * @since 1.0.0
5
+ */
6
+
7
+ import * as Effect from "effect/Effect"
8
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
9
+
10
+ /**
11
+ * Adds the run-key claim table without changing existing control data.
12
+ *
13
+ * @category migrations
14
+ * @since 1.0.0
15
+ */
16
+ export const runKeys = Effect.gen(function*() {
17
+ const sql = yield* SqlClient.SqlClient
18
+ yield* sql`CREATE TABLE IF NOT EXISTS control_run_keys (
19
+ idempotency_key TEXT PRIMARY KEY,
20
+ fingerprint TEXT NOT NULL,
21
+ claimant TEXT NOT NULL
22
+ )`
23
+ })
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Durable signal admission and immutable wait bindings.
3
+ * @since 1.0.0
4
+ */
5
+
6
+ import * as Dialect from "@smthrs/database/Dialect"
7
+ import * as Effect from "effect/Effect"
8
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
9
+
10
+ /**
11
+ * Adds the signal inbox without replaying legacy messages that lack delivery identity.
12
+ * @category migrations
13
+ * @since 1.0.0
14
+ */
15
+ export const signalCommands = Effect.gen(function*() {
16
+ const sql = yield* SqlClient.SqlClient
17
+ yield* sql`CREATE TABLE IF NOT EXISTS control_signal_commands (
18
+ seq ${Dialect.identity(sql)},
19
+ command_id TEXT NOT NULL UNIQUE,
20
+ run_id TEXT NOT NULL,
21
+ payload_json TEXT NOT NULL,
22
+ wait_token TEXT,
23
+ state TEXT NOT NULL DEFAULT 'pending' CHECK (state IN ('pending', 'delivered', 'rejected', 'terminal'))
24
+ )`
25
+ yield* sql`CREATE UNIQUE INDEX IF NOT EXISTS control_signal_commands_wait ON control_signal_commands(wait_token) WHERE wait_token IS NOT NULL`
26
+ yield* sql`CREATE INDEX IF NOT EXISTS control_signal_commands_pending ON control_signal_commands(state, seq)`
27
+ })
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Preserve the actual decision without guessing erased legacy answers.
3
+ * @since 1.0.0
4
+ */
5
+
6
+ import * as Dialect from "@smthrs/database/Dialect"
7
+ import * as Effect from "effect/Effect"
8
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
9
+
10
+ /**
11
+ * Idempotent for both recorded migrations and standalone runtime bootstrap.
12
+ * @category migrations
13
+ * @since 1.0.0
14
+ */
15
+ export const approvalDecisions = Effect.gen(function*() {
16
+ const sql = yield* SqlClient.SqlClient
17
+ yield* sql.withTransaction(Effect.gen(function*() {
18
+ const columns = yield* Dialect.columns(sql, "control_tokens")
19
+ if (columns.some((column) => column.name === "decision_json")) return
20
+ // NULL is intentional: old terminal tokens erased their answer. Their
21
+ // decoder refuses recovery instead of inferring approval from a grant.
22
+ // An undecided token still has its unambiguous resolved=0 representation.
23
+ yield* sql`ALTER TABLE control_tokens ADD COLUMN decision_json TEXT`
24
+ }))
25
+ })
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Record who admitted each signal command.
3
+ * @since 1.0.0
4
+ */
5
+
6
+ import * as Dialect from "@smthrs/database/Dialect"
7
+ import * as Effect from "effect/Effect"
8
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
9
+
10
+ /**
11
+ * Adds the admitting principal to the signal inbox.
12
+ *
13
+ * NULL is intentional for existing rows: a command admitted before this column
14
+ * has no recorded identity, so it cannot answer a human wait, which requires
15
+ * `ApprovalAuthority` to authorize the admitting principal.
16
+ *
17
+ * @category migrations
18
+ * @since 1.0.0
19
+ */
20
+ export const signalPrincipals = Effect.gen(function*() {
21
+ const sql = yield* SqlClient.SqlClient
22
+ yield* sql.withTransaction(Effect.gen(function*() {
23
+ const columns = yield* Dialect.columns(sql, "control_signal_commands")
24
+ if (columns.some((column) => column.name === "principal_json")) return
25
+ yield* sql`ALTER TABLE control_signal_commands ADD COLUMN principal_json TEXT`
26
+ }))
27
+ })
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Record who launched each run.
3
+ * @since 1.0.0
4
+ */
5
+
6
+ import * as Dialect from "@smthrs/database/Dialect"
7
+ import * as Effect from "effect/Effect"
8
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
9
+
10
+ /**
11
+ * Adds the launching principal to the launch index.
12
+ *
13
+ * NULL is intentional for existing rows: a run launched before these columns
14
+ * has no recorded launcher, so only a reader that sees every run lists or
15
+ * watches it.
16
+ *
17
+ * @category migrations
18
+ * @since 1.0.0
19
+ */
20
+ export const runPrincipals = Effect.gen(function*() {
21
+ const sql = yield* SqlClient.SqlClient
22
+ yield* sql.withTransaction(Effect.gen(function*() {
23
+ const columns = yield* Dialect.columns(sql, "control_runs")
24
+ if (!columns.some((column) => column.name === "principal_id")) {
25
+ yield* sql`ALTER TABLE control_runs ADD COLUMN principal_id TEXT`
26
+ }
27
+ if (!columns.some((column) => column.name === "principal_kind")) {
28
+ yield* sql`ALTER TABLE control_runs ADD COLUMN principal_kind TEXT`
29
+ }
30
+ }))
31
+ })
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Record the operator consent a resume delegation carries.
3
+ * @since 1.0.0
4
+ */
5
+
6
+ import * as Dialect from "@smthrs/database/Dialect"
7
+ import * as Effect from "effect/Effect"
8
+ import * as SqlClient from "effect/unstable/sql/SqlClient"
9
+
10
+ /**
11
+ * Adds the journal sequence of an operator's explicit resume to the pending
12
+ * resume delegations.
13
+ *
14
+ * NULL is intentional for existing rows: a delegation recorded before this
15
+ * column is an approval or a wake, which is background intent.
16
+ *
17
+ * @category migrations
18
+ * @since 1.0.0
19
+ */
20
+ export const resumeConsent = Effect.gen(function*() {
21
+ const sql = yield* SqlClient.SqlClient
22
+ yield* sql.withTransaction(Effect.gen(function*() {
23
+ const columns = yield* Dialect.columns(sql, "control_run_resumes")
24
+ if (!columns.some((column) => column.name === "consent_seq")) {
25
+ yield* sql`ALTER TABLE control_run_resumes ADD COLUMN consent_seq ${Dialect.integer(sql)}`
26
+ }
27
+ }))
28
+ })
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Deterministic in-memory Control stack for package and consumer tests.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+
7
+ import * as TestJournal from "@smthrs/journal/test/TestJournal"
8
+ import { NotificationQueue } from "@smthrs/notifications"
9
+ import { Registry } from "@smthrs/registry"
10
+ import { Crypto, Effect, Layer } from "effect"
11
+ import * as ControlExecutor from "../ControlExecutor.ts"
12
+ import * as ControlLive from "../ControlLive.ts"
13
+ import * as ControlRuntime from "../ControlRuntime.ts"
14
+
15
+ const browserCrypto = Layer.succeed(
16
+ Crypto.Crypto,
17
+ Crypto.make({
18
+ /* v8 ignore next -- `Crypto.make` requires a random-byte primitive, and the deterministic runtime this bundle composes derives every identifier from a counter, so only `digest` is ever called here */
19
+ randomBytes: (size) => globalThis.crypto.getRandomValues(new Uint8Array(size)),
20
+ digest: (algorithm, data) =>
21
+ Effect.promise(() => globalThis.crypto.subtle.digest(algorithm, data.slice().buffer)).pipe(
22
+ Effect.map((buffer) => new Uint8Array(buffer))
23
+ )
24
+ })
25
+ )
26
+
27
+ /**
28
+ * Provides Control, ControlRuntime, the in-memory journal bundle, and an empty
29
+ * registry. Runtime flow metadata falls back to the reserved system catalog.
30
+ *
31
+ * @category layers
32
+ * @since 0.1.0
33
+ */
34
+ export const layer = (
35
+ options?: ControlRuntime.MemoryOptions,
36
+ executor: ControlExecutor.Service = ControlExecutor.makeNoop()
37
+ ) => {
38
+ const journal = TestJournal.layer()
39
+ const dependencies = Layer.mergeAll(
40
+ ControlRuntime.layerMemory(options).pipe(Layer.provide(browserCrypto)),
41
+ journal,
42
+ NotificationQueue.layer.pipe(Layer.provide(journal)),
43
+ ControlExecutor.layer(executor),
44
+ Registry.layerNoop()
45
+ )
46
+ return Layer.provideMerge(ControlLive.layer, dependencies)
47
+ }