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.
- package/dist/commands/create/project.d.ts +3 -0
- package/dist/commands/create/project.js +166 -21
- package/dist/commands/create/utils/Examples.d.ts +2 -2
- package/dist/commands/create/utils/Examples.js +9 -3
- package/dist/commands/dev/index.js +13 -1
- package/dist/commands/runtime/add.js +92 -29
- package/dist/commands/runtime/index.js +1 -0
- package/dist/commands/runtime/shared.js +4 -0
- package/dist/scaffold-repo/examples/ts-workflows/mcp-greeter.ts +59 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-csharp-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-go-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-java-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-php-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-python3-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-ruby-hello.ts +36 -0
- package/dist/scaffold-repo/examples/ts-workflows/runtime-rust-hello.ts +36 -0
- package/dist/scaffold-repo/infra/development/3055.dat +602 -0
- package/dist/scaffold-repo/infra/development/3057.dat +203 -0
- package/dist/scaffold-repo/infra/development/3059.dat +19 -0
- package/dist/scaffold-repo/infra/development/3061.dat +1003 -0
- package/dist/scaffold-repo/infra/development/3062.dat +5465 -0
- package/dist/scaffold-repo/infra/development/3063.dat +1003 -0
- package/dist/scaffold-repo/infra/development/3065.dat +606 -0
- package/dist/scaffold-repo/infra/development/3067.dat +603 -0
- package/dist/scaffold-repo/infra/development/3069.dat +112 -0
- package/dist/scaffold-repo/infra/development/3071.dat +4584 -0
- package/dist/scaffold-repo/infra/development/3073.dat +9 -0
- package/dist/scaffold-repo/infra/development/3075.dat +14599 -0
- package/dist/scaffold-repo/infra/development/3077.dat +16047 -0
- package/dist/scaffold-repo/infra/development/3079.dat +5 -0
- package/dist/scaffold-repo/infra/development/3081.dat +5 -0
- package/dist/scaffold-repo/infra/development/docker-compose.yml +106 -0
- package/dist/scaffold-repo/infra/development/schema.sql +1616 -0
- package/dist/scaffold-repo/infra/development/toc.dat +0 -0
- package/dist/scaffold-repo/infra/metrics/alertmanager.yml +43 -0
- package/dist/scaffold-repo/infra/metrics/alloy-config.alloy +75 -0
- package/dist/scaffold-repo/infra/metrics/dashboard.json +1152 -0
- package/dist/scaffold-repo/infra/metrics/dashboards/blok-overview.json +314 -0
- package/dist/scaffold-repo/infra/metrics/dashboards/blok-system.json +175 -0
- package/dist/scaffold-repo/infra/metrics/dashboards/blok-tracing.json +235 -0
- package/dist/scaffold-repo/infra/metrics/dashboards/blok-triggers.json +258 -0
- package/dist/scaffold-repo/infra/metrics/datasources.yml +43 -0
- package/dist/scaffold-repo/infra/metrics/default.yaml +8 -0
- package/dist/scaffold-repo/infra/metrics/docker-compose.yml +193 -0
- package/dist/scaffold-repo/infra/metrics/loki-config.yaml +50 -0
- package/dist/scaffold-repo/infra/metrics/nginx.conf +25 -0
- package/dist/scaffold-repo/infra/metrics/prometheus.yml +51 -0
- package/dist/scaffold-repo/infra/metrics/rules/blok-alerts.yml +114 -0
- package/dist/scaffold-repo/infra/metrics/telegraf.conf +41 -0
- package/dist/scaffold-repo/infra/metrics/tempo.yaml +81 -0
- package/dist/scaffold-repo/infra/milvus/docker-compose.yml +73 -0
- package/dist/scaffold-repo/sdk/javascript/README.md +151 -0
- package/dist/scaffold-repo/sdk/javascript/bootstrap.min.css +11660 -0
- package/dist/scaffold-repo/sdk/javascript/image-ai.html +316 -0
- package/dist/scaffold-repo/sdk/javascript/nanosdk.js +180 -0
- package/dist/scaffold-repo/sdk/javascript/nanosdk.min.js +100 -0
- package/dist/scaffold-repo/sdk/javascript/pdf.html +63 -0
- package/dist/scaffold-repo/sdk/javascript/test.html +68 -0
- package/dist/scaffold-repo/sdks/CLAUDE.md +67 -0
- package/dist/scaffold-repo/sdks/csharp/.dockerignore +7 -0
- package/dist/scaffold-repo/sdks/csharp/Blok.Core.sln +24 -0
- package/dist/scaffold-repo/sdks/csharp/Dockerfile +42 -0
- package/dist/scaffold-repo/sdks/csharp/README.md +138 -0
- package/dist/scaffold-repo/sdks/csharp/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Blok.Core.csproj +39 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Config/ServerConfig.cs +90 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokError.cs +538 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokErrorCategory.cs +112 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BlokErrorSeverity.cs +40 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/BuildContextSnapshot.cs +168 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/ErrorCategory.cs +13 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Errors/NodeException.cs +44 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/LogEntry.cs +34 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/LogLevel.cs +12 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Logging/Logger.cs +92 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/IMiddleware.cs +14 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/LoggingMiddleware.cs +46 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/MiddlewareChain.cs +35 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Middleware/RecoveryMiddleware.cs +63 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/INodeHandler.cs +17 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/NodeRegistry.cs +128 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Node/TypedNode.cs +140 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/ApiCallNode.cs +129 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/BlokErrorDemoNode.cs +125 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/ChainTestNode.cs +79 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/HelloWorldNode.cs +45 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/TransformDataNode.cs +119 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Nodes/TypedGreetNode.cs +23 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Program.cs +26 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Server/BlokNodeRuntimeService.cs +536 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Server/RuntimeServer.cs +183 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Testing/MockContextBuilder.cs +117 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Testing/TestNodeRunner.cs +50 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Context.cs +56 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionMetrics.cs +21 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionRequest.cs +15 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/ExecutionResult.cs +104 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/HealthStatus.cs +18 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/NodeConfig.cs +59 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Request.cs +57 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Types/Response.cs +24 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/UserNodeRegistry.cs +17 -0
- package/dist/scaffold-repo/sdks/csharp/src/Blok.Core/Validation/SchemaValidator.cs +198 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Blok.Core.Tests.csproj +25 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Errors/BlokErrorTests.cs +458 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Logging/LoggerTests.cs +129 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Node/NodeRegistryTests.cs +145 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Testing/MockContextTests.cs +153 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/TypedNodeTests.cs +69 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Types/ExecutionResultTests.cs +110 -0
- package/dist/scaffold-repo/sdks/csharp/tests/Blok.Core.Tests/Validation/SchemaValidatorTests.cs +233 -0
- package/dist/scaffold-repo/sdks/go/Dockerfile +33 -0
- package/dist/scaffold-repo/sdks/go/README.md +255 -0
- package/dist/scaffold-repo/sdks/go/blok_error.go +803 -0
- package/dist/scaffold-repo/sdks/go/blok_error_test.go +433 -0
- package/dist/scaffold-repo/sdks/go/cmd/server/main.go +45 -0
- package/dist/scaffold-repo/sdks/go/cmd/server/register_user_nodes.go +12 -0
- package/dist/scaffold-repo/sdks/go/config.go +157 -0
- package/dist/scaffold-repo/sdks/go/config_test.go +129 -0
- package/dist/scaffold-repo/sdks/go/define_node.go +87 -0
- package/dist/scaffold-repo/sdks/go/define_node_test.go +75 -0
- package/dist/scaffold-repo/sdks/go/errors.go +104 -0
- package/dist/scaffold-repo/sdks/go/errors_test.go +95 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/apicall.go +117 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/blokerrordemo.go +80 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/chaintest.go +63 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/helloworld.go +41 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/transformdata.go +176 -0
- package/dist/scaffold-repo/sdks/go/examples/nodes/typedgreet.go +34 -0
- package/dist/scaffold-repo/sdks/go/genpb/blok/runtime/v1/runtime.pb.go +2070 -0
- package/dist/scaffold-repo/sdks/go/genpb/blok/runtime/v1/runtime_grpc.pb.go +273 -0
- package/dist/scaffold-repo/sdks/go/go.mod +25 -0
- package/dist/scaffold-repo/sdks/go/go.sum +66 -0
- package/dist/scaffold-repo/sdks/go/grpc_server.go +670 -0
- package/dist/scaffold-repo/sdks/go/grpc_server_test.go +474 -0
- package/dist/scaffold-repo/sdks/go/logging.go +144 -0
- package/dist/scaffold-repo/sdks/go/logging_test.go +139 -0
- package/dist/scaffold-repo/sdks/go/middleware.go +152 -0
- package/dist/scaffold-repo/sdks/go/middleware_test.go +222 -0
- package/dist/scaffold-repo/sdks/go/node.go +50 -0
- package/dist/scaffold-repo/sdks/go/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/go/registry.go +156 -0
- package/dist/scaffold-repo/sdks/go/registry_test.go +195 -0
- package/dist/scaffold-repo/sdks/go/server.go +207 -0
- package/dist/scaffold-repo/sdks/go/server_test.go +186 -0
- package/dist/scaffold-repo/sdks/go/shutdown.go +32 -0
- package/dist/scaffold-repo/sdks/go/testutil.go +169 -0
- package/dist/scaffold-repo/sdks/go/testutil_test.go +124 -0
- package/dist/scaffold-repo/sdks/go/types.go +295 -0
- package/dist/scaffold-repo/sdks/go/types_test.go +251 -0
- package/dist/scaffold-repo/sdks/go/validation.go +210 -0
- package/dist/scaffold-repo/sdks/go/validation_test.go +262 -0
- package/dist/scaffold-repo/sdks/go/worker.go +577 -0
- package/dist/scaffold-repo/sdks/java/Dockerfile +33 -0
- package/dist/scaffold-repo/sdks/java/README.md +221 -0
- package/dist/scaffold-repo/sdks/java/pom.xml +163 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/Main.java +90 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/UserNodeRegistry.java +19 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/config/ServerConfig.java +244 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokError.java +576 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokErrorCategory.java +68 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BlokErrorSeverity.java +31 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/BuildContextSnapshot.java +132 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/ErrorCategory.java +22 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/errors/NodeException.java +176 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/LogEntry.java +78 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/LogLevel.java +48 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/logging/Logger.java +160 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/LoggingMiddleware.java +65 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/Middleware.java +29 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/MiddlewareChain.java +59 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/middleware/RecoveryMiddleware.java +53 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeHandler.java +40 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeReflector.java +18 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/NodeRegistry.java +205 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/node/TypedNode.java +143 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/ApiCallNode.java +145 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/BlokErrorDemoNode.java +109 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/ChainTestNode.java +65 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/HelloWorldNode.java +62 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/TransformDataNode.java +121 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/nodes/TypedGreetNode.java +41 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/BlokGrpcServer.java +103 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/BlokNodeRuntimeService.java +501 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/server/RuntimeServer.java +176 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/testing/MockContext.java +120 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/testing/TestRunner.java +59 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Context.java +167 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionMetrics.java +80 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionRequest.java +61 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/ExecutionResult.java +188 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/HealthStatus.java +77 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/NodeConfig.java +139 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Request.java +154 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/types/Response.java +77 -0
- package/dist/scaffold-repo/sdks/java/src/main/java/com/blok/blok/validation/SchemaValidator.java +178 -0
- package/dist/scaffold-repo/sdks/java/src/main/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/errors/BlokErrorTest.java +416 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/logging/LoggerTest.java +176 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/node/NodeRegistryTest.java +227 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/node/TypedNodeTest.java +76 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/server/RuntimeServerTest.java +197 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/types/ExecutionResultTest.java +194 -0
- package/dist/scaffold-repo/sdks/java/src/test/java/com/blok/blok/validation/SchemaValidatorTest.java +246 -0
- package/dist/scaffold-repo/sdks/php/.rr.yaml +29 -0
- package/dist/scaffold-repo/sdks/php/Dockerfile +61 -0
- package/dist/scaffold-repo/sdks/php/README.md +387 -0
- package/dist/scaffold-repo/sdks/php/composer.json +41 -0
- package/dist/scaffold-repo/sdks/php/examples/ApiCallNode.php +103 -0
- package/dist/scaffold-repo/sdks/php/examples/BlokErrorDemoNode.php +90 -0
- package/dist/scaffold-repo/sdks/php/examples/ChainTestNode.php +56 -0
- package/dist/scaffold-repo/sdks/php/examples/HelloWorldNode.php +39 -0
- package/dist/scaffold-repo/sdks/php/examples/TransformDataNode.php +94 -0
- package/dist/scaffold-repo/sdks/php/examples/TypedGreetNode.php +57 -0
- package/dist/scaffold-repo/sdks/php/phpunit.xml +23 -0
- package/dist/scaffold-repo/sdks/php/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/php/src/Config/ServerConfig.php +83 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BlokError.php +467 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorBuilder.php +121 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorCategory.php +83 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BlokErrorSeverity.php +30 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/BuildContextSnapshot.php +141 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/ErrorCategory.php +17 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/NodeException.php +107 -0
- package/dist/scaffold-repo/sdks/php/src/Errors/Origin.php +35 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ErrorCategory.php +118 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ErrorSeverity.php +72 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteEvent.php +181 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteOptions.php +159 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteRequest.php +328 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ExecuteResponse.php +288 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthRequest.php +59 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthResponse/Status.php +54 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/HealthResponse.php +113 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ListNodesRequest.php +32 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/ListNodesResponse.php +154 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/LogLine.php +156 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/Metrics.php +165 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeDescriptor.php +174 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeError.php +627 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeRef.php +134 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeRuntimeClient.php +101 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/NodeStarted.php +68 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/PartialResult.php +59 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/Progress.php +85 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/RuntimeState.php +142 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/StepInfo.php +168 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/TriggerInfo.php +289 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/Blok/Runtime/V1/WorkflowInfo.php +176 -0
- package/dist/scaffold-repo/sdks/php/src/Genpb/GPBMetadata/Blok/Runtime/V1/Runtime.php +26 -0
- package/dist/scaffold-repo/sdks/php/src/Logging/LogEntry.php +47 -0
- package/dist/scaffold-repo/sdks/php/src/Logging/LogLevel.php +50 -0
- package/dist/scaffold-repo/sdks/php/src/Logging/Logger.php +133 -0
- package/dist/scaffold-repo/sdks/php/src/Node/NodeHandler.php +35 -0
- package/dist/scaffold-repo/sdks/php/src/Node/NodeReflector.php +21 -0
- package/dist/scaffold-repo/sdks/php/src/Node/NodeRegistry.php +172 -0
- package/dist/scaffold-repo/sdks/php/src/Node/TypedNode.php +159 -0
- package/dist/scaffold-repo/sdks/php/src/Server/BlokNodeRuntimeService.php +504 -0
- package/dist/scaffold-repo/sdks/php/src/Server/DecodeException.php +13 -0
- package/dist/scaffold-repo/sdks/php/src/Server/Middleware.php +18 -0
- package/dist/scaffold-repo/sdks/php/src/Server/MiddlewarePipeline.php +33 -0
- package/dist/scaffold-repo/sdks/php/src/Server/NodeRuntimeInterface.php +40 -0
- package/dist/scaffold-repo/sdks/php/src/Server/Server.php +157 -0
- package/dist/scaffold-repo/sdks/php/src/Testing/MockContext.php +161 -0
- package/dist/scaffold-repo/sdks/php/src/Testing/TestRunner.php +78 -0
- package/dist/scaffold-repo/sdks/php/src/Types/Context.php +80 -0
- package/dist/scaffold-repo/sdks/php/src/Types/ExecutionMetrics.php +48 -0
- package/dist/scaffold-repo/sdks/php/src/Types/ExecutionRequest.php +38 -0
- package/dist/scaffold-repo/sdks/php/src/Types/ExecutionResult.php +143 -0
- package/dist/scaffold-repo/sdks/php/src/Types/HealthStatus.php +42 -0
- package/dist/scaffold-repo/sdks/php/src/Types/NodeConfig.php +72 -0
- package/dist/scaffold-repo/sdks/php/src/Types/Request.php +82 -0
- package/dist/scaffold-repo/sdks/php/src/Types/Response.php +44 -0
- package/dist/scaffold-repo/sdks/php/src/Validation/SchemaValidator.php +197 -0
- package/dist/scaffold-repo/sdks/php/tests/Errors/BlokErrorTest.php +402 -0
- package/dist/scaffold-repo/sdks/php/tests/Logging/LoggerTest.php +165 -0
- package/dist/scaffold-repo/sdks/php/tests/Node/NodeRegistryTest.php +139 -0
- package/dist/scaffold-repo/sdks/php/tests/Node/TypedNodeTest.php +84 -0
- package/dist/scaffold-repo/sdks/php/tests/Server/BlokNodeRuntimeServiceTest.php +288 -0
- package/dist/scaffold-repo/sdks/php/tests/Testing/MockContextTest.php +184 -0
- package/dist/scaffold-repo/sdks/php/tests/Types/ExecutionResultTest.php +136 -0
- package/dist/scaffold-repo/sdks/php/tests/Validation/SchemaValidatorTest.php +191 -0
- package/dist/scaffold-repo/sdks/python3/Dockerfile +62 -0
- package/dist/scaffold-repo/sdks/python3/blok/__init__.py +61 -0
- package/dist/scaffold-repo/sdks/python3/blok/config/__init__.py +3 -0
- package/dist/scaffold-repo/sdks/python3/blok/config/server_config.py +116 -0
- package/dist/scaffold-repo/sdks/python3/blok/errors/__init__.py +50 -0
- package/dist/scaffold-repo/sdks/python3/blok/errors/blok_error.py +555 -0
- package/dist/scaffold-repo/sdks/python3/blok/errors/node_error.py +64 -0
- package/dist/scaffold-repo/sdks/python3/blok/logging/__init__.py +3 -0
- package/dist/scaffold-repo/sdks/python3/blok/logging/logger.py +82 -0
- package/dist/scaffold-repo/sdks/python3/blok/middleware/__init__.py +4 -0
- package/dist/scaffold-repo/sdks/python3/blok/middleware/logging_middleware.py +35 -0
- package/dist/scaffold-repo/sdks/python3/blok/middleware/recovery_middleware.py +36 -0
- package/dist/scaffold-repo/sdks/python3/blok/node/__init__.py +4 -0
- package/dist/scaffold-repo/sdks/python3/blok/node/define_node.py +239 -0
- package/dist/scaffold-repo/sdks/python3/blok/node/node_handler.py +35 -0
- package/dist/scaffold-repo/sdks/python3/blok/node/node_registry.py +136 -0
- package/dist/scaffold-repo/sdks/python3/blok/runtime/__init__.py +0 -0
- package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/__init__.py +0 -0
- package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/runtime_pb2.py +112 -0
- package/dist/scaffold-repo/sdks/python3/blok/runtime/v1/runtime_pb2_grpc.py +259 -0
- package/dist/scaffold-repo/sdks/python3/blok/server/__init__.py +3 -0
- package/dist/scaffold-repo/sdks/python3/blok/server/grpc_server.py +757 -0
- package/dist/scaffold-repo/sdks/python3/blok/server/runtime_server.py +165 -0
- package/dist/scaffold-repo/sdks/python3/blok/types/__init__.py +13 -0
- package/dist/scaffold-repo/sdks/python3/blok/types/context.py +162 -0
- package/dist/scaffold-repo/sdks/python3/blok/types/execution_request.py +74 -0
- package/dist/scaffold-repo/sdks/python3/blok/types/execution_result.py +103 -0
- package/dist/scaffold-repo/sdks/python3/blok/worker/__init__.py +10 -0
- package/dist/scaffold-repo/sdks/python3/blok/worker/job_message.py +34 -0
- package/dist/scaffold-repo/sdks/python3/blok/worker/worker.py +451 -0
- package/dist/scaffold-repo/sdks/python3/blok/worker/worker_config.py +129 -0
- package/dist/scaffold-repo/sdks/python3/examples/__init__.py +32 -0
- package/dist/scaffold-repo/sdks/python3/examples/api_call_node.py +85 -0
- package/dist/scaffold-repo/sdks/python3/examples/blok_error_demo_node.py +79 -0
- package/dist/scaffold-repo/sdks/python3/examples/chain_test_node.py +51 -0
- package/dist/scaffold-repo/sdks/python3/examples/hello_world_node.py +44 -0
- package/dist/scaffold-repo/sdks/python3/examples/transform_data_node.py +71 -0
- package/dist/scaffold-repo/sdks/python3/examples/typed_greet_node.py +25 -0
- package/dist/scaffold-repo/sdks/python3/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/python3/pyproject.toml +47 -0
- package/dist/scaffold-repo/sdks/python3/requirements.txt +17 -0
- package/dist/scaffold-repo/sdks/python3/tests/__init__.py +0 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_blok_error.py +341 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_define_node.py +135 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_discovery.py +99 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_grpc_codec.py +260 -0
- package/dist/scaffold-repo/sdks/python3/tests/test_grpc_server.py +398 -0
- package/dist/scaffold-repo/sdks/ruby/Dockerfile +37 -0
- package/dist/scaffold-repo/sdks/ruby/Gemfile +5 -0
- package/dist/scaffold-repo/sdks/ruby/README.md +210 -0
- package/dist/scaffold-repo/sdks/ruby/Rakefile +11 -0
- package/dist/scaffold-repo/sdks/ruby/blok.gemspec +43 -0
- package/dist/scaffold-repo/sdks/ruby/config.ru +15 -0
- package/dist/scaffold-repo/sdks/ruby/examples/api_call_node.rb +99 -0
- package/dist/scaffold-repo/sdks/ruby/examples/blok_error_demo_node.rb +79 -0
- package/dist/scaffold-repo/sdks/ruby/examples/chain_test_node.rb +51 -0
- package/dist/scaffold-repo/sdks/ruby/examples/hello_world_node.rb +40 -0
- package/dist/scaffold-repo/sdks/ruby/examples/transform_data_node.rb +82 -0
- package/dist/scaffold-repo/sdks/ruby/examples/typed_greet_node.rb +25 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/config/server_config.rb +76 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/blok_error.rb +476 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/build_context_snapshot.rb +99 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/error_category.rb +16 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/errors/node_error.rb +84 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/log_entry.rb +46 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/log_level.rb +49 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/logging/logger.rb +71 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/logging_middleware.rb +45 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/middleware.rb +36 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/middleware/recovery_middleware.rb +31 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/node/discovery.rb +59 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/node/node_handler.rb +43 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/node/node_registry.rb +107 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/node/typed_node.rb +180 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/runtime/v1/runtime_pb.rb +43 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/runtime/v1/runtime_services_pb.rb +55 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/server/grpc_server.rb +435 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/server/runtime_app.rb +86 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/testing/mock_context.rb +109 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/testing/test_runner.rb +40 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/context.rb +82 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_metrics.rb +43 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_request.rb +39 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/execution_result.rb +117 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/health_status.rb +42 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/node_config.rb +73 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/request.rb +71 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/types/response.rb +46 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/validation/schema_validator.rb +142 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok/version.rb +5 -0
- package/dist/scaffold-repo/sdks/ruby/lib/blok.rb +53 -0
- package/dist/scaffold-repo/sdks/ruby/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/ruby/test/errors/blok_error_test.rb +339 -0
- package/dist/scaffold-repo/sdks/ruby/test/logging/logger_test.rb +155 -0
- package/dist/scaffold-repo/sdks/ruby/test/node/node_registry_test.rb +132 -0
- package/dist/scaffold-repo/sdks/ruby/test/node/typed_node_test.rb +67 -0
- package/dist/scaffold-repo/sdks/ruby/test/test_helper.rb +6 -0
- package/dist/scaffold-repo/sdks/ruby/test/testing/mock_context_test.rb +150 -0
- package/dist/scaffold-repo/sdks/ruby/test/types/execution_result_test.rb +129 -0
- package/dist/scaffold-repo/sdks/ruby/test/validation/schema_validator_test.rb +270 -0
- package/dist/scaffold-repo/sdks/rust/Cargo.lock +3044 -0
- package/dist/scaffold-repo/sdks/rust/Cargo.toml +82 -0
- package/dist/scaffold-repo/sdks/rust/Dockerfile +40 -0
- package/dist/scaffold-repo/sdks/rust/README.md +73 -0
- package/dist/scaffold-repo/sdks/rust/build.rs +32 -0
- package/dist/scaffold-repo/sdks/rust/proto/blok/runtime/v1/runtime.proto +302 -0
- package/dist/scaffold-repo/sdks/rust/src/blok_error.rs +1168 -0
- package/dist/scaffold-repo/sdks/rust/src/config.rs +158 -0
- package/dist/scaffold-repo/sdks/rust/src/errors.rs +142 -0
- package/dist/scaffold-repo/sdks/rust/src/grpc_server.rs +635 -0
- package/dist/scaffold-repo/sdks/rust/src/lib.rs +65 -0
- package/dist/scaffold-repo/sdks/rust/src/logging.rs +195 -0
- package/dist/scaffold-repo/sdks/rust/src/main.rs +79 -0
- package/dist/scaffold-repo/sdks/rust/src/middleware.rs +181 -0
- package/dist/scaffold-repo/sdks/rust/src/node.rs +172 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/api_call.rs +93 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/blok_error_demo.rs +151 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/chain_test.rs +57 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/hello_world.rs +83 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/mod.rs +18 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/transform_data.rs +142 -0
- package/dist/scaffold-repo/sdks/rust/src/nodes/typed_greet.rs +56 -0
- package/dist/scaffold-repo/sdks/rust/src/registry.rs +204 -0
- package/dist/scaffold-repo/sdks/rust/src/server.rs +63 -0
- package/dist/scaffold-repo/sdks/rust/src/testing.rs +175 -0
- package/dist/scaffold-repo/sdks/rust/src/types.rs +338 -0
- package/dist/scaffold-repo/sdks/rust/src/user_nodes/mod.rs +10 -0
- package/dist/scaffold-repo/sdks/rust/src/validation.rs +232 -0
- package/dist/scaffold-repo/sdks/rust/src/worker.rs +509 -0
- package/dist/scaffold-repo/sdks/rust/tests/grpc_integration.rs +306 -0
- package/dist/scaffold-repo/sdks/rust/tests/typed_node.rs +104 -0
- package/dist/scaffold-repo/triggers/cron/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/cron/package.json +36 -0
- package/dist/scaffold-repo/triggers/cron/src/CronTrigger.ts +552 -0
- package/dist/scaffold-repo/triggers/cron/src/index.ts +77 -0
- package/dist/scaffold-repo/triggers/cron/tsconfig.json +32 -0
- package/dist/scaffold-repo/triggers/grpc/.env.example +8 -0
- package/dist/scaffold-repo/triggers/grpc/CHANGELOG.md +143 -0
- package/dist/scaffold-repo/triggers/grpc/README.md +25 -0
- package/dist/scaffold-repo/triggers/grpc/buf.gen.yaml +11 -0
- package/dist/scaffold-repo/triggers/grpc/buf.yaml +9 -0
- package/dist/scaffold-repo/triggers/grpc/localhost+2-key.pem +28 -0
- package/dist/scaffold-repo/triggers/grpc/localhost+2.pem +27 -0
- package/dist/scaffold-repo/triggers/grpc/package.json +61 -0
- package/dist/scaffold-repo/triggers/grpc/proto/workflow.proto +33 -0
- package/dist/scaffold-repo/triggers/grpc/src/GRpcTrigger.ts +297 -0
- package/dist/scaffold-repo/triggers/grpc/src/GrpcClient.ts +87 -0
- package/dist/scaffold-repo/triggers/grpc/src/GrpcServer.ts +68 -0
- package/dist/scaffold-repo/triggers/grpc/src/MessageDecode.ts +142 -0
- package/dist/scaffold-repo/triggers/grpc/src/NanoSDK.ts +146 -0
- package/dist/scaffold-repo/triggers/grpc/src/Nodes.ts +10 -0
- package/dist/scaffold-repo/triggers/grpc/src/Workflows.ts +5 -0
- package/dist/scaffold-repo/triggers/grpc/src/gen/workflow_pb.ts +142 -0
- package/dist/scaffold-repo/triggers/grpc/src/index.ts +22 -0
- package/dist/scaffold-repo/triggers/grpc/src/server.ts +8 -0
- package/dist/scaffold-repo/triggers/grpc/src/types/Message.ts +0 -0
- package/dist/scaffold-repo/triggers/grpc/src/types/RuntimeWorkflow.ts +7 -0
- package/dist/scaffold-repo/triggers/grpc/src/types/Workflows.ts +7 -0
- package/dist/scaffold-repo/triggers/grpc/tsconfig.json +34 -0
- package/dist/scaffold-repo/triggers/grpc/vitest.config.ts +29 -0
- package/dist/scaffold-repo/triggers/grpc/workflows/countries.json +27 -0
- package/dist/scaffold-repo/triggers/http/.blok/trace.db +0 -0
- package/dist/scaffold-repo/triggers/http/.blok/trace.db-shm +0 -0
- package/dist/scaffold-repo/triggers/http/.blok/trace.db-wal +0 -0
- package/dist/scaffold-repo/triggers/http/.dockerignore +23 -0
- package/dist/scaffold-repo/triggers/http/.env.example +8 -0
- package/dist/scaffold-repo/triggers/http/CHANGELOG.md +326 -0
- package/dist/scaffold-repo/triggers/http/Dockerfile +49 -0
- package/dist/scaffold-repo/triggers/http/Dockerfile.dev +34 -0
- package/dist/scaffold-repo/triggers/http/infra/docker-compose.yml +38 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Authentication.md +74 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Building.md +52 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Create_Node.md +123 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Create_Workflow.md +177 -0
- package/dist/scaffold-repo/triggers/http/notes/CLI_Commands/Deployment.md +69 -0
- package/dist/scaffold-repo/triggers/http/notes/Core_Concepts/Context.md +156 -0
- package/dist/scaffold-repo/triggers/http/notes/examples.md +104 -0
- package/dist/scaffold-repo/triggers/http/notes/index.md +51 -0
- package/dist/scaffold-repo/triggers/http/package.json +62 -0
- package/dist/scaffold-repo/triggers/http/public/favicon.ico +0 -0
- package/dist/scaffold-repo/triggers/http/public/metric/index.html +2101 -0
- package/dist/scaffold-repo/triggers/http/request.http +7 -0
- package/dist/scaffold-repo/triggers/http/src/AppRoutes.ts +64 -0
- package/dist/scaffold-repo/triggers/http/src/Nodes.ts +38 -0
- package/dist/scaffold-repo/triggers/http/src/Workflows.ts +18 -0
- package/dist/scaffold-repo/triggers/http/src/index.ts +86 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/chain-init/index.ts +48 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/chain-verify/index.ts +123 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/eval/index.ts +69 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/examples/README.md +14 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/examples/chat-ui/index.html +228 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/examples/chat-ui/index.ts +65 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/examples/index.ts +14 -0
- package/dist/scaffold-repo/triggers/http/src/nodes/runtime-bridge/index.ts +84 -0
- package/dist/scaffold-repo/triggers/http/src/runner/HonoTraceRouterAdapter.ts +199 -0
- package/dist/scaffold-repo/triggers/http/src/runner/HttpTrigger.ts +2039 -0
- package/dist/scaffold-repo/triggers/http/src/runner/MessageDecode.ts +57 -0
- package/dist/scaffold-repo/triggers/http/src/runner/Util.ts +52 -0
- package/dist/scaffold-repo/triggers/http/src/runner/WorkflowRouter.ts +411 -0
- package/dist/scaffold-repo/triggers/http/src/runner/metrics/opentelemetry_metrics.ts +84 -0
- package/dist/scaffold-repo/triggers/http/src/runner/metrics/opentelemetry_traces.ts +30 -0
- package/dist/scaffold-repo/triggers/http/src/runner/nodeCatalog.ts +128 -0
- package/dist/scaffold-repo/triggers/http/src/runner/responseEmitter.ts +138 -0
- package/dist/scaffold-repo/triggers/http/src/runner/scanWorkflows.ts +201 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/ErrorResponse.ts +3 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/NodeTypes.ts +13 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/Nodes.ts +5 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/RuntimeWorkflow.ts +7 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/WorkflowRequest.ts +8 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/WorkflowResponse.ts +7 -0
- package/dist/scaffold-repo/triggers/http/src/runner/types/Workflows.ts +14 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/countries-cats-helper.ts +30 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/countries-handle-dsl.ts +25 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/countries-helper.ts +18 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/empty.ts +16 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/eval/eval-retrieve.ts +23 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/eval/eval-run.ts +39 -0
- package/dist/scaffold-repo/triggers/http/src/workflows/eval/foreign-auth.ts +24 -0
- package/dist/scaffold-repo/triggers/http/tsconfig.json +39 -0
- package/dist/scaffold-repo/triggers/http/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-message.json +87 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-page.json +25 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-stream.json +30 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-tool-calculator.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/agent-tool-weather.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-message.json +54 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-page.json +25 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-memory-stream.json +30 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-message.json +25 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-page.json +20 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/chat-stream.json +30 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/countries-py.json +27 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/countries-vs-facts.json +50 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/countries.json +27 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/cross-runtime-chain.json +89 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/dashboard-gen.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/db-manager.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/empty.json +13 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/fanout-enqueue.json +48 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/fanout-worker.json +41 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/feedback.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/films.json +27 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/image-capture.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/launches-by-year.json +27 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/loadtest.json +24 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/admin-only.json +31 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/auth-check.json +59 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/github-webhook-verify.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/jwt-auth.json +46 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/rate-limit.json +70 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/middleware/redis-rate-limit.json +71 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/mongodb.json +24 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/rentals-pdf.json +65 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-admin-delete-user.json +42 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-async-job-poller.json +45 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-csv-import.json +122 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-data-export.json +105 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-event-router.json +97 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-issues.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-pr.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-handler-push.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-github-webhook-router.json +88 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-hello-global-mw.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-hello-with-mw.json +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-jwt-protected.json +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-multi-tenant-router.json +90 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-nested-control-flow.json +207 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-order-fulfillment.json +211 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-parallel-foreach-with-wait.json +47 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-polling-with-backoff.json +55 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-protected.json +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-redis-protected.json +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-saga.json +122 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-acme.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-beta.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-tenant-gamma.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-travel-booking.json +200 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-user-signup-saga.json +186 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v05-webhook-fanout.json +49 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v06-reliability-showcase.json +80 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v07-sse-publish.json +24 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v07-sse-stream.json +26 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/v07-ws-echo.json +38 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-issues.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-pr.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github-push.json +32 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-github.json +87 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear-comment.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear-issue.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-linear.json +74 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe-customer-created.json +22 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe-invoice-paid.json +32 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/webhook-stripe.json +24 -0
- package/dist/scaffold-repo/triggers/http/workflows/json/workflow-docs.json +34 -0
- package/dist/scaffold-repo/triggers/http/workflows/toml/countries.toml +21 -0
- package/dist/scaffold-repo/triggers/http/workflows/xml/countries.xml +23 -0
- package/dist/scaffold-repo/triggers/http/workflows/yaml/countries.yaml +19 -0
- package/dist/scaffold-repo/triggers/mcp/README.md +131 -0
- package/dist/scaffold-repo/triggers/mcp/package.json +39 -0
- package/dist/scaffold-repo/triggers/mcp/src/McpTrigger.ts +581 -0
- package/dist/scaffold-repo/triggers/mcp/src/index.ts +41 -0
- package/dist/scaffold-repo/triggers/mcp/tsconfig.json +32 -0
- package/dist/scaffold-repo/triggers/pubsub/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/pubsub/package.json +66 -0
- package/dist/scaffold-repo/triggers/pubsub/src/PubSubTrigger.ts +424 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/AWSSNSAdapter.ts +352 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/AzureServiceBusAdapter.ts +303 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/GCPPubSubAdapter.ts +327 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/KafkaPubSubAdapter.ts +247 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/KafkaPubSubAdapter.ts.bak +251 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/NATSPubSubAdapter.ts +333 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/RedisStreamsPubSubAdapter.ts +256 -0
- package/dist/scaffold-repo/triggers/pubsub/src/adapters/factory.ts +88 -0
- package/dist/scaffold-repo/triggers/pubsub/src/index.ts +67 -0
- package/dist/scaffold-repo/triggers/pubsub/template/.env.example +8 -0
- package/dist/scaffold-repo/triggers/pubsub/template/package.json +45 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/Nodes.ts +20 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/Workflows.ts +8 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/index.ts +41 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/runner/PubSubServer.ts +39 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/runner/types/Workflows.ts +7 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/workflows/messages/on-message.ts +42 -0
- package/dist/scaffold-repo/triggers/pubsub/template/src/workflows/publish-order.ts +22 -0
- package/dist/scaffold-repo/triggers/pubsub/template/tsconfig.json +31 -0
- package/dist/scaffold-repo/triggers/pubsub/template/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/pubsub/tsconfig.json +32 -0
- package/dist/scaffold-repo/triggers/sse/.env.example +8 -0
- package/dist/scaffold-repo/triggers/sse/CHANGELOG.md +12 -0
- package/dist/scaffold-repo/triggers/sse/Dockerfile +47 -0
- package/dist/scaffold-repo/triggers/sse/Dockerfile.dev +33 -0
- package/dist/scaffold-repo/triggers/sse/package.json +37 -0
- package/dist/scaffold-repo/triggers/sse/src/SSETrigger.ts +489 -0
- package/dist/scaffold-repo/triggers/sse/src/bus.ts +208 -0
- package/dist/scaffold-repo/triggers/sse/src/index.ts +38 -0
- package/dist/scaffold-repo/triggers/sse/src/workflows/events/README.md +129 -0
- package/dist/scaffold-repo/triggers/sse/src/workflows/events/publish-demo.ts +40 -0
- package/dist/scaffold-repo/triggers/sse/src/workflows/events/stream-demo.ts +43 -0
- package/dist/scaffold-repo/triggers/sse/tsconfig.json +22 -0
- package/dist/scaffold-repo/triggers/sse/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/webhook/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/webhook/package.json +36 -0
- package/dist/scaffold-repo/triggers/webhook/src/WebhookTrigger.ts +465 -0
- package/dist/scaffold-repo/triggers/webhook/src/index.ts +51 -0
- package/dist/scaffold-repo/triggers/webhook/src/verifiers.ts +394 -0
- package/dist/scaffold-repo/triggers/webhook/tsconfig.json +32 -0
- package/dist/scaffold-repo/triggers/websocket/.env.example +8 -0
- package/dist/scaffold-repo/triggers/websocket/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/websocket/package.json +50 -0
- package/dist/scaffold-repo/triggers/websocket/src/Backplane.ts +167 -0
- package/dist/scaffold-repo/triggers/websocket/src/WebSocketTrigger.ts +910 -0
- package/dist/scaffold-repo/triggers/websocket/src/index.ts +50 -0
- package/dist/scaffold-repo/triggers/websocket/src/workflows/events/README.md +93 -0
- package/dist/scaffold-repo/triggers/websocket/src/workflows/events/echo-demo.ts +56 -0
- package/dist/scaffold-repo/triggers/websocket/tsconfig.json +22 -0
- package/dist/scaffold-repo/triggers/websocket/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/worker/CHANGELOG.md +22 -0
- package/dist/scaffold-repo/triggers/worker/package.json +68 -0
- package/dist/scaffold-repo/triggers/worker/src/WorkerTrigger.ts +943 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/BullMQAdapter.ts +296 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/InMemoryAdapter.ts +280 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/KafkaAdapter.ts +347 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/NATSAdapter.ts +505 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/PgBossAdapter.ts +319 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/RabbitMQAdapter.ts +318 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/RedisStreamsAdapter.ts +513 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/SQSAdapter.ts +314 -0
- package/dist/scaffold-repo/triggers/worker/src/adapters/factory.ts +111 -0
- package/dist/scaffold-repo/triggers/worker/src/index.ts +95 -0
- package/dist/scaffold-repo/triggers/worker/template/.env.example +18 -0
- package/dist/scaffold-repo/triggers/worker/template/package.json +46 -0
- package/dist/scaffold-repo/triggers/worker/template/src/Nodes.ts +20 -0
- package/dist/scaffold-repo/triggers/worker/template/src/Workflows.ts +8 -0
- package/dist/scaffold-repo/triggers/worker/template/src/index.ts +41 -0
- package/dist/scaffold-repo/triggers/worker/template/src/runner/WorkerServer.ts +34 -0
- package/dist/scaffold-repo/triggers/worker/template/src/runner/types/Workflows.ts +7 -0
- package/dist/scaffold-repo/triggers/worker/template/src/workflows/jobs/process-job.ts +40 -0
- package/dist/scaffold-repo/triggers/worker/template/tsconfig.json +31 -0
- package/dist/scaffold-repo/triggers/worker/template/vitest.config.ts +39 -0
- package/dist/scaffold-repo/triggers/worker/tsconfig.json +32 -0
- package/dist/scaffold-repo/workflows/json/agent-message.json +87 -0
- package/dist/scaffold-repo/workflows/json/agent-page.json +25 -0
- package/dist/scaffold-repo/workflows/json/agent-stream.json +30 -0
- package/dist/scaffold-repo/workflows/json/agent-tool-calculator.json +22 -0
- package/dist/scaffold-repo/workflows/json/agent-tool-weather.json +22 -0
- package/dist/scaffold-repo/workflows/json/chat-memory-message.json +54 -0
- package/dist/scaffold-repo/workflows/json/chat-memory-page.json +25 -0
- package/dist/scaffold-repo/workflows/json/chat-memory-stream.json +30 -0
- package/dist/scaffold-repo/workflows/json/chat-message.json +25 -0
- package/dist/scaffold-repo/workflows/json/chat-page.json +20 -0
- package/dist/scaffold-repo/workflows/json/chat-stream.json +30 -0
- package/dist/scaffold-repo/workflows/json/countries-vs-facts.json +50 -0
- package/dist/scaffold-repo/workflows/json/countries.json +27 -0
- package/dist/scaffold-repo/workflows/json/cron-heartbeat.json +15 -0
- package/dist/scaffold-repo/workflows/json/fanout-enqueue.json +48 -0
- package/dist/scaffold-repo/workflows/json/fanout-worker.json +41 -0
- package/dist/scaffold-repo/workflows/json/pubsub-on-order.json +24 -0
- package/dist/scaffold-repo/workflows/json/webhook-github-issues.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-github-pr.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-github-push.json +32 -0
- package/dist/scaffold-repo/workflows/json/webhook-github.json +87 -0
- package/dist/scaffold-repo/workflows/json/webhook-linear-comment.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-linear-issue.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-linear.json +74 -0
- package/dist/scaffold-repo/workflows/json/webhook-stripe-customer-created.json +22 -0
- package/dist/scaffold-repo/workflows/json/webhook-stripe-invoice-paid.json +32 -0
- package/dist/scaffold-repo/workflows/json/webhook-stripe.json +24 -0
- package/dist/services/runtime-detector.d.ts +2 -0
- package/dist/services/runtime-detector.js +35 -11
- package/dist/services/runtime-setup.d.ts +1 -0
- package/dist/services/runtime-setup.js +17 -7
- package/package.json +4 -4
|
@@ -0,0 +1,943 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkerTrigger - Background job processing for Blok workflows
|
|
3
|
+
*
|
|
4
|
+
* Extends TriggerBase to support long-running background jobs:
|
|
5
|
+
* - Concurrency controls (max N concurrent jobs)
|
|
6
|
+
* - Retry logic with exponential backoff
|
|
7
|
+
* - Job timeouts
|
|
8
|
+
* - Job priority and delay scheduling
|
|
9
|
+
* - Dead letter queue support
|
|
10
|
+
*
|
|
11
|
+
* Pattern:
|
|
12
|
+
* 1. loadNodes() - Load available nodes into NodeMap
|
|
13
|
+
* 2. loadWorkflows() - Load workflows with worker triggers
|
|
14
|
+
* 3. listen() - Connect to job backend and start processing
|
|
15
|
+
* 4. For each job:
|
|
16
|
+
* - Create context with this.createContext()
|
|
17
|
+
* - Populate ctx.request with job data
|
|
18
|
+
* - Execute workflow via this.run(ctx)
|
|
19
|
+
* - Ack on success, retry or DLQ on failure
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { type WorkerTriggerOpts, type WorkflowV2Builder, tryParseDuration } from "@blokjs/helper";
|
|
23
|
+
import {
|
|
24
|
+
type BlokService,
|
|
25
|
+
ConcurrencyLimitError,
|
|
26
|
+
ConcurrencyMetrics,
|
|
27
|
+
Configuration,
|
|
28
|
+
DebounceCoordinator,
|
|
29
|
+
DefaultLogger,
|
|
30
|
+
DeferredDispatchSignal,
|
|
31
|
+
type GlobalOptions,
|
|
32
|
+
Janitor,
|
|
33
|
+
NodeMap,
|
|
34
|
+
QueueExpiredError,
|
|
35
|
+
RunCancelledError,
|
|
36
|
+
RunTracker,
|
|
37
|
+
TriggerBase,
|
|
38
|
+
type TriggerResponse,
|
|
39
|
+
WorkflowRegistry,
|
|
40
|
+
bootstrapTracing,
|
|
41
|
+
} from "@blokjs/runner";
|
|
42
|
+
import type { Context, NodeBase, RequestContext } from "@blokjs/shared";
|
|
43
|
+
import { type Span, SpanStatusCode, metrics, trace } from "@opentelemetry/api";
|
|
44
|
+
import { v4 as uuid } from "uuid";
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* F4 / F24 — thrown by `executeWithTimeout` when a worker job exceeds its
|
|
48
|
+
* trigger-level `config.timeout`. A dedicated type (instead of a plain
|
|
49
|
+
* `Error`) lets `handleJob`'s catch discriminate the timeout: it aborts the
|
|
50
|
+
* detached run via `ctx.signal` and flips the run record to `timedOut`
|
|
51
|
+
* (matching the per-step `maxDuration` taxonomy) rather than routing the
|
|
52
|
+
* timeout through the generic retry/DLQ path.
|
|
53
|
+
*/
|
|
54
|
+
export class WorkerTimeoutError extends Error {
|
|
55
|
+
public readonly timeoutMs: number;
|
|
56
|
+
/** Run id of the aborted run, when known — used to flip status to `timedOut`. */
|
|
57
|
+
public readonly runId?: string;
|
|
58
|
+
|
|
59
|
+
constructor(timeoutMs: number, runId?: string) {
|
|
60
|
+
super(`Job timed out after ${timeoutMs}ms`);
|
|
61
|
+
this.name = "WorkerTimeoutError";
|
|
62
|
+
this.timeoutMs = timeoutMs;
|
|
63
|
+
this.runId = runId;
|
|
64
|
+
Object.setPrototypeOf(this, WorkerTimeoutError.prototype);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Job received from worker queue
|
|
70
|
+
*/
|
|
71
|
+
export interface WorkerJob {
|
|
72
|
+
/** Unique job ID */
|
|
73
|
+
id: string;
|
|
74
|
+
/** Job data payload */
|
|
75
|
+
data: unknown;
|
|
76
|
+
/** Job metadata headers */
|
|
77
|
+
headers: Record<string, string>;
|
|
78
|
+
/** Queue name this job belongs to */
|
|
79
|
+
queue: string;
|
|
80
|
+
/** Job priority (higher = more important) */
|
|
81
|
+
priority: number;
|
|
82
|
+
/** Number of attempts made so far */
|
|
83
|
+
attempts: number;
|
|
84
|
+
/** Maximum retry attempts */
|
|
85
|
+
maxRetries: number;
|
|
86
|
+
/** Timestamp when job was created */
|
|
87
|
+
createdAt: Date;
|
|
88
|
+
/** Delay before processing (ms) */
|
|
89
|
+
delay?: number;
|
|
90
|
+
/** Job timeout (ms) */
|
|
91
|
+
timeout?: number;
|
|
92
|
+
/** Original raw job from provider */
|
|
93
|
+
raw: unknown;
|
|
94
|
+
/** Mark job as completed */
|
|
95
|
+
complete: () => Promise<void>;
|
|
96
|
+
/** Mark job as failed (optionally requeue) */
|
|
97
|
+
fail: (error: Error, requeue?: boolean) => Promise<void>;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Worker adapter interface - implemented by each job backend
|
|
102
|
+
*/
|
|
103
|
+
export interface WorkerAdapter {
|
|
104
|
+
/** Provider name (e.g., "bullmq", "in-memory") */
|
|
105
|
+
readonly provider: string;
|
|
106
|
+
|
|
107
|
+
/** Connect to the job backend */
|
|
108
|
+
connect(): Promise<void>;
|
|
109
|
+
|
|
110
|
+
/** Disconnect from the job backend */
|
|
111
|
+
disconnect(): Promise<void>;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Start processing jobs from a queue
|
|
115
|
+
* @param config Worker trigger configuration
|
|
116
|
+
* @param handler Callback for each job
|
|
117
|
+
*/
|
|
118
|
+
process(config: WorkerTriggerOpts, handler: (job: WorkerJob) => Promise<void>): Promise<void>;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Add a job to a queue (for programmatic dispatching)
|
|
122
|
+
* @param queue Queue name
|
|
123
|
+
* @param data Job payload
|
|
124
|
+
* @param opts Job options
|
|
125
|
+
*/
|
|
126
|
+
addJob(
|
|
127
|
+
queue: string,
|
|
128
|
+
data: unknown,
|
|
129
|
+
opts?: {
|
|
130
|
+
priority?: number;
|
|
131
|
+
delay?: number;
|
|
132
|
+
retries?: number;
|
|
133
|
+
timeout?: number;
|
|
134
|
+
jobId?: string;
|
|
135
|
+
},
|
|
136
|
+
): Promise<string>;
|
|
137
|
+
|
|
138
|
+
/** Stop processing a specific queue */
|
|
139
|
+
stopProcessing(queue: string): Promise<void>;
|
|
140
|
+
|
|
141
|
+
/** Check if connected */
|
|
142
|
+
isConnected(): boolean;
|
|
143
|
+
|
|
144
|
+
/** Health check */
|
|
145
|
+
healthCheck(): Promise<boolean>;
|
|
146
|
+
|
|
147
|
+
/** Get queue stats */
|
|
148
|
+
getQueueStats(queue: string): Promise<WorkerQueueStats>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Queue statistics
|
|
153
|
+
*/
|
|
154
|
+
export interface WorkerQueueStats {
|
|
155
|
+
/** Number of jobs waiting to be processed */
|
|
156
|
+
waiting: number;
|
|
157
|
+
/** Number of jobs currently being processed */
|
|
158
|
+
active: number;
|
|
159
|
+
/** Number of completed jobs */
|
|
160
|
+
completed: number;
|
|
161
|
+
/** Number of failed jobs */
|
|
162
|
+
failed: number;
|
|
163
|
+
/** Number of delayed jobs */
|
|
164
|
+
delayed: number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Workflow model with worker trigger configuration
|
|
169
|
+
*/
|
|
170
|
+
interface WorkerWorkflowModel {
|
|
171
|
+
path: string;
|
|
172
|
+
config: {
|
|
173
|
+
name: string;
|
|
174
|
+
version: string;
|
|
175
|
+
trigger?: {
|
|
176
|
+
worker?: WorkerTriggerOpts;
|
|
177
|
+
[key: string]: unknown;
|
|
178
|
+
};
|
|
179
|
+
[key: string]: unknown;
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* WorkerTrigger - Abstract base class for worker-based triggers
|
|
185
|
+
*
|
|
186
|
+
* Provides background job processing with:
|
|
187
|
+
* - Configurable concurrency per queue
|
|
188
|
+
* - Automatic retries with exponential backoff
|
|
189
|
+
* - Job timeouts with automatic failure
|
|
190
|
+
* - Priority-based job ordering
|
|
191
|
+
* - Delayed job scheduling
|
|
192
|
+
* - Queue statistics and monitoring
|
|
193
|
+
*/
|
|
194
|
+
export abstract class WorkerTrigger extends TriggerBase {
|
|
195
|
+
protected nodeMap: GlobalOptions = {} as GlobalOptions;
|
|
196
|
+
protected readonly tracer = trace.getTracer(
|
|
197
|
+
process.env.PROJECT_NAME || "trigger-worker-workflow",
|
|
198
|
+
process.env.PROJECT_VERSION || "0.0.1",
|
|
199
|
+
);
|
|
200
|
+
protected readonly logger = new DefaultLogger();
|
|
201
|
+
/** OBS-02 T4 — graceful shutdown for the OTel tracer provider, if tracing was enabled. */
|
|
202
|
+
private tracingShutdown: (() => Promise<void>) | null = null;
|
|
203
|
+
/**
|
|
204
|
+
* v0.7 PR 5 — the "default" adapter, used when a workflow's
|
|
205
|
+
* `trigger.worker.provider` field is omitted AND the
|
|
206
|
+
* `BLOK_WORKER_ADAPTER` env var is unset. Subclasses MAY set this
|
|
207
|
+
* for back-compat with the pre-v0.7 single-adapter pattern
|
|
208
|
+
* (`class WorkerServer extends WorkerTrigger { protected adapter = new NATSWorkerAdapter() }`).
|
|
209
|
+
*
|
|
210
|
+
* When unset AND no per-workflow provider is specified, the factory
|
|
211
|
+
* falls back to `in-memory`. The factory pool (`adapters/factory.ts`)
|
|
212
|
+
* tracks one connected adapter per provider so multiple workflows
|
|
213
|
+
* with the same provider share a single broker connection.
|
|
214
|
+
*/
|
|
215
|
+
protected adapter?: WorkerAdapter;
|
|
216
|
+
|
|
217
|
+
/** Active queues being processed */
|
|
218
|
+
protected activeQueues: Set<string> = new Set();
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* v0.7 PR 5 — adapter pool, keyed by provider name. Populated lazily
|
|
222
|
+
* inside `listen()` as workflows are matched to providers. Each
|
|
223
|
+
* adapter is connected once and reused across workflows that share
|
|
224
|
+
* its provider. Drained in `stop()`.
|
|
225
|
+
*/
|
|
226
|
+
protected adapterPool: Map<string, WorkerAdapter> = new Map();
|
|
227
|
+
|
|
228
|
+
// Subclasses provide these
|
|
229
|
+
protected abstract nodes: Record<string, BlokService<unknown>>;
|
|
230
|
+
protected abstract workflows: Record<string, WorkflowV2Builder>;
|
|
231
|
+
|
|
232
|
+
// Constructor removed in v0.6.3 — pre-fix it called `loadNodes()` +
|
|
233
|
+
// `loadWorkflows()`, but subclasses use class-field assignments for
|
|
234
|
+
// `nodes` / `workflows` (the canonical TypeScript pattern). Those
|
|
235
|
+
// fields run AFTER super(), so accessing `this.nodes` from the parent
|
|
236
|
+
// constructor read `undefined` and crashed with
|
|
237
|
+
// `TypeError: undefined is not an object (Object.keys(this.nodes))`.
|
|
238
|
+
// The registry init now happens at the start of `listen()`, after
|
|
239
|
+
// the subclass's fields are initialized.
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Load nodes into the node map
|
|
243
|
+
*/
|
|
244
|
+
loadNodes(): void {
|
|
245
|
+
this.nodeMap.nodes = new NodeMap();
|
|
246
|
+
// Register each node under its own node.name (the canonical use: ref, ADR
|
|
247
|
+
// 0002) — the Nodes.ts map keys are cosmetic; the collision guard catches dups.
|
|
248
|
+
this.nodeMap.nodes.addNodes(Object.values(this.nodes) as unknown as NodeBase[]);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Load workflows into the workflow map
|
|
253
|
+
*/
|
|
254
|
+
loadWorkflows(): void {
|
|
255
|
+
this.nodeMap.workflows = this.workflows;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Start the worker processor - main entry point
|
|
260
|
+
*/
|
|
261
|
+
async listen(): Promise<number> {
|
|
262
|
+
const startTime = this.startCounter();
|
|
263
|
+
|
|
264
|
+
// OBS-02 T4 — opt-in distributed tracing for worker jobs. When
|
|
265
|
+
// OTEL_EXPORTER_OTLP_ENDPOINT is set, install an OTel SDK so the spans
|
|
266
|
+
// the runner creates per job/step export to Tempo/Jaeger/etc. Mirrors
|
|
267
|
+
// HttpTrigger's B1 wiring; no-op + zero overhead when the env var is unset.
|
|
268
|
+
await this.maybeBootstrapTracing();
|
|
269
|
+
|
|
270
|
+
// Populate the trigger's node + workflow registries from the
|
|
271
|
+
// subclass's `nodes` / `workflows` fields. v0.6.3 fix — pre-fix
|
|
272
|
+
// these calls lived in the constructor and crashed because class
|
|
273
|
+
// fields haven't run yet at super-constructor time. See the comment
|
|
274
|
+
// where the old constructor used to live for the full reason.
|
|
275
|
+
this.loadNodes();
|
|
276
|
+
this.loadWorkflows();
|
|
277
|
+
|
|
278
|
+
// F6 (worker part) — feed the WorkflowRegistry from the worker nodeMap.
|
|
279
|
+
// Worker-only deployments never instantiate an HttpTrigger, so without
|
|
280
|
+
// this the registry is empty and any trigger-level / process-global
|
|
281
|
+
// middleware name or `subworkflow:` step fails at runtime. Workflows
|
|
282
|
+
// flagged `middleware: true` are registered with `isMiddleware`.
|
|
283
|
+
this.registerWorkflowsFromNodeMap(this.logger);
|
|
284
|
+
|
|
285
|
+
// F14 (worker part) — seed BLOK_GLOBAL_MIDDLEWARE from env. Only
|
|
286
|
+
// HttpTrigger did this before, so a pure worker process silently
|
|
287
|
+
// dropped the documented env-var configuration.
|
|
288
|
+
this.seedGlobalMiddlewareFromEnv(this.logger);
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
// Tier 2 quick-wins follow-up · install crash handlers + recover
|
|
292
|
+
// orphaned runs from a previous (dead) process. Idempotent + opt-out
|
|
293
|
+
// via `BLOK_CRASH_AUTOFLIP_DISABLED=1`.
|
|
294
|
+
try {
|
|
295
|
+
WorkerTrigger.installCrashHandlers(this.logger);
|
|
296
|
+
const orphaned = WorkerTrigger.recoverOrphanedRuns(undefined, this.logger);
|
|
297
|
+
if (orphaned > 0) {
|
|
298
|
+
this.logger.log(`[crash-autoflip] flipped ${orphaned} orphaned run(s) to crashed on boot`);
|
|
299
|
+
}
|
|
300
|
+
} catch (err) {
|
|
301
|
+
this.logger.error(`[crash-autoflip] setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Tier 2 follow-up · start the periodic storage janitor.
|
|
305
|
+
// Idempotent (singleton); opt-out via `BLOK_JANITOR_DISABLED=1`.
|
|
306
|
+
try {
|
|
307
|
+
Janitor.getInstance(RunTracker.getInstance().getStore(), this.logger).start();
|
|
308
|
+
} catch (err) {
|
|
309
|
+
this.logger.error(`[janitor] setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Tier 2 follow-up · install graceful shutdown handlers
|
|
313
|
+
// (SIGTERM / SIGINT). Idempotent; opt-out via
|
|
314
|
+
// `BLOK_GRACEFUL_SHUTDOWN_DISABLED=1`.
|
|
315
|
+
try {
|
|
316
|
+
WorkerTrigger.installShutdownHandlers(this, this.logger);
|
|
317
|
+
} catch (err) {
|
|
318
|
+
this.logger.error(`[shutdown] setup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Find all workflows with worker triggers
|
|
322
|
+
const workerWorkflows = this.getWorkerWorkflows();
|
|
323
|
+
|
|
324
|
+
if (workerWorkflows.length === 0) {
|
|
325
|
+
this.logger.log("No workflows with worker triggers found");
|
|
326
|
+
return this.endCounter(startTime);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Start processing each queue, dispatching to the right adapter
|
|
330
|
+
// based on the workflow's `provider` field (with back-compat
|
|
331
|
+
// fallback to `this.adapter` when subclasses still set it).
|
|
332
|
+
for (const workflow of workerWorkflows) {
|
|
333
|
+
const config = workflow.config.trigger?.worker as WorkerTriggerOpts;
|
|
334
|
+
const adapter = await this.resolveAdapterForWorkflow(config);
|
|
335
|
+
this.logger.log(
|
|
336
|
+
`Starting worker for queue: ${config.queue} via ${adapter.provider} (concurrency=${config.concurrency}, retries=${config.retries})`,
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
this.activeQueues.add(config.queue);
|
|
340
|
+
|
|
341
|
+
await adapter.process(config, async (job) => {
|
|
342
|
+
await this.handleJob(job, workflow, config);
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
this.logger.log(`Worker trigger started. Processing ${workerWorkflows.length} queue(s)`);
|
|
347
|
+
|
|
348
|
+
// Enable HMR in development mode
|
|
349
|
+
if (process.env.BLOK_HMR === "true" || process.env.NODE_ENV === "development") {
|
|
350
|
+
await this.enableHotReload();
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return this.endCounter(startTime);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
this.logger.error(`Failed to start worker trigger: ${(error as Error).message}`);
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Stop all workers and disconnect
|
|
362
|
+
*/
|
|
363
|
+
/**
|
|
364
|
+
* OBS-02 T4 — install the OpenTelemetry SDK at boot when an OTLP endpoint is
|
|
365
|
+
* configured, so the spans the runner already creates for worker jobs export
|
|
366
|
+
* to a backend (Tempo/Jaeger/…). No-op when `OTEL_EXPORTER_OTLP_ENDPOINT` is
|
|
367
|
+
* unset or `BLOK_TRACING_DISABLED=1`. Stores the shutdown so `stop()` flushes.
|
|
368
|
+
*/
|
|
369
|
+
private async maybeBootstrapTracing(): Promise<void> {
|
|
370
|
+
if (process.env.BLOK_TRACING_DISABLED === "1") return;
|
|
371
|
+
const base = process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
372
|
+
if (!base) return;
|
|
373
|
+
const endpoint = process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ? base : `${base.replace(/\/$/, "")}/v1/traces`;
|
|
374
|
+
try {
|
|
375
|
+
const result = await bootstrapTracing({
|
|
376
|
+
serviceName: process.env.APP_NAME || process.env.PROJECT_NAME || "blok-worker",
|
|
377
|
+
serviceVersion: process.env.PROJECT_VERSION,
|
|
378
|
+
exporter: "otlp",
|
|
379
|
+
endpoint,
|
|
380
|
+
});
|
|
381
|
+
if (result) {
|
|
382
|
+
this.tracingShutdown = result.shutdown;
|
|
383
|
+
this.logger.log(`[blok][tracing] OTLP distributed tracing enabled → ${endpoint}`);
|
|
384
|
+
} else {
|
|
385
|
+
this.logger.error(
|
|
386
|
+
"[blok][tracing] OTEL_EXPORTER_OTLP_ENDPOINT is set but the OTel trace SDK isn't installed — tracing is OFF.",
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
} catch (err) {
|
|
390
|
+
this.logger.error(`[blok][tracing] failed to initialize: ${(err as Error).message}`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
async stop(): Promise<void> {
|
|
395
|
+
// OBS-02 T4 — flush pending spans before draining so the last jobs'
|
|
396
|
+
// spans aren't lost on shutdown.
|
|
397
|
+
if (this.tracingShutdown) {
|
|
398
|
+
await this.tracingShutdown().catch((err) =>
|
|
399
|
+
this.logger.error(`[blok][tracing] shutdown failed: ${(err as Error).message}`),
|
|
400
|
+
);
|
|
401
|
+
this.tracingShutdown = null;
|
|
402
|
+
}
|
|
403
|
+
// Stop each queue on its owning adapter — adapters are tracked
|
|
404
|
+
// in the pool so multi-provider workers all drain cleanly.
|
|
405
|
+
for (const queue of this.activeQueues) {
|
|
406
|
+
for (const adapter of this.adapterPool.values()) {
|
|
407
|
+
try {
|
|
408
|
+
await adapter.stopProcessing(queue);
|
|
409
|
+
} catch {
|
|
410
|
+
/* swallow — adapter may not own this queue */
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
this.logger.log(`Stopped processing queue: ${queue}`);
|
|
414
|
+
}
|
|
415
|
+
this.activeQueues.clear();
|
|
416
|
+
// Disconnect every adapter we ever connected.
|
|
417
|
+
for (const adapter of this.adapterPool.values()) {
|
|
418
|
+
try {
|
|
419
|
+
await adapter.disconnect();
|
|
420
|
+
} catch (err) {
|
|
421
|
+
this.logger.error(`[blok][worker] disconnect failed: ${(err as Error).message}`);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
this.adapterPool.clear();
|
|
425
|
+
this.destroyMonitoring();
|
|
426
|
+
this.logger.log("Worker trigger stopped");
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
protected override async onHmrWorkflowChange(): Promise<void> {
|
|
430
|
+
this.logger.log("[HMR] Worker workflow changed, reloading...");
|
|
431
|
+
await this.waitForInFlightRequests();
|
|
432
|
+
await this.stop();
|
|
433
|
+
this.loadWorkflows();
|
|
434
|
+
await this.listen();
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Dispatch a job to a worker queue
|
|
439
|
+
*/
|
|
440
|
+
async dispatch(
|
|
441
|
+
queue: string,
|
|
442
|
+
data: unknown,
|
|
443
|
+
opts?: {
|
|
444
|
+
priority?: number;
|
|
445
|
+
delay?: number;
|
|
446
|
+
retries?: number;
|
|
447
|
+
timeout?: number;
|
|
448
|
+
jobId?: string;
|
|
449
|
+
},
|
|
450
|
+
): Promise<string> {
|
|
451
|
+
// Back-compat: when a subclass set `this.adapter`, use it.
|
|
452
|
+
// Otherwise dispatch via the first pool adapter — typically the
|
|
453
|
+
// only one when a process owns one trigger workflow.
|
|
454
|
+
const adapter =
|
|
455
|
+
this.adapter ??
|
|
456
|
+
(this.adapterPool.size > 0 ? (this.adapterPool.values().next().value as WorkerAdapter) : undefined);
|
|
457
|
+
if (!adapter) {
|
|
458
|
+
throw new Error(
|
|
459
|
+
"[blok][worker] dispatch() called before any adapter is connected. Call listen() first, or set this.adapter on the subclass.",
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
return adapter.addJob(queue, data, opts);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Get statistics for a queue
|
|
467
|
+
*/
|
|
468
|
+
async getQueueStats(queue: string): Promise<WorkerQueueStats> {
|
|
469
|
+
const adapter =
|
|
470
|
+
this.adapter ??
|
|
471
|
+
(this.adapterPool.size > 0 ? (this.adapterPool.values().next().value as WorkerAdapter) : undefined);
|
|
472
|
+
if (!adapter) {
|
|
473
|
+
throw new Error(
|
|
474
|
+
"[blok][worker] getQueueStats() called before any adapter is connected. Call listen() first, or set this.adapter on the subclass.",
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
return adapter.getQueueStats(queue);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Get list of active queues
|
|
482
|
+
*/
|
|
483
|
+
getActiveQueues(): string[] {
|
|
484
|
+
return Array.from(this.activeQueues);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* v0.7 PR 5 — pick the adapter for a workflow's `provider` field.
|
|
489
|
+
*
|
|
490
|
+
* Resolution order:
|
|
491
|
+
* 1. Subclass-set `this.adapter` (back-compat: pre-v0.7 pattern
|
|
492
|
+
* where one process binds to one adapter at construction time).
|
|
493
|
+
* 2. Per-workflow `provider` field, looked up via the factory.
|
|
494
|
+
* 3. `BLOK_WORKER_ADAPTER` env var.
|
|
495
|
+
* 4. `in-memory` fallback.
|
|
496
|
+
*
|
|
497
|
+
* Adapters are connected on first use and pooled per provider so
|
|
498
|
+
* multiple workflows sharing a provider share one broker
|
|
499
|
+
* connection. Health-dependency registration also happens here so
|
|
500
|
+
* each provider is tracked individually in `/health`.
|
|
501
|
+
*/
|
|
502
|
+
protected async resolveAdapterForWorkflow(config: WorkerTriggerOpts): Promise<WorkerAdapter> {
|
|
503
|
+
// Subclass override wins for back-compat.
|
|
504
|
+
if (this.adapter) {
|
|
505
|
+
if (!this.adapter.isConnected()) {
|
|
506
|
+
await this.adapter.connect();
|
|
507
|
+
this.logger.log(`Connected to ${this.adapter.provider} worker system (subclass adapter)`);
|
|
508
|
+
this.registerAdapterHealth(this.adapter);
|
|
509
|
+
}
|
|
510
|
+
// Pool-track so stop() can drain it.
|
|
511
|
+
this.adapterPool.set(this.adapter.provider, this.adapter);
|
|
512
|
+
return this.adapter;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Lazy-import the factory so the worker package doesn't pull in
|
|
516
|
+
// every adapter on import — only the ones actually exercised.
|
|
517
|
+
const { resolveProvider, createWorkerAdapter } = await import("./adapters/factory");
|
|
518
|
+
const provider = resolveProvider(config.provider);
|
|
519
|
+
let adapter = this.adapterPool.get(provider);
|
|
520
|
+
if (!adapter) {
|
|
521
|
+
adapter = createWorkerAdapter(provider);
|
|
522
|
+
await adapter.connect();
|
|
523
|
+
this.logger.log(`Connected to ${adapter.provider} worker system`);
|
|
524
|
+
this.registerAdapterHealth(adapter);
|
|
525
|
+
this.adapterPool.set(provider, adapter);
|
|
526
|
+
}
|
|
527
|
+
return adapter;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
private registerAdapterHealth(adapter: WorkerAdapter): void {
|
|
531
|
+
this.registerHealthDependency(`worker-${adapter.provider}`, async () => {
|
|
532
|
+
const healthy = await adapter.healthCheck();
|
|
533
|
+
return {
|
|
534
|
+
status: healthy ? ("healthy" as const) : ("unhealthy" as const),
|
|
535
|
+
lastChecked: Date.now(),
|
|
536
|
+
message: healthy ? "Connected" : "Connection lost",
|
|
537
|
+
};
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Get all workflows that have worker triggers
|
|
543
|
+
*/
|
|
544
|
+
protected getWorkerWorkflows(): WorkerWorkflowModel[] {
|
|
545
|
+
const workflows: WorkerWorkflowModel[] = [];
|
|
546
|
+
|
|
547
|
+
for (const [path, workflow] of Object.entries(this.nodeMap.workflows || {})) {
|
|
548
|
+
const workflowConfig = (workflow as unknown as { _config: WorkerWorkflowModel["config"] })._config;
|
|
549
|
+
|
|
550
|
+
// F11 — discover the worker trigger by direct key access, NOT by
|
|
551
|
+
// inspecting only the FIRST key. A multi-trigger workflow such as
|
|
552
|
+
// `trigger: { http: {...}, worker: { queue: "jobs" } }` declares
|
|
553
|
+
// `worker` second; the old `Object.keys(trigger)[0] === "worker"`
|
|
554
|
+
// check silently dropped it, making discovery depend on JS object
|
|
555
|
+
// key insertion order. Every sibling trigger (HTTP/SSE/Webhook)
|
|
556
|
+
// already reads its key directly.
|
|
557
|
+
if (workflowConfig?.trigger?.worker) {
|
|
558
|
+
workflows.push({
|
|
559
|
+
path,
|
|
560
|
+
config: workflowConfig,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return workflows;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Handle an incoming job
|
|
570
|
+
*/
|
|
571
|
+
protected async handleJob(job: WorkerJob, workflow: WorkerWorkflowModel, config: WorkerTriggerOpts): Promise<void> {
|
|
572
|
+
const jobId = job.id || uuid();
|
|
573
|
+
const defaultMeter = metrics.getMeter("default");
|
|
574
|
+
const workerJobs = defaultMeter.createCounter("worker_jobs_processed", {
|
|
575
|
+
description: "Worker jobs processed",
|
|
576
|
+
});
|
|
577
|
+
const workerErrors = defaultMeter.createCounter("worker_jobs_failed", {
|
|
578
|
+
description: "Worker job failures",
|
|
579
|
+
});
|
|
580
|
+
const workerRetries = defaultMeter.createCounter("worker_jobs_retried", {
|
|
581
|
+
description: "Worker job retries",
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
await this.tracer.startActiveSpan(`worker:${config.queue}`, async (span: Span) => {
|
|
585
|
+
// F2 — give each job its OWN Configuration so concurrent jobs
|
|
586
|
+
// (`concurrency > 1`, or two queues in one process) never read a
|
|
587
|
+
// step list / name / trigger config another job's `init()`
|
|
588
|
+
// overwrote. Declared outside the try so the catch can flip the
|
|
589
|
+
// run's status via the per-job config name.
|
|
590
|
+
const configuration = new Configuration();
|
|
591
|
+
// F4 — captured from createContext so the timeout path can abort
|
|
592
|
+
// the detached run cooperatively.
|
|
593
|
+
let runCtx: Context | undefined;
|
|
594
|
+
try {
|
|
595
|
+
const start = performance.now();
|
|
596
|
+
|
|
597
|
+
// Bug 03 — resolve the already-loaded workflow object from the
|
|
598
|
+
// in-memory nodeMap and pass it as the `preloaded` arg (mirrors
|
|
599
|
+
// HTTP). This routes init through the preloaded branch and skips
|
|
600
|
+
// the disk-based `LocalStorage` resolver whose dot heuristic
|
|
601
|
+
// rejected dotted `domain.action` workflow names ("File type not
|
|
602
|
+
// supported"). Fallback to `workflow.config` so `preloaded` is
|
|
603
|
+
// never undefined (which would re-trigger the disk branch).
|
|
604
|
+
const preloaded =
|
|
605
|
+
(this.nodeMap.workflows && (this.nodeMap.workflows as Record<string, unknown>)[workflow.path]) ??
|
|
606
|
+
workflow.config;
|
|
607
|
+
|
|
608
|
+
// F2 — initialize the per-job Configuration instead of the shared
|
|
609
|
+
// `this.configuration`.
|
|
610
|
+
await configuration.init(workflow.path, this.nodeMap, preloaded);
|
|
611
|
+
|
|
612
|
+
// Create context — bind it to the per-job Configuration (F2).
|
|
613
|
+
const ctx: Context = this.createContext(undefined, workflow.path, jobId, configuration);
|
|
614
|
+
runCtx = ctx;
|
|
615
|
+
|
|
616
|
+
// Populate request with job data
|
|
617
|
+
ctx.request = {
|
|
618
|
+
body: job.data,
|
|
619
|
+
headers: job.headers,
|
|
620
|
+
query: {},
|
|
621
|
+
params: {
|
|
622
|
+
queue: job.queue,
|
|
623
|
+
jobId: job.id,
|
|
624
|
+
attempt: String(job.attempts),
|
|
625
|
+
priority: String(job.priority),
|
|
626
|
+
},
|
|
627
|
+
} as unknown as RequestContext;
|
|
628
|
+
|
|
629
|
+
// Store worker metadata in context
|
|
630
|
+
if (!ctx.vars) ctx.vars = {};
|
|
631
|
+
ctx.vars._worker_job = {
|
|
632
|
+
id: job.id,
|
|
633
|
+
queue: job.queue,
|
|
634
|
+
attempts: String(job.attempts),
|
|
635
|
+
maxRetries: String(job.maxRetries),
|
|
636
|
+
priority: String(job.priority),
|
|
637
|
+
createdAt: job.createdAt.toISOString(),
|
|
638
|
+
delay: String(job.delay ?? 0),
|
|
639
|
+
timeout: String(job.timeout ?? 0),
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
ctx.logger.log(
|
|
643
|
+
`Processing job ${jobId} from ${config.queue} (attempt ${job.attempts + 1}/${job.maxRetries + 1})`,
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
// v0.6 · apply the merged middleware chain (process-global →
|
|
647
|
+
// workflow-level → trigger-level) on the same ctx the main
|
|
648
|
+
// workflow will see. State mutations from middleware
|
|
649
|
+
// (e.g. ctx.state.identity) carry forward. Middleware that
|
|
650
|
+
// throws (via `@blokjs/throw`) propagates to the outer
|
|
651
|
+
// catch and is routed through the worker's retry / DLQ
|
|
652
|
+
// logic exactly like a main-workflow error.
|
|
653
|
+
//
|
|
654
|
+
// F2 — pass the per-job `configuration` so trigger-level
|
|
655
|
+
// (`trigger.worker.middleware`) and workflow-level middleware
|
|
656
|
+
// are read from the object THIS job initialized. Without it the
|
|
657
|
+
// chain would read the never-initialized shared `this.configuration`
|
|
658
|
+
// (the worker no longer calls `this.configuration.init`) and
|
|
659
|
+
// silently drop everything but the process-global chain.
|
|
660
|
+
await this.applyMiddlewareChain(ctx, this.nodeMap, configuration);
|
|
661
|
+
|
|
662
|
+
// Execute workflow with timeout if configured.
|
|
663
|
+
// F2 — pass the per-job `configuration` into `run` so the runner
|
|
664
|
+
// reads the same object this job initialized.
|
|
665
|
+
let response: TriggerResponse;
|
|
666
|
+
if (config.timeout && config.timeout > 0) {
|
|
667
|
+
response = await this.executeWithTimeout(ctx, config.timeout, configuration);
|
|
668
|
+
} else {
|
|
669
|
+
response = await this.run(ctx, configuration);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const end = performance.now();
|
|
673
|
+
|
|
674
|
+
// Set span attributes
|
|
675
|
+
span.setAttribute("success", true);
|
|
676
|
+
span.setAttribute("job_id", jobId);
|
|
677
|
+
span.setAttribute("queue", config.queue);
|
|
678
|
+
span.setAttribute("attempts", job.attempts);
|
|
679
|
+
span.setAttribute("elapsed_ms", end - start);
|
|
680
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
681
|
+
|
|
682
|
+
// Record metrics
|
|
683
|
+
workerJobs.add(1, {
|
|
684
|
+
env: process.env.NODE_ENV,
|
|
685
|
+
queue: config.queue,
|
|
686
|
+
workflow_name: configuration.name,
|
|
687
|
+
success: "true",
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
ctx.logger.log(`Job completed in ${(end - start).toFixed(2)}ms: ${jobId}`);
|
|
691
|
+
|
|
692
|
+
// Mark job as completed
|
|
693
|
+
await job.complete();
|
|
694
|
+
} catch (error) {
|
|
695
|
+
const errorMessage = (error as Error).message;
|
|
696
|
+
|
|
697
|
+
// Tier 2 #5 + #7 — deferred dispatch (delay/TTL/debounce).
|
|
698
|
+
// The run was deferred to a future timer; ACK without retry.
|
|
699
|
+
// The in-process scheduler owns the eventual dispatch, NOT
|
|
700
|
+
// the broker — re-queueing here would create a duplicate.
|
|
701
|
+
if (error instanceof DeferredDispatchSignal) {
|
|
702
|
+
span.setAttribute("success", false);
|
|
703
|
+
span.setAttribute("deferred", true);
|
|
704
|
+
span.setAttribute("deferred_status", error.info.status);
|
|
705
|
+
span.setStatus({ code: SpanStatusCode.OK, message: `deferred:${error.info.status}` });
|
|
706
|
+
|
|
707
|
+
this.logger.log(
|
|
708
|
+
`[scheduling] job ${jobId} runId=${error.info.runId} status=${error.info.status} ` +
|
|
709
|
+
`scheduledAt=${error.info.scheduledAt} pingCount=${error.info.pingCount} → ACK (no requeue)`,
|
|
710
|
+
);
|
|
711
|
+
|
|
712
|
+
await job.complete();
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// PR 1-5 polish — queue-mode TTL elapsed. The run is already
|
|
717
|
+
// flipped to `expired` (see TriggerBase queue branch); ACK
|
|
718
|
+
// without retry so the broker doesn't redeliver — the run
|
|
719
|
+
// will never succeed (timer won't re-fire). Distinct from
|
|
720
|
+
// the throttled NACK below.
|
|
721
|
+
if (error instanceof QueueExpiredError) {
|
|
722
|
+
span.setAttribute("success", false);
|
|
723
|
+
span.setAttribute("queue_expired", true);
|
|
724
|
+
span.setStatus({ code: SpanStatusCode.OK, message: "queue_expired" });
|
|
725
|
+
|
|
726
|
+
this.logger.log(
|
|
727
|
+
`[concurrency] job ${jobId} runId=${error.info.runId} key='${error.info.concurrencyKey}' ` +
|
|
728
|
+
`queueExpiredAt=${error.info.queueExpiredAt} → ACK (no requeue, run expired)`,
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
await job.complete();
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// Tier 2 #6 — concurrency gate denial. Distinct from a normal
|
|
736
|
+
// failure: NACK with redelivery so the broker re-queues the
|
|
737
|
+
// job with its existing back-off semantics. Doesn't count
|
|
738
|
+
// against the workflow's retry budget (different invariant).
|
|
739
|
+
// We always pass `willRetry: true` regardless of `job.attempts`
|
|
740
|
+
// because throttling is a transient resource state, not a
|
|
741
|
+
// permanent failure.
|
|
742
|
+
if (error instanceof ConcurrencyLimitError) {
|
|
743
|
+
span.setAttribute("success", false);
|
|
744
|
+
span.setAttribute("will_retry", true);
|
|
745
|
+
span.setAttribute("throttled", true);
|
|
746
|
+
span.setStatus({ code: SpanStatusCode.OK, message: "concurrency_limit_reached" });
|
|
747
|
+
|
|
748
|
+
this.logger.log(
|
|
749
|
+
`[concurrency] job ${jobId} key='${error.info.concurrencyKey}' ` +
|
|
750
|
+
`limit=${error.info.concurrencyLimit} inFlight=${error.info.currentInFlight} → NACK + redelivery`,
|
|
751
|
+
);
|
|
752
|
+
|
|
753
|
+
workerRetries.add(1, {
|
|
754
|
+
env: process.env.NODE_ENV,
|
|
755
|
+
queue: config.queue,
|
|
756
|
+
workflow_name: configuration?.name || "unknown",
|
|
757
|
+
reason: "throttled",
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
await job.fail(error as Error, true);
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// F3 — the run was cancelled by an operator
|
|
765
|
+
// (`POST /__blok/runs/:runId/cancel`). `RunnerSteps` throws
|
|
766
|
+
// `RunCancelledError`, which `TriggerBase.run` re-throws
|
|
767
|
+
// untouched (status already flipped to `cancelled`). The run is
|
|
768
|
+
// terminal — ACK the broker WITHOUT requeue so the
|
|
769
|
+
// deliberately-cancelled, often non-idempotent work doesn't run
|
|
770
|
+
// again on redelivery.
|
|
771
|
+
if (error instanceof RunCancelledError) {
|
|
772
|
+
span.setAttribute("success", false);
|
|
773
|
+
span.setAttribute("cancelled", true);
|
|
774
|
+
span.setStatus({ code: SpanStatusCode.OK, message: "run_cancelled" });
|
|
775
|
+
|
|
776
|
+
this.logger.log(`Job ${jobId} cancelled (run already terminal) → ACK (no requeue)`);
|
|
777
|
+
|
|
778
|
+
await job.complete();
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// F4 / F24 — trigger-level `config.timeout` elapsed. The detached
|
|
783
|
+
// run was already aborted via `ctx.signal` inside
|
|
784
|
+
// `executeWithTimeout`, so it unwinds with `RunCancelledError`
|
|
785
|
+
// at the next between-step check. Flip the run record to the
|
|
786
|
+
// dedicated `timedOut` status (matching the per-step
|
|
787
|
+
// `maxDuration` taxonomy) instead of routing through the generic
|
|
788
|
+
// retry/DLQ path, and ACK without requeue.
|
|
789
|
+
if (error instanceof WorkerTimeoutError) {
|
|
790
|
+
span.setAttribute("success", false);
|
|
791
|
+
span.setAttribute("timed_out", true);
|
|
792
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: "job_timed_out" });
|
|
793
|
+
|
|
794
|
+
const timedOutRunId = error.runId ?? (runCtx as { _traceRunId?: string } | undefined)?._traceRunId;
|
|
795
|
+
if (timedOutRunId) {
|
|
796
|
+
try {
|
|
797
|
+
RunTracker.getInstance().markRunTimedOut(timedOutRunId, {
|
|
798
|
+
stepId: "__worker_timeout__",
|
|
799
|
+
maxDurationMs: error.timeoutMs,
|
|
800
|
+
attemptsExhausted: job.attempts + 1,
|
|
801
|
+
});
|
|
802
|
+
} catch (markErr) {
|
|
803
|
+
this.logger.error(
|
|
804
|
+
`[blok][worker] markRunTimedOut failed for run ${timedOutRunId}: ${markErr instanceof Error ? markErr.message : String(markErr)}`,
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
workerErrors.add(1, {
|
|
810
|
+
env: process.env.NODE_ENV,
|
|
811
|
+
queue: config.queue,
|
|
812
|
+
workflow_name: configuration?.name || "unknown",
|
|
813
|
+
reason: "timeout",
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
this.logger.error(
|
|
817
|
+
`Job ${jobId} timed out after ${error.timeoutMs}ms → run flipped to timedOut, ACK (no requeue)`,
|
|
818
|
+
);
|
|
819
|
+
|
|
820
|
+
await job.complete();
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
const shouldRetry = job.attempts < job.maxRetries;
|
|
825
|
+
|
|
826
|
+
// Set span error
|
|
827
|
+
span.setAttribute("success", false);
|
|
828
|
+
span.setAttribute("will_retry", shouldRetry);
|
|
829
|
+
span.recordException(error as Error);
|
|
830
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: errorMessage });
|
|
831
|
+
|
|
832
|
+
if (shouldRetry) {
|
|
833
|
+
// Retry with exponential backoff. `config.delay` widened to
|
|
834
|
+
// `string | number | undefined` in Tier 2 #5 (duration strings).
|
|
835
|
+
// `calculateBackoff` only handles numbers; normalize via
|
|
836
|
+
// tryParseDuration. Fail-open to undefined → default backoff.
|
|
837
|
+
const delayMs =
|
|
838
|
+
typeof config.delay === "number"
|
|
839
|
+
? config.delay
|
|
840
|
+
: typeof config.delay === "string"
|
|
841
|
+
? (tryParseDuration(config.delay) ?? undefined)
|
|
842
|
+
: undefined;
|
|
843
|
+
const backoffMs = this.calculateBackoff(job.attempts, delayMs);
|
|
844
|
+
workerRetries.add(1, {
|
|
845
|
+
env: process.env.NODE_ENV,
|
|
846
|
+
queue: config.queue,
|
|
847
|
+
workflow_name: configuration?.name || "unknown",
|
|
848
|
+
attempt: String(job.attempts + 1),
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
this.logger.error(
|
|
852
|
+
`Job ${jobId} failed (attempt ${job.attempts + 1}/${job.maxRetries + 1}), retrying in ${backoffMs}ms: ${errorMessage}`,
|
|
853
|
+
);
|
|
854
|
+
|
|
855
|
+
await job.fail(error as Error, true);
|
|
856
|
+
} else {
|
|
857
|
+
// Max retries exhausted - send to DLQ
|
|
858
|
+
workerErrors.add(1, {
|
|
859
|
+
env: process.env.NODE_ENV,
|
|
860
|
+
queue: config.queue,
|
|
861
|
+
workflow_name: configuration?.name || "unknown",
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
this.logger.error(
|
|
865
|
+
`Job ${jobId} permanently failed after ${job.attempts + 1} attempts: ${errorMessage}`,
|
|
866
|
+
(error as Error).stack,
|
|
867
|
+
);
|
|
868
|
+
|
|
869
|
+
await job.fail(error as Error, false);
|
|
870
|
+
}
|
|
871
|
+
} finally {
|
|
872
|
+
span.end();
|
|
873
|
+
}
|
|
874
|
+
});
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Execute workflow with a timeout.
|
|
879
|
+
*
|
|
880
|
+
* F4 — on timeout, fire the ctx AbortController so the detached `run`
|
|
881
|
+
* unwinds cooperatively (it throws `RunCancelledError` at the next
|
|
882
|
+
* between-step check; long uninterruptible nodes should still poll
|
|
883
|
+
* `ctx.signal.aborted`). The promise rejects with a dedicated
|
|
884
|
+
* {@link WorkerTimeoutError} carrying the run id so `handleJob`'s catch can
|
|
885
|
+
* flip the run record to `timedOut` (F24). The second `run` (broker
|
|
886
|
+
* redelivery) is prevented because we ACK without requeue on timeout.
|
|
887
|
+
*
|
|
888
|
+
* F2 — `configuration` is the per-job Configuration; threaded into `run`.
|
|
889
|
+
*/
|
|
890
|
+
protected async executeWithTimeout(
|
|
891
|
+
ctx: Context,
|
|
892
|
+
timeoutMs: number,
|
|
893
|
+
configuration?: Configuration,
|
|
894
|
+
): Promise<TriggerResponse> {
|
|
895
|
+
return new Promise<TriggerResponse>((resolve, reject) => {
|
|
896
|
+
let settled = false;
|
|
897
|
+
const timer = setTimeout(() => {
|
|
898
|
+
if (settled) return;
|
|
899
|
+
settled = true;
|
|
900
|
+
|
|
901
|
+
// F4 — abort the detached run so it stops executing rather than
|
|
902
|
+
// continuing to settle its own run record out of band.
|
|
903
|
+
const privateSlot = ctx._PRIVATE_ as { abortController?: AbortController } | null;
|
|
904
|
+
try {
|
|
905
|
+
privateSlot?.abortController?.abort();
|
|
906
|
+
} catch {
|
|
907
|
+
/* best-effort — abort never throws, but guard anyway */
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
const runId = (ctx as { _traceRunId?: string })._traceRunId;
|
|
911
|
+
reject(new WorkerTimeoutError(timeoutMs, runId));
|
|
912
|
+
}, timeoutMs);
|
|
913
|
+
|
|
914
|
+
this.run(ctx, configuration)
|
|
915
|
+
.then((result) => {
|
|
916
|
+
clearTimeout(timer);
|
|
917
|
+
if (settled) return; // already timed out — ignore the late result
|
|
918
|
+
settled = true;
|
|
919
|
+
resolve(result);
|
|
920
|
+
})
|
|
921
|
+
.catch((error) => {
|
|
922
|
+
clearTimeout(timer);
|
|
923
|
+
if (settled) return; // already rejected with WorkerTimeoutError
|
|
924
|
+
settled = true;
|
|
925
|
+
reject(error);
|
|
926
|
+
});
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Calculate exponential backoff delay
|
|
932
|
+
* Formula: min(baseDelay * 2^attempt, 30000) + jitter
|
|
933
|
+
*/
|
|
934
|
+
protected calculateBackoff(attempt: number, baseDelay?: number): number {
|
|
935
|
+
const base = baseDelay ?? 1000;
|
|
936
|
+
const maxDelay = 30000; // 30 seconds max
|
|
937
|
+
const exponential = Math.min(base * 2 ** attempt, maxDelay);
|
|
938
|
+
const jitter = Math.random() * exponential * 0.1; // 10% jitter
|
|
939
|
+
return Math.floor(exponential + jitter);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
export default WorkerTrigger;
|