effect-start 0.23.1 → 0.26.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 (351) hide show
  1. package/package.json +18 -86
  2. package/src/Development.ts +3 -1
  3. package/src/Entity.ts +17 -0
  4. package/src/Fetch.ts +271 -0
  5. package/src/SqlIntrospect.ts +64 -70
  6. package/src/Start.ts +21 -24
  7. package/src/StartApp.ts +1 -1
  8. package/src/bun/BunServer.ts +42 -10
  9. package/src/hyper/HyperHtml.ts +0 -1
  10. package/src/sql/bun/index.ts +1 -1
  11. package/src/sql/index.ts +1 -0
  12. package/src/sql/libsql/index.ts +173 -0
  13. package/src/sql/libsql/libsql.d.ts +39 -0
  14. package/src/sql/mssql/index.ts +1 -1
  15. package/dist/BlobStore.d.ts +0 -80
  16. package/dist/BlobStore.js +0 -19
  17. package/dist/ChildProcess.d.ts +0 -60
  18. package/dist/ChildProcess.js +0 -30
  19. package/dist/Commander.d.ts +0 -100
  20. package/dist/Commander.js +0 -326
  21. package/dist/ContentNegotiation.d.ts +0 -12
  22. package/dist/ContentNegotiation.js +0 -359
  23. package/dist/Cookies.d.ts +0 -47
  24. package/dist/Cookies.js +0 -302
  25. package/dist/Development.d.ts +0 -39
  26. package/dist/Development.js +0 -58
  27. package/dist/Effectify.d.ts +0 -209
  28. package/dist/Effectify.js +0 -19
  29. package/dist/Entity.d.ts +0 -47
  30. package/dist/Entity.js +0 -224
  31. package/dist/FilePathPattern.d.ts +0 -29
  32. package/dist/FilePathPattern.js +0 -86
  33. package/dist/FileRouter.d.ts +0 -56
  34. package/dist/FileRouter.js +0 -148
  35. package/dist/FileRouterCodegen.d.ts +0 -18
  36. package/dist/FileRouterCodegen.js +0 -227
  37. package/dist/FileRouterPattern.d.ts +0 -9
  38. package/dist/FileRouterPattern.js +0 -35
  39. package/dist/FileSystem.d.ts +0 -158
  40. package/dist/FileSystem.js +0 -70
  41. package/dist/Http.d.ts +0 -37
  42. package/dist/Http.js +0 -88
  43. package/dist/HttpAppExtra.d.ts +0 -7
  44. package/dist/HttpAppExtra.js +0 -320
  45. package/dist/HttpUtils.d.ts +0 -3
  46. package/dist/HttpUtils.js +0 -11
  47. package/dist/PathPattern.d.ts +0 -134
  48. package/dist/PathPattern.js +0 -413
  49. package/dist/PlatformError.d.ts +0 -38
  50. package/dist/PlatformError.js +0 -25
  51. package/dist/PlatformRuntime.d.ts +0 -27
  52. package/dist/PlatformRuntime.js +0 -46
  53. package/dist/Route.d.ts +0 -97
  54. package/dist/Route.js +0 -100
  55. package/dist/RouteBody.d.ts +0 -47
  56. package/dist/RouteBody.js +0 -67
  57. package/dist/RouteError.d.ts +0 -98
  58. package/dist/RouteError.js +0 -55
  59. package/dist/RouteHook.d.ts +0 -12
  60. package/dist/RouteHook.js +0 -40
  61. package/dist/RouteHttp.d.ts +0 -21
  62. package/dist/RouteHttp.js +0 -258
  63. package/dist/RouteHttpTracer.d.ts +0 -10
  64. package/dist/RouteHttpTracer.js +0 -62
  65. package/dist/RouteMount.d.ts +0 -86
  66. package/dist/RouteMount.js +0 -63
  67. package/dist/RouteSchema.d.ts +0 -86
  68. package/dist/RouteSchema.js +0 -188
  69. package/dist/RouteSse.d.ts +0 -21
  70. package/dist/RouteSse.js +0 -79
  71. package/dist/RouteTree.d.ts +0 -57
  72. package/dist/RouteTree.js +0 -93
  73. package/dist/RouteTrie.d.ts +0 -20
  74. package/dist/RouteTrie.js +0 -152
  75. package/dist/RouterPattern.d.ts +0 -118
  76. package/dist/RouterPattern.js +0 -269
  77. package/dist/SchemaExtra.d.ts +0 -7
  78. package/dist/SchemaExtra.js +0 -74
  79. package/dist/Socket.d.ts +0 -27
  80. package/dist/Socket.js +0 -29
  81. package/dist/Sql.d.ts +0 -34
  82. package/dist/Sql.js +0 -5
  83. package/dist/SqlIntrospect.d.ts +0 -91
  84. package/dist/SqlIntrospect.js +0 -466
  85. package/dist/Start.d.ts +0 -44
  86. package/dist/Start.js +0 -49
  87. package/dist/StartApp.d.ts +0 -19
  88. package/dist/StartApp.js +0 -21
  89. package/dist/StreamExtra.d.ts +0 -28
  90. package/dist/StreamExtra.js +0 -100
  91. package/dist/System.d.ts +0 -7
  92. package/dist/System.js +0 -22
  93. package/dist/TuplePathPattern.d.ts +0 -9
  94. package/dist/TuplePathPattern.js +0 -68
  95. package/dist/Unique.d.ts +0 -50
  96. package/dist/Unique.js +0 -187
  97. package/dist/Values.d.ts +0 -27
  98. package/dist/Values.js +0 -36
  99. package/dist/bun/BunBlobStoreDisk.d.ts +0 -6
  100. package/dist/bun/BunBlobStoreDisk.js +0 -116
  101. package/dist/bun/BunBlobStoreS3.d.ts +0 -11
  102. package/dist/bun/BunBlobStoreS3.js +0 -89
  103. package/dist/bun/BunBlobWatcherDisk.d.ts +0 -6
  104. package/dist/bun/BunBlobWatcherDisk.js +0 -60
  105. package/dist/bun/BunBlobWatcherQueue.d.ts +0 -6
  106. package/dist/bun/BunBlobWatcherQueue.js +0 -17
  107. package/dist/bun/BunBundle.d.ts +0 -11
  108. package/dist/bun/BunBundle.js +0 -137
  109. package/dist/bun/BunChildProcessSpawner.d.ts +0 -3
  110. package/dist/bun/BunChildProcessSpawner.js +0 -103
  111. package/dist/bun/BunHttpServer.d.ts +0 -44
  112. package/dist/bun/BunHttpServer.js +0 -186
  113. package/dist/bun/BunHttpServer_web.d.ts +0 -60
  114. package/dist/bun/BunHttpServer_web.js +0 -252
  115. package/dist/bun/BunImportTrackerPlugin.d.ts +0 -13
  116. package/dist/bun/BunImportTrackerPlugin.js +0 -69
  117. package/dist/bun/BunPlatformHttpServer.d.ts +0 -10
  118. package/dist/bun/BunPlatformHttpServer.js +0 -53
  119. package/dist/bun/BunRoute.d.ts +0 -48
  120. package/dist/bun/BunRoute.js +0 -121
  121. package/dist/bun/BunRuntime.d.ts +0 -2
  122. package/dist/bun/BunRuntime.js +0 -31
  123. package/dist/bun/BunServer.d.ts +0 -40
  124. package/dist/bun/BunServer.js +0 -157
  125. package/dist/bun/BunServerRequest.d.ts +0 -60
  126. package/dist/bun/BunServerRequest.js +0 -252
  127. package/dist/bun/BunSql.d.ts +0 -4
  128. package/dist/bun/BunSql.js +0 -81
  129. package/dist/bun/BunVirtualFilesPlugin.d.ts +0 -4
  130. package/dist/bun/BunVirtualFilesPlugin.js +0 -40
  131. package/dist/bun/_BunEnhancedResolve.d.ts +0 -45
  132. package/dist/bun/_BunEnhancedResolve.js +0 -102
  133. package/dist/bun/index.d.ts +0 -5
  134. package/dist/bun/index.js +0 -5
  135. package/dist/bundler/Bundle.d.ts +0 -61
  136. package/dist/bundler/Bundle.js +0 -48
  137. package/dist/bundler/BundleFiles.d.ts +0 -13
  138. package/dist/bundler/BundleFiles.js +0 -96
  139. package/dist/bundler/BundleHttp.d.ts +0 -45
  140. package/dist/bundler/BundleHttp.js +0 -176
  141. package/dist/bundler/BundleRoute.d.ts +0 -27
  142. package/dist/bundler/BundleRoute.js +0 -51
  143. package/dist/client/Overlay.d.ts +0 -2
  144. package/dist/client/Overlay.js +0 -32
  145. package/dist/client/ScrollState.d.ts +0 -6
  146. package/dist/client/ScrollState.js +0 -94
  147. package/dist/client/index.d.ts +0 -6
  148. package/dist/client/index.js +0 -79
  149. package/dist/console/Console.d.ts +0 -6
  150. package/dist/console/Console.js +0 -26
  151. package/dist/console/ConsoleErrors.d.ts +0 -3
  152. package/dist/console/ConsoleErrors.js +0 -200
  153. package/dist/console/ConsoleLogger.d.ts +0 -3
  154. package/dist/console/ConsoleLogger.js +0 -47
  155. package/dist/console/ConsoleMetrics.d.ts +0 -3
  156. package/dist/console/ConsoleMetrics.js +0 -61
  157. package/dist/console/ConsoleProcess.d.ts +0 -3
  158. package/dist/console/ConsoleProcess.js +0 -49
  159. package/dist/console/ConsoleStore.d.ts +0 -144
  160. package/dist/console/ConsoleStore.js +0 -61
  161. package/dist/console/ConsoleTracer.d.ts +0 -3
  162. package/dist/console/ConsoleTracer.js +0 -94
  163. package/dist/console/Simulation.d.ts +0 -2
  164. package/dist/console/Simulation.js +0 -633
  165. package/dist/console/index.d.ts +0 -3
  166. package/dist/console/index.js +0 -3
  167. package/dist/console/routes/errors/route.d.ts +0 -10
  168. package/dist/console/routes/errors/route.js +0 -47
  169. package/dist/console/routes/fiberDetail.d.ts +0 -16
  170. package/dist/console/routes/fiberDetail.js +0 -38
  171. package/dist/console/routes/fibers/route.d.ts +0 -10
  172. package/dist/console/routes/fibers/route.js +0 -19
  173. package/dist/console/routes/git/route.d.ts +0 -11
  174. package/dist/console/routes/git/route.js +0 -33
  175. package/dist/console/routes/layout.d.ts +0 -9
  176. package/dist/console/routes/layout.js +0 -3
  177. package/dist/console/routes/logs/route.d.ts +0 -10
  178. package/dist/console/routes/logs/route.js +0 -32
  179. package/dist/console/routes/metrics/route.d.ts +0 -10
  180. package/dist/console/routes/metrics/route.js +0 -17
  181. package/dist/console/routes/route.d.ts +0 -6
  182. package/dist/console/routes/route.js +0 -5
  183. package/dist/console/routes/routes/route.d.ts +0 -6
  184. package/dist/console/routes/routes/route.js +0 -20
  185. package/dist/console/routes/services/route.d.ts +0 -6
  186. package/dist/console/routes/services/route.js +0 -12
  187. package/dist/console/routes/system/route.d.ts +0 -10
  188. package/dist/console/routes/system/route.js +0 -18
  189. package/dist/console/routes/traceDetail.d.ts +0 -16
  190. package/dist/console/routes/traceDetail.js +0 -14
  191. package/dist/console/routes/traces/route.d.ts +0 -10
  192. package/dist/console/routes/traces/route.js +0 -39
  193. package/dist/console/routes/tree.d.ts +0 -153
  194. package/dist/console/routes/tree.js +0 -29
  195. package/dist/console/ui/Errors.d.ts +0 -4
  196. package/dist/console/ui/Errors.js +0 -15
  197. package/dist/console/ui/Fibers.d.ts +0 -24
  198. package/dist/console/ui/Fibers.js +0 -121
  199. package/dist/console/ui/Git.d.ts +0 -20
  200. package/dist/console/ui/Git.js +0 -95
  201. package/dist/console/ui/Logs.d.ts +0 -4
  202. package/dist/console/ui/Logs.js +0 -25
  203. package/dist/console/ui/Metrics.d.ts +0 -4
  204. package/dist/console/ui/Metrics.js +0 -26
  205. package/dist/console/ui/Routes.d.ts +0 -8
  206. package/dist/console/ui/Routes.js +0 -70
  207. package/dist/console/ui/Services.d.ts +0 -10
  208. package/dist/console/ui/Services.js +0 -246
  209. package/dist/console/ui/Shell.d.ts +0 -10
  210. package/dist/console/ui/Shell.js +0 -7
  211. package/dist/console/ui/System.d.ts +0 -4
  212. package/dist/console/ui/System.js +0 -35
  213. package/dist/console/ui/Traces.d.ts +0 -12
  214. package/dist/console/ui/Traces.js +0 -179
  215. package/dist/datastar/actions/fetch.d.ts +0 -30
  216. package/dist/datastar/actions/fetch.js +0 -403
  217. package/dist/datastar/actions/peek.d.ts +0 -1
  218. package/dist/datastar/actions/peek.js +0 -13
  219. package/dist/datastar/actions/setAll.d.ts +0 -1
  220. package/dist/datastar/actions/setAll.js +0 -12
  221. package/dist/datastar/actions/toggleAll.d.ts +0 -1
  222. package/dist/datastar/actions/toggleAll.js +0 -12
  223. package/dist/datastar/attributes/attr.d.ts +0 -1
  224. package/dist/datastar/attributes/attr.js +0 -48
  225. package/dist/datastar/attributes/bind.d.ts +0 -1
  226. package/dist/datastar/attributes/bind.js +0 -175
  227. package/dist/datastar/attributes/class.d.ts +0 -1
  228. package/dist/datastar/attributes/class.js +0 -47
  229. package/dist/datastar/attributes/computed.d.ts +0 -1
  230. package/dist/datastar/attributes/computed.js +0 -26
  231. package/dist/datastar/attributes/effect.d.ts +0 -1
  232. package/dist/datastar/attributes/effect.js +0 -9
  233. package/dist/datastar/attributes/indicator.d.ts +0 -1
  234. package/dist/datastar/attributes/indicator.js +0 -30
  235. package/dist/datastar/attributes/init.d.ts +0 -1
  236. package/dist/datastar/attributes/init.js +0 -26
  237. package/dist/datastar/attributes/jsonSignals.d.ts +0 -1
  238. package/dist/datastar/attributes/jsonSignals.js +0 -30
  239. package/dist/datastar/attributes/on.d.ts +0 -1
  240. package/dist/datastar/attributes/on.js +0 -78
  241. package/dist/datastar/attributes/onIntersect.d.ts +0 -1
  242. package/dist/datastar/attributes/onIntersect.js +0 -53
  243. package/dist/datastar/attributes/onInterval.d.ts +0 -1
  244. package/dist/datastar/attributes/onInterval.js +0 -30
  245. package/dist/datastar/attributes/onSignalPatch.d.ts +0 -1
  246. package/dist/datastar/attributes/onSignalPatch.js +0 -42
  247. package/dist/datastar/attributes/ref.d.ts +0 -1
  248. package/dist/datastar/attributes/ref.js +0 -10
  249. package/dist/datastar/attributes/show.d.ts +0 -1
  250. package/dist/datastar/attributes/show.js +0 -31
  251. package/dist/datastar/attributes/signals.d.ts +0 -1
  252. package/dist/datastar/attributes/signals.js +0 -17
  253. package/dist/datastar/attributes/style.d.ts +0 -1
  254. package/dist/datastar/attributes/style.js +0 -50
  255. package/dist/datastar/attributes/text.d.ts +0 -1
  256. package/dist/datastar/attributes/text.js +0 -26
  257. package/dist/datastar/engine.d.ts +0 -162
  258. package/dist/datastar/engine.js +0 -999
  259. package/dist/datastar/happydom.d.ts +0 -1
  260. package/dist/datastar/happydom.js +0 -8
  261. package/dist/datastar/index.d.ts +0 -24
  262. package/dist/datastar/index.js +0 -24
  263. package/dist/datastar/load.d.ts +0 -24
  264. package/dist/datastar/load.js +0 -24
  265. package/dist/datastar/utils.d.ts +0 -51
  266. package/dist/datastar/utils.js +0 -202
  267. package/dist/datastar/watchers/patchElements.d.ts +0 -1
  268. package/dist/datastar/watchers/patchElements.js +0 -399
  269. package/dist/datastar/watchers/patchSignals.d.ts +0 -1
  270. package/dist/datastar/watchers/patchSignals.js +0 -14
  271. package/dist/experimental/EncryptedCookies.d.ts +0 -48
  272. package/dist/experimental/EncryptedCookies.js +0 -212
  273. package/dist/experimental/SseHttpResponse.d.ts +0 -7
  274. package/dist/experimental/SseHttpResponse.js +0 -28
  275. package/dist/experimental/index.d.ts +0 -1
  276. package/dist/experimental/index.js +0 -1
  277. package/dist/hyper/Hyper.d.ts +0 -25
  278. package/dist/hyper/Hyper.js +0 -23
  279. package/dist/hyper/HyperHtml.d.ts +0 -23
  280. package/dist/hyper/HyperHtml.js +0 -150
  281. package/dist/hyper/HyperHtml.test.d.ts +0 -1
  282. package/dist/hyper/HyperHtml.test.js +0 -197
  283. package/dist/hyper/HyperNode.d.ts +0 -14
  284. package/dist/hyper/HyperNode.js +0 -11
  285. package/dist/hyper/HyperRoute.d.ts +0 -8
  286. package/dist/hyper/HyperRoute.js +0 -32
  287. package/dist/hyper/HyperRoute.test.d.ts +0 -1
  288. package/dist/hyper/HyperRoute.test.js +0 -83
  289. package/dist/hyper/html.d.ts +0 -11
  290. package/dist/hyper/html.js +0 -30
  291. package/dist/hyper/index.d.ts +0 -6
  292. package/dist/hyper/index.js +0 -5
  293. package/dist/hyper/jsx-runtime.d.ts +0 -7
  294. package/dist/hyper/jsx-runtime.js +0 -8
  295. package/dist/index.d.ts +0 -8
  296. package/dist/index.js +0 -8
  297. package/dist/inference_check.d.ts +0 -1
  298. package/dist/inference_check.js +0 -15
  299. package/dist/lint/plugin.d.ts +0 -86
  300. package/dist/lint/plugin.js +0 -341
  301. package/dist/middlewares/BasicAuthMiddleware.d.ts +0 -8
  302. package/dist/middlewares/BasicAuthMiddleware.js +0 -22
  303. package/dist/middlewares/index.d.ts +0 -1
  304. package/dist/middlewares/index.js +0 -1
  305. package/dist/node/Effectify.d.ts +0 -209
  306. package/dist/node/Effectify.js +0 -19
  307. package/dist/node/FileSystem.d.ts +0 -7
  308. package/dist/node/FileSystem.js +0 -420
  309. package/dist/node/NodeFileSystem.d.ts +0 -7
  310. package/dist/node/NodeFileSystem.js +0 -410
  311. package/dist/node/NodeUtils.d.ts +0 -2
  312. package/dist/node/NodeUtils.js +0 -20
  313. package/dist/node/PlatformError.d.ts +0 -46
  314. package/dist/node/PlatformError.js +0 -43
  315. package/dist/node/Utils.d.ts +0 -1
  316. package/dist/node/Utils.js +0 -19
  317. package/dist/repro_fail.d.ts +0 -1
  318. package/dist/repro_fail.js +0 -14
  319. package/dist/sql/bun/index.d.ts +0 -3
  320. package/dist/sql/bun/index.js +0 -75
  321. package/dist/sql/mssql/docker.d.ts +0 -2
  322. package/dist/sql/mssql/docker.js +0 -67
  323. package/dist/sql/mssql/index.d.ts +0 -21
  324. package/dist/sql/mssql/index.js +0 -113
  325. package/dist/testing/TestHttpClient.d.ts +0 -13
  326. package/dist/testing/TestHttpClient.js +0 -68
  327. package/dist/testing/TestLogger.d.ts +0 -13
  328. package/dist/testing/TestLogger.js +0 -32
  329. package/dist/testing/index.d.ts +0 -2
  330. package/dist/testing/index.js +0 -2
  331. package/dist/testing/utils.d.ts +0 -9
  332. package/dist/testing/utils.js +0 -39
  333. package/dist/x/cloudflare/CloudflareTunnel.d.ts +0 -10
  334. package/dist/x/cloudflare/CloudflareTunnel.js +0 -30
  335. package/dist/x/cloudflare/index.d.ts +0 -1
  336. package/dist/x/cloudflare/index.js +0 -1
  337. package/dist/x/datastar/Datastar.d.ts +0 -6
  338. package/dist/x/datastar/Datastar.js +0 -47
  339. package/dist/x/datastar/index.d.ts +0 -1
  340. package/dist/x/datastar/index.js +0 -1
  341. package/dist/x/tailscale/TailscaleTunnel.d.ts +0 -15
  342. package/dist/x/tailscale/TailscaleTunnel.js +0 -68
  343. package/dist/x/tailscale/index.d.ts +0 -1
  344. package/dist/x/tailscale/index.js +0 -1
  345. package/dist/x/tailwind/TailwindPlugin.d.ts +0 -23
  346. package/dist/x/tailwind/TailwindPlugin.js +0 -219
  347. package/dist/x/tailwind/compile.d.ts +0 -19
  348. package/dist/x/tailwind/compile.js +0 -154
  349. package/dist/x/tailwind/plugin.d.ts +0 -2
  350. package/dist/x/tailwind/plugin.js +0 -15
  351. /package/src/{Sql.ts → sql/Sql.ts} +0 -0
