blokctl 1.2.0 → 1.4.0

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 (693) hide show
  1. package/dist/commands/create/project.d.ts +3 -0
  2. package/dist/commands/create/project.js +166 -21
  3. package/dist/commands/create/utils/Examples.d.ts +2 -2
  4. package/dist/commands/create/utils/Examples.js +9 -3
  5. package/dist/commands/dev/index.js +13 -1
  6. package/dist/commands/runtime/add.js +92 -29
  7. package/dist/commands/runtime/index.js +1 -0
  8. package/dist/commands/runtime/shared.js +4 -0
  9. package/dist/scaffold-repo/examples/ts-workflows/mcp-greeter.ts +59 -0
  10. package/dist/scaffold-repo/examples/ts-workflows/runtime-csharp-hello.ts +36 -0
  11. package/dist/scaffold-repo/examples/ts-workflows/runtime-go-hello.ts +36 -0
  12. package/dist/scaffold-repo/examples/ts-workflows/runtime-java-hello.ts +36 -0
  13. package/dist/scaffold-repo/examples/ts-workflows/runtime-php-hello.ts +36 -0
  14. package/dist/scaffold-repo/examples/ts-workflows/runtime-python3-hello.ts +36 -0
  15. package/dist/scaffold-repo/examples/ts-workflows/runtime-ruby-hello.ts +36 -0
  16. package/dist/scaffold-repo/examples/ts-workflows/runtime-rust-hello.ts +36 -0
  17. package/dist/scaffold-repo/infra/development/3055.dat +602 -0
  18. package/dist/scaffold-repo/infra/development/3057.dat +203 -0
  19. package/dist/scaffold-repo/infra/development/3059.dat +19 -0
  20. package/dist/scaffold-repo/infra/development/3061.dat +1003 -0
  21. package/dist/scaffold-repo/infra/development/3062.dat +5465 -0
  22. package/dist/scaffold-repo/infra/development/3063.dat +1003 -0
  23. package/dist/scaffold-repo/infra/development/3065.dat +606 -0
  24. package/dist/scaffold-repo/infra/development/3067.dat +603 -0
  25. package/dist/scaffold-repo/infra/development/3069.dat +112 -0
  26. package/dist/scaffold-repo/infra/development/3071.dat +4584 -0
  27. package/dist/scaffold-repo/infra/development/3073.dat +9 -0
  28. package/dist/scaffold-repo/infra/development/3075.dat +14599 -0
  29. package/dist/scaffold-repo/infra/development/3077.dat +16047 -0
  30. package/dist/scaffold-repo/infra/development/3079.dat +5 -0
  31. package/dist/scaffold-repo/infra/development/3081.dat +5 -0
  32. package/dist/scaffold-repo/infra/development/docker-compose.yml +106 -0
  33. package/dist/scaffold-repo/infra/development/schema.sql +1616 -0
  34. package/dist/scaffold-repo/infra/development/toc.dat +0 -0
  35. package/dist/scaffold-repo/infra/metrics/alertmanager.yml +43 -0
  36. package/dist/scaffold-repo/infra/metrics/alloy-config.alloy +75 -0
  37. package/dist/scaffold-repo/infra/metrics/dashboard.json +1152 -0
  38. package/dist/scaffold-repo/infra/metrics/dashboards/blok-overview.json +314 -0
  39. package/dist/scaffold-repo/infra/metrics/dashboards/blok-system.json +175 -0
  40. package/dist/scaffold-repo/infra/metrics/dashboards/blok-tracing.json +235 -0
  41. package/dist/scaffold-repo/infra/metrics/dashboards/blok-triggers.json +258 -0
  42. package/dist/scaffold-repo/infra/metrics/datasources.yml +43 -0
  43. package/dist/scaffold-repo/infra/metrics/default.yaml +8 -0
  44. package/dist/scaffold-repo/infra/metrics/docker-compose.yml +193 -0
  45. package/dist/scaffold-repo/infra/metrics/loki-config.yaml +50 -0
  46. package/dist/scaffold-repo/infra/metrics/nginx.conf +25 -0
  47. package/dist/scaffold-repo/infra/metrics/prometheus.yml +51 -0
  48. package/dist/scaffold-repo/infra/metrics/rules/blok-alerts.yml +114 -0
  49. package/dist/scaffold-repo/infra/metrics/telegraf.conf +41 -0
  50. package/dist/scaffold-repo/infra/metrics/tempo.yaml +81 -0
  51. package/dist/scaffold-repo/infra/milvus/docker-compose.yml +73 -0
  52. package/dist/scaffold-repo/sdk/javascript/README.md +151 -0
  53. package/dist/scaffold-repo/sdk/javascript/bootstrap.min.css +11660 -0
  54. package/dist/scaffold-repo/sdk/javascript/image-ai.html +316 -0
  55. package/dist/scaffold-repo/sdk/javascript/nanosdk.js +180 -0
  56. package/dist/scaffold-repo/sdk/javascript/nanosdk.min.js +100 -0
  57. package/dist/scaffold-repo/sdk/javascript/pdf.html +63 -0
  58. package/dist/scaffold-repo/sdk/javascript/test.html +68 -0
  59. package/dist/scaffold-repo/sdks/CLAUDE.md +67 -0
  60. package/dist/scaffold-repo/sdks/csharp/.dockerignore +7 -0
  61. package/dist/scaffold-repo/sdks/csharp/Blok.Core.sln +24 -0
  62. package/dist/scaffold-repo/sdks/csharp/Dockerfile +42 -0
  63. package/dist/scaffold-repo/sdks/csharp/README.md +138 -0
  64. package/dist/scaffold-repo/sdks/csharp/proto/blok/runtime/v1/runtime.proto +302 -0
  65. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Blok.Core.csproj +39 -0
  66. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Config/ServerConfig.cs +90 -0
  67. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokError.cs +538 -0
  68. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokErrorCategory.cs +112 -0
  69. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokErrorSeverity.cs +40 -0
  70. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BuildContextSnapshot.cs +168 -0
  71. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/ErrorCategory.cs +13 -0
  72. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/NodeException.cs +44 -0
  73. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/LogEntry.cs +34 -0
  74. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/LogLevel.cs +12 -0
  75. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/Logger.cs +92 -0
  76. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/IMiddleware.cs +14 -0
  77. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/LoggingMiddleware.cs +46 -0
  78. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/MiddlewareChain.cs +35 -0
  79. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/RecoveryMiddleware.cs +63 -0
  80. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/INodeHandler.cs +17 -0
  81. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/NodeRegistry.cs +128 -0
  82. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/TypedNode.cs +140 -0
  83. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/ApiCallNode.cs +129 -0
  84. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/BlokErrorDemoNode.cs +125 -0
  85. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/ChainTestNode.cs +79 -0
  86. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/HelloWorldNode.cs +45 -0
  87. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/TransformDataNode.cs +119 -0
  88. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/TypedGreetNode.cs +23 -0
  89. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Program.cs +26 -0
  90. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Server/BlokNodeRuntimeService.cs +536 -0
  91. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Server/RuntimeServer.cs +183 -0
  92. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Testing/MockContextBuilder.cs +117 -0
  93. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Testing/TestNodeRunner.cs +50 -0
  94. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Context.cs +56 -0
  95. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionMetrics.cs +21 -0
  96. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionRequest.cs +15 -0
  97. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionResult.cs +104 -0
  98. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/HealthStatus.cs +18 -0
  99. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/NodeConfig.cs +59 -0
  100. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Request.cs +57 -0
  101. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Response.cs +24 -0
  102. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/UserNodeRegistry.cs +17 -0
  103. package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Validation/SchemaValidator.cs +198 -0
  104. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Blok.Core.Tests.csproj +25 -0
  105. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Errors/BlokErrorTests.cs +458 -0
  106. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Logging/LoggerTests.cs +129 -0
  107. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Node/NodeRegistryTests.cs +145 -0
  108. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Testing/MockContextTests.cs +153 -0
  109. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/TypedNodeTests.cs +69 -0
  110. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Types/ExecutionResultTests.cs +110 -0
  111. package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Validation/SchemaValidatorTests.cs +233 -0
  112. package/dist/scaffold-repo/sdks/go/Dockerfile +33 -0
  113. package/dist/scaffold-repo/sdks/go/README.md +255 -0
  114. package/dist/scaffold-repo/sdks/go/blok_error.go +803 -0
  115. package/dist/scaffold-repo/sdks/go/blok_error_test.go +433 -0
  116. package/dist/scaffold-repo/sdks/go/cmd/server/main.go +45 -0
  117. package/dist/scaffold-repo/sdks/go/cmd/server/register_user_nodes.go +12 -0
  118. package/dist/scaffold-repo/sdks/go/config.go +157 -0
  119. package/dist/scaffold-repo/sdks/go/config_test.go +129 -0
  120. package/dist/scaffold-repo/sdks/go/define_node.go +87 -0
  121. package/dist/scaffold-repo/sdks/go/define_node_test.go +75 -0
  122. package/dist/scaffold-repo/sdks/go/errors.go +104 -0
  123. package/dist/scaffold-repo/sdks/go/errors_test.go +95 -0
  124. package/dist/scaffold-repo/sdks/go/examples/nodes/apicall.go +117 -0
  125. package/dist/scaffold-repo/sdks/go/examples/nodes/blokerrordemo.go +80 -0
  126. package/dist/scaffold-repo/sdks/go/examples/nodes/chaintest.go +63 -0
  127. package/dist/scaffold-repo/sdks/go/examples/nodes/helloworld.go +41 -0
  128. package/dist/scaffold-repo/sdks/go/examples/nodes/transformdata.go +176 -0
  129. package/dist/scaffold-repo/sdks/go/examples/nodes/typedgreet.go +34 -0
  130. package/dist/scaffold-repo/sdks/go/genpb/blok/runtime/v1/runtime.pb.go +2070 -0
  131. package/dist/scaffold-repo/sdks/go/genpb/blok/runtime/v1/runtime_grpc.pb.go +273 -0
  132. package/dist/scaffold-repo/sdks/go/go.mod +25 -0
  133. package/dist/scaffold-repo/sdks/go/go.sum +66 -0
  134. package/dist/scaffold-repo/sdks/go/grpc_server.go +670 -0
  135. package/dist/scaffold-repo/sdks/go/grpc_server_test.go +474 -0
  136. package/dist/scaffold-repo/sdks/go/logging.go +144 -0
  137. package/dist/scaffold-repo/sdks/go/logging_test.go +139 -0
  138. package/dist/scaffold-repo/sdks/go/middleware.go +152 -0
  139. package/dist/scaffold-repo/sdks/go/middleware_test.go +222 -0
  140. package/dist/scaffold-repo/sdks/go/node.go +50 -0
  141. package/dist/scaffold-repo/sdks/go/proto/blok/runtime/v1/runtime.proto +302 -0
  142. package/dist/scaffold-repo/sdks/go/registry.go +156 -0
  143. package/dist/scaffold-repo/sdks/go/registry_test.go +195 -0
  144. package/dist/scaffold-repo/sdks/go/server.go +207 -0
  145. package/dist/scaffold-repo/sdks/go/server_test.go +186 -0
  146. package/dist/scaffold-repo/sdks/go/shutdown.go +32 -0
  147. package/dist/scaffold-repo/sdks/go/testutil.go +169 -0
  148. package/dist/scaffold-repo/sdks/go/testutil_test.go +124 -0
  149. package/dist/scaffold-repo/sdks/go/types.go +295 -0
  150. package/dist/scaffold-repo/sdks/go/types_test.go +251 -0
  151. package/dist/scaffold-repo/sdks/go/validation.go +210 -0
  152. package/dist/scaffold-repo/sdks/go/validation_test.go +262 -0
  153. package/dist/scaffold-repo/sdks/go/worker.go +577 -0
  154. package/dist/scaffold-repo/sdks/java/Dockerfile +33 -0
  155. package/dist/scaffold-repo/sdks/java/README.md +221 -0
  156. package/dist/scaffold-repo/sdks/java/pom.xml +163 -0
  157. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/Main.java +90 -0
  158. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/UserNodeRegistry.java +19 -0
  159. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/config/ServerConfig.java +244 -0
  160. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokError.java +576 -0
  161. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokErrorCategory.java +68 -0
  162. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokErrorSeverity.java +31 -0
  163. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BuildContextSnapshot.java +132 -0
  164. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/ErrorCategory.java +22 -0
  165. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/NodeException.java +176 -0
  166. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/LogEntry.java +78 -0
  167. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/LogLevel.java +48 -0
  168. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/Logger.java +160 -0
  169. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/LoggingMiddleware.java +65 -0
  170. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/Middleware.java +29 -0
  171. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/MiddlewareChain.java +59 -0
  172. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/RecoveryMiddleware.java +53 -0
  173. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeHandler.java +40 -0
  174. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeReflector.java +18 -0
  175. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeRegistry.java +205 -0
  176. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/TypedNode.java +143 -0
  177. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/ApiCallNode.java +145 -0
  178. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/BlokErrorDemoNode.java +109 -0
  179. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/ChainTestNode.java +65 -0
  180. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/HelloWorldNode.java +62 -0
  181. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/TransformDataNode.java +121 -0
  182. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/TypedGreetNode.java +41 -0
  183. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/BlokGrpcServer.java +103 -0
  184. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/BlokNodeRuntimeService.java +501 -0
  185. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/RuntimeServer.java +176 -0
  186. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/testing/MockContext.java +120 -0
  187. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/testing/TestRunner.java +59 -0
  188. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Context.java +167 -0
  189. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionMetrics.java +80 -0
  190. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionRequest.java +61 -0
  191. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionResult.java +188 -0
  192. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/HealthStatus.java +77 -0
  193. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/NodeConfig.java +139 -0
  194. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Request.java +154 -0
  195. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Response.java +77 -0
  196. package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/validation/SchemaValidator.java +178 -0
  197. package/dist/scaffold-repo/sdks/java/src/main/proto/blok/runtime/v1/runtime.proto +302 -0
  198. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/errors/BlokErrorTest.java +416 -0
  199. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/logging/LoggerTest.java +176 -0
  200. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/node/NodeRegistryTest.java +227 -0
  201. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/node/TypedNodeTest.java +76 -0
  202. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/server/RuntimeServerTest.java +197 -0
  203. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/types/ExecutionResultTest.java +194 -0
  204. package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/validation/SchemaValidatorTest.java +246 -0
  205. package/dist/scaffold-repo/sdks/php/.rr.yaml +29 -0
  206. package/dist/scaffold-repo/sdks/php/Dockerfile +61 -0
  207. package/dist/scaffold-repo/sdks/php/README.md +387 -0
  208. package/dist/scaffold-repo/sdks/php/composer.json +41 -0
  209. package/dist/scaffold-repo/sdks/php/examples/ApiCallNode.php +103 -0
  210. package/dist/scaffold-repo/sdks/php/examples/BlokErrorDemoNode.php +90 -0
  211. package/dist/scaffold-repo/sdks/php/examples/ChainTestNode.php +56 -0
  212. package/dist/scaffold-repo/sdks/php/examples/HelloWorldNode.php +39 -0
  213. package/dist/scaffold-repo/sdks/php/examples/TransformDataNode.php +94 -0
  214. package/dist/scaffold-repo/sdks/php/examples/TypedGreetNode.php +57 -0
  215. package/dist/scaffold-repo/sdks/php/phpunit.xml +23 -0
  216. package/dist/scaffold-repo/sdks/php/proto/blok/runtime/v1/runtime.proto +302 -0
  217. package/dist/scaffold-repo/sdks/php/src/Config/ServerConfig.php +83 -0
  218. package/dist/scaffold-repo/sdks/php/src/Errors/BlokError.php +467 -0
  219. package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorBuilder.php +121 -0
  220. package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorCategory.php +83 -0
  221. package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorSeverity.php +30 -0
  222. package/dist/scaffold-repo/sdks/php/src/Errors/BuildContextSnapshot.php +141 -0
  223. package/dist/scaffold-repo/sdks/php/src/Errors/ErrorCategory.php +17 -0
  224. package/dist/scaffold-repo/sdks/php/src/Errors/NodeException.php +107 -0
  225. package/dist/scaffold-repo/sdks/php/src/Errors/Origin.php +35 -0
  226. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ErrorCategory.php +118 -0
  227. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ErrorSeverity.php +72 -0
  228. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteEvent.php +181 -0
  229. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteOptions.php +159 -0
  230. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteRequest.php +328 -0
  231. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteResponse.php +288 -0
  232. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthRequest.php +59 -0
  233. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthResponse/Status.php +54 -0
  234. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthResponse.php +113 -0
  235. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ListNodesRequest.php +32 -0
  236. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ListNodesResponse.php +154 -0
  237. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/LogLine.php +156 -0
  238. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/Metrics.php +165 -0
  239. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeDescriptor.php +174 -0
  240. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeError.php +627 -0
  241. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeRef.php +134 -0
  242. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeRuntimeClient.php +101 -0
  243. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeStarted.php +68 -0
  244. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/PartialResult.php +59 -0
  245. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/Progress.php +85 -0
  246. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/RuntimeState.php +142 -0
  247. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/StepInfo.php +168 -0
  248. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/TriggerInfo.php +289 -0
  249. package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/WorkflowInfo.php +176 -0
  250. package/dist/scaffold-repo/sdks/php/src/Genpb/GPBMetadata/Blok/Runtime/V1/Runtime.php +26 -0
  251. package/dist/scaffold-repo/sdks/php/src/Logging/LogEntry.php +47 -0
  252. package/dist/scaffold-repo/sdks/php/src/Logging/LogLevel.php +50 -0
  253. package/dist/scaffold-repo/sdks/php/src/Logging/Logger.php +133 -0
  254. package/dist/scaffold-repo/sdks/php/src/Node/NodeHandler.php +35 -0
  255. package/dist/scaffold-repo/sdks/php/src/Node/NodeReflector.php +21 -0
  256. package/dist/scaffold-repo/sdks/php/src/Node/NodeRegistry.php +172 -0
  257. package/dist/scaffold-repo/sdks/php/src/Node/TypedNode.php +159 -0
  258. package/dist/scaffold-repo/sdks/php/src/Server/BlokNodeRuntimeService.php +504 -0
  259. package/dist/scaffold-repo/sdks/php/src/Server/DecodeException.php +13 -0
  260. package/dist/scaffold-repo/sdks/php/src/Server/Middleware.php +18 -0
  261. package/dist/scaffold-repo/sdks/php/src/Server/MiddlewarePipeline.php +33 -0
  262. package/dist/scaffold-repo/sdks/php/src/Server/NodeRuntimeInterface.php +40 -0
  263. package/dist/scaffold-repo/sdks/php/src/Server/Server.php +157 -0
  264. package/dist/scaffold-repo/sdks/php/src/Testing/MockContext.php +161 -0
  265. package/dist/scaffold-repo/sdks/php/src/Testing/TestRunner.php +78 -0
  266. package/dist/scaffold-repo/sdks/php/src/Types/Context.php +80 -0
  267. package/dist/scaffold-repo/sdks/php/src/Types/ExecutionMetrics.php +48 -0
  268. package/dist/scaffold-repo/sdks/php/src/Types/ExecutionRequest.php +38 -0
  269. package/dist/scaffold-repo/sdks/php/src/Types/ExecutionResult.php +143 -0
  270. package/dist/scaffold-repo/sdks/php/src/Types/HealthStatus.php +42 -0
  271. package/dist/scaffold-repo/sdks/php/src/Types/NodeConfig.php +72 -0
  272. package/dist/scaffold-repo/sdks/php/src/Types/Request.php +82 -0
  273. package/dist/scaffold-repo/sdks/php/src/Types/Response.php +44 -0
  274. package/dist/scaffold-repo/sdks/php/src/Validation/SchemaValidator.php +197 -0
  275. package/dist/scaffold-repo/sdks/php/tests/Errors/BlokErrorTest.php +402 -0
  276. package/dist/scaffold-repo/sdks/php/tests/Logging/LoggerTest.php +165 -0
  277. package/dist/scaffold-repo/sdks/php/tests/Node/NodeRegistryTest.php +139 -0
  278. package/dist/scaffold-repo/sdks/php/tests/Node/TypedNodeTest.php +84 -0
  279. package/dist/scaffold-repo/sdks/php/tests/Server/BlokNodeRuntimeServiceTest.php +288 -0
  280. package/dist/scaffold-repo/sdks/php/tests/Testing/MockContextTest.php +184 -0
  281. package/dist/scaffold-repo/sdks/php/tests/Types/ExecutionResultTest.php +136 -0
  282. package/dist/scaffold-repo/sdks/php/tests/Validation/SchemaValidatorTest.php +191 -0
  283. package/dist/scaffold-repo/sdks/python3/Dockerfile +62 -0
  284. package/dist/scaffold-repo/sdks/python3/blok/__init__.py +61 -0
  285. package/dist/scaffold-repo/sdks/python3/blok/config/__init__.py +3 -0
  286. package/dist/scaffold-repo/sdks/python3/blok/config/server_config.py +116 -0
  287. package/dist/scaffold-repo/sdks/python3/blok/errors/__init__.py +50 -0
  288. package/dist/scaffold-repo/sdks/python3/blok/errors/blok_error.py +555 -0
  289. package/dist/scaffold-repo/sdks/python3/blok/errors/node_error.py +64 -0
  290. package/dist/scaffold-repo/sdks/python3/blok/logging/__init__.py +3 -0
  291. package/dist/scaffold-repo/sdks/python3/blok/logging/logger.py +82 -0
  292. package/dist/scaffold-repo/sdks/python3/blok/middleware/__init__.py +4 -0
  293. package/dist/scaffold-repo/sdks/python3/blok/middleware/logging_middleware.py +35 -0
  294. package/dist/scaffold-repo/sdks/python3/blok/middleware/recovery_middleware.py +36 -0
  295. package/dist/scaffold-repo/sdks/python3/blok/node/__init__.py +4 -0
  296. package/dist/scaffold-repo/sdks/python3/blok/node/define_node.py +239 -0
  297. package/dist/scaffold-repo/sdks/python3/blok/node/node_handler.py +35 -0
  298. package/dist/scaffold-repo/sdks/python3/blok/node/node_registry.py +136 -0
  299. package/dist/scaffold-repo/sdks/python3/blok/runtime/__init__.py +0 -0
  300. package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/__init__.py +0 -0
  301. package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/runtime_pb2.py +112 -0
  302. package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/runtime_pb2_grpc.py +259 -0
  303. package/dist/scaffold-repo/sdks/python3/blok/server/__init__.py +3 -0
  304. package/dist/scaffold-repo/sdks/python3/blok/server/grpc_server.py +757 -0
  305. package/dist/scaffold-repo/sdks/python3/blok/server/runtime_server.py +165 -0
  306. package/dist/scaffold-repo/sdks/python3/blok/types/__init__.py +13 -0
  307. package/dist/scaffold-repo/sdks/python3/blok/types/context.py +162 -0
  308. package/dist/scaffold-repo/sdks/python3/blok/types/execution_request.py +74 -0
  309. package/dist/scaffold-repo/sdks/python3/blok/types/execution_result.py +103 -0
  310. package/dist/scaffold-repo/sdks/python3/blok/worker/__init__.py +10 -0
  311. package/dist/scaffold-repo/sdks/python3/blok/worker/job_message.py +34 -0
  312. package/dist/scaffold-repo/sdks/python3/blok/worker/worker.py +451 -0
  313. package/dist/scaffold-repo/sdks/python3/blok/worker/worker_config.py +129 -0
  314. package/dist/scaffold-repo/sdks/python3/examples/__init__.py +32 -0
  315. package/dist/scaffold-repo/sdks/python3/examples/api_call_node.py +85 -0
  316. package/dist/scaffold-repo/sdks/python3/examples/blok_error_demo_node.py +79 -0
  317. package/dist/scaffold-repo/sdks/python3/examples/chain_test_node.py +51 -0
  318. package/dist/scaffold-repo/sdks/python3/examples/hello_world_node.py +44 -0
  319. package/dist/scaffold-repo/sdks/python3/examples/transform_data_node.py +71 -0
  320. package/dist/scaffold-repo/sdks/python3/examples/typed_greet_node.py +25 -0
  321. package/dist/scaffold-repo/sdks/python3/proto/blok/runtime/v1/runtime.proto +302 -0
  322. package/dist/scaffold-repo/sdks/python3/pyproject.toml +47 -0
  323. package/dist/scaffold-repo/sdks/python3/requirements.txt +17 -0
  324. package/dist/scaffold-repo/sdks/python3/tests/__init__.py +0 -0
  325. package/dist/scaffold-repo/sdks/python3/tests/test_blok_error.py +341 -0
  326. package/dist/scaffold-repo/sdks/python3/tests/test_define_node.py +135 -0
  327. package/dist/scaffold-repo/sdks/python3/tests/test_discovery.py +99 -0
  328. package/dist/scaffold-repo/sdks/python3/tests/test_grpc_codec.py +260 -0
  329. package/dist/scaffold-repo/sdks/python3/tests/test_grpc_server.py +398 -0
  330. package/dist/scaffold-repo/sdks/ruby/Dockerfile +37 -0
  331. package/dist/scaffold-repo/sdks/ruby/Gemfile +5 -0
  332. package/dist/scaffold-repo/sdks/ruby/README.md +210 -0
  333. package/dist/scaffold-repo/sdks/ruby/Rakefile +11 -0
  334. package/dist/scaffold-repo/sdks/ruby/blok.gemspec +43 -0
  335. package/dist/scaffold-repo/sdks/ruby/config.ru +15 -0
  336. package/dist/scaffold-repo/sdks/ruby/examples/api_call_node.rb +99 -0
  337. package/dist/scaffold-repo/sdks/ruby/examples/blok_error_demo_node.rb +79 -0
  338. package/dist/scaffold-repo/sdks/ruby/examples/chain_test_node.rb +51 -0
  339. package/dist/scaffold-repo/sdks/ruby/examples/hello_world_node.rb +40 -0
  340. package/dist/scaffold-repo/sdks/ruby/examples/transform_data_node.rb +82 -0
  341. package/dist/scaffold-repo/sdks/ruby/examples/typed_greet_node.rb +25 -0
  342. package/dist/scaffold-repo/sdks/ruby/lib/blok/config/server_config.rb +76 -0
  343. package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/blok_error.rb +476 -0
  344. package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/build_context_snapshot.rb +99 -0
  345. package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/error_category.rb +16 -0
  346. package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/node_error.rb +84 -0
  347. package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/log_entry.rb +46 -0
  348. package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/log_level.rb +49 -0
  349. package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/logger.rb +71 -0
  350. package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/logging_middleware.rb +45 -0
  351. package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/middleware.rb +36 -0
  352. package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/recovery_middleware.rb +31 -0
  353. package/dist/scaffold-repo/sdks/ruby/lib/blok/node/discovery.rb +59 -0
  354. package/dist/scaffold-repo/sdks/ruby/lib/blok/node/node_handler.rb +43 -0
  355. package/dist/scaffold-repo/sdks/ruby/lib/blok/node/node_registry.rb +107 -0
  356. package/dist/scaffold-repo/sdks/ruby/lib/blok/node/typed_node.rb +180 -0
  357. package/dist/scaffold-repo/sdks/ruby/lib/blok/runtime/v1/runtime_pb.rb +43 -0
  358. package/dist/scaffold-repo/sdks/ruby/lib/blok/runtime/v1/runtime_services_pb.rb +55 -0
  359. package/dist/scaffold-repo/sdks/ruby/lib/blok/server/grpc_server.rb +435 -0
  360. package/dist/scaffold-repo/sdks/ruby/lib/blok/server/runtime_app.rb +86 -0
  361. package/dist/scaffold-repo/sdks/ruby/lib/blok/testing/mock_context.rb +109 -0
  362. package/dist/scaffold-repo/sdks/ruby/lib/blok/testing/test_runner.rb +40 -0
  363. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/context.rb +82 -0
  364. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_metrics.rb +43 -0
  365. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_request.rb +39 -0
  366. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_result.rb +117 -0
  367. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/health_status.rb +42 -0
  368. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/node_config.rb +73 -0
  369. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/request.rb +71 -0
  370. package/dist/scaffold-repo/sdks/ruby/lib/blok/types/response.rb +46 -0
  371. package/dist/scaffold-repo/sdks/ruby/lib/blok/validation/schema_validator.rb +142 -0
  372. package/dist/scaffold-repo/sdks/ruby/lib/blok/version.rb +5 -0
  373. package/dist/scaffold-repo/sdks/ruby/lib/blok.rb +53 -0
  374. package/dist/scaffold-repo/sdks/ruby/proto/blok/runtime/v1/runtime.proto +302 -0
  375. package/dist/scaffold-repo/sdks/ruby/test/errors/blok_error_test.rb +339 -0
  376. package/dist/scaffold-repo/sdks/ruby/test/logging/logger_test.rb +155 -0
  377. package/dist/scaffold-repo/sdks/ruby/test/node/node_registry_test.rb +132 -0
  378. package/dist/scaffold-repo/sdks/ruby/test/node/typed_node_test.rb +67 -0
  379. package/dist/scaffold-repo/sdks/ruby/test/test_helper.rb +6 -0
  380. package/dist/scaffold-repo/sdks/ruby/test/testing/mock_context_test.rb +150 -0
  381. package/dist/scaffold-repo/sdks/ruby/test/types/execution_result_test.rb +129 -0
  382. package/dist/scaffold-repo/sdks/ruby/test/validation/schema_validator_test.rb +270 -0
  383. package/dist/scaffold-repo/sdks/rust/Cargo.lock +3044 -0
  384. package/dist/scaffold-repo/sdks/rust/Cargo.toml +82 -0
  385. package/dist/scaffold-repo/sdks/rust/Dockerfile +40 -0
  386. package/dist/scaffold-repo/sdks/rust/README.md +73 -0
  387. package/dist/scaffold-repo/sdks/rust/build.rs +32 -0
  388. package/dist/scaffold-repo/sdks/rust/proto/blok/runtime/v1/runtime.proto +302 -0
  389. package/dist/scaffold-repo/sdks/rust/src/blok_error.rs +1168 -0
  390. package/dist/scaffold-repo/sdks/rust/src/config.rs +158 -0
  391. package/dist/scaffold-repo/sdks/rust/src/errors.rs +142 -0
  392. package/dist/scaffold-repo/sdks/rust/src/grpc_server.rs +635 -0
  393. package/dist/scaffold-repo/sdks/rust/src/lib.rs +65 -0
  394. package/dist/scaffold-repo/sdks/rust/src/logging.rs +195 -0
  395. package/dist/scaffold-repo/sdks/rust/src/main.rs +79 -0
  396. package/dist/scaffold-repo/sdks/rust/src/middleware.rs +181 -0
  397. package/dist/scaffold-repo/sdks/rust/src/node.rs +172 -0
  398. package/dist/scaffold-repo/sdks/rust/src/nodes/api_call.rs +93 -0
  399. package/dist/scaffold-repo/sdks/rust/src/nodes/blok_error_demo.rs +151 -0
  400. package/dist/scaffold-repo/sdks/rust/src/nodes/chain_test.rs +57 -0
  401. package/dist/scaffold-repo/sdks/rust/src/nodes/hello_world.rs +83 -0
  402. package/dist/scaffold-repo/sdks/rust/src/nodes/mod.rs +18 -0
  403. package/dist/scaffold-repo/sdks/rust/src/nodes/transform_data.rs +142 -0
  404. package/dist/scaffold-repo/sdks/rust/src/nodes/typed_greet.rs +56 -0
  405. package/dist/scaffold-repo/sdks/rust/src/registry.rs +204 -0
  406. package/dist/scaffold-repo/sdks/rust/src/server.rs +63 -0
  407. package/dist/scaffold-repo/sdks/rust/src/testing.rs +175 -0
  408. package/dist/scaffold-repo/sdks/rust/src/types.rs +338 -0
  409. package/dist/scaffold-repo/sdks/rust/src/user_nodes/mod.rs +10 -0
  410. package/dist/scaffold-repo/sdks/rust/src/validation.rs +232 -0
  411. package/dist/scaffold-repo/sdks/rust/src/worker.rs +509 -0
  412. package/dist/scaffold-repo/sdks/rust/tests/grpc_integration.rs +306 -0
  413. package/dist/scaffold-repo/sdks/rust/tests/typed_node.rs +104 -0
  414. package/dist/scaffold-repo/triggers/cron/CHANGELOG.md +22 -0
  415. package/dist/scaffold-repo/triggers/cron/package.json +36 -0
  416. package/dist/scaffold-repo/triggers/cron/src/CronTrigger.ts +552 -0
  417. package/dist/scaffold-repo/triggers/cron/src/index.ts +77 -0
  418. package/dist/scaffold-repo/triggers/cron/tsconfig.json +32 -0
  419. package/dist/scaffold-repo/triggers/grpc/.env.example +8 -0
  420. package/dist/scaffold-repo/triggers/grpc/CHANGELOG.md +143 -0
  421. package/dist/scaffold-repo/triggers/grpc/README.md +25 -0
  422. package/dist/scaffold-repo/triggers/grpc/buf.gen.yaml +11 -0
  423. package/dist/scaffold-repo/triggers/grpc/buf.yaml +9 -0
  424. package/dist/scaffold-repo/triggers/grpc/localhost+2-key.pem +28 -0
  425. package/dist/scaffold-repo/triggers/grpc/localhost+2.pem +27 -0
  426. package/dist/scaffold-repo/triggers/grpc/package.json +61 -0
  427. package/dist/scaffold-repo/triggers/grpc/proto/workflow.proto +33 -0
  428. package/dist/scaffold-repo/triggers/grpc/src/GRpcTrigger.ts +297 -0
  429. package/dist/scaffold-repo/triggers/grpc/src/GrpcClient.ts +87 -0
  430. package/dist/scaffold-repo/triggers/grpc/src/GrpcServer.ts +68 -0
  431. package/dist/scaffold-repo/triggers/grpc/src/MessageDecode.ts +142 -0
  432. package/dist/scaffold-repo/triggers/grpc/src/NanoSDK.ts +146 -0
  433. package/dist/scaffold-repo/triggers/grpc/src/Nodes.ts +10 -0
  434. package/dist/scaffold-repo/triggers/grpc/src/Workflows.ts +5 -0
  435. package/dist/scaffold-repo/triggers/grpc/src/gen/workflow_pb.ts +142 -0
  436. package/dist/scaffold-repo/triggers/grpc/src/index.ts +22 -0
  437. package/dist/scaffold-repo/triggers/grpc/src/server.ts +8 -0
  438. package/dist/scaffold-repo/triggers/grpc/src/types/Message.ts +0 -0
  439. package/dist/scaffold-repo/triggers/grpc/src/types/RuntimeWorkflow.ts +7 -0
  440. package/dist/scaffold-repo/triggers/grpc/src/types/Workflows.ts +7 -0
  441. package/dist/scaffold-repo/triggers/grpc/tsconfig.json +34 -0
  442. package/dist/scaffold-repo/triggers/grpc/vitest.config.ts +29 -0
  443. package/dist/scaffold-repo/triggers/grpc/workflows/countries.json +27 -0
  444. package/dist/scaffold-repo/triggers/http/.blok/trace.db +0 -0
  445. package/dist/scaffold-repo/triggers/http/.blok/trace.db-shm +0 -0
  446. package/dist/scaffold-repo/triggers/http/.blok/trace.db-wal +0 -0
  447. package/dist/scaffold-repo/triggers/http/.dockerignore +23 -0
  448. package/dist/scaffold-repo/triggers/http/.env.example +8 -0
  449. package/dist/scaffold-repo/triggers/http/CHANGELOG.md +326 -0
  450. package/dist/scaffold-repo/triggers/http/Dockerfile +49 -0
  451. package/dist/scaffold-repo/triggers/http/Dockerfile.dev +34 -0
  452. package/dist/scaffold-repo/triggers/http/infra/docker-compose.yml +38 -0
  453. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Authentication.md +74 -0
  454. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Building.md +52 -0
  455. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Create_Node.md +123 -0
  456. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Create_Workflow.md +177 -0
  457. package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Deployment.md +69 -0
  458. package/dist/scaffold-repo/triggers/http/notes/Core_Concepts/Context.md +156 -0
  459. package/dist/scaffold-repo/triggers/http/notes/examples.md +104 -0
  460. package/dist/scaffold-repo/triggers/http/notes/index.md +51 -0
  461. package/dist/scaffold-repo/triggers/http/package.json +62 -0
  462. package/dist/scaffold-repo/triggers/http/public/favicon.ico +0 -0
  463. package/dist/scaffold-repo/triggers/http/public/metric/index.html +2101 -0
  464. package/dist/scaffold-repo/triggers/http/request.http +7 -0
  465. package/dist/scaffold-repo/triggers/http/src/AppRoutes.ts +64 -0
  466. package/dist/scaffold-repo/triggers/http/src/Nodes.ts +38 -0
  467. package/dist/scaffold-repo/triggers/http/src/Workflows.ts +18 -0
  468. package/dist/scaffold-repo/triggers/http/src/index.ts +86 -0
  469. package/dist/scaffold-repo/triggers/http/src/nodes/chain-init/index.ts +48 -0
  470. package/dist/scaffold-repo/triggers/http/src/nodes/chain-verify/index.ts +123 -0
  471. package/dist/scaffold-repo/triggers/http/src/nodes/eval/index.ts +69 -0
  472. package/dist/scaffold-repo/triggers/http/src/nodes/examples/README.md +14 -0
  473. package/dist/scaffold-repo/triggers/http/src/nodes/examples/chat-ui/index.html +228 -0
  474. package/dist/scaffold-repo/triggers/http/src/nodes/examples/chat-ui/index.ts +65 -0
  475. package/dist/scaffold-repo/triggers/http/src/nodes/examples/index.ts +14 -0
  476. package/dist/scaffold-repo/triggers/http/src/nodes/runtime-bridge/index.ts +84 -0
  477. package/dist/scaffold-repo/triggers/http/src/runner/HonoTraceRouterAdapter.ts +199 -0
  478. package/dist/scaffold-repo/triggers/http/src/runner/HttpTrigger.ts +2039 -0
  479. package/dist/scaffold-repo/triggers/http/src/runner/MessageDecode.ts +57 -0
  480. package/dist/scaffold-repo/triggers/http/src/runner/Util.ts +52 -0
  481. package/dist/scaffold-repo/triggers/http/src/runner/WorkflowRouter.ts +411 -0
  482. package/dist/scaffold-repo/triggers/http/src/runner/metrics/opentelemetry_metrics.ts +84 -0
  483. package/dist/scaffold-repo/triggers/http/src/runner/metrics/opentelemetry_traces.ts +30 -0
  484. package/dist/scaffold-repo/triggers/http/src/runner/nodeCatalog.ts +128 -0
  485. package/dist/scaffold-repo/triggers/http/src/runner/responseEmitter.ts +138 -0
  486. package/dist/scaffold-repo/triggers/http/src/runner/scanWorkflows.ts +201 -0
  487. package/dist/scaffold-repo/triggers/http/src/runner/types/ErrorResponse.ts +3 -0
  488. package/dist/scaffold-repo/triggers/http/src/runner/types/NodeTypes.ts +13 -0
  489. package/dist/scaffold-repo/triggers/http/src/runner/types/Nodes.ts +5 -0
  490. package/dist/scaffold-repo/triggers/http/src/runner/types/RuntimeWorkflow.ts +7 -0
  491. package/dist/scaffold-repo/triggers/http/src/runner/types/WorkflowRequest.ts +8 -0
  492. package/dist/scaffold-repo/triggers/http/src/runner/types/WorkflowResponse.ts +7 -0
  493. package/dist/scaffold-repo/triggers/http/src/runner/types/Workflows.ts +14 -0
  494. package/dist/scaffold-repo/triggers/http/src/workflows/countries-cats-helper.ts +30 -0
  495. package/dist/scaffold-repo/triggers/http/src/workflows/countries-handle-dsl.ts +25 -0
  496. package/dist/scaffold-repo/triggers/http/src/workflows/countries-helper.ts +18 -0
  497. package/dist/scaffold-repo/triggers/http/src/workflows/empty.ts +16 -0
  498. package/dist/scaffold-repo/triggers/http/src/workflows/eval/eval-retrieve.ts +23 -0
  499. package/dist/scaffold-repo/triggers/http/src/workflows/eval/eval-run.ts +39 -0
  500. package/dist/scaffold-repo/triggers/http/src/workflows/eval/foreign-auth.ts +24 -0
  501. package/dist/scaffold-repo/triggers/http/tsconfig.json +39 -0
  502. package/dist/scaffold-repo/triggers/http/vitest.config.ts +39 -0
  503. package/dist/scaffold-repo/triggers/http/workflows/json/agent-message.json +87 -0
  504. package/dist/scaffold-repo/triggers/http/workflows/json/agent-page.json +25 -0
  505. package/dist/scaffold-repo/triggers/http/workflows/json/agent-stream.json +30 -0
  506. package/dist/scaffold-repo/triggers/http/workflows/json/agent-tool-calculator.json +22 -0
  507. package/dist/scaffold-repo/triggers/http/workflows/json/agent-tool-weather.json +22 -0
  508. package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-message.json +54 -0
  509. package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-page.json +25 -0
  510. package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-stream.json +30 -0
  511. package/dist/scaffold-repo/triggers/http/workflows/json/chat-message.json +25 -0
  512. package/dist/scaffold-repo/triggers/http/workflows/json/chat-page.json +20 -0
  513. package/dist/scaffold-repo/triggers/http/workflows/json/chat-stream.json +30 -0
  514. package/dist/scaffold-repo/triggers/http/workflows/json/countries-py.json +27 -0
  515. package/dist/scaffold-repo/triggers/http/workflows/json/countries-vs-facts.json +50 -0
  516. package/dist/scaffold-repo/triggers/http/workflows/json/countries.json +27 -0
  517. package/dist/scaffold-repo/triggers/http/workflows/json/cross-runtime-chain.json +89 -0
  518. package/dist/scaffold-repo/triggers/http/workflows/json/dashboard-gen.json +34 -0
  519. package/dist/scaffold-repo/triggers/http/workflows/json/db-manager.json +34 -0
  520. package/dist/scaffold-repo/triggers/http/workflows/json/empty.json +13 -0
  521. package/dist/scaffold-repo/triggers/http/workflows/json/fanout-enqueue.json +48 -0
  522. package/dist/scaffold-repo/triggers/http/workflows/json/fanout-worker.json +41 -0
  523. package/dist/scaffold-repo/triggers/http/workflows/json/feedback.json +34 -0
  524. package/dist/scaffold-repo/triggers/http/workflows/json/films.json +27 -0
  525. package/dist/scaffold-repo/triggers/http/workflows/json/image-capture.json +34 -0
  526. package/dist/scaffold-repo/triggers/http/workflows/json/launches-by-year.json +27 -0
  527. package/dist/scaffold-repo/triggers/http/workflows/json/loadtest.json +24 -0
  528. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/admin-only.json +31 -0
  529. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/auth-check.json +59 -0
  530. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/github-webhook-verify.json +34 -0
  531. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/jwt-auth.json +46 -0
  532. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/rate-limit.json +70 -0
  533. package/dist/scaffold-repo/triggers/http/workflows/json/middleware/redis-rate-limit.json +71 -0
  534. package/dist/scaffold-repo/triggers/http/workflows/json/mongodb.json +24 -0
  535. package/dist/scaffold-repo/triggers/http/workflows/json/rentals-pdf.json +65 -0
  536. package/dist/scaffold-repo/triggers/http/workflows/json/v05-admin-delete-user.json +42 -0
  537. package/dist/scaffold-repo/triggers/http/workflows/json/v05-async-job-poller.json +45 -0
  538. package/dist/scaffold-repo/triggers/http/workflows/json/v05-csv-import.json +122 -0
  539. package/dist/scaffold-repo/triggers/http/workflows/json/v05-data-export.json +105 -0
  540. package/dist/scaffold-repo/triggers/http/workflows/json/v05-event-router.json +97 -0
  541. package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-issues.json +22 -0
  542. package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-pr.json +22 -0
  543. package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-push.json +22 -0
  544. package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-webhook-router.json +88 -0
  545. package/dist/scaffold-repo/triggers/http/workflows/json/v05-hello-global-mw.json +22 -0
  546. package/dist/scaffold-repo/triggers/http/workflows/json/v05-hello-with-mw.json +23 -0
  547. package/dist/scaffold-repo/triggers/http/workflows/json/v05-jwt-protected.json +23 -0
  548. package/dist/scaffold-repo/triggers/http/workflows/json/v05-multi-tenant-router.json +90 -0
  549. package/dist/scaffold-repo/triggers/http/workflows/json/v05-nested-control-flow.json +207 -0
  550. package/dist/scaffold-repo/triggers/http/workflows/json/v05-order-fulfillment.json +211 -0
  551. package/dist/scaffold-repo/triggers/http/workflows/json/v05-parallel-foreach-with-wait.json +47 -0
  552. package/dist/scaffold-repo/triggers/http/workflows/json/v05-polling-with-backoff.json +55 -0
  553. package/dist/scaffold-repo/triggers/http/workflows/json/v05-protected.json +23 -0
  554. package/dist/scaffold-repo/triggers/http/workflows/json/v05-redis-protected.json +23 -0
  555. package/dist/scaffold-repo/triggers/http/workflows/json/v05-saga.json +122 -0
  556. package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-acme.json +22 -0
  557. package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-beta.json +22 -0
  558. package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-gamma.json +22 -0
  559. package/dist/scaffold-repo/triggers/http/workflows/json/v05-travel-booking.json +200 -0
  560. package/dist/scaffold-repo/triggers/http/workflows/json/v05-user-signup-saga.json +186 -0
  561. package/dist/scaffold-repo/triggers/http/workflows/json/v05-webhook-fanout.json +49 -0
  562. package/dist/scaffold-repo/triggers/http/workflows/json/v06-reliability-showcase.json +80 -0
  563. package/dist/scaffold-repo/triggers/http/workflows/json/v07-sse-publish.json +24 -0
  564. package/dist/scaffold-repo/triggers/http/workflows/json/v07-sse-stream.json +26 -0
  565. package/dist/scaffold-repo/triggers/http/workflows/json/v07-ws-echo.json +38 -0
  566. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-issues.json +22 -0
  567. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-pr.json +22 -0
  568. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-push.json +32 -0
  569. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github.json +87 -0
  570. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear-comment.json +22 -0
  571. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear-issue.json +22 -0
  572. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear.json +74 -0
  573. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe-customer-created.json +22 -0
  574. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe-invoice-paid.json +32 -0
  575. package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe.json +24 -0
  576. package/dist/scaffold-repo/triggers/http/workflows/json/workflow-docs.json +34 -0
  577. package/dist/scaffold-repo/triggers/http/workflows/toml/countries.toml +21 -0
  578. package/dist/scaffold-repo/triggers/http/workflows/xml/countries.xml +23 -0
  579. package/dist/scaffold-repo/triggers/http/workflows/yaml/countries.yaml +19 -0
  580. package/dist/scaffold-repo/triggers/mcp/README.md +131 -0
  581. package/dist/scaffold-repo/triggers/mcp/package.json +39 -0
  582. package/dist/scaffold-repo/triggers/mcp/src/McpTrigger.ts +581 -0
  583. package/dist/scaffold-repo/triggers/mcp/src/index.ts +41 -0
  584. package/dist/scaffold-repo/triggers/mcp/tsconfig.json +32 -0
  585. package/dist/scaffold-repo/triggers/pubsub/CHANGELOG.md +22 -0
  586. package/dist/scaffold-repo/triggers/pubsub/package.json +66 -0
  587. package/dist/scaffold-repo/triggers/pubsub/src/PubSubTrigger.ts +424 -0
  588. package/dist/scaffold-repo/triggers/pubsub/src/adapters/AWSSNSAdapter.ts +352 -0
  589. package/dist/scaffold-repo/triggers/pubsub/src/adapters/AzureServiceBusAdapter.ts +303 -0
  590. package/dist/scaffold-repo/triggers/pubsub/src/adapters/GCPPubSubAdapter.ts +327 -0
  591. package/dist/scaffold-repo/triggers/pubsub/src/adapters/KafkaPubSubAdapter.ts +247 -0
  592. package/dist/scaffold-repo/triggers/pubsub/src/adapters/KafkaPubSubAdapter.ts.bak +251 -0
  593. package/dist/scaffold-repo/triggers/pubsub/src/adapters/NATSPubSubAdapter.ts +333 -0
  594. package/dist/scaffold-repo/triggers/pubsub/src/adapters/RedisStreamsPubSubAdapter.ts +256 -0
  595. package/dist/scaffold-repo/triggers/pubsub/src/adapters/factory.ts +88 -0
  596. package/dist/scaffold-repo/triggers/pubsub/src/index.ts +67 -0
  597. package/dist/scaffold-repo/triggers/pubsub/template/.env.example +8 -0
  598. package/dist/scaffold-repo/triggers/pubsub/template/package.json +45 -0
  599. package/dist/scaffold-repo/triggers/pubsub/template/src/Nodes.ts +20 -0
  600. package/dist/scaffold-repo/triggers/pubsub/template/src/Workflows.ts +8 -0
  601. package/dist/scaffold-repo/triggers/pubsub/template/src/index.ts +41 -0
  602. package/dist/scaffold-repo/triggers/pubsub/template/src/runner/PubSubServer.ts +39 -0
  603. package/dist/scaffold-repo/triggers/pubsub/template/src/runner/types/Workflows.ts +7 -0
  604. package/dist/scaffold-repo/triggers/pubsub/template/src/workflows/messages/on-message.ts +42 -0
  605. package/dist/scaffold-repo/triggers/pubsub/template/src/workflows/publish-order.ts +22 -0
  606. package/dist/scaffold-repo/triggers/pubsub/template/tsconfig.json +31 -0
  607. package/dist/scaffold-repo/triggers/pubsub/template/vitest.config.ts +39 -0
  608. package/dist/scaffold-repo/triggers/pubsub/tsconfig.json +32 -0
  609. package/dist/scaffold-repo/triggers/sse/.env.example +8 -0
  610. package/dist/scaffold-repo/triggers/sse/CHANGELOG.md +12 -0
  611. package/dist/scaffold-repo/triggers/sse/Dockerfile +47 -0
  612. package/dist/scaffold-repo/triggers/sse/Dockerfile.dev +33 -0
  613. package/dist/scaffold-repo/triggers/sse/package.json +37 -0
  614. package/dist/scaffold-repo/triggers/sse/src/SSETrigger.ts +489 -0
  615. package/dist/scaffold-repo/triggers/sse/src/bus.ts +208 -0
  616. package/dist/scaffold-repo/triggers/sse/src/index.ts +38 -0
  617. package/dist/scaffold-repo/triggers/sse/src/workflows/events/README.md +129 -0
  618. package/dist/scaffold-repo/triggers/sse/src/workflows/events/publish-demo.ts +40 -0
  619. package/dist/scaffold-repo/triggers/sse/src/workflows/events/stream-demo.ts +43 -0
  620. package/dist/scaffold-repo/triggers/sse/tsconfig.json +22 -0
  621. package/dist/scaffold-repo/triggers/sse/vitest.config.ts +39 -0
  622. package/dist/scaffold-repo/triggers/webhook/CHANGELOG.md +22 -0
  623. package/dist/scaffold-repo/triggers/webhook/package.json +36 -0
  624. package/dist/scaffold-repo/triggers/webhook/src/WebhookTrigger.ts +465 -0
  625. package/dist/scaffold-repo/triggers/webhook/src/index.ts +51 -0
  626. package/dist/scaffold-repo/triggers/webhook/src/verifiers.ts +394 -0
  627. package/dist/scaffold-repo/triggers/webhook/tsconfig.json +32 -0
  628. package/dist/scaffold-repo/triggers/websocket/.env.example +8 -0
  629. package/dist/scaffold-repo/triggers/websocket/CHANGELOG.md +22 -0
  630. package/dist/scaffold-repo/triggers/websocket/package.json +50 -0
  631. package/dist/scaffold-repo/triggers/websocket/src/Backplane.ts +167 -0
  632. package/dist/scaffold-repo/triggers/websocket/src/WebSocketTrigger.ts +910 -0
  633. package/dist/scaffold-repo/triggers/websocket/src/index.ts +50 -0
  634. package/dist/scaffold-repo/triggers/websocket/src/workflows/events/README.md +93 -0
  635. package/dist/scaffold-repo/triggers/websocket/src/workflows/events/echo-demo.ts +56 -0
  636. package/dist/scaffold-repo/triggers/websocket/tsconfig.json +22 -0
  637. package/dist/scaffold-repo/triggers/websocket/vitest.config.ts +39 -0
  638. package/dist/scaffold-repo/triggers/worker/CHANGELOG.md +22 -0
  639. package/dist/scaffold-repo/triggers/worker/package.json +68 -0
  640. package/dist/scaffold-repo/triggers/worker/src/WorkerTrigger.ts +943 -0
  641. package/dist/scaffold-repo/triggers/worker/src/adapters/BullMQAdapter.ts +296 -0
  642. package/dist/scaffold-repo/triggers/worker/src/adapters/InMemoryAdapter.ts +280 -0
  643. package/dist/scaffold-repo/triggers/worker/src/adapters/KafkaAdapter.ts +347 -0
  644. package/dist/scaffold-repo/triggers/worker/src/adapters/NATSAdapter.ts +505 -0
  645. package/dist/scaffold-repo/triggers/worker/src/adapters/PgBossAdapter.ts +319 -0
  646. package/dist/scaffold-repo/triggers/worker/src/adapters/RabbitMQAdapter.ts +318 -0
  647. package/dist/scaffold-repo/triggers/worker/src/adapters/RedisStreamsAdapter.ts +513 -0
  648. package/dist/scaffold-repo/triggers/worker/src/adapters/SQSAdapter.ts +314 -0
  649. package/dist/scaffold-repo/triggers/worker/src/adapters/factory.ts +111 -0
  650. package/dist/scaffold-repo/triggers/worker/src/index.ts +95 -0
  651. package/dist/scaffold-repo/triggers/worker/template/.env.example +18 -0
  652. package/dist/scaffold-repo/triggers/worker/template/package.json +46 -0
  653. package/dist/scaffold-repo/triggers/worker/template/src/Nodes.ts +20 -0
  654. package/dist/scaffold-repo/triggers/worker/template/src/Workflows.ts +8 -0
  655. package/dist/scaffold-repo/triggers/worker/template/src/index.ts +41 -0
  656. package/dist/scaffold-repo/triggers/worker/template/src/runner/WorkerServer.ts +34 -0
  657. package/dist/scaffold-repo/triggers/worker/template/src/runner/types/Workflows.ts +7 -0
  658. package/dist/scaffold-repo/triggers/worker/template/src/workflows/jobs/process-job.ts +40 -0
  659. package/dist/scaffold-repo/triggers/worker/template/tsconfig.json +31 -0
  660. package/dist/scaffold-repo/triggers/worker/template/vitest.config.ts +39 -0
  661. package/dist/scaffold-repo/triggers/worker/tsconfig.json +32 -0
  662. package/dist/scaffold-repo/workflows/json/agent-message.json +87 -0
  663. package/dist/scaffold-repo/workflows/json/agent-page.json +25 -0
  664. package/dist/scaffold-repo/workflows/json/agent-stream.json +30 -0
  665. package/dist/scaffold-repo/workflows/json/agent-tool-calculator.json +22 -0
  666. package/dist/scaffold-repo/workflows/json/agent-tool-weather.json +22 -0
  667. package/dist/scaffold-repo/workflows/json/chat-memory-message.json +54 -0
  668. package/dist/scaffold-repo/workflows/json/chat-memory-page.json +25 -0
  669. package/dist/scaffold-repo/workflows/json/chat-memory-stream.json +30 -0
  670. package/dist/scaffold-repo/workflows/json/chat-message.json +25 -0
  671. package/dist/scaffold-repo/workflows/json/chat-page.json +20 -0
  672. package/dist/scaffold-repo/workflows/json/chat-stream.json +30 -0
  673. package/dist/scaffold-repo/workflows/json/countries-vs-facts.json +50 -0
  674. package/dist/scaffold-repo/workflows/json/countries.json +27 -0
  675. package/dist/scaffold-repo/workflows/json/cron-heartbeat.json +15 -0
  676. package/dist/scaffold-repo/workflows/json/fanout-enqueue.json +48 -0
  677. package/dist/scaffold-repo/workflows/json/fanout-worker.json +41 -0
  678. package/dist/scaffold-repo/workflows/json/pubsub-on-order.json +24 -0
  679. package/dist/scaffold-repo/workflows/json/webhook-github-issues.json +22 -0
  680. package/dist/scaffold-repo/workflows/json/webhook-github-pr.json +22 -0
  681. package/dist/scaffold-repo/workflows/json/webhook-github-push.json +32 -0
  682. package/dist/scaffold-repo/workflows/json/webhook-github.json +87 -0
  683. package/dist/scaffold-repo/workflows/json/webhook-linear-comment.json +22 -0
  684. package/dist/scaffold-repo/workflows/json/webhook-linear-issue.json +22 -0
  685. package/dist/scaffold-repo/workflows/json/webhook-linear.json +74 -0
  686. package/dist/scaffold-repo/workflows/json/webhook-stripe-customer-created.json +22 -0
  687. package/dist/scaffold-repo/workflows/json/webhook-stripe-invoice-paid.json +32 -0
  688. package/dist/scaffold-repo/workflows/json/webhook-stripe.json +24 -0
  689. package/dist/services/runtime-detector.d.ts +2 -0
  690. package/dist/services/runtime-detector.js +35 -11
  691. package/dist/services/runtime-setup.d.ts +1 -0
  692. package/dist/services/runtime-setup.js +17 -7
  693. package/package.json +4 -4
