@blokjs/runner 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/dist/Blok.d.ts +19 -0
  2. package/dist/Blok.js +184 -0
  3. package/dist/Blok.js.map +1 -0
  4. package/dist/BlokResponse.d.ts +16 -0
  5. package/dist/BlokResponse.js +28 -0
  6. package/dist/BlokResponse.js.map +1 -0
  7. package/dist/Configuration.d.ts +37 -0
  8. package/dist/Configuration.js +248 -0
  9. package/dist/Configuration.js.map +1 -0
  10. package/dist/ConfigurationResolver.d.ts +7 -0
  11. package/dist/ConfigurationResolver.js +15 -0
  12. package/dist/ConfigurationResolver.js.map +1 -0
  13. package/dist/DefaultLogger.d.ts +65 -0
  14. package/dist/DefaultLogger.js +101 -0
  15. package/dist/DefaultLogger.js.map +1 -0
  16. package/dist/LocalStorage.d.ts +7 -0
  17. package/dist/LocalStorage.js +56 -0
  18. package/dist/LocalStorage.js.map +1 -0
  19. package/dist/MemoryUsage.d.ts +22 -0
  20. package/dist/MemoryUsage.js +83 -0
  21. package/dist/MemoryUsage.js.map +1 -0
  22. package/dist/NodeMap.d.ts +7 -0
  23. package/dist/NodeMap.js +13 -0
  24. package/dist/NodeMap.js.map +1 -0
  25. package/dist/ResolverBase.d.ts +8 -0
  26. package/dist/ResolverBase.js +18 -0
  27. package/dist/ResolverBase.js.map +1 -0
  28. package/dist/Runner.d.ts +25 -0
  29. package/dist/Runner.js +32 -0
  30. package/dist/Runner.js.map +1 -0
  31. package/dist/RunnerNode.d.ts +9 -0
  32. package/dist/RunnerNode.js +8 -0
  33. package/dist/RunnerNode.js.map +1 -0
  34. package/dist/RunnerNodeBase.d.ts +4 -0
  35. package/dist/RunnerNodeBase.js +3 -0
  36. package/dist/RunnerNodeBase.js.map +1 -0
  37. package/dist/RunnerSteps.d.ts +14 -0
  38. package/dist/RunnerSteps.js +110 -0
  39. package/dist/RunnerSteps.js.map +1 -0
  40. package/dist/RuntimeAdapterNode.d.ts +19 -0
  41. package/dist/RuntimeAdapterNode.js +87 -0
  42. package/dist/RuntimeAdapterNode.js.map +1 -0
  43. package/dist/RuntimeRegistry.d.ts +61 -0
  44. package/dist/RuntimeRegistry.js +87 -0
  45. package/dist/RuntimeRegistry.js.map +1 -0
  46. package/dist/TriggerBase.d.ts +119 -0
  47. package/dist/TriggerBase.js +413 -0
  48. package/dist/TriggerBase.js.map +1 -0
  49. package/dist/adapters/BunRuntimeAdapter.d.ts +38 -0
  50. package/dist/adapters/BunRuntimeAdapter.js +169 -0
  51. package/dist/adapters/BunRuntimeAdapter.js.map +1 -0
  52. package/dist/adapters/DockerRuntimeAdapter.d.ts +85 -0
  53. package/dist/adapters/DockerRuntimeAdapter.js +298 -0
  54. package/dist/adapters/DockerRuntimeAdapter.js.map +1 -0
  55. package/dist/adapters/HttpRuntimeAdapter.d.ts +58 -0
  56. package/dist/adapters/HttpRuntimeAdapter.js +152 -0
  57. package/dist/adapters/HttpRuntimeAdapter.js.map +1 -0
  58. package/dist/adapters/NodeJsRuntimeAdapter.d.ts +23 -0
  59. package/dist/adapters/NodeJsRuntimeAdapter.js +67 -0
  60. package/dist/adapters/NodeJsRuntimeAdapter.js.map +1 -0
  61. package/dist/adapters/RuntimeAdapter.d.ts +42 -0
  62. package/dist/adapters/RuntimeAdapter.js +2 -0
  63. package/dist/adapters/RuntimeAdapter.js.map +1 -0
  64. package/dist/adapters/WasmRuntimeAdapter.d.ts +69 -0
  65. package/dist/adapters/WasmRuntimeAdapter.js +279 -0
  66. package/dist/adapters/WasmRuntimeAdapter.js.map +1 -0
  67. package/dist/cache/NodeResultCache.d.ts +286 -0
  68. package/dist/cache/NodeResultCache.js +499 -0
  69. package/dist/cache/NodeResultCache.js.map +1 -0
  70. package/dist/cache/index.d.ts +1 -0
  71. package/dist/cache/index.js +2 -0
  72. package/dist/cache/index.js.map +1 -0
  73. package/dist/cost/CostEstimator.d.ts +57 -0
  74. package/dist/cost/CostEstimator.js +171 -0
  75. package/dist/cost/CostEstimator.js.map +1 -0
  76. package/dist/cost/index.d.ts +4 -0
  77. package/dist/cost/index.js +3 -0
  78. package/dist/cost/index.js.map +1 -0
  79. package/dist/cost/pricing.d.ts +24 -0
  80. package/dist/cost/pricing.js +169 -0
  81. package/dist/cost/pricing.js.map +1 -0
  82. package/dist/defineNode.d.ts +155 -0
  83. package/dist/defineNode.js +191 -0
  84. package/dist/defineNode.js.map +1 -0
  85. package/dist/graphql/GraphQLSchemaGenerator.d.ts +129 -0
  86. package/dist/graphql/GraphQLSchemaGenerator.js +425 -0
  87. package/dist/graphql/GraphQLSchemaGenerator.js.map +1 -0
  88. package/dist/hmr/FileWatcher.d.ts +62 -0
  89. package/dist/hmr/FileWatcher.js +185 -0
  90. package/dist/hmr/FileWatcher.js.map +1 -0
  91. package/dist/hmr/HmrDevConsole.d.ts +13 -0
  92. package/dist/hmr/HmrDevConsole.js +46 -0
  93. package/dist/hmr/HmrDevConsole.js.map +1 -0
  94. package/dist/hmr/HotReloadManager.d.ts +84 -0
  95. package/dist/hmr/HotReloadManager.js +195 -0
  96. package/dist/hmr/HotReloadManager.js.map +1 -0
  97. package/dist/hmr/index.d.ts +39 -0
  98. package/dist/hmr/index.js +38 -0
  99. package/dist/hmr/index.js.map +1 -0
  100. package/dist/index.d.ts +107 -0
  101. package/dist/index.js +107 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/integrations/APMIntegration.d.ts +141 -0
  104. package/dist/integrations/APMIntegration.js +212 -0
  105. package/dist/integrations/APMIntegration.js.map +1 -0
  106. package/dist/integrations/AzureMonitorIntegration.d.ts +118 -0
  107. package/dist/integrations/AzureMonitorIntegration.js +254 -0
  108. package/dist/integrations/AzureMonitorIntegration.js.map +1 -0
  109. package/dist/integrations/CloudWatchIntegration.d.ts +135 -0
  110. package/dist/integrations/CloudWatchIntegration.js +293 -0
  111. package/dist/integrations/CloudWatchIntegration.js.map +1 -0
  112. package/dist/integrations/SentryIntegration.d.ts +153 -0
  113. package/dist/integrations/SentryIntegration.js +200 -0
  114. package/dist/integrations/SentryIntegration.js.map +1 -0
  115. package/dist/integrations/index.d.ts +19 -0
  116. package/dist/integrations/index.js +16 -0
  117. package/dist/integrations/index.js.map +1 -0
  118. package/dist/marketplace/RuntimeAutoScaler.d.ts +148 -0
  119. package/dist/marketplace/RuntimeAutoScaler.js +366 -0
  120. package/dist/marketplace/RuntimeAutoScaler.js.map +1 -0
  121. package/dist/marketplace/RuntimeCatalog.d.ts +174 -0
  122. package/dist/marketplace/RuntimeCatalog.js +339 -0
  123. package/dist/marketplace/RuntimeCatalog.js.map +1 -0
  124. package/dist/marketplace/RuntimeDiscovery.d.ts +86 -0
  125. package/dist/marketplace/RuntimeDiscovery.js +219 -0
  126. package/dist/marketplace/RuntimeDiscovery.js.map +1 -0
  127. package/dist/marketplace/RuntimeHealthMonitor.d.ts +100 -0
  128. package/dist/marketplace/RuntimeHealthMonitor.js +241 -0
  129. package/dist/marketplace/RuntimeHealthMonitor.js.map +1 -0
  130. package/dist/marketplace/RuntimeMetricsDashboard.d.ts +113 -0
  131. package/dist/marketplace/RuntimeMetricsDashboard.js +293 -0
  132. package/dist/marketplace/RuntimeMetricsDashboard.js.map +1 -0
  133. package/dist/monitoring/CircuitBreaker.d.ts +107 -0
  134. package/dist/monitoring/CircuitBreaker.js +238 -0
  135. package/dist/monitoring/CircuitBreaker.js.map +1 -0
  136. package/dist/monitoring/DistributedTracer.d.ts +125 -0
  137. package/dist/monitoring/DistributedTracer.js +230 -0
  138. package/dist/monitoring/DistributedTracer.js.map +1 -0
  139. package/dist/monitoring/HealthCheck.d.ts +54 -0
  140. package/dist/monitoring/HealthCheck.js +102 -0
  141. package/dist/monitoring/HealthCheck.js.map +1 -0
  142. package/dist/monitoring/PerformanceProfiler.d.ts +63 -0
  143. package/dist/monitoring/PerformanceProfiler.js +229 -0
  144. package/dist/monitoring/PerformanceProfiler.js.map +1 -0
  145. package/dist/monitoring/PrometheusBootstrap.d.ts +30 -0
  146. package/dist/monitoring/PrometheusBootstrap.js +71 -0
  147. package/dist/monitoring/PrometheusBootstrap.js.map +1 -0
  148. package/dist/monitoring/PrometheusMetricsBridge.d.ts +60 -0
  149. package/dist/monitoring/PrometheusMetricsBridge.js +216 -0
  150. package/dist/monitoring/PrometheusMetricsBridge.js.map +1 -0
  151. package/dist/monitoring/RateLimiter.d.ts +58 -0
  152. package/dist/monitoring/RateLimiter.js +128 -0
  153. package/dist/monitoring/RateLimiter.js.map +1 -0
  154. package/dist/monitoring/StructuredLogger.d.ts +131 -0
  155. package/dist/monitoring/StructuredLogger.js +207 -0
  156. package/dist/monitoring/StructuredLogger.js.map +1 -0
  157. package/dist/monitoring/TracingBootstrap.d.ts +69 -0
  158. package/dist/monitoring/TracingBootstrap.js +129 -0
  159. package/dist/monitoring/TracingBootstrap.js.map +1 -0
  160. package/dist/monitoring/TriggerMetricsCollector.d.ts +94 -0
  161. package/dist/monitoring/TriggerMetricsCollector.js +174 -0
  162. package/dist/monitoring/TriggerMetricsCollector.js.map +1 -0
  163. package/dist/monitoring/index.d.ts +9 -0
  164. package/dist/monitoring/index.js +10 -0
  165. package/dist/monitoring/index.js.map +1 -0
  166. package/dist/openapi/OpenAPIGenerator.d.ts +192 -0
  167. package/dist/openapi/OpenAPIGenerator.js +373 -0
  168. package/dist/openapi/OpenAPIGenerator.js.map +1 -0
  169. package/dist/openapi/index.d.ts +20 -0
  170. package/dist/openapi/index.js +20 -0
  171. package/dist/openapi/index.js.map +1 -0
  172. package/dist/security/ABAC.d.ts +224 -0
  173. package/dist/security/ABAC.js +380 -0
  174. package/dist/security/ABAC.js.map +1 -0
  175. package/dist/security/AuditLogger.d.ts +242 -0
  176. package/dist/security/AuditLogger.js +317 -0
  177. package/dist/security/AuditLogger.js.map +1 -0
  178. package/dist/security/AuthMiddleware.d.ts +163 -0
  179. package/dist/security/AuthMiddleware.js +274 -0
  180. package/dist/security/AuthMiddleware.js.map +1 -0
  181. package/dist/security/EncryptionAtRest.d.ts +206 -0
  182. package/dist/security/EncryptionAtRest.js +236 -0
  183. package/dist/security/EncryptionAtRest.js.map +1 -0
  184. package/dist/security/OAuthProvider.d.ts +334 -0
  185. package/dist/security/OAuthProvider.js +719 -0
  186. package/dist/security/OAuthProvider.js.map +1 -0
  187. package/dist/security/PIIDetector.d.ts +233 -0
  188. package/dist/security/PIIDetector.js +354 -0
  189. package/dist/security/PIIDetector.js.map +1 -0
  190. package/dist/security/RBAC.d.ts +143 -0
  191. package/dist/security/RBAC.js +285 -0
  192. package/dist/security/RBAC.js.map +1 -0
  193. package/dist/security/SecretManager.d.ts +652 -0
  194. package/dist/security/SecretManager.js +1146 -0
  195. package/dist/security/SecretManager.js.map +1 -0
  196. package/dist/security/TLSConfig.d.ts +305 -0
  197. package/dist/security/TLSConfig.js +550 -0
  198. package/dist/security/TLSConfig.js.map +1 -0
  199. package/dist/security/index.d.ts +79 -0
  200. package/dist/security/index.js +80 -0
  201. package/dist/security/index.js.map +1 -0
  202. package/dist/testing/TestHarness.d.ts +189 -0
  203. package/dist/testing/TestHarness.js +272 -0
  204. package/dist/testing/TestHarness.js.map +1 -0
  205. package/dist/testing/TestLogger.d.ts +103 -0
  206. package/dist/testing/TestLogger.js +153 -0
  207. package/dist/testing/TestLogger.js.map +1 -0
  208. package/dist/testing/WorkflowTestRunner.d.ts +172 -0
  209. package/dist/testing/WorkflowTestRunner.js +355 -0
  210. package/dist/testing/WorkflowTestRunner.js.map +1 -0
  211. package/dist/testing/index.d.ts +21 -0
  212. package/dist/testing/index.js +22 -0
  213. package/dist/testing/index.js.map +1 -0
  214. package/dist/tracing/InMemoryRunStore.d.ts +44 -0
  215. package/dist/tracing/InMemoryRunStore.js +341 -0
  216. package/dist/tracing/InMemoryRunStore.js.map +1 -0
  217. package/dist/tracing/PostgresRunStore.d.ts +82 -0
  218. package/dist/tracing/PostgresRunStore.js +640 -0
  219. package/dist/tracing/PostgresRunStore.js.map +1 -0
  220. package/dist/tracing/RunStore.d.ts +38 -0
  221. package/dist/tracing/RunStore.js +2 -0
  222. package/dist/tracing/RunStore.js.map +1 -0
  223. package/dist/tracing/RunTracker.d.ts +75 -0
  224. package/dist/tracing/RunTracker.js +374 -0
  225. package/dist/tracing/RunTracker.js.map +1 -0
  226. package/dist/tracing/SqliteRunStore.d.ts +53 -0
  227. package/dist/tracing/SqliteRunStore.js +703 -0
  228. package/dist/tracing/SqliteRunStore.js.map +1 -0
  229. package/dist/tracing/TraceRouter.d.ts +47 -0
  230. package/dist/tracing/TraceRouter.js +904 -0
  231. package/dist/tracing/TraceRouter.js.map +1 -0
  232. package/dist/tracing/TracingLogger.d.ts +21 -0
  233. package/dist/tracing/TracingLogger.js +62 -0
  234. package/dist/tracing/TracingLogger.js.map +1 -0
  235. package/dist/tracing/createStore.d.ts +30 -0
  236. package/dist/tracing/createStore.js +75 -0
  237. package/dist/tracing/createStore.js.map +1 -0
  238. package/dist/tracing/index.d.ts +13 -0
  239. package/dist/tracing/index.js +9 -0
  240. package/dist/tracing/index.js.map +1 -0
  241. package/dist/tracing/sanitize.d.ts +7 -0
  242. package/dist/tracing/sanitize.js +95 -0
  243. package/dist/tracing/sanitize.js.map +1 -0
  244. package/dist/tracing/types.d.ts +178 -0
  245. package/dist/tracing/types.js +3 -0
  246. package/dist/tracing/types.js.map +1 -0
  247. package/dist/types/Average.d.ts +11 -0
  248. package/dist/types/Average.js +2 -0
  249. package/dist/types/Average.js.map +1 -0
  250. package/dist/types/Condition.d.ts +8 -0
  251. package/dist/types/Condition.js +2 -0
  252. package/dist/types/Condition.js.map +1 -0
  253. package/dist/types/Conditions.d.ts +5 -0
  254. package/dist/types/Conditions.js +2 -0
  255. package/dist/types/Conditions.js.map +1 -0
  256. package/dist/types/Config.d.ts +12 -0
  257. package/dist/types/Config.js +2 -0
  258. package/dist/types/Config.js.map +1 -0
  259. package/dist/types/Flow.d.ts +5 -0
  260. package/dist/types/Flow.js +2 -0
  261. package/dist/types/Flow.js.map +1 -0
  262. package/dist/types/GlobalOptions.d.ts +11 -0
  263. package/dist/types/GlobalOptions.js +2 -0
  264. package/dist/types/GlobalOptions.js.map +1 -0
  265. package/dist/types/Inputs.d.ts +5 -0
  266. package/dist/types/Inputs.js +2 -0
  267. package/dist/types/Inputs.js.map +1 -0
  268. package/dist/types/JsonLikeObject.d.ts +3 -0
  269. package/dist/types/JsonLikeObject.js +2 -0
  270. package/dist/types/JsonLikeObject.js.map +1 -0
  271. package/dist/types/Mapper.d.ts +5 -0
  272. package/dist/types/Mapper.js +2 -0
  273. package/dist/types/Mapper.js.map +1 -0
  274. package/dist/types/Node.d.ts +10 -0
  275. package/dist/types/Node.js +2 -0
  276. package/dist/types/Node.js.map +1 -0
  277. package/dist/types/ParamsDictionary.d.ts +3 -0
  278. package/dist/types/ParamsDictionary.js +2 -0
  279. package/dist/types/ParamsDictionary.js.map +1 -0
  280. package/dist/types/Properties.d.ts +5 -0
  281. package/dist/types/Properties.js +2 -0
  282. package/dist/types/Properties.js.map +1 -0
  283. package/dist/types/Targets.d.ts +5 -0
  284. package/dist/types/Targets.js +2 -0
  285. package/dist/types/Targets.js.map +1 -0
  286. package/dist/types/Trigger.d.ts +5 -0
  287. package/dist/types/Trigger.js +2 -0
  288. package/dist/types/Trigger.js.map +1 -0
  289. package/dist/types/TriggerHttp.d.ts +7 -0
  290. package/dist/types/TriggerHttp.js +2 -0
  291. package/dist/types/TriggerHttp.js.map +1 -0
  292. package/dist/types/TriggerResponse.d.ts +6 -0
  293. package/dist/types/TriggerResponse.js +2 -0
  294. package/dist/types/TriggerResponse.js.map +1 -0
  295. package/dist/types/Triggers.d.ts +5 -0
  296. package/dist/types/Triggers.js +2 -0
  297. package/dist/types/Triggers.js.map +1 -0
  298. package/dist/types/TryCatch.d.ts +6 -0
  299. package/dist/types/TryCatch.js +2 -0
  300. package/dist/types/TryCatch.js.map +1 -0
  301. package/dist/visualization/NodeDependencyGraph.d.ts +76 -0
  302. package/dist/visualization/NodeDependencyGraph.js +418 -0
  303. package/dist/visualization/NodeDependencyGraph.js.map +1 -0
  304. package/dist/visualization/WorkflowVisualizer.d.ts +144 -0
  305. package/dist/visualization/WorkflowVisualizer.js +446 -0
  306. package/dist/visualization/WorkflowVisualizer.js.map +1 -0
  307. package/package.json +95 -0
