@beignet/core 0.0.2 → 0.0.4

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 (360) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/README.md +821 -30
  3. package/dist/application/index.d.ts +28 -2
  4. package/dist/application/index.d.ts.map +1 -1
  5. package/dist/application/index.js +140 -12
  6. package/dist/application/index.js.map +1 -1
  7. package/dist/client/client.d.ts +2 -2
  8. package/dist/client/client.d.ts.map +1 -1
  9. package/dist/client/client.js +136 -48
  10. package/dist/client/client.js.map +1 -1
  11. package/dist/client/error-messages.d.ts +14 -0
  12. package/dist/client/error-messages.d.ts.map +1 -0
  13. package/dist/client/error-messages.js +23 -0
  14. package/dist/client/error-messages.js.map +1 -0
  15. package/dist/client/index.d.ts +8 -4
  16. package/dist/client/index.d.ts.map +1 -1
  17. package/dist/client/index.js +6 -2
  18. package/dist/client/index.js.map +1 -1
  19. package/dist/client/types.d.ts +35 -5
  20. package/dist/client/types.d.ts.map +1 -1
  21. package/dist/client-only.d.ts +8 -0
  22. package/dist/client-only.d.ts.map +1 -0
  23. package/dist/client-only.js +8 -0
  24. package/dist/client-only.js.map +1 -0
  25. package/dist/config/index.d.ts +5 -5
  26. package/dist/config/index.d.ts.map +1 -1
  27. package/dist/config/index.js +2 -2
  28. package/dist/config/index.js.map +1 -1
  29. package/dist/contracts/catalog-errors.d.ts +27 -0
  30. package/dist/contracts/catalog-errors.d.ts.map +1 -0
  31. package/dist/contracts/catalog-errors.js +69 -0
  32. package/dist/contracts/catalog-errors.js.map +1 -0
  33. package/dist/contracts/contract-builder.d.ts +15 -12
  34. package/dist/contracts/contract-builder.d.ts.map +1 -1
  35. package/dist/contracts/contract-builder.js +15 -41
  36. package/dist/contracts/contract-builder.js.map +1 -1
  37. package/dist/contracts/contract-group.d.ts +11 -8
  38. package/dist/contracts/contract-group.d.ts.map +1 -1
  39. package/dist/contracts/contract-group.js +13 -40
  40. package/dist/contracts/contract-group.js.map +1 -1
  41. package/dist/contracts/contract-like.d.ts +1 -1
  42. package/dist/contracts/contract-like.d.ts.map +1 -1
  43. package/dist/contracts/index.d.ts +13 -9
  44. package/dist/contracts/index.d.ts.map +1 -1
  45. package/dist/contracts/index.js +9 -5
  46. package/dist/contracts/index.js.map +1 -1
  47. package/dist/contracts/openapi-meta.d.ts +48 -0
  48. package/dist/contracts/openapi-meta.d.ts.map +1 -1
  49. package/dist/contracts/openapi-meta.js +3 -0
  50. package/dist/contracts/openapi-meta.js.map +1 -1
  51. package/dist/contracts/path-template.d.ts +1 -1
  52. package/dist/contracts/path-template.js +2 -2
  53. package/dist/contracts/path-template.js.map +1 -1
  54. package/dist/contracts/schema-shape.d.ts +37 -0
  55. package/dist/contracts/schema-shape.d.ts.map +1 -0
  56. package/dist/contracts/schema-shape.js +61 -0
  57. package/dist/contracts/schema-shape.js.map +1 -0
  58. package/dist/contracts/success-status.d.ts +32 -0
  59. package/dist/contracts/success-status.d.ts.map +1 -0
  60. package/dist/contracts/success-status.js +18 -0
  61. package/dist/contracts/success-status.js.map +1 -0
  62. package/dist/contracts/types.d.ts +25 -5
  63. package/dist/contracts/types.d.ts.map +1 -1
  64. package/dist/contracts/types.js.map +1 -1
  65. package/dist/contracts/utils.d.ts +1 -1
  66. package/dist/contracts/utils.d.ts.map +1 -1
  67. package/dist/contracts/utils.js +1 -1
  68. package/dist/contracts/utils.js.map +1 -1
  69. package/dist/domain/events.d.ts +1 -1
  70. package/dist/domain/events.d.ts.map +1 -1
  71. package/dist/domain/events.js +1 -1
  72. package/dist/domain/events.js.map +1 -1
  73. package/dist/domain/index.d.ts +3 -3
  74. package/dist/domain/index.d.ts.map +1 -1
  75. package/dist/domain/index.js +3 -3
  76. package/dist/domain/index.js.map +1 -1
  77. package/dist/errors/catalog.d.ts +9 -1
  78. package/dist/errors/catalog.d.ts.map +1 -1
  79. package/dist/errors/catalog.js +7 -1
  80. package/dist/errors/catalog.js.map +1 -1
  81. package/dist/errors/http.d.ts +10 -0
  82. package/dist/errors/http.d.ts.map +1 -1
  83. package/dist/errors/http.js +11 -1
  84. package/dist/errors/http.js.map +1 -1
  85. package/dist/errors/index.d.ts +4 -4
  86. package/dist/errors/index.d.ts.map +1 -1
  87. package/dist/errors/index.js +4 -4
  88. package/dist/errors/index.js.map +1 -1
  89. package/dist/errors/response.d.ts +4 -1
  90. package/dist/errors/response.d.ts.map +1 -1
  91. package/dist/errors/response.js.map +1 -1
  92. package/dist/events/index.d.ts +10 -12
  93. package/dist/events/index.d.ts.map +1 -1
  94. package/dist/events/index.js +10 -10
  95. package/dist/events/index.js.map +1 -1
  96. package/dist/idempotency/index.d.ts +5 -3
  97. package/dist/idempotency/index.d.ts.map +1 -1
  98. package/dist/idempotency/index.js.map +1 -1
  99. package/dist/jobs/index.d.ts +148 -16
  100. package/dist/jobs/index.d.ts.map +1 -1
  101. package/dist/jobs/index.js +174 -14
  102. package/dist/jobs/index.js.map +1 -1
  103. package/dist/notifications/index.d.ts +14 -16
  104. package/dist/notifications/index.d.ts.map +1 -1
  105. package/dist/notifications/index.js +14 -14
  106. package/dist/notifications/index.js.map +1 -1
  107. package/dist/openapi/index.d.ts +8 -3
  108. package/dist/openapi/index.d.ts.map +1 -1
  109. package/dist/openapi/index.js +41 -29
  110. package/dist/openapi/index.js.map +1 -1
  111. package/dist/openapi/schema-introspector.d.ts +37 -0
  112. package/dist/openapi/schema-introspector.d.ts.map +1 -1
  113. package/dist/openapi/schema-introspector.js +23 -17
  114. package/dist/openapi/schema-introspector.js.map +1 -1
  115. package/dist/outbox/index.d.ts +18 -4
  116. package/dist/outbox/index.d.ts.map +1 -1
  117. package/dist/outbox/index.js +104 -4
  118. package/dist/outbox/index.js.map +1 -1
  119. package/dist/ports/audit.d.ts +56 -10
  120. package/dist/ports/audit.d.ts.map +1 -1
  121. package/dist/ports/audit.js +71 -3
  122. package/dist/ports/audit.js.map +1 -1
  123. package/dist/ports/auth.d.ts +92 -0
  124. package/dist/ports/auth.d.ts.map +1 -1
  125. package/dist/ports/auth.js +92 -0
  126. package/dist/ports/auth.js.map +1 -1
  127. package/dist/ports/events.d.ts +2 -2
  128. package/dist/ports/events.d.ts.map +1 -1
  129. package/dist/ports/index.d.ts +62 -33
  130. package/dist/ports/index.d.ts.map +1 -1
  131. package/dist/ports/index.js +28 -34
  132. package/dist/ports/index.js.map +1 -1
  133. package/dist/ports/policy.d.ts +32 -3
  134. package/dist/ports/policy.d.ts.map +1 -1
  135. package/dist/ports/policy.js +13 -2
  136. package/dist/ports/policy.js.map +1 -1
  137. package/dist/ports/testing.d.ts +1030 -2
  138. package/dist/ports/testing.d.ts.map +1 -1
  139. package/dist/ports/testing.js +1031 -1
  140. package/dist/ports/testing.js.map +1 -1
  141. package/dist/ports/unbound.d.ts +21 -0
  142. package/dist/ports/unbound.d.ts.map +1 -0
  143. package/dist/ports/unbound.js +57 -0
  144. package/dist/ports/unbound.js.map +1 -0
  145. package/dist/ports/unit-of-work.d.ts +1 -1
  146. package/dist/ports/unit-of-work.d.ts.map +1 -1
  147. package/dist/ports/unit-of-work.js +1 -1
  148. package/dist/ports/unit-of-work.js.map +1 -1
  149. package/dist/providers/index.d.ts +3 -2
  150. package/dist/providers/index.d.ts.map +1 -1
  151. package/dist/providers/index.js +3 -2
  152. package/dist/providers/index.js.map +1 -1
  153. package/dist/providers/instrumentation.d.ts +46 -5
  154. package/dist/providers/instrumentation.d.ts.map +1 -1
  155. package/dist/providers/instrumentation.js +25 -6
  156. package/dist/providers/instrumentation.js.map +1 -1
  157. package/dist/providers/metadata.d.ts +39 -0
  158. package/dist/providers/metadata.d.ts.map +1 -0
  159. package/dist/providers/metadata.js +169 -0
  160. package/dist/providers/metadata.js.map +1 -0
  161. package/dist/providers/provider.d.ts +114 -9
  162. package/dist/providers/provider.d.ts.map +1 -1
  163. package/dist/providers/provider.js +3 -20
  164. package/dist/providers/provider.js.map +1 -1
  165. package/dist/schedules/index.d.ts +94 -13
  166. package/dist/schedules/index.d.ts.map +1 -1
  167. package/dist/schedules/index.js +66 -12
  168. package/dist/schedules/index.js.map +1 -1
  169. package/dist/server/audit-context.d.ts +29 -0
  170. package/dist/server/audit-context.d.ts.map +1 -0
  171. package/dist/server/audit-context.js +44 -0
  172. package/dist/server/audit-context.js.map +1 -0
  173. package/dist/server/context.d.ts +141 -0
  174. package/dist/server/context.d.ts.map +1 -0
  175. package/dist/server/context.js +39 -0
  176. package/dist/server/context.js.map +1 -0
  177. package/dist/server/contract-like.d.ts +1 -1
  178. package/dist/server/contract-like.d.ts.map +1 -1
  179. package/dist/server/contract-like.js +1 -1
  180. package/dist/server/contract-like.js.map +1 -1
  181. package/dist/server/health.d.ts +2 -2
  182. package/dist/server/health.d.ts.map +1 -1
  183. package/dist/server/hooks/auth.d.ts +89 -65
  184. package/dist/server/hooks/auth.d.ts.map +1 -1
  185. package/dist/server/hooks/auth.js +84 -55
  186. package/dist/server/hooks/auth.js.map +1 -1
  187. package/dist/server/hooks/cors.d.ts +1 -1
  188. package/dist/server/hooks/cors.d.ts.map +1 -1
  189. package/dist/server/hooks/errors.d.ts +2 -2
  190. package/dist/server/hooks/errors.d.ts.map +1 -1
  191. package/dist/server/hooks/errors.js +2 -2
  192. package/dist/server/hooks/errors.js.map +1 -1
  193. package/dist/server/hooks/idempotency.d.ts +78 -0
  194. package/dist/server/hooks/idempotency.d.ts.map +1 -0
  195. package/dist/server/hooks/idempotency.js +154 -0
  196. package/dist/server/hooks/idempotency.js.map +1 -0
  197. package/dist/server/hooks/index.d.ts +8 -7
  198. package/dist/server/hooks/index.d.ts.map +1 -1
  199. package/dist/server/hooks/index.js +6 -5
  200. package/dist/server/hooks/index.js.map +1 -1
  201. package/dist/server/hooks/logging.d.ts +2 -2
  202. package/dist/server/hooks/logging.d.ts.map +1 -1
  203. package/dist/server/hooks/logging.js +1 -1
  204. package/dist/server/hooks/logging.js.map +1 -1
  205. package/dist/server/hooks/rate-limit.d.ts +25 -7
  206. package/dist/server/hooks/rate-limit.d.ts.map +1 -1
  207. package/dist/server/hooks/rate-limit.js +47 -12
  208. package/dist/server/hooks/rate-limit.js.map +1 -1
  209. package/dist/server/hooks.d.ts +1 -1
  210. package/dist/server/hooks.d.ts.map +1 -1
  211. package/dist/server/hooks.js +1 -1
  212. package/dist/server/hooks.js.map +1 -1
  213. package/dist/server/http.d.ts +84 -6
  214. package/dist/server/http.d.ts.map +1 -1
  215. package/dist/server/index.d.ts +36 -12
  216. package/dist/server/index.d.ts.map +1 -1
  217. package/dist/server/index.js +24 -8
  218. package/dist/server/index.js.map +1 -1
  219. package/dist/server/instrumentation.d.ts +108 -0
  220. package/dist/server/instrumentation.d.ts.map +1 -0
  221. package/dist/server/instrumentation.js +297 -0
  222. package/dist/server/instrumentation.js.map +1 -0
  223. package/dist/server/openapi.d.ts +3 -3
  224. package/dist/server/openapi.d.ts.map +1 -1
  225. package/dist/server/openapi.js +1 -1
  226. package/dist/server/openapi.js.map +1 -1
  227. package/dist/server/providers/index.d.ts +3 -3
  228. package/dist/server/providers/index.d.ts.map +1 -1
  229. package/dist/server/providers/index.js +3 -3
  230. package/dist/server/providers/index.js.map +1 -1
  231. package/dist/server/providers/loadProviderConfig.d.ts +2 -2
  232. package/dist/server/providers/loadProviderConfig.d.ts.map +1 -1
  233. package/dist/server/providers/loadProviderConfig.js +2 -2
  234. package/dist/server/providers/loadProviderConfig.js.map +1 -1
  235. package/dist/server/request-context.d.ts +67 -0
  236. package/dist/server/request-context.d.ts.map +1 -0
  237. package/dist/server/request-context.js +79 -0
  238. package/dist/server/request-context.js.map +1 -0
  239. package/dist/server/server-context.d.ts +38 -0
  240. package/dist/server/server-context.d.ts.map +1 -0
  241. package/dist/server/server-context.js +38 -0
  242. package/dist/server/server-context.js.map +1 -0
  243. package/dist/server/server.d.ts +148 -35
  244. package/dist/server/server.d.ts.map +1 -1
  245. package/dist/server/server.js +482 -145
  246. package/dist/server/server.js.map +1 -1
  247. package/dist/server/types.d.ts +2 -2
  248. package/dist/server/types.d.ts.map +1 -1
  249. package/dist/server/types.js +2 -2
  250. package/dist/server/types.js.map +1 -1
  251. package/dist/server/use-case-route.d.ts +263 -0
  252. package/dist/server/use-case-route.d.ts.map +1 -0
  253. package/dist/server/use-case-route.js +77 -0
  254. package/dist/server/use-case-route.js.map +1 -0
  255. package/dist/server-only.d.ts +8 -0
  256. package/dist/server-only.d.ts.map +1 -0
  257. package/dist/server-only.js +8 -0
  258. package/dist/server-only.js.map +1 -0
  259. package/dist/tasks/index.d.ts +139 -0
  260. package/dist/tasks/index.d.ts.map +1 -0
  261. package/dist/tasks/index.js +98 -0
  262. package/dist/tasks/index.js.map +1 -0
  263. package/dist/testing/index.d.ts +611 -5
  264. package/dist/testing/index.d.ts.map +1 -1
  265. package/dist/testing/index.js +434 -4
  266. package/dist/testing/index.js.map +1 -1
  267. package/dist/tracing/index.d.ts +89 -0
  268. package/dist/tracing/index.d.ts.map +1 -0
  269. package/dist/tracing/index.js +101 -0
  270. package/dist/tracing/index.js.map +1 -0
  271. package/dist/uploads/client.d.ts +278 -0
  272. package/dist/uploads/client.d.ts.map +1 -0
  273. package/dist/uploads/client.js +428 -0
  274. package/dist/uploads/client.js.map +1 -0
  275. package/dist/uploads/index.d.ts +361 -0
  276. package/dist/uploads/index.d.ts.map +1 -0
  277. package/dist/uploads/index.js +543 -0
  278. package/dist/uploads/index.js.map +1 -0
  279. package/package.json +34 -3
  280. package/src/application/index.ts +193 -10
  281. package/src/client/client.ts +148 -150
  282. package/src/client/error-messages.ts +35 -0
  283. package/src/client/index.ts +12 -4
  284. package/src/client/types.ts +44 -5
  285. package/src/client-only.ts +7 -0
  286. package/src/config/index.ts +6 -6
  287. package/src/contracts/catalog-errors.ts +115 -0
  288. package/src/contracts/contract-builder.ts +39 -76
  289. package/src/contracts/contract-group.ts +33 -68
  290. package/src/contracts/contract-like.ts +1 -1
  291. package/src/contracts/index.ts +24 -11
  292. package/src/contracts/openapi-meta.ts +55 -0
  293. package/src/contracts/path-template.ts +2 -2
  294. package/src/contracts/schema-shape.ts +75 -0
  295. package/src/contracts/success-status.ts +68 -0
  296. package/src/contracts/types.ts +32 -5
  297. package/src/contracts/utils.ts +5 -2
  298. package/src/domain/events.ts +6 -2
  299. package/src/domain/index.ts +3 -3
  300. package/src/errors/catalog.ts +9 -1
  301. package/src/errors/http.ts +11 -1
  302. package/src/errors/index.ts +4 -4
  303. package/src/errors/response.ts +4 -1
  304. package/src/events/index.ts +12 -26
  305. package/src/idempotency/index.ts +5 -3
  306. package/src/jobs/index.ts +340 -29
  307. package/src/notifications/index.ts +17 -27
  308. package/src/openapi/index.ts +73 -38
  309. package/src/openapi/schema-introspector.ts +68 -17
  310. package/src/outbox/index.ts +151 -6
  311. package/src/ports/audit.ts +120 -11
  312. package/src/ports/auth.ts +132 -0
  313. package/src/ports/events.ts +2 -2
  314. package/src/ports/index.ts +104 -35
  315. package/src/ports/policy.ts +50 -3
  316. package/src/ports/testing.ts +2220 -33
  317. package/src/ports/unbound.ts +64 -0
  318. package/src/ports/unit-of-work.ts +6 -2
  319. package/src/providers/index.ts +16 -3
  320. package/src/providers/instrumentation.ts +93 -8
  321. package/src/providers/metadata.ts +234 -0
  322. package/src/providers/provider.ts +168 -9
  323. package/src/schedules/index.ts +173 -23
  324. package/src/server/audit-context.ts +45 -0
  325. package/src/server/context.ts +224 -0
  326. package/src/server/contract-like.ts +1 -1
  327. package/src/server/health.ts +2 -2
  328. package/src/server/hooks/auth.ts +175 -158
  329. package/src/server/hooks/cors.ts +1 -1
  330. package/src/server/hooks/errors.ts +7 -4
  331. package/src/server/hooks/idempotency.ts +263 -0
  332. package/src/server/hooks/index.ts +15 -12
  333. package/src/server/hooks/logging.ts +3 -3
  334. package/src/server/hooks/rate-limit.ts +85 -17
  335. package/src/server/hooks.ts +1 -1
  336. package/src/server/http.ts +112 -6
  337. package/src/server/index.ts +63 -12
  338. package/src/server/instrumentation.ts +470 -0
  339. package/src/server/openapi.ts +4 -4
  340. package/src/server/providers/index.ts +6 -3
  341. package/src/server/providers/loadProviderConfig.ts +4 -4
  342. package/src/server/request-context.ts +116 -0
  343. package/src/server/server-context.ts +44 -0
  344. package/src/server/server.ts +1045 -229
  345. package/src/server/types.ts +2 -2
  346. package/src/server/use-case-route.ts +430 -0
  347. package/src/server-only.ts +7 -0
  348. package/src/tasks/index.ts +275 -0
  349. package/src/testing/index.ts +1153 -6
  350. package/src/tracing/index.ts +176 -0
  351. package/src/uploads/client.ts +861 -0
  352. package/src/uploads/index.ts +1071 -0
  353. package/dist/ports/mailer.d.ts +0 -6
  354. package/dist/ports/mailer.d.ts.map +0 -1
  355. package/dist/ports/mailer.js +0 -2
  356. package/dist/ports/mailer.js.map +0 -1
  357. package/dist/ports/schedules.d.ts +0 -9
  358. package/dist/ports/schedules.d.ts.map +0 -1
  359. package/dist/ports/schedules.js +0 -2
  360. package/dist/ports/schedules.js.map +0 -1
