@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,107 @@
1
+ /**
2
+ * Cancellation attribution as the control plane reads it back.
3
+ *
4
+ * A cancellation is durable but anonymous. `flows_runs.cancel_requested_at_ms`
5
+ * records that somebody asked, and nothing in the row records who, why, or
6
+ * whether the run was asked at all rather than swept up in an ancestor's
7
+ * cascade. Three journals hold the missing halves: the control plane's own
8
+ * `control.run.cancel-requested`, the engine's `flows.engine.interrupted`, and
9
+ * the ancestry the run store already keeps. This module folds them into one
10
+ * answer per run.
11
+ *
12
+ * The fold is pure and scope-independent: it reads whatever evidence it is
13
+ * handed and never issues a query, so the caller chooses how much to read.
14
+ * `SqlControlRuntime` uses two scopes. A listing folds the whole database,
15
+ * because every row is going to be answered for anyway. A single-run read
16
+ * folds only that run and its ancestor chain, which is the smallest scope that
17
+ * can still answer the question: cascade is a fact about a run's ancestors, so
18
+ * it cannot be decided one row at a time — a child's cancellation is
19
+ * attributed to whoever asked for its nearest cancelled ancestor's, however
20
+ * many rounds up that is.
21
+ *
22
+ * The two foreign event types are named as strings rather than imported,
23
+ * exactly as in {@link Lineage}: a control plane reads journals, not engines.
24
+ *
25
+ * @since 0.1.0
26
+ */
27
+ import type { Cancellation, Principal } from "./ControlSchema.ts";
28
+ /**
29
+ * The journal event type the control plane records an attributed cancel under.
30
+ *
31
+ * @category constants
32
+ * @since 0.1.0
33
+ */
34
+ export declare const requestedEventType = "control.run.cancel-requested";
35
+ /**
36
+ * The journal event type the engine records an interruption under.
37
+ *
38
+ * @category constants
39
+ * @since 0.1.0
40
+ */
41
+ export declare const interruptedEventType = "flows.engine.interrupted";
42
+ /**
43
+ * One attributed cancel request, as the control plane journaled it.
44
+ *
45
+ * @category models
46
+ * @since 0.1.0
47
+ */
48
+ export interface Request {
49
+ readonly requestedAt: number;
50
+ readonly principal?: Principal | undefined;
51
+ readonly reason?: string | undefined;
52
+ }
53
+ /**
54
+ * What one run row discloses about its own cancellation.
55
+ *
56
+ * `cancelRequestedAt` is the run store's unfenced request column, and
57
+ * `cancelledAt` is the moment the engine journaled the interruption. Either
58
+ * one alone is evidence that this run was cancelled, and so is an attributed
59
+ * request naming the run: a control plane that cancels a run it owns
60
+ * interrupts the fiber rather than asking the column, and the journal entry it
61
+ * wrote is the whole record.
62
+ *
63
+ * @category models
64
+ * @since 0.1.0
65
+ */
66
+ export interface Evidence {
67
+ readonly runId: string;
68
+ readonly parentRunId?: string | undefined;
69
+ readonly cancelRequestedAt?: number | undefined;
70
+ readonly cancelledAt?: number | undefined;
71
+ }
72
+ /**
73
+ * Everything the fold reads.
74
+ *
75
+ * @category models
76
+ * @since 0.1.0
77
+ */
78
+ export interface Input {
79
+ readonly runs: ReadonlyArray<Evidence>;
80
+ /** Attributed requests the control plane journaled, by run id. */
81
+ readonly requests: ReadonlyMap<string, Request>;
82
+ }
83
+ /**
84
+ * Attributes every cancelled run in one pass.
85
+ *
86
+ * Three sources, in the order a run's own evidence outranks its ancestors':
87
+ *
88
+ * 1. A `control.run.cancel-requested` entry names this run. Somebody asked for
89
+ * this run by name, and the entry says who and why.
90
+ * 2. A cancelled ancestor exists. The run was swept up in that cancellation,
91
+ * so it reports `cascade`, names the ancestor whose request started it, and
92
+ * inherits that request's principal and reason — the honest answer to "who
93
+ * cancelled this child" is the operator who cancelled its parent.
94
+ * 3. Neither. The engine cancelled the run on its own account: a lease
95
+ * expiry, a budget, a supervisor. There is no principal to report, and
96
+ * inventing one would be worse than saying nothing.
97
+ *
98
+ * The ancestor walk carries a visited set. A cyclic parent chain is not
99
+ * reachable through the engine's cycle detection, but a projection that hung
100
+ * on corrupt ancestry would take the control plane down with it.
101
+ *
102
+ * @param input the run evidence and the attributed requests
103
+ * @category projections
104
+ * @since 0.1.0
105
+ */
106
+ export declare const attribute: (input: Input) => ReadonlyMap<string, Cancellation>;
107
+ //# sourceMappingURL=Cancellation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Cancellation.d.ts","sourceRoot":"","sources":["../../src/Cancellation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEjE;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,iCAAiC,CAAA;AAEhE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,6BAA6B,CAAA;AAE9D;;;;;GAKG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CACrC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC1C;AAED;;;;;GAKG;AACH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAA;IACtC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAChD;AAwBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,SAAS,GAAI,OAAO,KAAK,KAAG,WAAW,CAAC,MAAM,EAAE,YAAY,CAqCxE,CAAA"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var Cancellation_exports = {};
20
+ __export(Cancellation_exports, {
21
+ attribute: () => attribute,
22
+ interruptedEventType: () => interruptedEventType,
23
+ requestedEventType: () => requestedEventType
24
+ });
25
+ module.exports = __toCommonJS(Cancellation_exports);
26
+ const requestedEventType = "control.run.cancel-requested";
27
+ const interruptedEventType = "flows.engine.interrupted";
28
+ const cancelled = (evidence, requests) => evidence.cancelRequestedAt !== void 0 || evidence.cancelledAt !== void 0 || requests.has(evidence.runId);
29
+ const requestedAtOf = (evidence, request) => {
30
+ return request?.requestedAt ?? evidence.cancelRequestedAt ?? evidence.cancelledAt ?? 0;
31
+ };
32
+ const attributed = (source, requestedAt, request, cascadedFrom) => ({
33
+ requestedAt,
34
+ source,
35
+ ...request?.principal === void 0 ? {} : { principal: request.principal },
36
+ ...request?.reason === void 0 ? {} : { reason: request.reason },
37
+ ...cascadedFrom === void 0 ? {} : { cascadedFrom }
38
+ });
39
+ const attribute = (input) => {
40
+ const evidence = new Map(input.runs.map((run) => [run.runId, run]));
41
+ const result = /* @__PURE__ */ new Map();
42
+ for (const run of input.runs) {
43
+ if (!cancelled(run, input.requests)) continue;
44
+ const own = input.requests.get(run.runId);
45
+ const requestedAt = requestedAtOf(run, own);
46
+ if (own !== void 0) {
47
+ result.set(run.runId, attributed("control", requestedAt, own));
48
+ continue;
49
+ }
50
+ const visited = /* @__PURE__ */ new Set([run.runId]);
51
+ let ancestorId = run.parentRunId;
52
+ let cascadedFrom;
53
+ let origin;
54
+ while (ancestorId !== void 0 && !visited.has(ancestorId)) {
55
+ visited.add(ancestorId);
56
+ const ancestor = evidence.get(ancestorId);
57
+ if (ancestor === void 0) break;
58
+ if (cancelled(ancestor, input.requests)) {
59
+ if (cascadedFrom === void 0) cascadedFrom = ancestorId;
60
+ origin = input.requests.get(ancestorId);
61
+ if (origin !== void 0) break;
62
+ }
63
+ ancestorId = ancestor.parentRunId;
64
+ }
65
+ result.set(
66
+ run.runId,
67
+ cascadedFrom === void 0 ? attributed("engine", requestedAt, void 0) : attributed("cascade", requestedAt, origin, cascadedFrom)
68
+ );
69
+ }
70
+ return result;
71
+ };
72
+ //# sourceMappingURL=Cancellation.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/Cancellation.ts"],
4
+ "sourcesContent": ["/**\n * Cancellation attribution as the control plane reads it back.\n *\n * A cancellation is durable but anonymous. `flows_runs.cancel_requested_at_ms`\n * records that somebody asked, and nothing in the row records who, why, or\n * whether the run was asked at all rather than swept up in an ancestor's\n * cascade. Three journals hold the missing halves: the control plane's own\n * `control.run.cancel-requested`, the engine's `flows.engine.interrupted`, and\n * the ancestry the run store already keeps. This module folds them into one\n * answer per run.\n *\n * The fold is pure and scope-independent: it reads whatever evidence it is\n * handed and never issues a query, so the caller chooses how much to read.\n * `SqlControlRuntime` uses two scopes. A listing folds the whole database,\n * because every row is going to be answered for anyway. A single-run read\n * folds only that run and its ancestor chain, which is the smallest scope that\n * can still answer the question: cascade is a fact about a run's ancestors, so\n * it cannot be decided one row at a time \u2014 a child's cancellation is\n * attributed to whoever asked for its nearest cancelled ancestor's, however\n * many rounds up that is.\n *\n * The two foreign event types are named as strings rather than imported,\n * exactly as in {@link Lineage}: a control plane reads journals, not engines.\n *\n * @since 0.1.0\n */\n\nimport type { Cancellation, Principal } from \"./ControlSchema.ts\"\n\n/**\n * The journal event type the control plane records an attributed cancel under.\n *\n * @category constants\n * @since 0.1.0\n */\nexport const requestedEventType = \"control.run.cancel-requested\"\n\n/**\n * The journal event type the engine records an interruption under.\n *\n * @category constants\n * @since 0.1.0\n */\nexport const interruptedEventType = \"flows.engine.interrupted\"\n\n/**\n * One attributed cancel request, as the control plane journaled it.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Request {\n readonly requestedAt: number\n readonly principal?: Principal | undefined\n readonly reason?: string | undefined\n}\n\n/**\n * What one run row discloses about its own cancellation.\n *\n * `cancelRequestedAt` is the run store's unfenced request column, and\n * `cancelledAt` is the moment the engine journaled the interruption. Either\n * one alone is evidence that this run was cancelled, and so is an attributed\n * request naming the run: a control plane that cancels a run it owns\n * interrupts the fiber rather than asking the column, and the journal entry it\n * wrote is the whole record.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Evidence {\n readonly runId: string\n readonly parentRunId?: string | undefined\n readonly cancelRequestedAt?: number | undefined\n readonly cancelledAt?: number | undefined\n}\n\n/**\n * Everything the fold reads.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Input {\n readonly runs: ReadonlyArray<Evidence>\n /** Attributed requests the control plane journaled, by run id. */\n readonly requests: ReadonlyMap<string, Request>\n}\n\nconst cancelled = (evidence: Evidence, requests: Input[\"requests\"]): boolean =>\n evidence.cancelRequestedAt !== undefined || evidence.cancelledAt !== undefined ||\n requests.has(evidence.runId)\n\nconst requestedAtOf = (evidence: Evidence, request: Request | undefined): number => {\n /* v8 ignore next -- the trailing zero is unreachable: a run is attributed only once one of the three sources above exists, which is exactly what `cancelled` reads */\n return request?.requestedAt ?? evidence.cancelRequestedAt ?? evidence.cancelledAt ?? 0\n}\n\nconst attributed = (\n source: Cancellation[\"source\"],\n requestedAt: number,\n request: Request | undefined,\n cascadedFrom?: string\n): Cancellation => ({\n requestedAt,\n source,\n ...(request?.principal === undefined ? {} : { principal: request.principal }),\n ...(request?.reason === undefined ? {} : { reason: request.reason }),\n ...(cascadedFrom === undefined ? {} : { cascadedFrom })\n})\n\n/**\n * Attributes every cancelled run in one pass.\n *\n * Three sources, in the order a run's own evidence outranks its ancestors':\n *\n * 1. A `control.run.cancel-requested` entry names this run. Somebody asked for\n * this run by name, and the entry says who and why.\n * 2. A cancelled ancestor exists. The run was swept up in that cancellation,\n * so it reports `cascade`, names the ancestor whose request started it, and\n * inherits that request's principal and reason \u2014 the honest answer to \"who\n * cancelled this child\" is the operator who cancelled its parent.\n * 3. Neither. The engine cancelled the run on its own account: a lease\n * expiry, a budget, a supervisor. There is no principal to report, and\n * inventing one would be worse than saying nothing.\n *\n * The ancestor walk carries a visited set. A cyclic parent chain is not\n * reachable through the engine's cycle detection, but a projection that hung\n * on corrupt ancestry would take the control plane down with it.\n *\n * @param input the run evidence and the attributed requests\n * @category projections\n * @since 0.1.0\n */\nexport const attribute = (input: Input): ReadonlyMap<string, Cancellation> => {\n const evidence = new Map(input.runs.map((run) => [run.runId, run]))\n const result = new Map<string, Cancellation>()\n for (const run of input.runs) {\n if (!cancelled(run, input.requests)) continue\n const own = input.requests.get(run.runId)\n const requestedAt = requestedAtOf(run, own)\n if (own !== undefined) {\n result.set(run.runId, attributed(\"control\", requestedAt, own))\n continue\n }\n const visited = new Set<string>([run.runId])\n let ancestorId = run.parentRunId\n let cascadedFrom: string | undefined\n let origin: Request | undefined\n while (ancestorId !== undefined && !visited.has(ancestorId)) {\n visited.add(ancestorId)\n const ancestor = evidence.get(ancestorId)\n if (ancestor === undefined) break\n if (cancelled(ancestor, input.requests)) {\n // The nearest cancelled ancestor is the run this one was swept up\n // with; the request that started it may be further up still, because\n // a cascade cascades.\n if (cascadedFrom === undefined) cascadedFrom = ancestorId\n origin = input.requests.get(ancestorId)\n if (origin !== undefined) break\n }\n ancestorId = ancestor.parentRunId\n }\n result.set(\n run.runId,\n cascadedFrom === undefined\n ? attributed(\"engine\", requestedAt, undefined)\n : attributed(\"cascade\", requestedAt, origin, cascadedFrom)\n )\n }\n return result\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCO,MAAM,qBAAqB;AAQ3B,MAAM,uBAAuB;AA8CpC,MAAM,YAAY,CAAC,UAAoB,aACrC,SAAS,sBAAsB,UAAa,SAAS,gBAAgB,UACrE,SAAS,IAAI,SAAS,KAAK;AAE7B,MAAM,gBAAgB,CAAC,UAAoB,YAAyC;AAElF,SAAO,SAAS,eAAe,SAAS,qBAAqB,SAAS,eAAe;AACvF;AAEA,MAAM,aAAa,CACjB,QACA,aACA,SACA,kBACkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA,GAAI,SAAS,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,QAAQ,UAAU;AAAA,EAC3E,GAAI,SAAS,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;AAAA,EAClE,GAAI,iBAAiB,SAAY,CAAC,IAAI,EAAE,aAAa;AACvD;AAyBO,MAAM,YAAY,CAAC,UAAoD;AAC5E,QAAM,WAAW,IAAI,IAAI,MAAM,KAAK,IAAI,CAAC,QAAQ,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;AAClE,QAAM,SAAS,oBAAI,IAA0B;AAC7C,aAAW,OAAO,MAAM,MAAM;AAC5B,QAAI,CAAC,UAAU,KAAK,MAAM,QAAQ,EAAG;AACrC,UAAM,MAAM,MAAM,SAAS,IAAI,IAAI,KAAK;AACxC,UAAM,cAAc,cAAc,KAAK,GAAG;AAC1C,QAAI,QAAQ,QAAW;AACrB,aAAO,IAAI,IAAI,OAAO,WAAW,WAAW,aAAa,GAAG,CAAC;AAC7D;AAAA,IACF;AACA,UAAM,UAAU,oBAAI,IAAY,CAAC,IAAI,KAAK,CAAC;AAC3C,QAAI,aAAa,IAAI;AACrB,QAAI;AACJ,QAAI;AACJ,WAAO,eAAe,UAAa,CAAC,QAAQ,IAAI,UAAU,GAAG;AAC3D,cAAQ,IAAI,UAAU;AACtB,YAAM,WAAW,SAAS,IAAI,UAAU;AACxC,UAAI,aAAa,OAAW;AAC5B,UAAI,UAAU,UAAU,MAAM,QAAQ,GAAG;AAIvC,YAAI,iBAAiB,OAAW,gBAAe;AAC/C,iBAAS,MAAM,SAAS,IAAI,UAAU;AACtC,YAAI,WAAW,OAAW;AAAA,MAC5B;AACA,mBAAa,SAAS;AAAA,IACxB;AACA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,iBAAiB,SACb,WAAW,UAAU,aAAa,MAAS,IAC3C,WAAW,WAAW,aAAa,QAAQ,YAAY;AAAA,IAC7D;AAAA,EACF;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Channel contracts and the in-memory channel coordinator.
3
+ *
4
+ * A channel verifies opaque transport data before it decodes or maps it. The
5
+ * resulting request is then dispatched through the Control service; channels
6
+ * do not acquire an execution path of their own.
7
+ *
8
+ * @since 0.1.0
9
+ */
10
+ import { Context, Effect, Layer, type Schema } from "effect";
11
+ import { Control } from "./Control.ts";
12
+ import { type ControlError, InvalidInput, type Unauthorized, Unavailable } from "./ControlError.ts";
13
+ import { ControlRuntime } from "./ControlRuntime.ts";
14
+ import type { FlowId, IdempotencyKey, Receipt, RunId, RunSummary, SignalPayload } from "./ControlSchema.ts";
15
+ /**
16
+ * Opaque request data passed to a channel before decoding.
17
+ *
18
+ * @category models
19
+ * @since 0.1.0
20
+ */
21
+ export interface RawInbound {
22
+ readonly body: Uint8Array;
23
+ readonly headers: Readonly<Record<string, string | undefined>>;
24
+ readonly idempotencyKey: IdempotencyKey;
25
+ }
26
+ /**
27
+ * The channel mapping after a verified payload has been decoded.
28
+ *
29
+ * @category models
30
+ * @since 0.1.0
31
+ */
32
+ export type InboundResult = {
33
+ readonly _tag: "Start";
34
+ readonly flowId: FlowId;
35
+ readonly input: unknown;
36
+ } | {
37
+ readonly _tag: "Signal";
38
+ readonly runId: RunId;
39
+ readonly signal: SignalPayload;
40
+ };
41
+ /**
42
+ * A process-local per-channel delivery record. `messageId` identifies an existing
43
+ * platform message, so a reconnect can update it instead of posting again.
44
+ *
45
+ * @category models
46
+ * @since 0.1.0
47
+ */
48
+ export interface Delivery {
49
+ readonly cursor: string;
50
+ readonly messageId?: string | undefined;
51
+ }
52
+ /**
53
+ * A side-effect-free outbound projection. Network delivery belongs to the
54
+ * transport adapter, which consumes this value after it is journaled.
55
+ *
56
+ * @category models
57
+ * @since 0.1.0
58
+ */
59
+ export interface DeliveryProjection {
60
+ readonly cursor: string;
61
+ readonly messageId?: string | undefined;
62
+ readonly operation: "post" | "edit" | "noop";
63
+ readonly message: unknown;
64
+ }
65
+ /**
66
+ * A bidirectional platform adapter.
67
+ *
68
+ * `verify` must only inspect opaque bytes and headers. It always precedes
69
+ * `decode`, preventing untrusted public requests from reaching planning.
70
+ *
71
+ * @category services
72
+ * @since 0.1.0
73
+ */
74
+ export interface Channel<A = unknown> {
75
+ readonly name: string;
76
+ readonly schema: Schema.Schema<A>;
77
+ /**
78
+ * Non-secret HTTP header names whose values change the decoded command.
79
+ * Names are matched case-insensitively and folded into durable idempotency;
80
+ * signature, authorization, and credential headers must not be declared.
81
+ */
82
+ readonly fingerprintHeaders?: ReadonlyArray<string> | undefined;
83
+ readonly verify: (raw: RawInbound) => Effect.Effect<void, Unauthorized>;
84
+ /** Deterministic, side-effect-free decoding; retries may evaluate it again. */
85
+ readonly decode: (raw: RawInbound) => Effect.Effect<A, InvalidInput>;
86
+ /** Deterministic, side-effect-free mapping; retries may evaluate it again. */
87
+ readonly map: (payload: A) => Effect.Effect<InboundResult, InvalidInput>;
88
+ readonly project: (run: RunSummary, delivery: Delivery | undefined) => DeliveryProjection;
89
+ }
90
+ /**
91
+ * A registered channel with its payload type hidden. Decoding and mapping stay
92
+ * paired, so lookup never exposes a mapper accepting arbitrary unknown data.
93
+ *
94
+ * @category models
95
+ * @since 1.0.0
96
+ */
97
+ export interface RegisteredChannel extends Omit<Channel, "decode" | "map"> {
98
+ readonly decodeAndMap: (raw: RawInbound) => Effect.Effect<InboundResult, InvalidInput>;
99
+ }
100
+ /**
101
+ * Arguments for ingesting one authenticated channel request.
102
+ *
103
+ * @category models
104
+ * @since 0.1.0
105
+ */
106
+ export interface IngestRequest {
107
+ readonly channel: string;
108
+ readonly raw: RawInbound;
109
+ }
110
+ /**
111
+ * Arguments for projecting one run onto a channel.
112
+ *
113
+ * @category models
114
+ * @since 0.1.0
115
+ */
116
+ export interface ProjectRequest {
117
+ readonly channel: string;
118
+ readonly run: RunSummary;
119
+ }
120
+ /**
121
+ * The channel coordinator.
122
+ *
123
+ * @category services
124
+ * @since 0.1.0
125
+ */
126
+ export interface Channels {
127
+ readonly register: <A>(channel: Channel<A>) => Effect.Effect<void>;
128
+ readonly lookup: (name: string) => Effect.Effect<RegisteredChannel, Unavailable>;
129
+ readonly ingest: (request: IngestRequest) => Effect.Effect<Receipt, ControlError>;
130
+ readonly project: (request: ProjectRequest) => Effect.Effect<DeliveryProjection, Unavailable>;
131
+ }
132
+ /**
133
+ * Service tag for channel registration, ingestion, and pure projection.
134
+ *
135
+ * @category services
136
+ * @since 0.1.0
137
+ */
138
+ export declare const Channels: Context.Service<Channels, Channels>;
139
+ /**
140
+ * Builds the coordinator over Control's durable mutation store.
141
+ *
142
+ * @category constructors
143
+ * @since 1.0.0
144
+ */
145
+ export declare const make: Effect.Effect<Channels, never, Control | ControlRuntime>;
146
+ /**
147
+ * Builds a process-local coordinator for adapter unit tests.
148
+ *
149
+ * Production hosts use {@link layer}; this constructor deliberately makes no
150
+ * restart guarantee.
151
+ *
152
+ * @category constructors
153
+ * @since 1.0.0
154
+ */
155
+ export declare const makeMemory: Effect.Effect<Channels, never, Control>;
156
+ /**
157
+ * Channel layer with durable inbound receipts supplied by `ControlRuntime`.
158
+ *
159
+ * @category layers
160
+ * @since 0.1.0
161
+ */
162
+ export declare const layer: Layer.Layer<Channels, never, Control | ControlRuntime>;
163
+ /**
164
+ * Process-local channel layer for adapter unit tests only.
165
+ *
166
+ * @category layers
167
+ * @since 1.0.0
168
+ */
169
+ export declare const layerMemory: Layer.Layer<Channels, never, Control>;
170
+ //# sourceMappingURL=Channels.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Channels.d.ts","sourceRoot":"","sources":["../../src/Channels.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,278 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var Channels_exports = {};
30
+ __export(Channels_exports, {
31
+ Channels: () => Channels,
32
+ layer: () => layer,
33
+ layerMemory: () => layerMemory,
34
+ make: () => make,
35
+ makeMemory: () => makeMemory
36
+ });
37
+ module.exports = __toCommonJS(Channels_exports);
38
+ var Sha256 = __toESM(require("@smthrs/crypto/Sha256"), 1);
39
+ var import_effect = require("effect");
40
+ var import_Control = require("./Control.js");
41
+ var import_ControlError = require("./ControlError.js");
42
+ var import_ControlRuntime = require("./ControlRuntime.js");
43
+ var import_planning = require("./internal/planning.js");
44
+ const eraseChannel = (channel) => ({
45
+ name: channel.name,
46
+ schema: channel.schema,
47
+ fingerprintHeaders: channel.fingerprintHeaders,
48
+ verify: (raw) => channel.verify(raw),
49
+ decodeAndMap: (raw) => import_effect.Effect.flatMap(channel.decode(raw), (payload) => channel.map(payload)),
50
+ project: (run, delivery) => channel.project(run, delivery)
51
+ });
52
+ const Channels = import_effect.Context.Service("/control/Channels");
53
+ const unavailable = (feature) => new import_ControlError.Unavailable({
54
+ feature,
55
+ ticket: "control-channel-registry"
56
+ });
57
+ const deliveryKey = (channel, run) => `${channel.length}:${channel}:${run.runId}`;
58
+ const scopedKey = (channel, key) => `channel:${channel.length}:${channel}:${key}`;
59
+ const mutationKey = (channel, key) => `channel.ingest:${scopedKey(channel, key)}`;
60
+ const typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
61
+ const typedArrayBuffer = Object.getOwnPropertyDescriptor(typedArrayPrototype, "buffer")?.get;
62
+ const typedArrayByteOffset = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteOffset")?.get;
63
+ const typedArrayByteLength = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
64
+ class InboundBoundaryError extends TypeError {
65
+ issue;
66
+ constructor(issue) {
67
+ super(issue);
68
+ this.issue = issue;
69
+ }
70
+ }
71
+ const boundary = (issue) => {
72
+ throw new InboundBoundaryError(issue);
73
+ };
74
+ const plainRecord = (input, path) => {
75
+ if (typeof input !== "object" || input === null || Array.isArray(input)) {
76
+ return boundary(`${path}: must be a plain record`);
77
+ }
78
+ const prototype = Object.getPrototypeOf(input);
79
+ if (prototype !== Object.prototype && prototype !== null) {
80
+ return boundary(`${path}: must have a plain prototype`);
81
+ }
82
+ return input;
83
+ };
84
+ const ownData = (input, key, path) => {
85
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
86
+ if (descriptor === void 0 || !("value" in descriptor)) return boundary(`${path}: must be an own data property`);
87
+ return descriptor.value;
88
+ };
89
+ const copyBody = (input) => {
90
+ if (typedArrayBuffer === void 0 || typedArrayByteOffset === void 0 || typedArrayByteLength === void 0) return boundary("raw.body: this host cannot inspect typed arrays");
91
+ try {
92
+ const buffer = Reflect.apply(typedArrayBuffer, input, []);
93
+ const byteOffset = Reflect.apply(typedArrayByteOffset, input, []);
94
+ const byteLength = Reflect.apply(typedArrayByteLength, input, []);
95
+ const source = new Uint8Array(buffer, byteOffset, byteLength);
96
+ const snapshot = new Uint8Array(byteLength);
97
+ snapshot.set(source);
98
+ return snapshot;
99
+ } catch {
100
+ return boundary("raw.body: must be a Uint8Array");
101
+ }
102
+ };
103
+ const snapshotHeaders = (input) => {
104
+ const record = plainRecord(input, "raw.headers");
105
+ const snapshot = /* @__PURE__ */ Object.create(null);
106
+ for (const key of Reflect.ownKeys(record)) {
107
+ if (typeof key !== "string") return boundary("raw.headers: symbol keys are not supported");
108
+ const descriptor = Object.getOwnPropertyDescriptor(record, key);
109
+ if (descriptor === void 0 || !("value" in descriptor) || !descriptor.enumerable) {
110
+ return boundary(`raw.headers.${key}: must be an enumerable data property`);
111
+ }
112
+ if (descriptor.value !== void 0 && typeof descriptor.value !== "string") {
113
+ return boundary(`raw.headers.${key}: must be a string or undefined`);
114
+ }
115
+ const normalized = key.toLowerCase();
116
+ if (Object.hasOwn(snapshot, normalized)) {
117
+ return boundary(`raw.headers.${normalized}: duplicate case-insensitive name`);
118
+ }
119
+ snapshot[normalized] = descriptor.value;
120
+ }
121
+ return Object.freeze(snapshot);
122
+ };
123
+ const snapshotRequest = (input) => import_effect.Effect.try({
124
+ try: () => {
125
+ const request = plainRecord(input, "request");
126
+ const channel = ownData(request, "channel", "request.channel");
127
+ const candidate = plainRecord(ownData(request, "raw", "request.raw"), "request.raw");
128
+ const idempotencyKey = ownData(candidate, "idempotencyKey", "raw.idempotencyKey");
129
+ if (typeof channel !== "string" || channel.length === 0) return boundary("request.channel: must be non-empty");
130
+ if (typeof idempotencyKey !== "string" || idempotencyKey.length === 0) {
131
+ return boundary("raw.idempotencyKey: must be non-empty");
132
+ }
133
+ return Object.freeze({
134
+ channel,
135
+ raw: Object.freeze({
136
+ body: copyBody(ownData(candidate, "body", "raw.body")),
137
+ headers: snapshotHeaders(ownData(candidate, "headers", "raw.headers")),
138
+ idempotencyKey
139
+ })
140
+ });
141
+ },
142
+ catch: (cause) => new import_ControlError.InvalidInput({
143
+ issue: cause instanceof InboundBoundaryError ? cause.issue : "channel request could not be inspected safely"
144
+ })
145
+ });
146
+ const normalizedFingerprintHeaders = (channel) => Array.from(new Set((channel.fingerprintHeaders ?? []).map((name) => name.toLowerCase()))).sort();
147
+ const fingerprint = (body, headers, names) => {
148
+ const document = JSON.stringify([
149
+ Sha256.digestSync(body),
150
+ names.map((name) => [name, headers[name] ?? null])
151
+ ]);
152
+ return `channel-ingress:v2:${Sha256.digestSync(new TextEncoder().encode(document))}`;
153
+ };
154
+ const externalReceipt = (receipt, key) => {
155
+ switch (receipt._tag) {
156
+ case "Accepted":
157
+ case "AlreadyApplied":
158
+ case "Parked":
159
+ return { ...receipt, receiptId: key };
160
+ default:
161
+ return receipt;
162
+ }
163
+ };
164
+ const makeWith = (runtime) => import_effect.Effect.gen(function* () {
165
+ const channels = yield* import_effect.Ref.make(/* @__PURE__ */ new Map());
166
+ const deliveries = /* @__PURE__ */ new Map();
167
+ const terminalDeliveries = /* @__PURE__ */ new Set();
168
+ const maximumTerminalDeliveries = 1024;
169
+ const ingestion = yield* import_effect.Semaphore.make(1);
170
+ const control = yield* import_Control.Control;
171
+ const lookup = import_effect.Effect.fn("Channels.lookup")(
172
+ function* (name) {
173
+ return yield* import_effect.Effect.flatMap(import_effect.Ref.get(channels), (registered) => {
174
+ const channel = registered.get(name);
175
+ return channel === void 0 ? import_effect.Effect.fail(unavailable(`channel "${name}" is not registered`)) : import_effect.Effect.succeed(channel);
176
+ });
177
+ }
178
+ );
179
+ return Channels.of({
180
+ register: import_effect.Effect.fn("Channels.register")(
181
+ (channel) => import_effect.Ref.update(channels, (registered) => {
182
+ const next = new Map(registered);
183
+ next.set(channel.name, eraseChannel(channel));
184
+ return next;
185
+ })
186
+ ),
187
+ lookup,
188
+ ingest: import_effect.Effect.fn("Channels.ingest")(
189
+ (request) => import_effect.Effect.flatMap(snapshotRequest(request), (snapshot) => ingestion.withPermits(1)(import_effect.Effect.gen(function* () {
190
+ const channel = yield* lookup(snapshot.channel);
191
+ const fingerprintHeaders = normalizedFingerprintHeaders(channel);
192
+ const bodyFingerprint = fingerprint(snapshot.raw.body, snapshot.raw.headers, fingerprintHeaders);
193
+ yield* channel.verify({ ...snapshot.raw, body: copyBody(snapshot.raw.body) });
194
+ const externalKey = snapshot.raw.idempotencyKey;
195
+ const durableKey = mutationKey(snapshot.channel, externalKey);
196
+ const prior = yield* runtime.lookupMutation(durableKey, bodyFingerprint);
197
+ if (prior !== void 0) return externalReceipt(prior, externalKey);
198
+ const mapped = yield* channel.decodeAndMap(snapshot.raw);
199
+ const key = scopedKey(snapshot.channel, externalKey);
200
+ let receipt;
201
+ if (mapped._tag === "Signal") {
202
+ receipt = yield* control.signal({
203
+ runId: mapped.runId,
204
+ signal: mapped.signal,
205
+ idempotencyKey: key,
206
+ principal: { id: snapshot.channel, kind: "channel", stampedAt: yield* import_effect.Clock.currentTimeMillis }
207
+ });
208
+ } else {
209
+ const plan = yield* control.plan({
210
+ flowId: mapped.flowId,
211
+ input: mapped.input,
212
+ idempotencyKey: key
213
+ });
214
+ receipt = yield* control.run({
215
+ _tag: "Plan",
216
+ planId: plan.planId,
217
+ digest: plan.digest,
218
+ envelope: plan.envelope,
219
+ idempotencyKey: key
220
+ });
221
+ }
222
+ if (receipt._tag !== "Conflict" && receipt._tag !== "Parked") {
223
+ yield* runtime.recordMutation(durableKey, bodyFingerprint, receipt);
224
+ }
225
+ return externalReceipt(receipt, externalKey);
226
+ })))
227
+ ),
228
+ project: import_effect.Effect.fn("Channels.project")(function* (request) {
229
+ const channel = yield* lookup(request.channel);
230
+ const key = deliveryKey(request.channel, request.run);
231
+ return yield* import_effect.Effect.sync(() => {
232
+ const prior = deliveries.get(key);
233
+ const projection = channel.project(request.run, prior);
234
+ if (projection.operation !== "noop" && (prior === void 0 || prior.cursor !== projection.cursor || prior.messageId !== projection.messageId)) {
235
+ deliveries.set(key, { cursor: projection.cursor, messageId: projection.messageId });
236
+ }
237
+ if (deliveries.has(key)) {
238
+ const status = request.run.status;
239
+ if (status === "completed" || status === "failed" || status === "cancelled") {
240
+ terminalDeliveries.add(key);
241
+ if (terminalDeliveries.size > maximumTerminalDeliveries) {
242
+ const oldest = terminalDeliveries.values().next().value;
243
+ terminalDeliveries.delete(oldest);
244
+ deliveries.delete(oldest);
245
+ }
246
+ } else {
247
+ terminalDeliveries.delete(key);
248
+ }
249
+ }
250
+ return projection;
251
+ });
252
+ })
253
+ });
254
+ });
255
+ const make = import_effect.Effect.gen(function* () {
256
+ const runtime = yield* import_ControlRuntime.ControlRuntime;
257
+ return yield* makeWith(runtime);
258
+ });
259
+ const makeMemory = import_effect.Effect.gen(function* () {
260
+ const records = yield* import_effect.Ref.make(
261
+ /* @__PURE__ */ new Map()
262
+ );
263
+ return yield* makeWith({
264
+ lookupMutation: (key, candidate) => import_effect.Ref.get(records).pipe(import_effect.Effect.map((stored) => {
265
+ const prior = stored.get(key);
266
+ if (prior === void 0) return void 0;
267
+ return prior.fingerprint === candidate ? (0, import_planning.alreadyApplied)(key, prior.receipt) : { _tag: "Conflict", message: `idempotency key ${key} was used for another mutation` };
268
+ })),
269
+ recordMutation: (key, candidate, receipt) => import_effect.Ref.update(records, (stored) => {
270
+ const next = new Map(stored);
271
+ next.set(key, { fingerprint: candidate, receipt });
272
+ return next;
273
+ })
274
+ });
275
+ });
276
+ const layer = import_effect.Layer.effect(Channels, make);
277
+ const layerMemory = import_effect.Layer.effect(Channels, makeMemory);
278
+ //# sourceMappingURL=Channels.js.map