@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
package/src/Control.ts ADDED
@@ -0,0 +1,337 @@
1
+ /**
2
+ * Transport-independent control-plane vtable.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+
7
+ import type { NotificationError } from "@smthrs/notifications/NotificationQueue"
8
+ import { Context, Effect, Layer, Stream } from "effect"
9
+ import type {
10
+ AlreadyResolved,
11
+ ClaimLost,
12
+ CodeDrift,
13
+ ControlError,
14
+ EnvelopeMismatch,
15
+ FlowNotFound,
16
+ InvalidInput,
17
+ LaunchFailed,
18
+ NoMatchingWait,
19
+ PersistenceError,
20
+ PlanDenied,
21
+ PlanDigestMismatch,
22
+ PlanNotFound,
23
+ RunNotFound,
24
+ TransportError,
25
+ Unauthorized,
26
+ Unavailable
27
+ } from "./ControlError.ts"
28
+ import { Unavailable as UnavailableError } from "./ControlError.ts"
29
+ import type {
30
+ ApprovalPayload,
31
+ ControlEvent,
32
+ Envelope,
33
+ FlowId,
34
+ IdempotencyKey,
35
+ ListRequest,
36
+ ListResponse,
37
+ PlanCard,
38
+ Principal,
39
+ Receipt,
40
+ RunId,
41
+ RunInputSchema,
42
+ SignalInputSchema,
43
+ SteerInputSchema,
44
+ WatchFilter
45
+ } from "./ControlSchema.ts"
46
+
47
+ /**
48
+ * Raw input submitted to planning. Decoding is owned by `ControlRuntime`.
49
+ *
50
+ * This local contract accepts `unknown` so the selected flow can decode its
51
+ * own input. `ControlSchema.PlanInputSchema` is the narrower JSON wire
52
+ * contract used by RPC clients.
53
+ *
54
+ * @category models
55
+ * @since 0.1.0
56
+ */
57
+ export interface PlanInput {
58
+ readonly flowId: FlowId
59
+ readonly input: unknown
60
+ readonly idempotencyKey?: IdempotencyKey | undefined
61
+ /** Budget fields that replace the flow's declared ones on this plan's envelope. */
62
+ readonly budget?: Envelope["budget"] | undefined
63
+ }
64
+
65
+ /**
66
+ * Starts an approved plan or joins/resumes an existing run.
67
+ *
68
+ * @category models
69
+ * @since 0.1.0
70
+ */
71
+ export type RunInput = typeof RunInputSchema.Type & {
72
+ /** Trusted runtime caller reserves the execution identity; absent from public RPC. */
73
+ readonly reservedRunId?: RunId | undefined
74
+ /** Authenticated actor used only to scope durable idempotency. */
75
+ readonly principal?: Principal | undefined
76
+ }
77
+
78
+ /**
79
+ * @category models
80
+ * @since 0.1.0
81
+ */
82
+ export type { ApprovalTarget } from "./ControlSchema.ts"
83
+
84
+ /**
85
+ * A listing request, restricted to one reader's runs when `reader` is set.
86
+ *
87
+ * The server sets `reader` to the authenticated principal unless its
88
+ * `RunVisibility` lets that principal see every run; `ControlSchema.ListRequest`
89
+ * excludes it from the wire, so a remote client cannot widen or borrow a view.
90
+ * A restricted reader sees only the runs its principal launched, and the fires
91
+ * that started them; an in-process caller that names no reader sees every run.
92
+ *
93
+ * @category models
94
+ * @since 1.0.0
95
+ */
96
+ export type ListInput = ListRequest & {
97
+ readonly reader?: Principal | undefined
98
+ }
99
+
100
+ /**
101
+ * A watch filter, restricted to one reader's runs when `reader` is set.
102
+ *
103
+ * A restricted reader receives the events of the runs its principal launched
104
+ * and nothing from a plan or from a run it did not launch. See {@link ListInput}.
105
+ *
106
+ * @category models
107
+ * @since 1.0.0
108
+ */
109
+ export type WatchInput = WatchFilter & {
110
+ readonly reader?: Principal | undefined
111
+ }
112
+
113
+ /**
114
+ * Full approval decision submitted to the authenticated server boundary.
115
+ *
116
+ * The local service may receive a runtime-stamped principal.
117
+ * `ControlSchema.ApprovalInputSchema` excludes it from the wire so a remote
118
+ * client cannot claim another identity.
119
+ *
120
+ * @category models
121
+ * @since 0.1.0
122
+ */
123
+ export interface ApprovalInput extends ApprovalPayload {
124
+ readonly principal?: Principal | undefined
125
+ }
126
+
127
+ /**
128
+ * Steering mutation arguments.
129
+ *
130
+ * @category models
131
+ * @since 0.1.0
132
+ */
133
+ export type SteerInput = typeof SteerInputSchema.Type & {
134
+ /**
135
+ * Set by the server to the authenticated principal unless its
136
+ * `RunVisibility` lets that principal see every run. A run the reader may
137
+ * not see fails `RunNotFound`, exactly as a missing run does. Not on the
138
+ * wire; an in-process caller that names no reader mutates any run.
139
+ */
140
+ readonly reader?: Principal | undefined
141
+ }
142
+
143
+ /**
144
+ * Signal mutation arguments.
145
+ *
146
+ * @category models
147
+ * @since 0.1.0
148
+ */
149
+ export type SignalInput = typeof SignalInputSchema.Type & {
150
+ /** Authenticated actor used only to scope durable idempotency. */
151
+ readonly principal?: Principal | undefined
152
+ /**
153
+ * Set by the server to the authenticated principal unless its
154
+ * `RunVisibility` lets that principal see every run. A run the reader may
155
+ * not see fails `RunNotFound`, exactly as a missing run does. Not on the
156
+ * wire; an in-process caller that names no reader mutates any run.
157
+ */
158
+ readonly reader?: Principal | undefined
159
+ }
160
+
161
+ /**
162
+ * Run lifecycle mutation arguments.
163
+ *
164
+ * The local contract includes the runtime-stamped principal.
165
+ * `ControlSchema.ReasonedMutationInputSchema` carries only the caller's reason
166
+ * over RPC.
167
+ *
168
+ * @category models
169
+ * @since 0.1.0
170
+ */
171
+ export interface RunMutationInput {
172
+ readonly runId: RunId
173
+ readonly idempotencyKey: IdempotencyKey
174
+ /**
175
+ * Why the run is being cancelled or resumed.
176
+ *
177
+ * Free text, recorded on the journal entry the mutation writes and projected
178
+ * back onto `RunSummary.cancellation`. An operator reading a cancelled run a
179
+ * week later asks "why", and a control plane that never carried the answer
180
+ * cannot produce one afterwards.
181
+ */
182
+ readonly reason?: string | undefined
183
+ /**
184
+ * Who is asking. Stamped by the runtime, which supplies its own principal
185
+ * when the caller names none.
186
+ */
187
+ readonly principal?: Principal | undefined
188
+ /**
189
+ * Resume only: run the flow's current code even when its execution digest
190
+ * differs from the one the run started with. Without it such a resume fails
191
+ * `CodeDrift` and leaves the run where it was.
192
+ */
193
+ readonly allowCodeDrift?: boolean | undefined
194
+ /**
195
+ * Set by the server to the authenticated principal unless its
196
+ * `RunVisibility` lets that principal see every run. A run the reader may
197
+ * not see fails `RunNotFound`, exactly as a missing run does. Not on the
198
+ * wire; an in-process caller that names no reader mutates any run.
199
+ */
200
+ readonly reader?: Principal | undefined
201
+ }
202
+
203
+ /**
204
+ * Transport-independent control operations.
205
+ *
206
+ * Every operation admits transport and authentication failures so the same
207
+ * service key can be provided by either a local implementation or an RPC client.
208
+ *
209
+ * @category models
210
+ * @since 0.1.0
211
+ */
212
+ export interface Service {
213
+ readonly plan: (
214
+ input: PlanInput
215
+ ) => Effect.Effect<
216
+ PlanCard,
217
+ FlowNotFound | InvalidInput | PersistenceError | Unavailable | TransportError | Unauthorized
218
+ >
219
+ readonly run: (
220
+ input: RunInput
221
+ ) => Effect.Effect<
222
+ Receipt,
223
+ | RunNotFound
224
+ | PlanNotFound
225
+ | PlanDenied
226
+ | PlanDigestMismatch
227
+ | EnvelopeMismatch
228
+ | ClaimLost
229
+ | CodeDrift
230
+ | InvalidInput
231
+ | LaunchFailed
232
+ | PersistenceError
233
+ | Unavailable
234
+ | TransportError
235
+ | Unauthorized
236
+ >
237
+ readonly approve: (
238
+ input: ApprovalInput
239
+ ) => Effect.Effect<
240
+ Receipt,
241
+ | PlanDigestMismatch
242
+ | EnvelopeMismatch
243
+ | AlreadyResolved
244
+ | PlanNotFound
245
+ | RunNotFound
246
+ | CodeDrift
247
+ | InvalidInput
248
+ | Unauthorized
249
+ | PersistenceError
250
+ | Unavailable
251
+ | TransportError
252
+ >
253
+ readonly deny: (
254
+ input: ApprovalInput
255
+ ) => Effect.Effect<
256
+ Receipt,
257
+ | PlanDigestMismatch
258
+ | EnvelopeMismatch
259
+ | AlreadyResolved
260
+ | PlanNotFound
261
+ | RunNotFound
262
+ | CodeDrift
263
+ | InvalidInput
264
+ | Unauthorized
265
+ | PersistenceError
266
+ | Unavailable
267
+ | TransportError
268
+ >
269
+ readonly steer: (
270
+ input: SteerInput
271
+ ) => Effect.Effect<
272
+ Receipt,
273
+ RunNotFound | InvalidInput | PersistenceError | Unavailable | TransportError | Unauthorized | NotificationError
274
+ >
275
+ readonly signal: (
276
+ input: SignalInput
277
+ ) => Effect.Effect<
278
+ Receipt,
279
+ RunNotFound | NoMatchingWait | InvalidInput | PersistenceError | Unavailable | TransportError | Unauthorized
280
+ >
281
+ readonly cancel: (
282
+ input: RunMutationInput
283
+ ) => Effect.Effect<
284
+ Receipt,
285
+ RunNotFound | ClaimLost | InvalidInput | PersistenceError | Unavailable | TransportError | Unauthorized
286
+ >
287
+ readonly resume: (
288
+ input: RunMutationInput
289
+ ) => Effect.Effect<
290
+ Receipt,
291
+ RunNotFound | ClaimLost | CodeDrift | InvalidInput | PersistenceError | Unavailable | TransportError | Unauthorized
292
+ >
293
+ readonly list: (input: ListInput) => Effect.Effect<ListResponse, ControlError>
294
+ /** Checkpoint `event.cursor` after processing each event and resume with `afterCursor`. */
295
+ readonly watch: (filter: WatchInput) => Stream.Stream<ControlEvent, ControlError>
296
+ }
297
+
298
+ /**
299
+ * Service key for the authoritative control-plane vtable.
300
+ *
301
+ * @category services
302
+ * @since 0.1.0
303
+ */
304
+ export class Control extends Context.Service<Control, Service>()("/control/Control") {}
305
+
306
+ /**
307
+ * Constructs a control service from an implementation record.
308
+ *
309
+ * @category constructors
310
+ * @since 0.1.0
311
+ */
312
+ export const make = (implementation: Service): Service => Control.of(implementation)
313
+
314
+ const unavailable = (feature: string): Unavailable =>
315
+ new UnavailableError({ feature, ticket: "control-runtime-engine-integration" })
316
+
317
+ /**
318
+ * Provides an unavailable control implementation for optional integrations.
319
+ *
320
+ * @category layers
321
+ * @since 0.1.0
322
+ */
323
+ export const layerNoop: Layer.Layer<Control> = Layer.succeed(
324
+ Control,
325
+ make({
326
+ plan: Effect.fn("Control.plan")(() => Effect.fail(unavailable("plan"))),
327
+ run: Effect.fn("Control.run")(() => Effect.fail(unavailable("run"))),
328
+ approve: Effect.fn("Control.approve")(() => Effect.fail(unavailable("approve"))),
329
+ deny: Effect.fn("Control.deny")(() => Effect.fail(unavailable("deny"))),
330
+ steer: Effect.fn("Control.steer")(() => Effect.fail(unavailable("steer"))),
331
+ signal: Effect.fn("Control.signal")(() => Effect.fail(unavailable("signal"))),
332
+ cancel: Effect.fn("Control.cancel")(() => Effect.fail(unavailable("cancel"))),
333
+ resume: Effect.fn("Control.resume")(() => Effect.fail(unavailable("resume"))),
334
+ list: Effect.fn("Control.list")(() => Effect.fail(unavailable("list"))),
335
+ watch: () => Stream.fail(unavailable("watch"))
336
+ })
337
+ )
@@ -0,0 +1,319 @@
1
+ /**
2
+ * RPC client layer projected back into the control service interface.
3
+ *
4
+ * @since 0.1.0
5
+ */
6
+
7
+ import { Cause, Effect, Layer, Result, Schema, Stream } from "effect"
8
+ import { HttpClient, HttpClientRequest } from "effect/unstable/http"
9
+ import { RpcClient, RpcClientError } from "effect/unstable/rpc"
10
+ import { Control, make } from "./Control.ts"
11
+ import { type ControlError, ControlErrorSchema, TransportError, Unauthorized } from "./ControlError.ts"
12
+ import { ControlRpcs } from "./ControlRpcs.ts"
13
+ import {
14
+ ApprovalInputSchema,
15
+ CancelInputSchema,
16
+ ListRequest,
17
+ PlanInputSchema,
18
+ ResumeInputSchema,
19
+ RunInputSchema,
20
+ SignalInputSchema,
21
+ SteerInputSchema,
22
+ WatchFilter
23
+ } from "./ControlSchema.ts"
24
+
25
+ /**
26
+ * Whether a value is one of the control plane's declared failures, as opposed
27
+ * to a defect that escaped some other layer.
28
+ *
29
+ * Derived from `ControlError.ControlErrorSchema` rather than restated, so a new
30
+ * error class cannot be a member of the union and a stranger to the client.
31
+ *
32
+ * @category refinements
33
+ * @since 0.1.0
34
+ */
35
+ export const isControlError = Schema.is(ControlErrorSchema)
36
+
37
+ interface TransportClassification {
38
+ readonly message: string
39
+ readonly retryable: boolean
40
+ }
41
+
42
+ const requestEncoding: TransportClassification = {
43
+ message: "The control request could not be encoded.",
44
+ retryable: false
45
+ }
46
+
47
+ const responseDecoding: TransportClassification = {
48
+ message: "The control response could not be decoded.",
49
+ retryable: false
50
+ }
51
+
52
+ const connectionFailure: TransportClassification = {
53
+ message: "The control server could not be reached.",
54
+ retryable: true
55
+ }
56
+
57
+ const clientHttpFailure: TransportClassification = {
58
+ message: "The control server rejected the HTTP request.",
59
+ retryable: false
60
+ }
61
+
62
+ const serverHttpFailure: TransportClassification = {
63
+ message: "The control server failed while handling the HTTP request.",
64
+ retryable: true
65
+ }
66
+
67
+ const invalidClientUrl: TransportClassification = {
68
+ message: "The control server URL is invalid.",
69
+ retryable: false
70
+ }
71
+
72
+ const unknownClientFailure: TransportClassification = {
73
+ message: "The control RPC client failed.",
74
+ retryable: false
75
+ }
76
+
77
+ const transportError = (cause: unknown, classification: TransportClassification): TransportError =>
78
+ new TransportError({
79
+ ...classification,
80
+ cause
81
+ })
82
+
83
+ // A `StatusCodeError` reported by the RPC client always carries the concrete
84
+ // error, and that error always carries its response. The three refusals below
85
+ // are what keeps a hand-built wrapper without one from being read as a 5xx and
86
+ // retried forever; none of them is reachable from the client's own transports.
87
+ const statusFrom = (cause: unknown): number | undefined => {
88
+ /* v8 ignore next -- a StatusCodeError cause always carries its response */
89
+ if (typeof cause !== "object" || cause === null || !("response" in cause)) return undefined
90
+ const response = cause.response
91
+ /* v8 ignore next -- as above: the response is an object carrying a status */
92
+ if (typeof response !== "object" || response === null || !("status" in response)) return undefined
93
+ /* v8 ignore next -- as above: the status is a number */
94
+ return typeof response.status === "number" ? response.status : undefined
95
+ }
96
+
97
+ type HttpFailureKind = Extract<RpcClientError.RpcClientError["reason"], { readonly _tag: "HttpError" }>["kind"]
98
+ type TransportReason = RpcClientError.RpcClientError["reason"]["_tag"]
99
+
100
+ /**
101
+ * What each HTTP failure means for a retry.
102
+ *
103
+ * `StatusCodeError` is absent on purpose: it is the one kind whose answer
104
+ * depends on the response, not on the kind.
105
+ */
106
+ const httpClassification: Record<Exclude<HttpFailureKind, "StatusCodeError">, TransportClassification> = {
107
+ TransportError: connectionFailure,
108
+ EncodeError: requestEncoding,
109
+ InvalidUrlError: invalidClientUrl,
110
+ DecodeError: responseDecoding,
111
+ EmptyBodyError: responseDecoding
112
+ }
113
+
114
+ /**
115
+ * What each non-HTTP transport failure means for a retry.
116
+ *
117
+ * A table rather than a switch, because the mapping is data: the compiler
118
+ * still requires every reason the RPC client can report to have an answer, and
119
+ * a reader can check the whole policy at a glance.
120
+ */
121
+ const reasonClassification: Record<Exclude<TransportReason, "HttpError">, TransportClassification> = {
122
+ RpcClientDefect: responseDecoding,
123
+ SocketReadError: connectionFailure,
124
+ SocketWriteError: connectionFailure,
125
+ SocketOpenError: connectionFailure,
126
+ // The socket cannot perform a requested protocol upgrade; retries of the
127
+ // same unsupported operation cannot change that host capability.
128
+ SocketUpgradeError: unknownClientFailure,
129
+ SocketCloseError: connectionFailure,
130
+ // A worker transport is not composable with this client, which speaks HTTP
131
+ // and WebSocket. The entries exist so the table stays exhaustive.
132
+ WorkerSpawnError: unknownClientFailure,
133
+ WorkerSendError: unknownClientFailure,
134
+ WorkerReceiveError: unknownClientFailure,
135
+ WorkerUnknownError: unknownClientFailure
136
+ }
137
+
138
+ const classifyRpcClientError = (error: RpcClientError.RpcClientError): TransportClassification => {
139
+ const reason = error.reason
140
+ if (reason._tag !== "HttpError") return reasonClassification[reason._tag]
141
+ if (reason.kind !== "StatusCodeError") return httpClassification[reason.kind]
142
+ // Effect's serializable HttpError keeps the concrete StatusCodeError in
143
+ // `cause`. The wrapper has no separate status field, so a hand-built wrapper
144
+ // without that cause cannot safely be classified as retryable and falls back
145
+ // to the client class.
146
+ const status = statusFrom(reason.cause)
147
+ return status !== undefined && status >= 500 && status <= 599
148
+ ? serverHttpFailure
149
+ : clientHttpFailure
150
+ }
151
+
152
+ const isRpcClientError = Schema.is(RpcClientError.RpcClientError)
153
+
154
+ const classify = (error: unknown): TransportClassification => {
155
+ if (Schema.isSchemaError(error)) return responseDecoding
156
+ if (isRpcClientError(error)) return classifyRpcClientError(error)
157
+ return unknownClientFailure
158
+ }
159
+
160
+ // Preserve the operation-specific control failures from the RPC schema while
161
+ // replacing transport and decoding failures with the public TransportError.
162
+ const normalizedFailure = <E>(cause: Cause.Cause<E>): Effect.Effect<never, (E & ControlError) | TransportError> => {
163
+ const failure = Cause.findError(cause)
164
+ if (Result.isSuccess(failure)) {
165
+ return Effect.fail(
166
+ isControlError(failure.success)
167
+ ? failure.success
168
+ : transportError(failure.success, classify(failure.success))
169
+ )
170
+ }
171
+ const defect = Cause.findDefect(cause)
172
+ // A cause with neither a failure nor a defect is an interruption, and an
173
+ // operator's own cancellation is not the server failing. It is re-raised
174
+ // exactly as it arrived rather than described as a transport failure.
175
+ /* v8 ignore next 2 -- the fiber propagates an interrupt-only cause without reaching this operator */
176
+ return Result.isSuccess(defect)
177
+ ? Effect.fail(transportError(defect.success, classify(defect.success)))
178
+ : Effect.failCause(cause as Cause.Cause<(E & ControlError) | TransportError>)
179
+ }
180
+
181
+ const normalize = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, (E & ControlError) | TransportError, R> =>
182
+ Effect.catchCause(effect, normalizedFailure)
183
+
184
+ type RequestEncoder = (input: unknown) => Effect.Effect<unknown, Schema.SchemaError>
185
+
186
+ const encoder = (schema: Schema.Top): RequestEncoder =>
187
+ // Every request schema in this module is service-free. `Schema.Top` erases
188
+ // that fact to `unknown`, so restore it at this one construction boundary.
189
+ Schema.encodeUnknownEffect(Schema.toCodecJson(schema)) as RequestEncoder
190
+
191
+ const planEncoder = encoder(PlanInputSchema)
192
+ const runEncoder = encoder(RunInputSchema)
193
+ const approvalEncoder = encoder(ApprovalInputSchema)
194
+ const steerEncoder = encoder(SteerInputSchema)
195
+ const signalEncoder = encoder(SignalInputSchema)
196
+ const cancelEncoder = encoder(CancelInputSchema)
197
+ const resumeEncoder = encoder(ResumeInputSchema)
198
+ const listEncoder = encoder(ListRequest)
199
+ const watchEncoder = encoder(WatchFilter)
200
+
201
+ const normalizeRequest = <A, E, R>(
202
+ encode: RequestEncoder,
203
+ input: unknown,
204
+ request: () => Effect.Effect<A, E, R>
205
+ ): Effect.Effect<A, (E & ControlError) | TransportError, R> =>
206
+ encode(input).pipe(
207
+ Effect.mapError((cause) => transportError(cause, requestEncoding)),
208
+ Effect.andThen(Effect.suspend(() => normalize(request())))
209
+ )
210
+
211
+ const normalizeStream = <A, E, R>(
212
+ stream: Stream.Stream<A, E, R>
213
+ ): Stream.Stream<A, (E & ControlError) | TransportError, R> =>
214
+ Stream.catchCause(stream, (cause) => Stream.fromEffect(normalizedFailure(cause)))
215
+
216
+ const normalizeStreamRequest = <A, E, R>(
217
+ encode: RequestEncoder,
218
+ input: unknown,
219
+ request: () => Stream.Stream<A, E, R>
220
+ ): Stream.Stream<A, (E & ControlError) | TransportError, R> =>
221
+ Stream.unwrap(
222
+ encode(input).pipe(
223
+ Effect.mapError((cause) => transportError(cause, requestEncoding)),
224
+ Effect.map(() => normalizeStream(request()))
225
+ )
226
+ )
227
+
228
+ /**
229
+ * Client transport configuration. Unary procedures use HTTP at this URL;
230
+ * `watch` uses the abstract WebSocket supplied by the platform layer.
231
+ *
232
+ * `credential` reaches the HTTP protocol only. It is attached as a bearer
233
+ * token on each HTTP RPC request; the `watch` stream rides a WebSocket whose
234
+ * upgrade request a browser cannot add headers to, so the socket carries no
235
+ * credential at all in a browser deployment. A deployment that authenticates
236
+ * control traffic must therefore front the socket (terminate auth at a proxy
237
+ * that injects the credential on the upgrade) or serve `watch` over the HTTP
238
+ * protocol instead.
239
+ *
240
+ * @category models
241
+ * @since 0.1.0
242
+ */
243
+ export interface ClientConfig {
244
+ readonly url: string
245
+ /**
246
+ * Bearer token attached to every HTTP RPC request when present.
247
+ *
248
+ * Not sent on the `watch` WebSocket: see {@link ClientConfig}.
249
+ */
250
+ readonly credential?: string | undefined
251
+ }
252
+
253
+ /**
254
+ * Provides `Control` through an RPC client while preserving the local vtable.
255
+ *
256
+ * @category layers
257
+ * @since 0.1.0
258
+ */
259
+ export const layer = (config: ClientConfig) => {
260
+ const http = RpcClient.layerProtocolHttp({
261
+ url: config.url,
262
+ transformClient: (client) => {
263
+ // The RPC protocol already admits HttpClientError, but transformClient's
264
+ // generic signature cannot express that filtering adds the same error
265
+ // its input client already carries.
266
+ const checked = HttpClient.filterStatusOk(client) as typeof client
267
+ return config.credential === undefined
268
+ ? checked
269
+ : HttpClient.mapRequest(checked, HttpClientRequest.bearerToken(config.credential))
270
+ }
271
+ })
272
+ const websocket = RpcClient.layerProtocolSocket()
273
+ return Layer.effect(
274
+ Control,
275
+ Effect.gen(function*() {
276
+ // Built into the layer's own scope: `Effect.provide(layer)` would close
277
+ // each protocol as soon as the client was constructed.
278
+ const httpServices = yield* Layer.build(http)
279
+ const websocketServices = yield* Layer.build(websocket)
280
+ const unary = yield* RpcClient.make(ControlRpcs).pipe(Effect.provide(httpServices))
281
+ const streaming = yield* RpcClient.make(ControlRpcs).pipe(Effect.provide(websocketServices))
282
+ return make({
283
+ plan: Effect.fn("Control.plan")((input) => normalizeRequest(planEncoder, input, () => unary.Plan(input))),
284
+ run: Effect.fn("Control.run")((input) => normalizeRequest(runEncoder, input, () => unary.Run(input))),
285
+ // RPC authenticates with this client's credential and does not carry
286
+ // local attribution. Refuse here before an agent becomes that operator.
287
+ approve: Effect.fn("Control.approve")((input) =>
288
+ normalizeRequest(approvalEncoder, input, () =>
289
+ input.principal?.kind === "agent"
290
+ ? Effect.fail(new Unauthorized({ message: "Approval decisions are operator-only" }))
291
+ : unary.Approve(input))
292
+ ),
293
+ deny: Effect.fn("Control.deny")((input) =>
294
+ normalizeRequest(approvalEncoder, input, () =>
295
+ input.principal?.kind === "agent"
296
+ ? Effect.fail(new Unauthorized({ message: "Approval decisions are operator-only" }))
297
+ : unary.Deny(input))
298
+ ),
299
+ steer: Effect.fn("Control.steer")((input) => normalizeRequest(steerEncoder, input, () => unary.Steer(input))),
300
+ signal: Effect.fn("Control.signal")((input) =>
301
+ normalizeRequest(signalEncoder, input, () => unary.Signal(input))
302
+ ),
303
+ cancel: Effect.fn("Control.cancel")((input) =>
304
+ normalizeRequest(cancelEncoder, input, () => unary.Cancel(input))
305
+ ),
306
+ resume: Effect.fn("Control.resume")((input) =>
307
+ normalizeRequest(resumeEncoder, input, () => unary.Resume(input))
308
+ ),
309
+ list: Effect.fn("Control.list")((input) => normalizeRequest(listEncoder, input, () => unary.List(input))),
310
+ // `watch` is the only procedure on the socket protocol, and the
311
+ // socket is why `credential` cannot protect it: a browser's WebSocket
312
+ // upgrade takes no headers, so the bearer token that authenticates
313
+ // every unary call above never reaches this stream. Credentialed
314
+ // deployments front the socket or use the HTTP protocol for watch.
315
+ watch: (input) => normalizeStreamRequest(watchEncoder, input, () => streaming.Watch(input))
316
+ })
317
+ })
318
+ )
319
+ }