@@ -1,4 +1,12 @@
1
1
  import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+ import {
3
+ type ProviderInstrumentationEventInput,
4
+ resolveProviderInstrumentationPort,
5
+ } from "../providers/instrumentation.js";
6
+ import {
7
+ createChildTraceContext,
8
+ type TraceContextInput,
9
+ } from "../tracing/index.js";
2
10
 
3
11
  /**
4
12
  * Any Standard Schema compatible validator.
@@ -315,6 +323,21 @@ function createUseCaseEventHelpers<Emits extends readonly DomainEventLike[]>(
315
323
  */
316
324
  export type UseCaseKind = "command" | "query";
317
325
 
326
+ /**
327
+ * Symbol key for the trusted run path attached to finalized use cases.
328
+ *
329
+ * The server route binder calls this method instead of `run` when the route's
330
+ * input was already validated by the exact same schema object at the HTTP
331
+ * boundary. It behaves like `run` but skips the input parse; output
332
+ * validation, instrumentation, events, and `onRun` are unchanged.
333
+ *
334
+ * The key uses `Symbol.for(...)` so the binder and the application builder
335
+ * agree on the key even across separately bundled copies of the package.
336
+ */
337
+ export const USE_CASE_TRUSTED_RUN: unique symbol = Symbol.for(
338
+ "beignet.useCase.trustedRun",
339
+ );
340
+
318
341
  /**
319
342
  * Finalized use case definition.
320
343
  *
@@ -390,10 +413,24 @@ export interface UseCaseRunEvent<Ctx> {
390
413
  */