@@ -0,0 +1,153 @@
1
+ import { GlobalLogger } from "@blokjs/shared";
2
+ /**
3
+ * TestLogger - A logger that captures log output for testing.
4
+ *
5
+ * Extends GlobalLogger to be compatible with the Context.logger interface
6
+ * while storing all log entries in memory for assertion and inspection.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const logger = new TestLogger();
11
+ * logger.info("User created");
12
+ * logger.warn("Rate limit approaching");
13
+ *
14
+ * // Assert specific messages were logged
15
+ * logger.assertLogged("User created", "info");
16
+ * logger.assertLogged(/rate limit/i, "warn");
17
+ *
18
+ * // Inspect all logs
19
+ * const errors = logger.getLogsByLevel("error");
20
+ * ```
21
+ */
22
+ export class TestLogger extends GlobalLogger {
23
+ entries;
24
+ constructor() {
25
+ super();
26
+ this.entries = [];
27
+ }
28
+ /**
29
+ * Log an info-level message.
30
+ */
31
+ info(message) {
32
+ this.addEntry("info", message);
33
+ }
34
+ /**
35
+ * Log a warning-level message.
36
+ */
37
+ warn(message) {
38
+ this.addEntry("warn", message);
39
+ }
40
+ /**
41
+ * Log a debug-level message.
42
+ */
43
+ debug(message) {
44
+ this.addEntry("debug", message);
45
+ }
46
+ /**
47
+ * Implementation of GlobalLogger.log - logs at info level.
48
+ */
49
+ log(message) {
50
+ this.addEntry("info", message);
51
+ }
52
+ /**
53
+ * Implementation of GlobalLogger.logLevel.
54
+ */
55
+ logLevel(level, message) {
56
+ this.addEntry(level, message);
57
+ }
58
+ /**
59
+ * Implementation of GlobalLogger.error.
60
+ */
61
+ error(message, _stack = "") {
62
+ this.addEntry("error", message);
63
+ }
64
+ /**
65
+ * Get all logged entries.
66
+ */
67
+ getLogs() {
68
+ return this.entries.map((entry) => entry.message);
69
+ }
70
+ /**
71
+ * Get all log entries with full metadata.
72
+ */
73
+ getEntries() {
74
+ return [...this.entries];
75
+ }
76
+ /**
77
+ * Get log entries filtered by level.
78
+ *
79
+ * @param level - The log level to filter by ("info", "warn", "error", "debug")
80
+ * @returns Array of matching log entries
81
+ */
82
+ getLogsByLevel(level) {
83
+ return this.entries.filter((entry) => entry.level === level);
84
+ }
85
+ /**
86
+ * Assert that a specific message was logged.
87
+ *
88
+ * @param message - String or RegExp to match against log messages
89
+ * @param level - Optional level to restrict the search to
90
+ * @throws Error if no matching log entry is found
91
+ */
92
+ assertLogged(message, level) {
93
+ const searchEntries = level ? this.getLogsByLevel(level) : this.entries;
94
+ const found = searchEntries.some((entry) => {
95
+ if (typeof message === "string") {
96
+ return entry.message.includes(message);
97
+ }
98
+ return message.test(entry.message);
99
+ });
100
+ if (!found) {
101
+ const levelInfo = level ? ` at level "${level}"` : "";
102
+ const loggedMessages = searchEntries.map((e) => ` [${e.level}] ${e.message}`).join("\n");
103
+ throw new Error(`Expected log message matching ${message}${levelInfo} but none was found.\n` +
104
+ `Logged messages:\n${loggedMessages || " (none)"}`);
105
+ }
106
+ }
107
+ /**
108
+ * Assert that a specific message was NOT logged.
109
+ *
110
+ * @param message - String or RegExp to match against log messages
111
+ * @param level - Optional level to restrict the search to
112
+ * @throws Error if a matching log entry is found
113
+ */
114
+ assertNotLogged(message, level) {
115
+ const searchEntries = level ? this.getLogsByLevel(level) : this.entries;
116
+ const found = searchEntries.some((entry) => {
117
+ if (typeof message === "string") {
118
+ return entry.message.includes(message);
119
+ }
120
+ return message.test(entry.message);
121
+ });
122
+ if (found) {
123
+ const levelInfo = level ? ` at level "${level}"` : "";
124
+ throw new Error(`Expected log message matching ${message}${levelInfo} to NOT be present, but it was found.`);
125
+ }
126
+ }
127
+ /**
128
+ * Clear all captured log entries.
129
+ */
130
+ clear() {
131
+ this.entries = [];
132
+ this.logs = [];
133
+ }
134
+ /**
135
+ * Get the total number of log entries.
136
+ */
137
+ get count() {
138
+ return this.entries.length;
139
+ }
140
+ /**
141
+ * Internal helper to add a log entry.
142
+ */
143
+ addEntry(level, message) {
144
+ const entry = {
145
+ level,
146
+ message,
147
+ timestamp: Date.now(),
148
+ };
149
+ this.entries.push(entry);
150
+ this.logs.push(message);
151
+ }
152
+ }
153
+ //# sourceMappingURL=TestLogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TestLogger.js","sourceRoot":"","sources":["../../src/testing/TestLogger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,172 @@
1
+ import type { Context } from "@blokjs/shared";
2
+ import BlokService from "../Blok";
3
+ import type { FunctionNode } from "../defineNode";
4
+ import type { TestContextOverrides, TestResult } from "./TestHarness";
5
+ /**
6
+ * Configuration options for the WorkflowTestRunner.
7
+ */
8
+ export interface WorkflowTestConfig {
9
+ /** Timeout in milliseconds for the entire workflow execution. Default: 30000 */
10
+ timeout?: number;
11
+ /** Whether to print execution details to the console. Default: false */
12
+ verbose?: boolean;
13
+ /** When true, all nodes without explicit implementations will be auto-mocked. Default: false */
14
+ mockAllNodes?: boolean;
15
+ }
16
+ /**
17
+ * Result of a workflow test execution.
18
+ */
19
+ export interface WorkflowTestResult {
20
+ /** Whether the entire workflow executed successfully */
21
+ success: boolean;
22
+ /** Final output of the workflow */
23
+ output: any;
24
+ /** Ordered trace of node executions */
25
+ trace: ExecutionTrace[];
26
+ /** Total execution duration in milliseconds */
27
+ durationMs: number;
28
+ /** Per-node results keyed by node name */
29
+ nodeResults: Map<string, TestResult<any>>;
30
+ }
31
+ /**
32
+ * A record of a single node execution within a workflow.
33
+ */
34
+ export interface ExecutionTrace {
35
+ /** Name of the node that was executed */
36
+ nodeName: string;
37
+ /** The index of this step in the workflow */
38
+ stepIndex: number;
39
+ /** Input data provided to the node */
40
+ input: any;
41
+ /** Output data returned by the node */
42
+ output: any;
43
+ /** Execution duration in milliseconds */
44
+ durationMs: number;
45
+ /** Whether this node executed successfully */
46
+ success: boolean;
47
+ /** Error message if the node failed */
48
+ error?: string;
49
+ /** Timestamp when this node started execution */
50
+ timestamp: number;
51
+ }
52
+ /**
53
+ * Options for a single workflow execution.
54
+ */
55
+ export interface WorkflowExecuteOptions {
56
+ /** HTTP headers to populate in the context request */
57
+ headers?: Record<string, string>;
58
+ /** Query parameters to populate in the context request */
59
+ query?: Record<string, string>;
60
+ /** Path parameters to populate in the context request */
61
+ params?: Record<string, string>;
62
+ /** Additional context overrides */
63
+ contextOverrides?: TestContextOverrides;
64
+ }
65
+ /**
66
+ * WorkflowTestRunner - For testing complete workflows.
67
+ *
68
+ * Allows you to register real or mock node implementations and execute
69
+ * workflow definitions in a controlled test environment. Captures a full
70
+ * execution trace showing which nodes ran, in what order, with what data.
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * import { WorkflowTestRunner } from "@blokjs/runner";
75
+ * import { defineNode } from "@blokjs/runner";
76
+ * import { z } from "zod";
77
+ *
78
+ * const runner = new WorkflowTestRunner({ verbose: true });
79
+ *
80
+ * // Register a real node
81
+ * runner.registerNode("validate-input", ValidateInputNode);
82
+ *
83
+ * // Register a mock for an external API call
84
+ * runner.mockNode("fetch-user", async (input) => {
85
+ * return { user: { id: input.userId, name: "Test User" } };
86
+ * });
87
+ *
88
+ * // Load and execute workflow
89
+ * runner.loadWorkflow({
90
+ * name: "get-user",
91
+ * steps: [
92
+ * { name: "step1", node: "validate-input", inputs: { userId: "abc-123" } },
93
+ * { name: "step2", node: "fetch-user", inputs: { userId: "${response.data.userId}" } },
94
+ * ],
95
+ * });
96
+ *
97
+ * const result = await runner.execute({ userId: "abc-123" });
98
+ * console.log(result.trace); // See execution order and data flow
99
+ * ```
100
+ */
101
+ export declare class WorkflowTestRunner {
102
+ private config;
103
+ private nodes;
104
+ private workflow;
105
+ private trace;
106
+ private nodeResults;
107
+ constructor(config?: WorkflowTestConfig);
108
+ /**
109
+ * Register a real node implementation for use in the workflow.
110
+ *
111
+ * @param name - The node name as referenced in the workflow steps
112
+ * @param node - A BlokService instance or a FunctionNode from defineNode()
113
+ */
114
+ registerNode(name: string, node: BlokService<any> | FunctionNode<any, any>): void;
115
+ /**
116
+ * Register a mock node that executes the provided handler function.
117
+ *
118
+ * Use this to simulate external API calls, database queries, or any
119
+ * node whose real implementation you want to skip during testing.
120
+ *
121
+ * @param name - The node name as referenced in the workflow steps
122
+ * @param handler - Async function that receives (input, ctx) and returns output
123
+ */
124
+ mockNode(name: string, handler: (input: any, ctx: Context) => Promise<any>): void;
125
+ /**
126
+ * Load a workflow definition from a JSON object or JSON string.
127
+ *
128
+ * The workflow should have a `steps` array where each step defines:
129
+ * - `name`: step identifier
130
+ * - `node`: the node type to execute
131
+ * - `inputs`: input data for the node (optional)
132
+ *
133
+ * @param workflow - Workflow definition object or JSON string
134
+ */
135
+ loadWorkflow(workflow: object | string): void;
136
+ /**
137
+ * Execute the loaded workflow with the given input.
138
+ *
139
+ * Each step in the workflow is executed sequentially. The output of each
140
+ * step is fed into the context for subsequent steps. A full execution
141
+ * trace is captured for inspection.
142
+ *
143
+ * @param input - Input data (populates request.body in the context)
144
+ * @param options - Optional execution configuration
145
+ * @returns WorkflowTestResult with output, trace, and per-node results
146
+ * @throws Error if no workflow is loaded or if a required node is not registered
147
+ */
148
+ execute(input: any, options?: WorkflowExecuteOptions): Promise<WorkflowTestResult>;
149
+ /**
150
+ * Get the execution trace from the most recent workflow run.
151
+ *
152
+ * @returns Array of ExecutionTrace entries in execution order
153
+ */
154
+ getTrace(): ExecutionTrace[];
155
+ /**
156
+ * Reset the runner state (clears trace, node results, and loaded workflow).
157
+ * Registered nodes and mocks are preserved.
158
+ */
159
+ reset(): void;
160
+ /**
161
+ * Fully reset the runner, including all registered nodes and mocks.
162
+ */
163
+ resetAll(): void;
164
+ /**
165
+ * Internal: Execute all workflow steps sequentially.
166
+ */
167
+ private executeSteps;
168
+ /**
169
+ * Internal: Execute a single workflow step.
170
+ */
171
+ private executeStep;
172
+ }
@@ -0,0 +1,355 @@
1
+ import BlokService from "../Blok";
2
+ import BlokResponse from "../BlokResponse";
3
+ import { TestLogger } from "./TestLogger";
4
+ /**
5
+ * A mock node implementation wrapping a user-provided handler function.
6
+ */
7
+ class MockNode extends BlokService {
8
+ handler;
9
+ constructor(name, handler) {
10
+ super();
11
+ this.name = name;
12
+ this.handler = handler;
13
+ }
14
+ async handle(ctx, inputs) {
15
+ const response = new BlokResponse();
16
+ try {
17
+ const result = await this.handler(inputs, ctx);
18
+ response.setSuccess(result);
19
+ }
20
+ catch (error) {
21
+ const { GlobalError } = await import("@blokjs/shared");
22
+ const globalError = new GlobalError(error instanceof Error ? error.message : String(error));
23
+ globalError.setCode(500);
24
+ globalError.setName(this.name);
25
+ response.setError(globalError);
26
+ }
27
+ return response;
28
+ }
29
+ }
30
+ /**
31
+ * An auto-mock node that returns an empty object for any input.
32
+ */
33
+ class AutoMockNode extends MockNode {
34
+ constructor(name) {
35
+ super(name, async () => ({}));
36
+ }
37
+ }
38
+ /**
39
+ * WorkflowTestRunner - For testing complete workflows.
40
+ *
41
+ * Allows you to register real or mock node implementations and execute
42
+ * workflow definitions in a controlled test environment. Captures a full
43
+ * execution trace showing which nodes ran, in what order, with what data.
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * import { WorkflowTestRunner } from "@blokjs/runner";
48
+ * import { defineNode } from "@blokjs/runner";
49
+ * import { z } from "zod";
50
+ *
51
+ * const runner = new WorkflowTestRunner({ verbose: true });
52
+ *
53
+ * // Register a real node
54
+ * runner.registerNode("validate-input", ValidateInputNode);
55
+ *
56
+ * // Register a mock for an external API call
57
+ * runner.mockNode("fetch-user", async (input) => {
58
+ * return { user: { id: input.userId, name: "Test User" } };
59
+ * });
60
+ *
61
+ * // Load and execute workflow
62
+ * runner.loadWorkflow({
63
+ * name: "get-user",
64
+ * steps: [
65
+ * { name: "step1", node: "validate-input", inputs: { userId: "abc-123" } },
66
+ * { name: "step2", node: "fetch-user", inputs: { userId: "${response.data.userId}" } },
67
+ * ],
68
+ * });
69
+ *
70
+ * const result = await runner.execute({ userId: "abc-123" });
71
+ * console.log(result.trace); // See execution order and data flow
72
+ * ```
73
+ */
74
+ export class WorkflowTestRunner {
75
+ config;
76
+ nodes;
77
+ workflow;
78
+ trace;
79
+ nodeResults;
80
+ constructor(config) {
81
+ this.config = {
82
+ timeout: config?.timeout ?? 30000,
83
+ verbose: config?.verbose ?? false,
84
+ mockAllNodes: config?.mockAllNodes ?? false,
85
+ };
86
+ this.nodes = new Map();
87
+ this.workflow = null;
88
+ this.trace = [];
89
+ this.nodeResults = new Map();
90
+ }
91
+ /**
92
+ * Register a real node implementation for use in the workflow.
93
+ *
94
+ * @param name - The node name as referenced in the workflow steps
95
+ * @param node - A BlokService instance or a FunctionNode from defineNode()
96
+ */
97
+ registerNode(name, node) {
98
+ node.name = name;
99
+ this.nodes.set(name, node);
100
+ if (this.config.verbose) {
101
+ console.log(`[WorkflowTestRunner] Registered node: ${name}`);
102
+ }
103
+ }
104
+ /**
105
+ * Register a mock node that executes the provided handler function.
106
+ *
107
+ * Use this to simulate external API calls, database queries, or any
108
+ * node whose real implementation you want to skip during testing.
109
+ *
110
+ * @param name - The node name as referenced in the workflow steps
111
+ * @param handler - Async function that receives (input, ctx) and returns output
112
+ */
113
+ mockNode(name, handler) {
114
+ const mockNodeInstance = new MockNode(name, handler);
115
+ this.nodes.set(name, mockNodeInstance);
116
+ if (this.config.verbose) {
117
+ console.log(`[WorkflowTestRunner] Mocked node: ${name}`);
118
+ }
119
+ }
120
+ /**
121
+ * Load a workflow definition from a JSON object or JSON string.
122
+ *
123
+ * The workflow should have a `steps` array where each step defines:
124
+ * - `name`: step identifier
125
+ * - `node`: the node type to execute
126
+ * - `inputs`: input data for the node (optional)
127
+ *
128
+ * @param workflow - Workflow definition object or JSON string
129
+ */
130
+ loadWorkflow(workflow) {
131
+ if (typeof workflow === "string") {
132
+ this.workflow = JSON.parse(workflow);
133
+ }
134
+ else {
135
+ this.workflow = workflow;
136
+ }
137
+ if (!this.workflow.steps || !Array.isArray(this.workflow.steps)) {
138
+ throw new Error("Workflow must have a 'steps' array");
139
+ }
140
+ if (this.config.verbose) {
141
+ console.log(`[WorkflowTestRunner] Loaded workflow: ${this.workflow.name ?? "(unnamed)"} ` +
142
+ `with ${this.workflow.steps.length} steps`);
143
+ }
144
+ }
145
+ /**
146
+ * Execute the loaded workflow with the given input.
147
+ *
148
+ * Each step in the workflow is executed sequentially. The output of each
149
+ * step is fed into the context for subsequent steps. A full execution
150
+ * trace is captured for inspection.
151
+ *
152
+ * @param input - Input data (populates request.body in the context)
153
+ * @param options - Optional execution configuration
154
+ * @returns WorkflowTestResult with output, trace, and per-node results
155
+ * @throws Error if no workflow is loaded or if a required node is not registered
156
+ */
157
+ async execute(input, options) {
158
+ if (!this.workflow) {
159
+ throw new Error("No workflow loaded. Call loadWorkflow() first.");
160
+ }
161
+ // Reset trace for this execution
162
+ this.trace = [];
163
+ this.nodeResults = new Map();
164
+ const logger = options?.contextOverrides?.logger ?? new TestLogger();
165
+ const workflowStartTime = performance.now();
166
+ // Build the initial context
167
+ const ctx = {
168
+ id: options?.contextOverrides?.id ?? `test-workflow-${Date.now()}`,
169
+ workflow_name: this.workflow.name ?? "test-workflow",
170
+ workflow_path: options?.contextOverrides?.workflow_path ?? "/test",
171
+ request: {
172
+ body: input ?? {},
173
+ headers: options?.headers ?? options?.contextOverrides?.request?.headers ?? {},
174
+ query: options?.query ?? options?.contextOverrides?.request?.query ?? {},
175
+ params: options?.params ?? options?.contextOverrides?.request?.params ?? {},
176
+ },
177
+ response: {
178
+ data: {},
179
+ error: null,
180
+ success: true,
181
+ contentType: "application/json",
182
+ },
183
+ error: options?.contextOverrides?.error ?? { message: [] },
184
+ logger: logger,
185
+ config: options?.contextOverrides?.config ?? {},
186
+ vars: options?.contextOverrides?.vars ?? {},
187
+ env: options?.contextOverrides?.env ?? {},
188
+ eventLogger: logger,
189
+ _PRIVATE_: {},
190
+ };
191
+ let workflowSuccess = true;
192
+ let workflowError = null;
193
+ // Create a timeout promise
194
+ const timeoutPromise = new Promise((_, reject) => {
195
+ setTimeout(() => {
196
+ reject(new Error(`Workflow execution timed out after ${this.config.timeout}ms`));
197
+ }, this.config.timeout);
198
+ });
199
+ try {
200
+ await Promise.race([this.executeSteps(ctx, this.workflow.steps), timeoutPromise]);
201
+ }
202
+ catch (error) {
203
+ workflowSuccess = false;
204
+ workflowError = error;
205
+ if (this.config.verbose) {
206
+ const errorMsg = error instanceof Error ? error.message : String(error);
207
+ console.log(`[WorkflowTestRunner] Workflow failed: ${errorMsg}`);
208
+ }
209
+ }
210
+ const workflowEndTime = performance.now();
211
+ return {
212
+ success: workflowSuccess,
213
+ output: workflowSuccess ? ctx.response?.data : workflowError,
214
+ trace: [...this.trace],
215
+ durationMs: workflowEndTime - workflowStartTime,
216
+ nodeResults: new Map(this.nodeResults),
217
+ };
218
+ }
219
+ /**
220
+ * Get the execution trace from the most recent workflow run.
221
+ *
222
+ * @returns Array of ExecutionTrace entries in execution order
223
+ */
224
+ getTrace() {
225
+ return [...this.trace];
226
+ }
227
+ /**
228
+ * Reset the runner state (clears trace, node results, and loaded workflow).
229
+ * Registered nodes and mocks are preserved.
230
+ */
231
+ reset() {
232
+ this.workflow = null;
233
+ this.trace = [];
234
+ this.nodeResults = new Map();
235
+ }
236
+ /**
237
+ * Fully reset the runner, including all registered nodes and mocks.
238
+ */
239
+ resetAll() {
240
+ this.reset();
241
+ this.nodes = new Map();
242
+ }
243
+ /**
244
+ * Internal: Execute all workflow steps sequentially.
245
+ */
246
+ async executeSteps(ctx, steps) {
247
+ for (let i = 0; i < steps.length; i++) {
248
+ const step = steps[i];
249
+ await this.executeStep(ctx, step, i);
250
+ }
251
+ }
252
+ /**
253
+ * Internal: Execute a single workflow step.
254
+ */
255
+ async executeStep(ctx, step, stepIndex) {
256
+ const nodeName = step.node;
257
+ let node = this.nodes.get(nodeName);
258
+ // Auto-mock if configured
259
+ if (!node && this.config.mockAllNodes) {
260
+ node = new AutoMockNode(nodeName);
261
+ this.nodes.set(nodeName, node);
262
+ if (this.config.verbose) {
263
+ console.log(`[WorkflowTestRunner] Auto-mocked node: ${nodeName}`);
264
+ }
265
+ }
266
+ if (!node) {
267
+ throw new Error(`Node "${nodeName}" is not registered. ` +
268
+ `Call registerNode("${nodeName}", nodeImpl) or mockNode("${nodeName}", handler) before executing.`);
269
+ }
270
+ // Determine input: use step.inputs if defined, otherwise use current response data
271
+ const stepInput = step.inputs ?? ctx.response?.data ?? {};
272
+ if (this.config.verbose) {
273
+ console.log(`[WorkflowTestRunner] Step ${stepIndex}: executing "${step.name}" (node: ${nodeName})`);
274
+ }
275
+ const startTime = performance.now();
276
+ const traceEntry = {
277
+ nodeName: step.name,
278
+ stepIndex,
279
+ input: stepInput,
280
+ output: null,
281
+ durationMs: 0,
282
+ success: false,
283
+ timestamp: Date.now(),
284
+ };
285
+ try {
286
+ const response = (await node.handle(ctx, stepInput));
287
+ const endTime = performance.now();
288
+ traceEntry.durationMs = endTime - startTime;
289
+ if (response.success === false || response.error) {
290
+ traceEntry.success = false;
291
+ traceEntry.error = response.error?.toString() ?? "Unknown error";
292
+ traceEntry.output = null;
293
+ this.nodeResults.set(step.name, {
294
+ success: false,
295
+ data: null,
296
+ error: response.error,
297
+ context: ctx,
298
+ durationMs: traceEntry.durationMs,
299
+ logs: ctx.logger.getLogs?.() ?? [],
300
+ });
301
+ this.trace.push(traceEntry);
302
+ throw new Error(`Node "${step.name}" (${nodeName}) failed: ${response.error?.toString() ?? "Unknown error"}`);
303
+ }
304
+ // Update context response with node output
305
+ ctx.response = {
306
+ data: response.data,
307
+ error: null,
308
+ success: true,
309
+ contentType: response.contentType ?? "application/json",
310
+ };
311
+ // If step sets a var, store output in vars
312
+ if (step.set_var) {
313
+ if (!ctx.vars)
314
+ ctx.vars = {};
315
+ ctx.vars[step.name] = response.data;
316
+ }
317
+ traceEntry.success = true;
318
+ traceEntry.output = response.data;
319
+ this.nodeResults.set(step.name, {
320
+ success: true,
321
+ data: response.data,
322
+ error: null,
323
+ context: ctx,
324
+ durationMs: traceEntry.durationMs,
325
+ logs: ctx.logger.getLogs?.() ?? [],
326
+ });
327
+ }
328
+ catch (error) {
329
+ const endTime = performance.now();
330
+ if (!traceEntry.durationMs) {
331
+ traceEntry.durationMs = endTime - startTime;
332
+ }
333
+ if (!traceEntry.error) {
334
+ const errorMsg = error instanceof Error ? error.message : String(error);
335
+ traceEntry.success = false;
336
+ traceEntry.error = errorMsg;
337
+ this.nodeResults.set(step.name, {
338
+ success: false,
339
+ data: null,
340
+ error,
341
+ context: ctx,
342
+ durationMs: traceEntry.durationMs,
343
+ logs: ctx.logger.getLogs?.() ?? [],
344
+ });
345
+ }
346
+ this.trace.push(traceEntry);
347
+ throw error;
348
+ }
349
+ this.trace.push(traceEntry);
350
+ if (this.config.verbose) {
351
+ console.log(`[WorkflowTestRunner] Step ${stepIndex}: "${step.name}" completed in ${traceEntry.durationMs.toFixed(2)}ms`);
352
+ }
353
+ }
354
+ }
355
+ //# sourceMappingURL=WorkflowTestRunner.js.map