@@ -1,633 +0,0 @@
1
- import * as Data from "effect/Data";
2
- import * as Duration from "effect/Duration";
3
- import * as Effect from "effect/Effect";
4
- import * as Layer from "effect/Layer";
5
- import * as Metric from "effect/Metric";
6
- import * as MetricBoundaries from "effect/MetricBoundaries";
7
- import * as Random from "effect/Random";
8
- import * as Schedule from "effect/Schedule";
9
- // ---------------------------------------------------------------------------
10
- // Helpers
11
- // ---------------------------------------------------------------------------
12
- const pick = (arr) => Random.nextIntBetween(0, arr.length).pipe(Effect.map((i) => arr[i]));
13
- const randomMs = (min, max) => Random.nextIntBetween(min, max).pipe(Effect.map((ms) => Duration.millis(ms)));
14
- const maybe = (pct, op) => Effect.gen(function* () {
15
- if ((yield* Random.nextIntBetween(0, 100)) < pct)
16
- yield* op;
17
- });
18
- // ---------------------------------------------------------------------------
19
- // Metrics
20
- // ---------------------------------------------------------------------------
21
- const httpRequestsTotal = Metric.counter("http.requests.total");
22
- const httpRequestDuration = Metric.histogram("http.request.duration_ms", MetricBoundaries.linear({ start: 0, width: 50, count: 20 }));
23
- const activeConnections = Metric.gauge("http.active_connections");
24
- const dbQueryDuration = Metric.histogram("db.query.duration_ms", MetricBoundaries.linear({ start: 0, width: 10, count: 25 }));
25
- const dbPoolSize = Metric.gauge("db.pool.active");
26
- const cacheHits = Metric.counter("cache.hits");
27
- const cacheMisses = Metric.counter("cache.misses");
28
- const queueDepth = Metric.gauge("queue.depth");
29
- const eventCount = Metric.counter("events.processed");
30
- const retryCount = Metric.counter("retry.total");
31
- const circuitBreakerTrips = Metric.counter("circuit_breaker.trips");
32
- const rateLimitRejections = Metric.counter("rate_limit.rejections");
33
- const serializationDuration = Metric.histogram("serialization.duration_ms", MetricBoundaries.linear({ start: 0, width: 5, count: 15 }));
34
- // ---------------------------------------------------------------------------
35
- // Simulated operations
36
- // ---------------------------------------------------------------------------
37
- const routes = [
38
- { method: "GET", path: "/api/users", handler: "UserController.list" },
39
- { method: "GET", path: "/api/users/:id", handler: "UserController.get" },
40
- { method: "POST", path: "/api/users", handler: "UserController.create" },
41
- { method: "PUT", path: "/api/users/:id", handler: "UserController.update" },
42
- { method: "DELETE", path: "/api/users/:id", handler: "UserController.delete" },
43
- { method: "GET", path: "/api/products", handler: "ProductController.list" },
44
- { method: "GET", path: "/api/products/:id", handler: "ProductController.get" },
45
- { method: "POST", path: "/api/orders", handler: "OrderController.create" },
46
- { method: "GET", path: "/api/orders/:id", handler: "OrderController.get" },
47
- { method: "PATCH", path: "/api/orders/:id/status", handler: "OrderController.updateStatus" },
48
- { method: "POST", path: "/api/auth/login", handler: "AuthController.login" },
49
- { method: "POST", path: "/api/auth/refresh", handler: "AuthController.refresh" },
50
- { method: "POST", path: "/api/auth/logout", handler: "AuthController.logout" },
51
- { method: "GET", path: "/api/search", handler: "SearchController.query" },
52
- { method: "GET", path: "/api/analytics/dashboard", handler: "AnalyticsController.dashboard" },
53
- { method: "POST", path: "/api/notifications/send", handler: "NotificationController.send" },
54
- { method: "POST", path: "/api/uploads/image", handler: "UploadController.image" },
55
- { method: "GET", path: "/api/health", handler: "HealthController.check" },
56
- { method: "GET", path: "/api/config", handler: "ConfigController.get" },
57
- { method: "POST", path: "/api/webhooks/stripe", handler: "WebhookController.stripe" },
58
- ];
59
- const dbQueries = [
60
- "SELECT * FROM users WHERE id = $1",
61
- "SELECT * FROM users ORDER BY created_at DESC LIMIT 20",
62
- "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
63
- "UPDATE users SET name = $1 WHERE id = $2",
64
- "SELECT p.*, c.name AS category FROM products p JOIN categories c ON p.category_id = c.id",
65
- "SELECT * FROM orders WHERE user_id = $1 ORDER BY created_at DESC",
66
- "INSERT INTO orders (user_id, total, status) VALUES ($1, $2, $3)",
67
- "SELECT u.*, COUNT(o.id) AS order_count FROM users u LEFT JOIN orders o ON u.id = o.id GROUP BY u.id",
68
- "DELETE FROM sessions WHERE expires_at < NOW()",
69
- "SELECT * FROM products WHERE tsv @@ plainto_tsquery($1) LIMIT 50",
70
- "SELECT o.*, json_agg(oi.*) AS items FROM orders o JOIN order_items oi ON o.id = oi.order_id WHERE o.id = $1 GROUP BY o.id",
71
- "WITH ranked AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY sales DESC) rn FROM products) SELECT * FROM ranked WHERE rn <= 5",
72
- "UPDATE inventory SET quantity = quantity - $1 WHERE product_id = $2 AND quantity >= $1 RETURNING quantity",
73
- ];
74
- const cacheKeys = [
75
- "user:profile:42",
76
- "user:profile:108",
77
- "product:listing:page:1",
78
- "product:detail:77",
79
- "session:abc123",
80
- "rate_limit:192.168.1.1",
81
- "search:results:shoes",
82
- "config:feature_flags",
83
- "analytics:dashboard:daily",
84
- "inventory:stock:sku_4421",
85
- "cart:user:42",
86
- ];
87
- const errorMessages = [
88
- "connection refused: upstream timeout after 30s",
89
- "UNIQUE constraint failed: users.email",
90
- "rate limit exceeded for client 10.0.3.44",
91
- "invalid JWT: token expired at 2025-12-01T00:00:00Z",
92
- "payment gateway returned 502",
93
- "deadlock detected on table orders",
94
- "request body exceeds 10MB limit",
95
- "foreign key constraint: order references missing user",
96
- "TLS handshake timeout with payment-service:443",
97
- "DNS resolution failed for analytics.internal.svc",
98
- ];
99
- // ---------------------------------------------------------------------------
100
- // Errors
101
- // ---------------------------------------------------------------------------
102
- class DatabaseError extends Data.TaggedError("DatabaseError") {
103
- }
104
- class AuthenticationError extends Data.TaggedError("AuthenticationError") {
105
- }
106
- class ExternalServiceError extends Data.TaggedError("ExternalServiceError") {
107
- }
108
- class TimeoutError extends Data.TaggedError("TimeoutError") {
109
- }
110
- class ValidationError extends Data.TaggedError("ValidationError") {
111
- }
112
- class TaskError extends Data.TaggedError("TaskError") {
113
- }
114
- class HttpError extends Data.TaggedError("HttpError") {
115
- }
116
- class RateLimitError extends Data.TaggedError("RateLimitError") {
117
- }
118
- class CircuitBreakerError extends Data.TaggedError("CircuitBreakerError") {
119
- }
120
- // ---------------------------------------------------------------------------
121
- // Leaf-level spans
122
- // ---------------------------------------------------------------------------
123
- const simulateDnsResolve = Effect.gen(function* () {
124
- const hosts = [
125
- "db-primary.internal",
126
- "cache-01.internal",
127
- "payment-service.prod",
128
- "queue.internal",
129
- "analytics.internal.svc",
130
- ];
131
- const host = yield* pick(hosts);
132
- yield* Effect.annotateCurrentSpan("dns.host", host);
133
- yield* Effect.sleep(yield* randomMs(0, 5));
134
- if ((yield* Random.nextIntBetween(0, 100)) < 2) {
135
- return yield* Effect.fail(new TimeoutError({ operation: `dns.resolve(${host})`, durationMs: 5000 }));
136
- }
137
- }).pipe(Effect.withSpan("dns.resolve"));
138
- const simulateTlsHandshake = Effect.gen(function* () {
139
- yield* Effect.sleep(yield* randomMs(2, 20));
140
- yield* Effect.annotateCurrentSpan("tls.version", "1.3");
141
- yield* Effect.annotateCurrentSpan("tls.cipher", "TLS_AES_256_GCM_SHA384");
142
- if ((yield* Random.nextIntBetween(0, 100)) < 1) {
143
- return yield* Effect.fail(new TimeoutError({ operation: "tls.handshake", durationMs: 10000 }));
144
- }
145
- }).pipe(Effect.withSpan("tls.handshake"));
146
- const simulateConnectionPoolAcquire = Effect.gen(function* () {
147
- const pool = yield* Random.nextIntBetween(1, 20);
148
- const maxPool = 20;
149
- yield* Effect.annotateCurrentSpan("pool.active", pool);
150
- yield* Effect.annotateCurrentSpan("pool.max", maxPool);
151
- yield* dbPoolSize.pipe(Metric.set(pool));
152
- yield* Effect.sleep(yield* randomMs(0, pool > 15 ? 50 : 5));
153
- if (pool >= 19 && (yield* Random.nextIntBetween(0, 100)) < 30) {
154
- return yield* Effect.die(new DatabaseError({ query: "", reason: "connection pool exhausted" }));
155
- }
156
- }).pipe(Effect.withSpan("db.pool.acquire"));
157
- const simulateConnectionPoolRelease = Effect.gen(function* () {
158
- yield* Effect.sleep(yield* randomMs(0, 1));
159
- }).pipe(Effect.withSpan("db.pool.release"));
160
- const simulateQueryParse = Effect.gen(function* () {
161
- yield* Effect.sleep(yield* randomMs(0, 3));
162
- yield* Effect.annotateCurrentSpan("db.parse.cached", (yield* Random.nextIntBetween(0, 100)) < 80);
163
- }).pipe(Effect.withSpan("db.query.parse"));
164
- const simulateQueryExecute = Effect.gen(function* () {
165
- const query = yield* pick(dbQueries);
166
- const delay = yield* randomMs(1, 80);
167
- yield* Effect.annotateCurrentSpan("db.statement", query);
168
- yield* Metric.update(dbQueryDuration, Math.round(Duration.toMillis(delay)));
169
- yield* Effect.sleep(delay);
170
- const roll = yield* Random.nextIntBetween(0, 100);
171
- if (roll < 2) {
172
- return yield* Effect.fail(new DatabaseError({ query, reason: "deadlock detected on table orders" }));
173
- }
174
- if (roll < 4) {
175
- return yield* Effect.fail(new TimeoutError({
176
- operation: "db.query.execute",
177
- durationMs: Math.round(Duration.toMillis(delay)),
178
- }));
179
- }
180
- }).pipe(Effect.withSpan("db.query.execute"));
181
- const simulateResultDeserialization = Effect.gen(function* () {
182
- const rowCount = yield* Random.nextIntBetween(0, 500);
183
- yield* Effect.annotateCurrentSpan("db.rows", rowCount);
184
- yield* Effect.sleep(yield* randomMs(0, rowCount > 100 ? 15 : 3));
185
- }).pipe(Effect.withSpan("db.result.deserialize"));
186
- const simulateDbQuery = Effect.gen(function* () {
187
- yield* simulateConnectionPoolAcquire;
188
- yield* simulateQueryParse;
189
- yield* simulateQueryExecute;
190
- yield* simulateResultDeserialization;
191
- yield* simulateConnectionPoolRelease;
192
- }).pipe(Effect.withSpan("db.query"));
193
- const simulateCacheSerialize = Effect.gen(function* () {
194
- const ms = yield* Random.nextIntBetween(0, 5);
195
- yield* Metric.update(serializationDuration, ms);
196
- yield* Effect.sleep(Duration.millis(ms));
197
- }).pipe(Effect.withSpan("cache.serialize"));
198
- const simulateCacheDeserialize = Effect.gen(function* () {
199
- const ms = yield* Random.nextIntBetween(0, 4);
200
- yield* Metric.update(serializationDuration, ms);
201
- yield* Effect.sleep(Duration.millis(ms));
202
- }).pipe(Effect.withSpan("cache.deserialize"));
203
- const simulateCache = Effect.gen(function* () {
204
- const key = yield* pick(cacheKeys);
205
- const hit = (yield* Random.nextIntBetween(0, 100)) < 75;
206
- yield* Effect.annotateCurrentSpan("cache.key", key);
207
- yield* Effect.annotateCurrentSpan("cache.hit", hit);
208
- yield* Effect.sleep(yield* randomMs(0, 3));
209
- if (hit) {
210
- yield* Metric.increment(cacheHits);
211
- yield* simulateCacheDeserialize;
212
- yield* Effect.logDebug(`cache hit: ${key}`);
213
- }
214
- else {
215
- yield* Metric.increment(cacheMisses);
216
- yield* Effect.logDebug(`cache miss: ${key}`);
217
- }
218
- }).pipe(Effect.withSpan("cache.lookup"));
219
- const simulateTokenDecode = Effect.gen(function* () {
220
- yield* Effect.sleep(yield* randomMs(0, 2));
221
- yield* Effect.annotateCurrentSpan("jwt.alg", "RS256");
222
- }).pipe(Effect.withSpan("jwt.decode"));
223
- const simulateTokenVerify = Effect.gen(function* () {
224
- yield* Effect.sleep(yield* randomMs(1, 8));
225
- const roll = yield* Random.nextIntBetween(0, 100);
226
- if (roll < 3) {
227
- return yield* Effect.fail(new AuthenticationError({ reason: "JWT expired at 2025-12-01T00:00:00Z" }));
228
- }
229
- if (roll < 5) {
230
- return yield* Effect.fail(new AuthenticationError({
231
- reason: "invalid signature",
232
- userId: "user_" + (yield* Random.nextIntBetween(100, 999)),
233
- }));
234
- }
235
- }).pipe(Effect.withSpan("jwt.verify"));
236
- const simulatePermissionCheck = Effect.gen(function* () {
237
- const roles = ["admin", "editor", "viewer", "moderator"];
238
- const role = yield* pick(roles);
239
- yield* Effect.annotateCurrentSpan("auth.role", role);
240
- yield* Effect.sleep(yield* randomMs(0, 3));
241
- if ((yield* Random.nextIntBetween(0, 100)) < 2) {
242
- return yield* Effect.fail(new AuthenticationError({ reason: `insufficient permissions for role: ${role}` }));
243
- }
244
- }).pipe(Effect.withSpan("auth.permission_check"));
245
- const simulateAuth = Effect.gen(function* () {
246
- yield* simulateTokenDecode;
247
- yield* simulateTokenVerify;
248
- yield* simulatePermissionCheck;
249
- yield* Effect.logDebug("token validated");
250
- }).pipe(Effect.withSpan("auth.validate"));
251
- const simulateRateLimit = Effect.gen(function* () {
252
- const ips = ["10.0.3.44", "192.168.1.1", "172.16.0.55", "10.0.7.12", "203.0.113.42"];
253
- const ip = yield* pick(ips);
254
- const remaining = yield* Random.nextIntBetween(0, 100);
255
- yield* Effect.annotateCurrentSpan("rate_limit.client_ip", ip);
256
- yield* Effect.annotateCurrentSpan("rate_limit.remaining", remaining);
257
- yield* Effect.sleep(yield* randomMs(0, 2));
258
- if (remaining < 3) {
259
- yield* Metric.increment(rateLimitRejections);
260
- yield* Effect.logWarning(`rate limit near threshold for ${ip}`);
261
- if ((yield* Random.nextIntBetween(0, 100)) < 40) {
262
- return yield* Effect.fail(new RateLimitError({ clientIp: ip, limit: 100 }));
263
- }
264
- }
265
- }).pipe(Effect.withSpan("middleware.rate_limit"));
266
- const simulateCors = Effect.gen(function* () {
267
- const origins = [
268
- "https://app.example.com",
269
- "https://admin.example.com",
270
- "https://mobile.example.com",
271
- "null",
272
- ];
273
- const origin = yield* pick(origins);
274
- yield* Effect.annotateCurrentSpan("cors.origin", origin);
275
- yield* Effect.sleep(yield* randomMs(0, 1));
276
- if (origin === "null") {
277
- yield* Effect.logWarning("CORS: rejected null origin");
278
- }
279
- }).pipe(Effect.withSpan("middleware.cors"));
280
- const simulateRequestParsing = Effect.gen(function* () {
281
- const contentTypes = [
282
- "application/json",
283
- "multipart/form-data",
284
- "application/x-www-form-urlencoded",
285
- "text/plain",
286
- ];
287
- const ct = yield* pick(contentTypes);
288
- yield* Effect.annotateCurrentSpan("http.content_type", ct);
289
- const bodySize = yield* Random.nextIntBetween(0, 50000);
290
- yield* Effect.annotateCurrentSpan("http.body_size", bodySize);
291
- yield* Effect.sleep(yield* randomMs(0, bodySize > 10000 ? 15 : 3));
292
- if (bodySize > 40000) {
293
- return yield* Effect.fail(new ValidationError({ field: "body", message: "request body exceeds 10MB limit" }));
294
- }
295
- if ((yield* Random.nextIntBetween(0, 100)) < 3) {
296
- return yield* Effect.fail(new ValidationError({ field: "body", message: "malformed JSON at position 42" }));
297
- }
298
- }).pipe(Effect.withSpan("http.parse_body"));
299
- const simulateInputValidation = Effect.gen(function* () {
300
- yield* Effect.sleep(yield* randomMs(0, 3));
301
- const fields = ["email", "name", "amount", "quantity", "phone", "address.zip"];
302
- if ((yield* Random.nextIntBetween(0, 100)) < 5) {
303
- const field = yield* pick(fields);
304
- return yield* Effect.fail(new ValidationError({ field, message: `invalid format for ${field}` }));
305
- }
306
- }).pipe(Effect.withSpan("validation.input"));
307
- const simulateResponseSerialization = Effect.gen(function* () {
308
- const formats = ["json", "msgpack", "protobuf"];
309
- const format = yield* pick(formats);
310
- yield* Effect.annotateCurrentSpan("serialization.format", format);
311
- const ms = yield* Random.nextIntBetween(0, 10);
312
- yield* Metric.update(serializationDuration, ms);
313
- yield* Effect.sleep(Duration.millis(ms));
314
- }).pipe(Effect.withSpan("http.serialize_response"));
315
- const simulateCompression = Effect.gen(function* () {
316
- const algos = ["gzip", "br", "none"];
317
- const algo = yield* pick(algos);
318
- yield* Effect.annotateCurrentSpan("compression.algorithm", algo);
319
- yield* Effect.sleep(yield* randomMs(0, algo === "none" ? 1 : 8));
320
- }).pipe(Effect.withSpan("http.compress"));
321
- const simulateAccessLog = Effect.gen(function* () {
322
- yield* Effect.sleep(yield* randomMs(0, 1));
323
- }).pipe(Effect.withSpan("middleware.access_log"));
324
- // ---------------------------------------------------------------------------
325
- // Composite sub-operations with deep nesting
326
- // ---------------------------------------------------------------------------
327
- const simulateCircuitBreaker = (inner, service) => Effect.gen(function* () {
328
- const failures = yield* Random.nextIntBetween(0, 10);
329
- yield* Effect.annotateCurrentSpan("circuit_breaker.service", service);
330
- yield* Effect.annotateCurrentSpan("circuit_breaker.failure_count", failures);
331
- if (failures >= 8) {
332
- yield* Metric.increment(circuitBreakerTrips);
333
- yield* Effect.logWarning(`circuit breaker OPEN for ${service}`);
334
- return yield* Effect.fail(new CircuitBreakerError({ service, failureCount: failures }));
335
- }
336
- yield* inner;
337
- }).pipe(Effect.withSpan("circuit_breaker"));
338
- const simulateRetry = (inner, opName) => Effect.gen(function* () {
339
- const maxRetries = 3;
340
- let attempt = 0;
341
- let succeeded = false;
342
- while (attempt < maxRetries && !succeeded) {
343
- attempt++;
344
- yield* Effect.annotateCurrentSpan("retry.attempt", attempt);
345
- const result = yield* inner.pipe(Effect.map(() => true), Effect.catchAll((e) => {
346
- if (attempt < maxRetries) {
347
- return Effect.gen(function* () {
348
- yield* Metric.increment(retryCount);
349
- yield* Effect.logWarning(`${opName} attempt ${attempt} failed, retrying`);
350
- yield* Effect.sleep(yield* randomMs(10, 50 * attempt));
351
- return false;
352
- });
353
- }
354
- return Effect.fail(e);
355
- }));
356
- succeeded = result;
357
- }
358
- }).pipe(Effect.withSpan("retry"));
359
- const simulateExternalCall = Effect.gen(function* () {
360
- const services = [
361
- "payment-service",
362
- "email-service",
363
- "notification-service",
364
- "inventory-service",
365
- "shipping-service",
366
- "tax-service",
367
- ];
368
- const service = yield* pick(services);
369
- yield* Effect.annotateCurrentSpan("peer.service", service);
370
- yield* simulateDnsResolve;
371
- yield* simulateTlsHandshake;
372
- const delay = yield* randomMs(10, 300);
373
- yield* Effect.annotateCurrentSpan("http.outgoing.duration_ms", Math.round(Duration.toMillis(delay)));
374
- yield* Effect.sleep(delay);
375
- const roll = yield* Random.nextIntBetween(0, 100);
376
- if (roll < 4) {
377
- yield* Effect.logError(`${service} responded with 503`);
378
- return yield* Effect.fail(new ExternalServiceError({ service, statusCode: 503, reason: "service unavailable" }));
379
- }
380
- if (roll < 6) {
381
- yield* Effect.logError(`${service} timed out after ${Math.round(Duration.toMillis(delay))}ms`);
382
- return yield* Effect.fail(new TimeoutError({
383
- operation: `${service} call`,
384
- durationMs: Math.round(Duration.toMillis(delay)),
385
- }));
386
- }
387
- if (roll < 8) {
388
- yield* Effect.logError(`${service} responded with 502`);
389
- return yield* Effect.fail(new ExternalServiceError({ service, statusCode: 502, reason: "bad gateway" }));
390
- }
391
- }).pipe(Effect.withSpan("http.outgoing"));
392
- const simulateExternalCallWithResilience = Effect.gen(function* () {
393
- const service = yield* pick([
394
- "payment-service",
395
- "email-service",
396
- "notification-service",
397
- "inventory-service",
398
- ]);
399
- yield* simulateCircuitBreaker(simulateRetry(simulateExternalCall, `external.${service}`), service);
400
- }).pipe(Effect.withSpan("external.resilient_call"));
401
- const simulateSearchQuery = Effect.gen(function* () {
402
- const terms = ["shoes", "laptop", "organic food", "headphones", "gift ideas"];
403
- const term = yield* pick(terms);
404
- yield* Effect.annotateCurrentSpan("search.query", term);
405
- yield* simulateCache;
406
- yield* Effect.gen(function* () {
407
- yield* Effect.sleep(yield* randomMs(5, 40));
408
- yield* Effect.annotateCurrentSpan("search.engine", "elasticsearch");
409
- yield* Effect.annotateCurrentSpan("search.index", "products_v3");
410
- const hits = yield* Random.nextIntBetween(0, 200);
411
- yield* Effect.annotateCurrentSpan("search.hits", hits);
412
- }).pipe(Effect.withSpan("search.execute"));
413
- yield* Effect.gen(function* () {
414
- yield* Effect.sleep(yield* randomMs(1, 10));
415
- yield* Effect.annotateCurrentSpan("search.boost", "relevance+recency");
416
- }).pipe(Effect.withSpan("search.rank"));
417
- yield* Effect.gen(function* () {
418
- yield* Effect.sleep(yield* randomMs(0, 5));
419
- }).pipe(Effect.withSpan("search.highlight"));
420
- }).pipe(Effect.withSpan("search.pipeline"));
421
- const simulateFileUpload = Effect.gen(function* () {
422
- const fileSize = yield* Random.nextIntBetween(1000, 5_000_000);
423
- yield* Effect.annotateCurrentSpan("upload.size_bytes", fileSize);
424
- yield* Effect.gen(function* () {
425
- yield* Effect.sleep(yield* randomMs(1, 10));
426
- const types = ["image/jpeg", "image/png", "application/pdf", "image/webp"];
427
- const mime = yield* pick(types);
428
- yield* Effect.annotateCurrentSpan("upload.mime", mime);
429
- if ((yield* Random.nextIntBetween(0, 100)) < 3) {
430
- return yield* Effect.fail(new ValidationError({ field: "file", message: "unsupported mime type" }));
431
- }
432
- }).pipe(Effect.withSpan("upload.validate_mime"));
433
- yield* Effect.gen(function* () {
434
- yield* Effect.sleep(yield* randomMs(0, 5));
435
- }).pipe(Effect.withSpan("upload.virus_scan"));
436
- yield* Effect.gen(function* () {
437
- yield* Effect.sleep(yield* randomMs(5, 50));
438
- yield* Effect.annotateCurrentSpan("upload.bucket", "user-uploads-prod");
439
- }).pipe(Effect.withSpan("upload.store_s3"));
440
- yield* Effect.gen(function* () {
441
- yield* simulateDbQuery;
442
- }).pipe(Effect.withSpan("upload.persist_metadata"));
443
- }).pipe(Effect.withSpan("upload.pipeline"));
444
- const simulateOrderWorkflow = Effect.gen(function* () {
445
- yield* Effect.annotateCurrentSpan("order.workflow", "create");
446
- yield* simulateInputValidation;
447
- yield* Effect.gen(function* () {
448
- yield* simulateDbQuery;
449
- yield* Effect.sleep(yield* randomMs(1, 10));
450
- }).pipe(Effect.withSpan("order.check_inventory"));
451
- yield* Effect.gen(function* () {
452
- yield* simulateExternalCallWithResilience;
453
- }).pipe(Effect.withSpan("order.process_payment"));
454
- yield* Effect.gen(function* () {
455
- yield* simulateDbQuery;
456
- }).pipe(Effect.withSpan("order.persist"));
457
- yield* Effect.gen(function* () {
458
- yield* simulateCache;
459
- yield* simulateCacheSerialize;
460
- }).pipe(Effect.withSpan("order.invalidate_cache"));
461
- yield* Effect.gen(function* () {
462
- yield* Effect.sleep(yield* randomMs(1, 10));
463
- yield* Effect.logInfo("order confirmation email queued");
464
- }).pipe(Effect.withSpan("order.queue_notification"));
465
- }).pipe(Effect.withSpan("order.workflow"));
466
- const simulateAnalyticsPipeline = Effect.gen(function* () {
467
- yield* Effect.gen(function* () {
468
- yield* simulateDbQuery;
469
- yield* simulateDbQuery;
470
- }).pipe(Effect.withSpan("analytics.fetch_raw"));
471
- yield* Effect.gen(function* () {
472
- yield* Effect.sleep(yield* randomMs(5, 30));
473
- yield* Effect.annotateCurrentSpan("analytics.aggregation", "time_series");
474
- }).pipe(Effect.withSpan("analytics.aggregate"));
475
- yield* Effect.gen(function* () {
476
- yield* simulateCache;
477
- }).pipe(Effect.withSpan("analytics.cache_result"));
478
- yield* Effect.gen(function* () {
479
- yield* Effect.sleep(yield* randomMs(2, 15));
480
- yield* Effect.annotateCurrentSpan("analytics.format", "dashboard_v2");
481
- }).pipe(Effect.withSpan("analytics.transform"));
482
- }).pipe(Effect.withSpan("analytics.pipeline"));
483
- // ---------------------------------------------------------------------------
484
- // Background tasks (also deeper now)
485
- // ---------------------------------------------------------------------------
486
- const simulateBackgroundTask = Effect.gen(function* () {
487
- const tasks = [
488
- "process-webhook",
489
- "send-email",
490
- "generate-report",
491
- "sync-inventory",
492
- "cleanup-sessions",
493
- "rebuild-search-index",
494
- "process-refund",
495
- "generate-invoice-pdf",
496
- "sync-crm",
497
- ];
498
- const task = yield* pick(tasks);
499
- yield* Effect.logInfo(`starting background task: ${task}`);
500
- yield* Effect.gen(function* () {
501
- yield* Effect.sleep(yield* randomMs(0, 5));
502
- yield* Effect.annotateCurrentSpan("task.priority", yield* pick(["low", "normal", "high", "critical"]));
503
- }).pipe(Effect.withSpan("task.dequeue"));
504
- yield* Effect.gen(function* () {
505
- yield* simulateDbQuery;
506
- }).pipe(Effect.withSpan("task.load_context"));
507
- yield* Effect.gen(function* () {
508
- yield* Effect.sleep(yield* randomMs(20, 300));
509
- const roll = yield* Random.nextIntBetween(0, 100);
510
- if (roll < 4) {
511
- return yield* Effect.fail(new TaskError({ task, reason: "execution exceeded 30s deadline" }));
512
- }
513
- if (roll < 7) {
514
- const err = yield* pick(errorMessages);
515
- yield* Effect.logError(`task ${task} failed: ${err}`);
516
- return yield* Effect.fail(new TaskError({ task, reason: err }));
517
- }
518
- if (roll < 9) {
519
- return yield* Effect.die(new TaskError({ task, reason: "out of memory" }));
520
- }
521
- }).pipe(Effect.withSpan("task.execute"));
522
- yield* maybe(60, Effect.gen(function* () {
523
- yield* simulateExternalCall;
524
- }).pipe(Effect.withSpan("task.external_dependency")));
525
- yield* Effect.gen(function* () {
526
- yield* simulateDbQuery;
527
- }).pipe(Effect.withSpan("task.persist_result"));
528
- yield* Effect.gen(function* () {
529
- yield* Effect.sleep(yield* randomMs(0, 3));
530
- }).pipe(Effect.withSpan("task.ack"));
531
- yield* Metric.increment(eventCount);
532
- yield* Effect.logInfo(`completed background task: ${task}`);
533
- }).pipe(Effect.withSpan("task.background"));
534
- // ---------------------------------------------------------------------------
535
- // Simulate a single HTTP request (deep middleware + handler pipeline)
536
- // ---------------------------------------------------------------------------
537
- const simulateRequest = Effect.gen(function* () {
538
- const route = yield* pick(routes);
539
- const statusCodes = [200, 200, 200, 200, 200, 201, 204, 301, 400, 401, 404, 500];
540
- yield* Metric.increment(httpRequestsTotal);
541
- yield* Metric.increment(activeConnections);
542
- const result = yield* Effect.gen(function* () {
543
- yield* Effect.annotateCurrentSpan("http.method", route.method);
544
- yield* Effect.annotateCurrentSpan("http.route", route.path);
545
- yield* Effect.annotateCurrentSpan("handler", route.handler);
546
- // middleware chain
547
- yield* simulateAccessLog;
548
- yield* simulateCors;
549
- yield* simulateRateLimit;
550
- yield* simulateRequestParsing;
551
- // auth (most routes)
552
- yield* maybe(70, simulateAuth);
553
- // handler body — pick a complex workflow or simple CRUD based on the route
554
- const handler = route.handler;
555
- if (handler === "OrderController.create" || handler === "OrderController.updateStatus") {
556
- yield* simulateOrderWorkflow;
557
- }
558
- else if (handler === "SearchController.query") {
559
- yield* simulateSearchQuery;
560
- }
561
- else if (handler === "UploadController.image") {
562
- yield* simulateFileUpload;
563
- }
564
- else if (handler === "AnalyticsController.dashboard") {
565
- yield* simulateAnalyticsPipeline;
566
- }
567
- else if (handler === "WebhookController.stripe") {
568
- yield* simulateInputValidation;
569
- yield* simulateExternalCallWithResilience;
570
- yield* simulateDbQuery;
571
- }
572
- else {
573
- // standard CRUD
574
- yield* maybe(50, simulateCache);
575
- yield* simulateDbQuery;
576
- yield* maybe(25, simulateExternalCall);
577
- yield* maybe(30, simulateDbQuery); // secondary query
578
- }
579
- // response pipeline
580
- yield* simulateResponseSerialization;
581
- yield* maybe(40, simulateCompression);
582
- const status = yield* pick(statusCodes);
583
- yield* Effect.annotateCurrentSpan("http.status_code", status);
584
- if (status >= 500) {
585
- const err = yield* pick(errorMessages);
586
- yield* Effect.logError(`${route.method} ${route.path} → ${status}: ${err}`);
587
- return yield* Effect.fail(new HttpError({
588
- method: route.method,
589
- path: route.path,
590
- statusCode: status,
591
- message: err,
592
- }));
593
- }
594
- if (status >= 400) {
595
- yield* Effect.logWarning(`${route.method} ${route.path} → ${status}`);
596
- }
597
- else {
598
- yield* Effect.logInfo(`${route.method} ${route.path} → ${status}`);
599
- }
600
- return status;
601
- }).pipe(Effect.withSpan(`${route.method} ${route.path}`));
602
- yield* activeConnections.pipe(Metric.set(0));
603
- const durationMs = yield* Random.nextIntBetween(5, 500);
604
- yield* Metric.update(httpRequestDuration, durationMs);
605
- return result;
606
- });
607
- // ---------------------------------------------------------------------------
608
- // Simulation loops
609
- // ---------------------------------------------------------------------------
610
- const requestLoop = Effect.gen(function* () {
611
- yield* Effect.logInfo("simulation: request loop started");
612
- yield* Effect.schedule(Effect.gen(function* () {
613
- const burst = yield* Random.nextIntBetween(1, 4);
614
- yield* Effect.forEach(Array.from({ length: burst }, (_, i) => i), () => simulateRequest.pipe(Effect.fork), { concurrency: "unbounded" });
615
- }), Schedule.jittered(Schedule.spaced("500 millis")));
616
- });
617
- const backgroundLoop = Effect.gen(function* () {
618
- yield* Effect.logInfo("simulation: background task loop started");
619
- yield* Effect.schedule(Effect.gen(function* () {
620
- yield* Effect.fork(simulateBackgroundTask);
621
- const depth = yield* Random.nextIntBetween(0, 25);
622
- yield* queueDepth.pipe(Metric.set(depth));
623
- }), Schedule.jittered(Schedule.spaced("2 seconds")));
624
- });
625
- // ---------------------------------------------------------------------------
626
- // Public API
627
- // ---------------------------------------------------------------------------
628
- export const layer = Layer.scopedDiscard(Effect.gen(function* () {
629
- yield* Effect.logInfo("simulation layer starting");
630
- yield* Effect.forkScoped(requestLoop);
631
- yield* Effect.forkScoped(backgroundLoop);
632
- yield* Effect.logInfo("simulation layer ready");
633
- }));
@@ -1,3 +0,0 @@
1
- export * as Console from "./Console.ts";
2
- export * as ConsoleStore from "./ConsoleStore.ts";
3
- export * as Simulation from "./Simulation.ts";
@@ -1,3 +0,0 @@
1
- export * as Console from "./Console.js";
2
- export * as ConsoleStore from "./ConsoleStore.js";
3
- export * as Simulation from "./Simulation.js";
@@ -1,10 +0,0 @@
1
- import * as Stream from "effect/Stream";
2
- import * as Route from "../../../Route.ts";
3
- declare const _default: import("../../../RouteMount.ts").RouteMount.Builder<{}, [Route.Route.Route<{
4
- method: "GET";
5
- format: "html";
6
- }, {}, string, never, never>, Route.Route.Route<{
7
- method: "GET";
8
- format: "text";
9
- }, {}, Stream.Stream<string, never, never>, never, never>]>;
10
- export default _default;