391
414
  export interface CreateUseCaseOptions<Ctx> {
392
415
  /**
393
- * Optional instrumentation hook called on use case start, end, and error.
416
+ * Optional app-owned observer called on use case start, end, and error.
417
+ *
418
+ * Observers run in addition to the built-in instrumentation.
394
419
  */
395
420
  onRun?: (event: UseCaseRunEvent<Ctx>) => void;
396
421
 
422
+ /**
423
+ * Built-in use-case instrumentation.
424
+ *
425
+ * By default every run records `usecase` lifecycle events (plus `error`
426
+ * events for failed runs) into the provider instrumentation port resolved
427
+ * from `ctx.ports` (`ports.instrumentation`, then `ports.devtools`). When no
428
+ * port is installed, runs stay silent. Pass `false` to opt out.
429
+ *
430
+ * @default true
431
+ */
432
+ instrumentation?: boolean;
433
+
397
434
  /**
398
435
  * Enable or disable schema validation for use case boundaries.
399
436
  *
@@ -423,6 +460,120 @@ function normalizeValidationOptions(
423
460
  return { input: true, output: true };
424
461
  }
425
462
 
463
+ type UseCaseRunInstrumentation = {
464
+ end(durationMs: number): void;
465
+ error(durationMs: number, error: unknown): void;
466
+ };
467
+
468
+ function getInstrumentationRequestId(ctx: unknown): string | undefined {
469
+ if (!ctx || typeof ctx !== "object") return undefined;
470
+ const requestId = (ctx as { requestId?: unknown }).requestId;
471
+ return typeof requestId === "string" ? requestId : undefined;
472
+ }
473
+
474
+ function getInstrumentationTrace(ctx: unknown): TraceContextInput | undefined {
475
+ if (!ctx || typeof ctx !== "object") return undefined;
476
+ const context = ctx as TraceContextInput;
477
+ if (!context.traceId && !context.spanId && !context.traceparent) {
478
+ return undefined;
479
+ }
480
+ return {
481
+ traceId: context.traceId,
482
+ spanId: context.spanId,
483
+ parentSpanId: context.parentSpanId,
484
+ traceparent: context.traceparent,
485
+ };
486
+ }
487
+
488
+ function getRunErrorMessage(error: unknown): string {
489
+ if (error instanceof Error) return error.message;
490
+ if (typeof error === "string") return error;
491
+ return "Unknown error";
492
+ }
493
+
494
+ /**
495
+ * Start built-in instrumentation for one use-case run.
496
+ *
497
+ * The instrumentation port is resolved from `ctx.ports` per run so use cases
498
+ * stay decoupled from any specific sink. Runs without a resolved port stay
499
+ * silent.
500
+ */
501
+ function startUseCaseRunInstrumentation(args: {
502
+ ctx: unknown;
503
+ name: string;
504
+ kind: UseCaseKind;
505
+ }): UseCaseRunInstrumentation | undefined {
506
+ const ports =
507
+ args.ctx && typeof args.ctx === "object"
508
+ ? (args.ctx as { ports?: unknown }).ports
509
+ : undefined;
510
+ const port = resolveProviderInstrumentationPort(
511
+ ports as Parameters<typeof resolveProviderInstrumentationPort>[0],
512
+ );
513
+ if (!port) return undefined;
514
+
515
+ const useCasesEnabled = port.isWatcherEnabled?.("useCases") ?? true;
516
+ const errorsEnabled = port.isWatcherEnabled?.("errors") ?? true;
517
+ if (!useCasesEnabled && !errorsEnabled) return undefined;
518
+
519
+ const requestId = getInstrumentationRequestId(args.ctx);
520
+ const trace = createChildTraceContext(
521
+ getInstrumentationTrace(args.ctx) ?? {},
522
+ );
523
+
524
+ const record = (event: ProviderInstrumentationEventInput) => {
525
+ try {
526
+ port.record(event);
527
+ } catch {
528
+ // Instrumentation sinks must never affect use-case behavior.
529
+ }
530
+ };
531
+
532
+ const recordPhase = (
533
+ phase: "start" | "end" | "error",
534
+ durationMs?: number,
535
+ error?: unknown,
536
+ ) => {
537
+ if (useCasesEnabled) {
538
+ record({
539
+ type: "usecase",
540
+ requestId,
541
+ traceId: trace.traceId,
542
+ spanId: trace.spanId,
543
+ parentSpanId: trace.parentSpanId,
544
+ traceparent: trace.traceparent,
545
+ name: args.name,
546
+ kind: args.kind,
547
+ phase,
548
+ durationMs,
549
+ error: phase === "error" ? getRunErrorMessage(error) : undefined,
550
+ });
551
+ }
552
+
553
+ if (phase === "error" && errorsEnabled) {
554
+ record({
555
+ type: "error",
556
+ requestId,
557
+ traceId: trace.traceId,
558
+ spanId: trace.spanId,
559
+ parentSpanId: trace.parentSpanId,
560
+ traceparent: trace.traceparent,
561
+ message: getRunErrorMessage(error),
562
+ stack: error instanceof Error ? error.stack : undefined,
563
+ useCaseName: args.name,
564
+ owner: "route",
565
+ });
566
+ }
567
+ };
568
+
569
+ recordPhase("start");
570
+
571
+ return {
572
+ end: (durationMs) => recordPhase("end", durationMs),
573
+ error: (durationMs, error) => recordPhase("error", durationMs, error),
574
+ };
575
+ }
576
+
426
577
  /**
427
578
  * Internal configuration for the use case builder
428
579
  */
@@ -464,6 +615,7 @@ class UseCaseBuilder<
464
615
  input: true,
465
616
  output: true,
466
617
  },