@@ -0,0 +1,1168 @@
1
+ //! Structured `BlokError` per master plan §17 — the canonical error contract
2
+ //! every Blok node SDK populates the same way. Mirrors the TypeScript
3
+ //! `BlokError` in `core/shared/src/BlokError.ts`, the Python `BlokError` in
4
+ //! `sdks/python3/blok/errors/blok_error.py`, and the Go `BlokError` in
5
+ //! `sdks/go/blok_error.go` so node authors writing in any language see the
6
+ //! same field shape.
7
+ //!
8
+ //! # Idiomatic usage
9
+ //!
10
+ //! ```rust,no_run
11
+ //! use blok::blok_error::{BlokError, BuildContextSnapshot};
12
+ //! use std::time::Duration;
13
+ //!
14
+ //! fn connect() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
15
+ //! Err(Box::new(
16
+ //! BlokError::dependency()
17
+ //! .code("POSTGRES_CONNECT_TIMEOUT")
18
+ //! .message("Could not connect to Postgres within 5s")
19
+ //! .description("Tried host=db.internal port=5432; timeout=5000ms")
20
+ //! .remediation("Check DATABASE_URL env var and network reachability")
21
+ //! .retryable(true)
22
+ //! .retry_after(Duration::from_secs(5))
23
+ //! .doc_url("https://docs.example.com/errors/POSTGRES_CONNECT_TIMEOUT")
24
+ //! .details(serde_json::json!({"host": "db.internal", "port": 5432}))
25
+ //! .build()
26
+ //! ))
27
+ //! }
28
+ //! ```
29
+ //!
30
+ //! The legacy `NodeError` in `errors.rs` (5 categories) stays available for
31
+ //! back-compat. New code should prefer `BlokError`.
32
+
33
+ use chrono::{DateTime, Utc};
34
+ use serde::{Deserialize, Serialize};
35
+ use std::collections::BTreeMap;
36
+ use std::fmt;
37
+ use std::time::Duration;
38
+
39
+ // =============================================================================
40
+ // Categories — 12 values mirroring proto blok.runtime.v1.ErrorCategory
41
+ // =============================================================================
42
+
43
+ /// The 12 canonical error categories every Blok node error falls into.
44
+ ///
45
+ /// Matches the proto `blok.runtime.v1.ErrorCategory` enum value-for-value, and
46
+ /// `BlokErrorCategory` is the Rust-side equivalent of the existing Go
47
+ /// `CategoryDependency`/Python `ErrorCategory.DEPENDENCY` constants.
48
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
49
+ pub enum BlokErrorCategory {
50
+ /// Input failed schema validation. Default `http_status=400`, non-retryable.
51
+ #[serde(rename = "VALIDATION")]
52
+ Validation,
53
+ /// Misconfiguration of the runner / node / environment. Default 500.
54
+ #[serde(rename = "CONFIGURATION")]
55
+ Configuration,
56
+ /// External dependency unreachable (DB, API). Default 502, retryable.
57
+ #[serde(rename = "DEPENDENCY")]
58
+ Dependency,
59
+ /// Deadline exceeded. Default 504, retryable.
60
+ #[serde(rename = "TIMEOUT")]
61
+ Timeout,
62
+ /// Caller lacks the right role/scope. Default 403.
63
+ #[serde(rename = "PERMISSION")]
64
+ Permission,
65
+ /// Caller exceeded a quota. Default 429, retryable with `retry_after_ms`.
66
+ #[serde(rename = "RATE_LIMIT")]
67
+ RateLimit,
68
+ /// Resource not found. Default 404.
69
+ #[serde(rename = "NOT_FOUND")]
70
+ NotFound,
71
+ /// Idempotency violation, concurrent update. Default 409.
72
+ #[serde(rename = "CONFLICT")]
73
+ Conflict,
74
+ /// Caller cancelled before completion. Default 499.
75
+ #[serde(rename = "CANCELLED")]
76
+ Cancelled,
77
+ /// SDK threw without classification — default fallback. Default 500.
78
+ #[serde(rename = "INTERNAL")]
79
+ Internal,
80
+ /// Wire-format / framing / serialization error. Default 502.
81
+ #[serde(rename = "PROTOCOL")]
82
+ Protocol,
83
+ /// Payload schema OK but values are unprocessable. Default 422.
84
+ #[serde(rename = "DATA")]
85
+ Data,
86
+ }
87
+
88
+ impl BlokErrorCategory {
89
+ /// String form matching the proto enum name (e.g. `"DEPENDENCY"`).
90
+ pub fn as_str(&self) -> &'static str {
91
+ match self {
92
+ Self::Validation => "VALIDATION",
93
+ Self::Configuration => "CONFIGURATION",
94
+ Self::Dependency => "DEPENDENCY",
95
+ Self::Timeout => "TIMEOUT",
96
+ Self::Permission => "PERMISSION",
97
+ Self::RateLimit => "RATE_LIMIT",
98
+ Self::NotFound => "NOT_FOUND",
99
+ Self::Conflict => "CONFLICT",
100
+ Self::Cancelled => "CANCELLED",
101
+ Self::Internal => "INTERNAL",
102
+ Self::Protocol => "PROTOCOL",
103
+ Self::Data => "DATA",
104
+ }
105
+ }
106
+
107
+ /// Parse a string into a category, falling back to `Internal` for unknown
108
+ /// values (matches Python/Go behaviour).
109
+ pub fn parse(value: &str) -> Self {
110
+ match value {
111
+ "VALIDATION" => Self::Validation,
112
+ "CONFIGURATION" => Self::Configuration,
113
+ "DEPENDENCY" => Self::Dependency,
114
+ "TIMEOUT" => Self::Timeout,
115
+ "PERMISSION" => Self::Permission,
116
+ "RATE_LIMIT" => Self::RateLimit,
117
+ "NOT_FOUND" => Self::NotFound,
118
+ "CONFLICT" => Self::Conflict,
119
+ "CANCELLED" => Self::Cancelled,
120
+ "PROTOCOL" => Self::Protocol,
121
+ "DATA" => Self::Data,
122
+ _ => Self::Internal,
123
+ }
124
+ }
125
+
126
+ /// Default HTTP status conventionally associated with this category.
127
+ pub fn default_http_status(&self) -> i32 {
128
+ match self {
129
+ Self::Validation => 400,
130
+ Self::Configuration => 500,
131
+ Self::Dependency => 502,
132
+ Self::Timeout => 504,
133
+ Self::Permission => 403,
134
+ Self::RateLimit => 429,
135
+ Self::NotFound => 404,
136
+ Self::Conflict => 409,
137
+ Self::Cancelled => 499,
138
+ Self::Internal => 500,
139
+ Self::Protocol => 502,
140
+ Self::Data => 422,
141
+ }
142
+ }
143
+
144
+ /// Default retryable hint conventionally associated with this category.
145
+ pub fn default_retryable(&self) -> bool {
146
+ matches!(self, Self::Dependency | Self::Timeout | Self::RateLimit)
147
+ }
148
+ }
149
+
150
+ impl fmt::Display for BlokErrorCategory {
151
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152
+ f.write_str(self.as_str())
153
+ }
154
+ }
155
+
156
+ // =============================================================================
157
+ // Severity — 4 values mirroring proto blok.runtime.v1.ErrorSeverity
158
+ // =============================================================================
159
+
160
+ /// How serious an error is. Default for thrown errors is `Error`.
161
+ #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
162
+ pub enum BlokErrorSeverity {
163
+ /// Informational, no action needed.
164
+ #[serde(rename = "INFO")]
165
+ Info,
166
+ /// Recoverable, worth surfacing.
167
+ #[serde(rename = "WARN")]
168
+ Warn,
169
+ /// Standard error level.
170
+ #[serde(rename = "ERROR")]
171
+ Error,
172
+ /// Process must terminate.
173
+ #[serde(rename = "FATAL")]
174
+ Fatal,
175
+ }
176
+
177
+ impl BlokErrorSeverity {
178
+ pub fn as_str(&self) -> &'static str {
179
+ match self {
180
+ Self::Info => "INFO",
181
+ Self::Warn => "WARN",
182
+ Self::Error => "ERROR",
183
+ Self::Fatal => "FATAL",
184
+ }
185
+ }
186
+
187
+ pub fn parse(value: &str) -> Self {
188
+ match value {
189
+ "INFO" => Self::Info,
190
+ "WARN" => Self::Warn,
191
+ "FATAL" => Self::Fatal,
192
+ _ => Self::Error,
193
+ }
194
+ }
195
+ }
196
+
197
+ impl fmt::Display for BlokErrorSeverity {
198
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199
+ f.write_str(self.as_str())
200
+ }
201
+ }
202
+
203
+ // =============================================================================
204
+ // SDK auto-enrichment defaults
205
+ // =============================================================================
206
+
207
+ /// SDK identifier reported on auto-enriched errors.
208
+ pub const DEFAULT_SDK_NAME: &str = "blok-rust";
209
+ /// Runtime kind reported on auto-enriched errors.
210
+ pub const DEFAULT_RUNTIME_KIND: &str = "runtime.rust";
211
+ /// Default cap on serialized `context_snapshot` size in bytes.
212
+ pub const CONTEXT_SNAPSHOT_MAX_BYTES: usize = 4096;
213
+
214
+ // =============================================================================
215
+ // BlokError — the structured error type
216
+ // =============================================================================
217
+
218
+ /// Canonical structured error per master plan §17.
219
+ ///
220
+ /// Returned from a `NodeHandler::execute` to convey category-aware failure info
221
+ /// that flows losslessly through the gRPC wire to the runner and into Studio
222
+ /// traces.
223
+ ///
224
+ /// Use [`BlokError::new`] (or the per-category factories like
225
+ /// [`BlokError::dependency`]) plus the builder methods to construct; direct
226
+ /// struct literal works too if the field-by-field form is more convenient.
227
+ #[derive(Debug, Clone, Serialize, Deserialize)]
228
+ pub struct BlokError {
229
+ pub category: BlokErrorCategory,
230
+ pub severity: BlokErrorSeverity,
231
+ pub code: String,
232
+ pub message: String,
233
+ #[serde(default)]
234
+ pub description: String,
235
+ #[serde(default)]
236
+ pub remediation: String,
237
+ #[serde(default, alias = "docUrl")]
238
+ pub doc_url: String,
239
+ #[serde(alias = "httpStatus")]
240
+ pub http_status: i32,
241
+ pub retryable: bool,
242
+ #[serde(default, alias = "retryAfterMs")]
243
+ pub retry_after_ms: i64,
244
+
245
+ #[serde(default, skip_serializing_if = "Option::is_none")]
246
+ pub details: Option<serde_json::Value>,
247
+ #[serde(default, alias = "contextSnapshot", skip_serializing_if = "Option::is_none")]
248
+ pub context_snapshot: Option<serde_json::Value>,
249
+
250
+ /// Cause-chain payloads, flattened at construction time so cross-wire
251
+ /// serialization doesn't double-count nested chains.
252
+ #[serde(default)]
253
+ pub causes: Vec<serde_json::Value>,
254
+ #[serde(default)]
255
+ pub stack: String,
256
+ pub at: DateTime<Utc>,
257
+
258
+ #[serde(default)]
259
+ pub node: String,
260
+ #[serde(default)]
261
+ pub sdk: String,
262
+ #[serde(default, alias = "sdkVersion")]
263
+ pub sdk_version: String,
264
+ #[serde(default, alias = "runtimeKind")]
265
+ pub runtime_kind: String,
266
+ }
267
+
268
+ impl BlokError {
269
+ /// Start a new builder for the given category. The default per-category
270
+ /// `http_status` and `retryable` hints are applied automatically and can
271
+ /// be overridden via the matching builder methods.
272
+ pub fn new(category: BlokErrorCategory) -> BlokErrorBuilder {
273
+ BlokErrorBuilder::new(category)
274
+ }
275
+
276
+ // --- Per-category factory shortcuts ------------------------------------
277
+
278
+ /// Builder for a `Validation` error (default 400, non-retryable).
279
+ pub fn validation() -> BlokErrorBuilder {
280
+ Self::new(BlokErrorCategory::Validation)
281
+ }
282
+ /// Builder for a `Configuration` error (default 500, non-retryable).
283
+ pub fn configuration() -> BlokErrorBuilder {
284
+ Self::new(BlokErrorCategory::Configuration)
285
+ }
286
+ /// Builder for a `Dependency` error (default 502, retryable).
287
+ pub fn dependency() -> BlokErrorBuilder {
288
+ Self::new(BlokErrorCategory::Dependency)
289
+ }
290
+ /// Builder for a `Timeout` error (default 504, retryable).
291
+ pub fn timeout() -> BlokErrorBuilder {
292
+ Self::new(BlokErrorCategory::Timeout)
293
+ }
294
+ /// Builder for a `Permission` error (default 403, non-retryable).
295
+ pub fn permission() -> BlokErrorBuilder {
296
+ Self::new(BlokErrorCategory::Permission)
297
+ }
298
+ /// Builder for a `RateLimit` error (default 429, retryable).
299
+ pub fn rate_limit() -> BlokErrorBuilder {
300
+ Self::new(BlokErrorCategory::RateLimit)
301
+ }
302
+ /// Builder for a `NotFound` error (default 404, non-retryable).
303
+ pub fn not_found() -> BlokErrorBuilder {
304
+ Self::new(BlokErrorCategory::NotFound)
305
+ }
306
+ /// Builder for a `Conflict` error (default 409, non-retryable).
307
+ pub fn conflict() -> BlokErrorBuilder {
308
+ Self::new(BlokErrorCategory::Conflict)
309
+ }
310
+ /// Builder for a `Cancelled` error (default 499, non-retryable).
311
+ pub fn cancelled() -> BlokErrorBuilder {
312
+ Self::new(BlokErrorCategory::Cancelled)
313
+ }
314
+ /// Builder for an `Internal` error (default 500, non-retryable).
315
+ pub fn internal() -> BlokErrorBuilder {
316
+ Self::new(BlokErrorCategory::Internal)
317
+ }
318
+ /// Builder for a `Protocol` error (default 502, non-retryable).
319
+ pub fn protocol() -> BlokErrorBuilder {
320
+ Self::new(BlokErrorCategory::Protocol)
321
+ }
322
+ /// Builder for a `Data` error (default 422, non-retryable).
323
+ pub fn data() -> BlokErrorBuilder {
324
+ Self::new(BlokErrorCategory::Data)
325
+ }
326
+
327
+ /// Wrap any error/value into a `BlokError`. Used by the runner's auto-wrap
328
+ /// layer so legacy `Box::new(io::Error::...)` still produces a structured
329
+ /// error.
330
+ ///
331
+ /// Categorization heuristic:
332
+ ///
333
+ /// * Already a `BlokError` (downcast hit) — passthrough; missing origin
334
+ /// fields filled in.
335
+ /// * `&str` / `String` — becomes the message; details mirrors the message.
336
+ /// * Anything implementing `std::error::Error` — wraps as `Internal`
337
+ /// with `code=UNCAUGHT_<TYPE>`, the original error preserved as the
338
+ /// first cause-chain entry.
339
+ pub fn from_error(
340
+ err: Box<dyn std::error::Error + Send + Sync>,
341
+ origin: &Origin,
342
+ ) -> Self {
343
+ // First try to reclaim a typed BlokError (handler returned one wrapped
344
+ // in `Box::new(...)`). If we get it back, just enrich origin.
345
+ match err.downcast::<BlokError>() {
346
+ Ok(boxed) => {
347
+ let mut e = *boxed;
348
+ e.apply_origin_if_missing(origin);
349
+ e
350
+ }
351
+ Err(other) => Self::from_dyn_error(other.as_ref(), origin),
352
+ }
353
+ }
354
+
355
+ /// Build a `BlokError` from a `&dyn std::error::Error` reference (no
356
+ /// ownership). Useful when the registry has already consumed the boxed
357
+ /// error or when wrapping a borrowed cause.
358
+ pub fn from_dyn_error(err: &(dyn std::error::Error + 'static), origin: &Origin) -> Self {
359
+ let type_name = std::any::type_name_of_val(err);
360
+ let code = uncaught_code(type_name);
361
+ let message = err.to_string();
362
+ let causes = flatten_causes(err);
363
+ let mut builder = Self::new(BlokErrorCategory::Internal)
364
+ .code(code)
365
+ .message(if message.is_empty() {
366
+ "Uncaught error".to_string()
367
+ } else {
368
+ message
369
+ });
370
+ builder = builder.apply_origin(origin);
371
+ let mut built = builder.build();
372
+ built.causes = causes;
373
+ built
374
+ }
375
+
376
+ /// Wrap an arbitrary string message as an `Internal` error.
377
+ pub fn from_message(message: impl Into<String>, origin: &Origin) -> Self {
378
+ let msg = message.into();
379
+ let details = serde_json::json!({"message": msg.clone()});
380
+ Self::new(BlokErrorCategory::Internal)
381
+ .code("UNCAUGHT_ERROR")
382
+ .message(msg)
383
+ .details(details)
384
+ .apply_origin(origin)
385
+ .build()
386
+ }
387
+
388
+ /// Lossless round-trip serialization to a `serde_json::Value` matching the
389
+ /// proto wire shape (snake_case keys).
390
+ pub fn to_json_value(&self) -> serde_json::Value {
391
+ serde_json::to_value(self).unwrap_or_else(|_| serde_json::Value::Null)
392
+ }
393
+
394
+ /// Inverse of [`Self::to_json_value`]. Tolerant of `camelCase` keys for
395
+ /// cross-language fixtures (uses serde aliases).
396
+ pub fn from_json_value(value: serde_json::Value) -> Result<Self, serde_json::Error> {
397
+ serde_json::from_value(value)
398
+ }
399
+
400
+ /// Fill in any missing origin fields. Won't overwrite fields the handler
401
+ /// set explicitly.
402
+ pub fn apply_origin_if_missing(&mut self, origin: &Origin) -> &mut Self {
403
+ if self.node.is_empty() {
404
+ self.node = origin.node.clone();
405
+ }
406
+ if self.sdk.is_empty() {
407
+ self.sdk = origin.sdk.clone();
408
+ }
409
+ if self.sdk_version.is_empty() {
410
+ self.sdk_version = origin.sdk_version.clone();
411
+ }
412
+ if self.runtime_kind.is_empty() {
413
+ self.runtime_kind = origin.runtime_kind.clone();
414
+ }
415
+ self
416
+ }
417
+ }
418
+
419
+ impl fmt::Display for BlokError {
420
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421
+ write!(f, "[{}] {}", self.category, self.message)
422
+ }
423
+ }
424
+
425
+ impl std::error::Error for BlokError {
426
+ // The cause chain on a BlokError is already flattened into `causes`,
427
+ // so we don't expose a `source()` — `errors.Is`/`errors.As`-equivalents
428
+ // walk the JSON payloads instead.
429
+ }
430
+
431
+ // =============================================================================
432
+ // Builder — chained construction matching master plan §17.5
433
+ // =============================================================================
434
+
435
+ /// Fluent constructor returned by [`BlokError::new`] and the per-category
436
+ /// shortcuts. Each builder method consumes `self` and returns the builder so
437
+ /// chained calls compose without intermediate variables.
438
+ ///
439
+ /// Call [`Self::build`] to finalize into a [`BlokError`] with `at`, `stack`,
440
+ /// and category defaults populated.
441
+ #[derive(Debug, Clone)]
442
+ pub struct BlokErrorBuilder {
443
+ err: BlokError,
444
+ }
445
+
446
+ impl BlokErrorBuilder {
447
+ fn new(category: BlokErrorCategory) -> Self {
448
+ Self {
449
+ err: BlokError {
450
+ category,
451
+ severity: BlokErrorSeverity::Error,
452
+ code: String::new(),
453
+ message: String::new(),
454
+ description: String::new(),
455
+ remediation: String::new(),
456
+ doc_url: String::new(),
457
+ http_status: category.default_http_status(),
458
+ retryable: category.default_retryable(),
459
+ retry_after_ms: 0,
460
+ details: None,
461
+ context_snapshot: None,
462
+ causes: Vec::new(),
463
+ stack: String::new(),
464
+ at: Utc::now(),
465
+ node: String::new(),
466
+ sdk: String::new(),
467
+ sdk_version: String::new(),
468
+ runtime_kind: String::new(),
469
+ },
470
+ }
471
+ }
472
+
473
+ /// Stable machine identifier (e.g. `"POSTGRES_CONNECT_TIMEOUT"`).
474
+ pub fn code(mut self, code: impl Into<String>) -> Self {
475
+ self.err.code = code.into();
476
+ self
477
+ }
478
+
479
+ /// One-sentence human summary.
480
+ pub fn message(mut self, message: impl Into<String>) -> Self {
481
+ self.err.message = message.into();
482
+ self
483
+ }
484
+
485
+ /// Multi-paragraph context (what was tried, why it failed).
486
+ pub fn description(mut self, description: impl Into<String>) -> Self {
487
+ self.err.description = description.into();
488
+ self
489
+ }
490
+
491
+ /// Suggested next step for the developer.
492
+ pub fn remediation(mut self, remediation: impl Into<String>) -> Self {
493
+ self.err.remediation = remediation.into();
494
+ self
495
+ }
496
+
497
+ /// Link to documentation explaining this error code.
498
+ pub fn doc_url(mut self, doc_url: impl Into<String>) -> Self {
499
+ self.err.doc_url = doc_url.into();
500
+ self
501
+ }
502
+
503
+ /// Override the default HTTP status for this category.
504
+ pub fn http_status(mut self, status: i32) -> Self {
505
+ self.err.http_status = status;
506
+ self
507
+ }
508
+
509
+ /// Override the default severity (`Error`).
510
+ pub fn severity(mut self, severity: BlokErrorSeverity) -> Self {
511
+ self.err.severity = severity;
512
+ self
513
+ }
514
+
515
+ /// Override the default retryable hint.
516
+ pub fn retryable(mut self, retryable: bool) -> Self {
517
+ self.err.retryable = retryable;
518
+ self
519
+ }
520
+
521
+ /// Suggested retry-after duration, stored as milliseconds in the proto
522
+ /// wire format.
523
+ pub fn retry_after(mut self, duration: Duration) -> Self {
524
+ self.err.retry_after_ms = duration.as_millis() as i64;
525
+ self
526
+ }
527
+
528
+ /// Suggested retry-after directly in milliseconds.
529
+ pub fn retry_after_ms(mut self, ms: i64) -> Self {
530
+ self.err.retry_after_ms = ms;
531
+ self
532
+ }
533
+
534
+ /// Category-specific structured details (Zod issues, SQL state, etc.).
535
+ pub fn details(mut self, details: serde_json::Value) -> Self {
536
+ self.err.details = Some(details);
537
+ self
538
+ }
539
+
540
+ /// Bounded slice of inputs/state at error time. Use
541
+ /// [`build_context_snapshot`] to construct one within the size budget.
542
+ pub fn context_snapshot(mut self, snapshot: serde_json::Value) -> Self {
543
+ self.err.context_snapshot = Some(snapshot);
544
+ self
545
+ }
546
+
547
+ /// Attach an underlying cause. The cause chain is walked at [`Self::build`]
548
+ /// time and flattened into the `.causes` payload list.
549
+ pub fn cause<E: std::error::Error + 'static>(mut self, cause: &E) -> Self {
550
+ self.err.causes = flatten_causes(cause);
551
+ self
552
+ }
553
+
554
+ /// Attach an already-flattened cause-chain (e.g. when re-serializing from
555
+ /// a wire payload).
556
+ pub fn causes(mut self, causes: Vec<serde_json::Value>) -> Self {
557
+ self.err.causes = causes;
558
+ self
559
+ }
560
+
561
+ /// Override the auto-filled node name (handlers normally don't set this).
562
+ pub fn node(mut self, node: impl Into<String>) -> Self {
563
+ self.err.node = node.into();
564
+ self
565
+ }
566
+
567
+ /// Override the auto-filled SDK identifier.
568
+ pub fn sdk(mut self, sdk: impl Into<String>) -> Self {
569
+ self.err.sdk = sdk.into();
570
+ self
571
+ }
572
+
573
+ /// Override the auto-filled SDK version.
574
+ pub fn sdk_version(mut self, version: impl Into<String>) -> Self {
575
+ self.err.sdk_version = version.into();
576
+ self
577
+ }
578
+
579
+ /// Override the auto-filled runtime kind.
580
+ pub fn runtime_kind(mut self, kind: impl Into<String>) -> Self {
581
+ self.err.runtime_kind = kind.into();
582
+ self
583
+ }
584
+
585
+ /// Override the captured stack trace.
586
+ pub fn stack(mut self, stack: impl Into<String>) -> Self {
587
+ self.err.stack = stack.into();
588
+ self
589
+ }
590
+
591
+ /// Apply origin fields from the runtime, only filling in unset ones.
592
+ pub fn apply_origin(mut self, origin: &Origin) -> Self {
593
+ self.err.apply_origin_if_missing(origin);
594
+ self
595
+ }
596
+
597
+ /// Finalize into a [`BlokError`]. Re-stamps `at` with the current UTC
598
+ /// timestamp.
599
+ pub fn build(mut self) -> BlokError {
600
+ self.err.at = Utc::now();
601
+ self.err
602
+ }
603
+ }
604
+
605
+ // =============================================================================
606
+ // Origin — auto-enrichment carrier
607
+ // =============================================================================
608
+
609
+ /// Auto-enrichment carrier the gRPC servicer fills into a handler-thrown
610
+ /// `BlokError` when the handler didn't set those fields explicitly.
611
+ #[derive(Debug, Clone)]
612
+ pub struct Origin {
613
+ pub node: String,
614
+ pub sdk: String,
615
+ pub sdk_version: String,
616
+ pub runtime_kind: String,
617
+ }
618
+
619
+ impl Origin {
620
+ /// Build an origin with the SDK constants ([`DEFAULT_SDK_NAME`],
621
+ /// [`DEFAULT_RUNTIME_KIND`]) and the caller-provided node name +
622
+ /// SDK version.
623
+ pub fn defaults(node: impl Into<String>, sdk_version: impl Into<String>) -> Self {
624
+ Self {
625
+ node: node.into(),
626
+ sdk: DEFAULT_SDK_NAME.to_string(),
627
+ sdk_version: sdk_version.into(),
628
+ runtime_kind: DEFAULT_RUNTIME_KIND.to_string(),
629
+ }
630
+ }
631
+ }
632
+
633
+ // =============================================================================
634
+ // Cause-chain flattening
635
+ // =============================================================================
636
+
637
+ /// Walk an error's `source()` chain and produce a flat list of payloads.
638
+ /// Mirrors the Python/Go `flatten_causes` shape.
639
+ ///
640
+ /// Cycle-safe (caps at 32 levels — pathological recursive errors don't blow
641
+ /// the stack). When a `BlokError` is encountered in the chain, its already-
642
+ /// flattened causes are appended without nesting.
643
+ pub fn flatten_causes(cause: &(dyn std::error::Error + 'static)) -> Vec<serde_json::Value> {
644
+ let mut causes: Vec<serde_json::Value> = Vec::new();
645
+ let mut current: Option<&(dyn std::error::Error + 'static)> = Some(cause);
646
+ let mut depth = 0usize;
647
+ while let Some(err) = current {
648
+ if depth >= 32 {
649
+ break;
650
+ }
651
+ depth += 1;
652
+ // BlokError chains are already flat; lift each link in directly.
653
+ if let Some(blok) = err.downcast_ref::<BlokError>() {
654
+ let mut payload = blok.to_json_value();
655
+ if let Some(obj) = payload.as_object_mut() {
656
+ obj.insert("causes".to_string(), serde_json::json!([]));
657
+ }
658
+ causes.push(payload);
659
+ for nested in &blok.causes {
660
+ causes.push(nested.clone());
661
+ }
662
+ return causes;
663
+ }
664
+ causes.push(err_to_payload(err));
665
+ current = err.source();
666
+ }
667
+ causes
668
+ }
669
+
670
+ fn err_to_payload(err: &(dyn std::error::Error + 'static)) -> serde_json::Value {
671
+ let type_name = std::any::type_name_of_val(err);
672
+ serde_json::json!({
673
+ "code": uncaught_code(type_name),
674
+ "category": BlokErrorCategory::Internal.as_str(),
675
+ "severity": BlokErrorSeverity::Error.as_str(),
676
+ "node": "",
677
+ "sdk": "",
678
+ "sdk_version": "",
679
+ "runtime_kind": "",
680
+ "at": Utc::now().to_rfc3339(),
681
+ "message": err.to_string(),
682
+ "description": "",
683
+ "remediation": "",
684
+ "doc_url": "",
685
+ "causes": [],
686
+ "stack": "",
687
+ "context_snapshot": serde_json::Value::Null,
688
+ "http_status": 500,
689
+ "retryable": false,
690
+ "retry_after_ms": 0,
691
+ "details": serde_json::Value::Null,
692
+ })
693
+ }
694
+
695
+ /// Derive an `UNCAUGHT_<TYPE>` code from a Rust type name.
696
+ ///
697
+ /// Strips module path qualifiers and uppercases the simple type name, matching
698
+ /// the Python `UNCAUGHT_CONNECTIONERROR` and Go `UNCAUGHT_<TYPE>` conventions.
699
+ /// Returns `"UNCAUGHT_ERROR"` if the input has no useful identifier characters.
700
+ fn uncaught_code(type_name: &str) -> String {
701
+ // Trim generics: "alloc::boxed::Box<core::error::Error>" → "alloc::boxed::Box"
702
+ let without_generics = match type_name.find('<') {
703
+ Some(i) => &type_name[..i],
704
+ None => type_name,
705
+ };
706
+ // Strip module path: "std::io::Error" → "Error"
707
+ let simple = match without_generics.rfind("::") {
708
+ Some(i) => &without_generics[i + 2..],
709
+ None => without_generics,
710
+ };
711
+ let upper: String = simple
712
+ .chars()
713
+ .filter(|c| c.is_ascii_alphanumeric())
714
+ .map(|c| c.to_ascii_uppercase())
715
+ .collect();
716
+ if upper.is_empty() {
717
+ "UNCAUGHT_ERROR".to_string()
718
+ } else {
719
+ format!("UNCAUGHT_{}", upper)
720
+ }
721
+ }
722
+
723
+ // =============================================================================
724
+ // BuildContextSnapshot helper
725
+ // =============================================================================
726
+
727
+ /// Marker re-export used in module docs so doctests compile under all features.
728
+ pub use self::build_context_snapshot as BuildContextSnapshot;
729
+
730
+ /// Build a JSON-friendly bounded slice of inputs + recent vars for the
731
+ /// `context_snapshot` field. Per master plan §17.6: 4KB cap by default + last
732
+ /// 16 vars keys, with progressive trimming when oversize. `inputs` is preserved
733
+ /// as-is — it's the most LLM-actionable context.
734
+ pub fn build_context_snapshot(
735
+ inputs: &std::collections::HashMap<String, serde_json::Value>,
736
+ vars: &std::collections::HashMap<String, serde_json::Value>,
737
+ ) -> serde_json::Value {
738
+ build_context_snapshot_with_opts(inputs, vars, CONTEXT_SNAPSHOT_MAX_BYTES, 16)
739
+ }
740
+
741
+ /// Customizable variant of [`build_context_snapshot`].
742
+ ///
743
+ /// `max_vars_keys=0` drops vars entirely; `max_bytes=0` disables byte-budget
744
+ /// trimming.
745
+ pub fn build_context_snapshot_with_opts(
746
+ inputs: &std::collections::HashMap<String, serde_json::Value>,
747
+ vars: &std::collections::HashMap<String, serde_json::Value>,
748
+ max_bytes: usize,
749
+ max_vars_keys: usize,
750
+ ) -> serde_json::Value {
751
+ let safe_inputs = json_safe_map(inputs);
752
+
753
+ // Use BTreeMap so the keys are sorted — gives a deterministic "last N" slice
754
+ // (Rust HashMap iteration order is randomized; LLM/Studio consumers don't
755
+ // care about the order, but tests do).
756
+ let sorted: BTreeMap<&String, &serde_json::Value> = vars.iter().collect();
757
+ let mut keys: Vec<String> = sorted.keys().map(|k| (*k).clone()).collect();
758
+ if keys.len() > max_vars_keys {
759
+ let drop = keys.len() - max_vars_keys;
760
+ keys.drain(..drop);
761
+ }
762
+
763
+ let mut recent: serde_json::Map<String, serde_json::Value> = serde_json::Map::new();
764
+ for k in &keys {
765
+ if let Some(v) = vars.get(k) {
766
+ recent.insert(k.clone(), json_safe(v));
767
+ }
768
+ }
769
+
770
+ let mut snapshot = serde_json::json!({
771
+ "inputs": safe_inputs,
772
+ "vars": serde_json::Value::Object(recent.clone()),
773
+ });
774
+
775
+ if max_bytes == 0 {
776
+ return snapshot;
777
+ }
778
+
779
+ let encoded = serde_json::to_vec(&snapshot).unwrap_or_default();
780
+ if encoded.len() <= max_bytes {
781
+ return snapshot;
782
+ }
783
+
784
+ // Trim from the front (oldest keys) until it fits.
785
+ let mut working = keys.clone();
786
+ while !working.is_empty() {
787
+ working.remove(0);
788
+ recent = serde_json::Map::new();
789
+ for k in &working {
790
+ if let Some(v) = vars.get(k) {
791
+ recent.insert(k.clone(), json_safe(v));
792
+ }
793
+ }
794
+ snapshot["vars"] = serde_json::Value::Object(recent.clone());
795
+ let encoded = serde_json::to_vec(&snapshot).unwrap_or_default();
796
+ if encoded.len() <= max_bytes {
797
+ return snapshot;
798
+ }
799
+ }
800
+
801
+ serde_json::json!({
802
+ "inputs": safe_inputs,
803
+ "vars": {},
804
+ "_truncated": true,
805
+ })
806
+ }
807
+
808
+ fn json_safe_map(
809
+ m: &std::collections::HashMap<String, serde_json::Value>,
810
+ ) -> serde_json::Value {
811
+ let mut out = serde_json::Map::with_capacity(m.len());
812
+ for (k, v) in m {
813
+ out.insert(k.clone(), json_safe(v));
814
+ }
815
+ serde_json::Value::Object(out)
816
+ }
817
+
818
+ fn json_safe(v: &serde_json::Value) -> serde_json::Value {
819
+ // serde_json::Value is already JSON-safe by construction; this is a deep
820
+ // clone with a hook for the future when richer types might flow through.
821
+ v.clone()
822
+ }
823
+
824
+ #[cfg(test)]
825
+ mod tests {
826
+ use super::*;
827
+ use std::collections::HashMap;
828
+
829
+ #[test]
830
+ fn category_default_status_matches_table() {
831
+ assert_eq!(BlokErrorCategory::Validation.default_http_status(), 400);
832
+ assert_eq!(BlokErrorCategory::Configuration.default_http_status(), 500);
833
+ assert_eq!(BlokErrorCategory::Dependency.default_http_status(), 502);
834
+ assert_eq!(BlokErrorCategory::Timeout.default_http_status(), 504);
835
+ assert_eq!(BlokErrorCategory::Permission.default_http_status(), 403);
836
+ assert_eq!(BlokErrorCategory::RateLimit.default_http_status(), 429);
837
+ assert_eq!(BlokErrorCategory::NotFound.default_http_status(), 404);
838
+ assert_eq!(BlokErrorCategory::Conflict.default_http_status(), 409);
839
+ assert_eq!(BlokErrorCategory::Cancelled.default_http_status(), 499);
840
+ assert_eq!(BlokErrorCategory::Internal.default_http_status(), 500);
841
+ assert_eq!(BlokErrorCategory::Protocol.default_http_status(), 502);
842
+ assert_eq!(BlokErrorCategory::Data.default_http_status(), 422);
843
+ }
844
+
845
+ #[test]
846
+ fn category_default_retryable_matches_table() {
847
+ assert!(BlokErrorCategory::Dependency.default_retryable());
848
+ assert!(BlokErrorCategory::Timeout.default_retryable());
849
+ assert!(BlokErrorCategory::RateLimit.default_retryable());
850
+ assert!(!BlokErrorCategory::Validation.default_retryable());
851
+ assert!(!BlokErrorCategory::Internal.default_retryable());
852
+ }
853
+
854
+ #[test]
855
+ fn category_parse_unknown_falls_back_to_internal() {
856
+ assert_eq!(BlokErrorCategory::parse("DEPENDENCY"), BlokErrorCategory::Dependency);
857
+ assert_eq!(BlokErrorCategory::parse("not-a-thing"), BlokErrorCategory::Internal);
858
+ }
859
+
860
+ #[test]
861
+ fn severity_parse_falls_back_to_error() {
862
+ assert_eq!(BlokErrorSeverity::parse("INFO"), BlokErrorSeverity::Info);
863
+ assert_eq!(BlokErrorSeverity::parse("xyz"), BlokErrorSeverity::Error);
864
+ }
865
+
866
+ #[test]
867
+ fn builder_dependency_defaults() {
868
+ let e = BlokError::dependency().code("X").message("y").build();
869
+ assert_eq!(e.category, BlokErrorCategory::Dependency);
870
+ assert_eq!(e.http_status, 502);
871
+ assert!(e.retryable);
872
+ assert_eq!(e.severity, BlokErrorSeverity::Error);
873
+ }
874
+
875
+ #[test]
876
+ fn builder_validation_defaults() {
877
+ let e = BlokError::validation().code("V").message("v").build();
878
+ assert_eq!(e.category, BlokErrorCategory::Validation);
879
+ assert_eq!(e.http_status, 400);
880
+ assert!(!e.retryable);
881
+ }
882
+
883
+ #[test]
884
+ fn builder_overrides_take_priority() {
885
+ let e = BlokError::dependency()
886
+ .http_status(599)
887
+ .retryable(false)
888
+ .severity(BlokErrorSeverity::Fatal)
889
+ .build();
890
+ assert_eq!(e.http_status, 599);
891
+ assert!(!e.retryable);
892
+ assert_eq!(e.severity, BlokErrorSeverity::Fatal);
893
+ }
894
+
895
+ #[test]
896
+ fn builder_retry_after_duration_into_ms() {
897
+ let e = BlokError::rate_limit()
898
+ .retry_after(Duration::from_secs(5))
899
+ .build();
900
+ assert_eq!(e.retry_after_ms, 5_000);
901
+ }
902
+
903
+ #[test]
904
+ fn builder_retry_after_ms_direct() {
905
+ let e = BlokError::timeout().retry_after_ms(750).build();
906
+ assert_eq!(e.retry_after_ms, 750);
907
+ }
908
+
909
+ #[test]
910
+ fn builder_details_round_trip() {
911
+ let e = BlokError::validation()
912
+ .details(serde_json::json!({"issues": [{"path": ["email"]}]}))
913
+ .build();
914
+ let det = e.details.as_ref().unwrap();
915
+ assert_eq!(det["issues"][0]["path"][0], "email");
916
+ }
917
+
918
+ #[test]
919
+ fn builder_attaches_cause_via_flatten() {
920
+ let cause = std::io::Error::new(std::io::ErrorKind::ConnectionRefused, "nope");
921
+ let e = BlokError::dependency().cause(&cause).build();
922
+ assert!(!e.causes.is_empty());
923
+ assert_eq!(e.causes[0]["category"], "INTERNAL");
924
+ assert_eq!(e.causes[0]["message"], "nope");
925
+ }
926
+
927
+ #[test]
928
+ fn builder_apply_origin_fills_only_missing() {
929
+ let origin = Origin::defaults("my-node", "1.2.3");
930
+ let e = BlokError::dependency().sdk("custom").apply_origin(&origin).build();
931
+ assert_eq!(e.sdk, "custom"); // explicit value preserved
932
+ assert_eq!(e.node, "my-node"); // empty filled
933
+ assert_eq!(e.sdk_version, "1.2.3");
934
+ assert_eq!(e.runtime_kind, "runtime.rust");
935
+ }
936
+
937
+ #[test]
938
+ fn from_message_creates_internal_error() {
939
+ let origin = Origin::defaults("x", "1.0.0");
940
+ let e = BlokError::from_message("boom", &origin);
941
+ assert_eq!(e.category, BlokErrorCategory::Internal);
942
+ assert_eq!(e.code, "UNCAUGHT_ERROR");
943
+ assert_eq!(e.message, "boom");
944
+ assert_eq!(e.details.unwrap()["message"], "boom");
945
+ }
946
+
947
+ #[test]
948
+ fn from_dyn_error_categorizes_as_internal() {
949
+ let cause = std::io::Error::new(std::io::ErrorKind::TimedOut, "slow");
950
+ let origin = Origin::defaults("x", "1.0.0");
951
+ let e = BlokError::from_dyn_error(&cause, &origin);
952
+ assert_eq!(e.category, BlokErrorCategory::Internal);
953
+ assert!(e.code.starts_with("UNCAUGHT_"));
954
+ assert_eq!(e.message, "slow");
955
+ assert_eq!(e.node, "x");
956
+ }
957
+
958
+ #[test]
959
+ fn from_error_passes_through_typed_blok_error() {
960
+ let origin = Origin::defaults("auto-node", "1.2.3");
961
+ let original = BlokError::rate_limit()
962
+ .code("UPSTREAM_RATE_LIMITED")
963
+ .message("limit hit")
964
+ .build();
965
+ let boxed: Box<dyn std::error::Error + Send + Sync> = Box::new(original);
966
+ let recovered = BlokError::from_error(boxed, &origin);
967
+ assert_eq!(recovered.category, BlokErrorCategory::RateLimit);
968
+ assert_eq!(recovered.code, "UPSTREAM_RATE_LIMITED");
969
+ // Origin auto-enrichment kicked in.
970
+ assert_eq!(recovered.node, "auto-node");
971
+ assert_eq!(recovered.sdk_version, "1.2.3");
972
+ }
973
+
974
+ #[test]
975
+ fn from_error_wraps_non_blok_error() {
976
+ let origin = Origin::defaults("auto", "1.0.0");
977
+ let cause = std::io::Error::other("disk full");
978
+ let boxed: Box<dyn std::error::Error + Send + Sync> = Box::new(cause);
979
+ let wrapped = BlokError::from_error(boxed, &origin);
980
+ assert_eq!(wrapped.category, BlokErrorCategory::Internal);
981
+ assert_eq!(wrapped.message, "disk full");
982
+ assert!(wrapped.code.starts_with("UNCAUGHT_"));
983
+ }
984
+
985
+ #[test]
986
+ fn to_json_value_round_trip() {
987
+ let e = BlokError::dependency()
988
+ .code("CODE")
989
+ .message("msg")
990
+ .description("desc")
991
+ .remediation("rem")
992
+ .retryable(true)
993
+ .retry_after_ms(1234)
994
+ .doc_url("https://example.com")
995
+ .details(serde_json::json!({"a": 1}))
996
+ .context_snapshot(serde_json::json!({"inputs": {}}))
997
+ .node("n")
998
+ .sdk("blok-rust")
999
+ .sdk_version("1.0.0")
1000
+ .runtime_kind("runtime.rust")
1001
+ .build();
1002
+
1003
+ let v = e.to_json_value();
1004
+ assert_eq!(v["category"], "DEPENDENCY");
1005
+ assert_eq!(v["code"], "CODE");
1006
+ assert_eq!(v["http_status"], 502);
1007
+ assert_eq!(v["retry_after_ms"], 1234);
1008
+
1009
+ let restored = BlokError::from_json_value(v).unwrap();
1010
+ assert_eq!(restored.category, BlokErrorCategory::Dependency);
1011
+ assert_eq!(restored.code, "CODE");
1012
+ assert_eq!(restored.message, "msg");
1013
+ assert_eq!(restored.description, "desc");
1014
+ assert_eq!(restored.retry_after_ms, 1234);
1015
+ }
1016
+
1017
+ #[test]
1018
+ fn from_json_value_accepts_camel_case() {
1019
+ let v = serde_json::json!({
1020
+ "category": "RATE_LIMIT",
1021
+ "severity": "ERROR",
1022
+ "code": "RL",
1023
+ "message": "too many",
1024
+ "httpStatus": 429,
1025
+ "retryable": true,
1026
+ "retryAfterMs": 60000,
1027
+ "at": "2026-04-29T00:00:00Z",
1028
+ "sdkVersion": "1.0.0",
1029
+ "runtimeKind": "runtime.rust",
1030
+ "docUrl": "https://docs/example"
1031
+ });
1032
+ let e = BlokError::from_json_value(v).unwrap();
1033
+ assert_eq!(e.category, BlokErrorCategory::RateLimit);
1034
+ assert_eq!(e.http_status, 429);
1035
+ assert_eq!(e.retry_after_ms, 60_000);
1036
+ assert_eq!(e.sdk_version, "1.0.0");
1037
+ assert_eq!(e.runtime_kind, "runtime.rust");
1038
+ assert_eq!(e.doc_url, "https://docs/example");
1039
+ }
1040
+
1041
+ #[test]
1042
+ fn display_formats_category_and_message() {
1043
+ let e = BlokError::dependency().code("X").message("nope").build();
1044
+ assert_eq!(e.to_string(), "[DEPENDENCY] nope");
1045
+ }
1046
+
1047
+ #[test]
1048
+ fn impls_std_error_trait() {
1049
+ fn assert_send_sync<T: std::error::Error + Send + Sync + 'static>() {}
1050
+ assert_send_sync::<BlokError>();
1051
+ }
1052
+
1053
+ #[test]
1054
+ fn flatten_causes_walks_source_chain() {
1055
+ // Build a tiny custom error that exposes a source.
1056
+ #[derive(Debug)]
1057
+ struct Wrap(std::io::Error);
1058
+ impl fmt::Display for Wrap {
1059
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1060
+ write!(f, "wrapped")
1061
+ }
1062
+ }
1063
+ impl std::error::Error for Wrap {
1064
+ fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1065
+ Some(&self.0)
1066
+ }
1067
+ }
1068
+
1069
+ let inner = std::io::Error::new(std::io::ErrorKind::Other, "inner");
1070
+ let wrap = Wrap(inner);
1071
+ let causes = flatten_causes(&wrap);
1072
+ assert_eq!(causes.len(), 2);
1073
+ assert_eq!(causes[0]["message"], "wrapped");
1074
+ assert_eq!(causes[1]["message"], "inner");
1075
+ }
1076
+
1077
+ #[test]
1078
+ fn flatten_causes_lifts_blok_error_link() {
1079
+ let inner_blok = BlokError::not_found()
1080
+ .code("INNER")
1081
+ .message("inner-msg")
1082
+ .build();
1083
+ // Sanity: lifting occurs when the chain root is a BlokError directly.
1084
+ let causes = flatten_causes(&inner_blok);
1085
+ assert_eq!(causes[0]["code"], "INNER");
1086
+ assert_eq!(causes[0]["category"], "NOT_FOUND");
1087
+ }
1088
+
1089
+ #[test]
1090
+ fn build_context_snapshot_preserves_small_payload() {
1091
+ let mut inputs = HashMap::new();
1092
+ inputs.insert("a".to_string(), serde_json::json!(1));
1093
+ let mut vars = HashMap::new();
1094
+ vars.insert("k1".to_string(), serde_json::json!("v1"));
1095
+ let snap = build_context_snapshot(&inputs, &vars);
1096
+ assert_eq!(snap["inputs"]["a"], 1);
1097
+ assert_eq!(snap["vars"]["k1"], "v1");
1098
+ }
1099
+
1100
+ #[test]
1101
+ fn build_context_snapshot_caps_at_max_bytes() {
1102
+ let inputs = HashMap::new();
1103
+ let mut vars = HashMap::new();
1104
+ // 80 keys with 100-char values each — well over 4KB combined.
1105
+ for i in 0..80u32 {
1106
+ vars.insert(format!("k{:03}", i), serde_json::json!("x".repeat(100)));
1107
+ }
1108
+ let snap = build_context_snapshot(&inputs, &vars);
1109
+ let encoded = serde_json::to_vec(&snap).unwrap();
1110
+ assert!(
1111
+ encoded.len() <= CONTEXT_SNAPSHOT_MAX_BYTES + 64, // small fudge for trailing whitespace
1112
+ "snapshot ({} bytes) exceeded budget {}",
1113
+ encoded.len(),
1114
+ CONTEXT_SNAPSHOT_MAX_BYTES
1115
+ );
1116
+ }
1117
+
1118
+ #[test]
1119
+ fn build_context_snapshot_keeps_last_n_keys() {
1120
+ let inputs = HashMap::new();
1121
+ let mut vars = HashMap::new();
1122
+ for i in 0..32u32 {
1123
+ vars.insert(format!("k{:02}", i), serde_json::json!(i));
1124
+ }
1125
+ let snap = build_context_snapshot_with_opts(&inputs, &vars, 0, 5);
1126
+ let kept = snap["vars"].as_object().unwrap();
1127
+ assert_eq!(kept.len(), 5);
1128
+ // Sorted insertion → "last 5" of "k00..k31" = k27..k31.
1129
+ assert!(kept.contains_key("k31"));
1130
+ assert!(!kept.contains_key("k00"));
1131
+ }
1132
+
1133
+ #[test]
1134
+ fn build_context_snapshot_disables_var_keys_when_zero() {
1135
+ let inputs = HashMap::new();
1136
+ let mut vars = HashMap::new();
1137
+ vars.insert("only".to_string(), serde_json::json!(1));
1138
+ let snap = build_context_snapshot_with_opts(&inputs, &vars, 0, 0);
1139
+ assert!(snap["vars"].as_object().unwrap().is_empty());
1140
+ }
1141
+
1142
+ #[test]
1143
+ fn uncaught_code_strips_module_path() {
1144
+ assert_eq!(uncaught_code("std::io::Error"), "UNCAUGHT_ERROR");
1145
+ assert_eq!(uncaught_code("ConnectionError"), "UNCAUGHT_CONNECTIONERROR");
1146
+ assert_eq!(uncaught_code(""), "UNCAUGHT_ERROR");
1147
+ assert_eq!(uncaught_code("foo::Bar<Baz>"), "UNCAUGHT_BAR");
1148
+ }
1149
+
1150
+ #[test]
1151
+ fn origin_defaults_uses_sdk_constants() {
1152
+ let o = Origin::defaults("n", "1.2.3");
1153
+ assert_eq!(o.sdk, DEFAULT_SDK_NAME);
1154
+ assert_eq!(o.runtime_kind, DEFAULT_RUNTIME_KIND);
1155
+ assert_eq!(o.node, "n");
1156
+ assert_eq!(o.sdk_version, "1.2.3");
1157
+ }
1158
+
1159
+ #[test]
1160
+ fn apply_origin_if_missing_preserves_explicit_fields() {
1161
+ let mut e = BlokError::internal().node("explicit").build();
1162
+ let origin = Origin::defaults("auto", "1.0.0");
1163
+ e.apply_origin_if_missing(&origin);
1164
+ assert_eq!(e.node, "explicit");
1165
+ assert_eq!(e.sdk, DEFAULT_SDK_NAME);
1166
+ assert_eq!(e.runtime_kind, DEFAULT_RUNTIME_KIND);
1167
+ }
1168
+ }