618
+ private readonly instrumented: boolean = true,
467
619
  ) {}
468
620
 
469
621
  /**
@@ -479,6 +631,7 @@ class UseCaseBuilder<
479
631
  },
480
632
  this.onRun,
481
633
  this.validation,
634
+ this.instrumented,
482
635
  );
483
636
  }
484
637
 
@@ -495,6 +648,7 @@ class UseCaseBuilder<
495
648
  },
496
649
  this.onRun,
497
650
  this.validation,
651
+ this.instrumented,
498
652
  );
499
653
  }
500
654
 
@@ -511,6 +665,7 @@ class UseCaseBuilder<
511
665
  },
512
666
  this.onRun,
513
667
  this.validation,
668
+ this.instrumented,
514
669
  );
515
670
  }
516
671
 
@@ -544,6 +699,7 @@ class UseCaseBuilder<
544
699
  const useCaseName = this.config.name;
545
700
  const useCaseKind = this.config.kind;
546
701
  const onRun = this.onRun;
702
+ const instrumented = this.instrumented;
547
703
  const inputSchema = this.config.input as Extract<
548
704
  InputSchema,
549
705
  StandardSchemaV1
@@ -558,7 +714,7 @@ class UseCaseBuilder<
558
714
  this.config.emits,
559
715
  );
560
716
 
561
- const runFn = async (
717
+ const execute = async (
562
718
  args: InputSchema extends StandardSchemaV1
563
719
  ? OutputSchema extends StandardSchemaV1
564
720
  ? {
@@ -567,8 +723,16 @@ class UseCaseBuilder<
567
723
  }
568
724
  : never
569
725
  : never,
726
+ parseInput: boolean,
570
727
  ) => {
571
728
  const startedAt = Date.now();
729
+ const instrumentation = instrumented
730
+ ? startUseCaseRunInstrumentation({
731
+ ctx: args.ctx,
732
+ name: useCaseName,
733
+ kind: useCaseKind,
734
+ })
735
+ : undefined;
572
736
  onRun?.({
573
737
  name: useCaseName,
574
738
  kind: useCaseKind,
@@ -577,9 +741,10 @@ class UseCaseBuilder<
577
741
  });
578
742
 
579
743
  try {
580
- const parsedInput = validation.input
581
- ? await parseSchema(inputSchema, args.input, useCaseName, "input")
582
- : (args.input as SchemaOutput<InputSchema>);
744
+ const parsedInput =
745
+ parseInput && validation.input
746
+ ? await parseSchema(inputSchema, args.input, useCaseName, "input")
747
+ : (args.input as SchemaOutput<InputSchema>);
583
748
 
584
749
  const rawResult = await fn({
585
750
  ctx: args.ctx,
@@ -591,21 +756,25 @@ class UseCaseBuilder<
591
756
  ? await parseSchema(outputSchema, rawResult, useCaseName, "output")
592
757
  : (rawResult as SchemaOutput<OutputSchema>);
593
758
 
759
+ const durationMs = Date.now() - startedAt;
760
+ instrumentation?.end(durationMs);
594
761
  onRun?.({
595
762
  name: useCaseName,
596
763
  kind: useCaseKind,
597
764
  phase: "end",
598
- durationMs: Date.now() - startedAt,
765
+ durationMs,
599
766
  ctx: args.ctx,
600
767
  });
601
768
 
602
769
  return result;
603
770
  } catch (err) {
771
+ const durationMs = Date.now() - startedAt;
772
+ instrumentation?.error(durationMs, err);
604
773
  onRun?.({
605
774
  name: useCaseName,
606
775
  kind: useCaseKind,
607
776
  phase: "error",
608
- durationMs: Date.now() - startedAt,
777
+ durationMs,
609
778
  error: err,
610
779
  ctx: args.ctx,
611
780
  });
@@ -613,18 +782,29 @@ class UseCaseBuilder<
613
782
  }
614
783
  };
615
784
 
785
+ type RunArgs = Parameters<typeof execute>[0];
786
+
616
787
  // Type assertion required to satisfy the conditional return type.
617
788
  // The runtime checks above ensure input/output schemas are set.
618
789
  // The conditional types ensure type safety at compile time - run() returns
619
790
  // UseCaseDef only when both InputSchema and OutputSchema are StandardSchemaV1.
620
- return {
791
+ const def = {
621
792
  name: this.config.name,
622
793
  kind: this.config.kind,
623
794
  inputSchema: this.config.input,
624
795
  outputSchema: this.config.output,
625
796
  emits: this.config.emits,
626
- run: runFn,
627
- } as unknown as InputSchema extends StandardSchemaV1
797
+ run: (args: RunArgs) => execute(args, true),
798
+ };
799
+
800
+ // The trusted run path skips only the input parse. It is non-enumerable so
801
+ // serialization and object spreads keep treating use cases as plain data.
802
+ Object.defineProperty(def, USE_CASE_TRUSTED_RUN, {
803
+ value: (args: RunArgs) => execute(args, false),
804
+ enumerable: false,
805
+ });
806
+
807
+ return def as unknown as InputSchema extends StandardSchemaV1
628
808
  ? OutputSchema extends StandardSchemaV1
629
809
  ? UseCaseDef<Ctx, Name, Kind, InputSchema, OutputSchema, Emits>
630
810
  : never
@@ -769,6 +949,7 @@ export function createUseCase<Ctx>(
769
949
  ): UseCaseBuilderRoot<Ctx> {
770
950
  const onRun = options?.onRun;
771
951
  const validation = normalizeValidationOptions(options?.validate);
952
+ const instrumented = options?.instrumentation !== false;
772
953
  return {
773
954
  command<Name extends string>(name: Name) {
774
955
  return new UseCaseBuilder<
@@ -786,6 +967,7 @@ export function createUseCase<Ctx>(
786
967
  },
787
968
  onRun,
788
969
  validation,
970
+ instrumented,
789
971
  );
790
972
  },
791
973
  query<Name extends string>(name: Name) {
@@ -804,6 +986,7 @@ export function createUseCase<Ctx>(
804
986
  },
805
987
  onRun,
806
988
  validation,
989
+ instrumented,
807
990
  );
808
991
  },
809
992
  };