@smoothbricks/lmao 0.2.2 → 0.3.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 (285) hide show
  1. package/README.md +206 -206
  2. package/dist/allocator.wasm +0 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +1 -0
  6. package/dist/lib/JsBufferStrategy.d.ts +4 -3
  7. package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
  8. package/dist/lib/JsBufferStrategy.js +18 -11
  9. package/dist/lib/arrow/lease.d.ts +10 -0
  10. package/dist/lib/arrow/lease.d.ts.map +1 -0
  11. package/dist/lib/arrow/lease.js +33 -0
  12. package/dist/lib/arrow/utils.d.ts +3 -4
  13. package/dist/lib/arrow/utils.d.ts.map +1 -1
  14. package/dist/lib/arrow/utils.js +12 -13
  15. package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
  16. package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
  17. package/dist/lib/arrow/vocabularyDictionary.js +95 -0
  18. package/dist/lib/bufferStrategy.d.ts +3 -2
  19. package/dist/lib/bufferStrategy.d.ts.map +1 -1
  20. package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
  21. package/dist/lib/cloudflare/traceRows.js +3 -2
  22. package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
  23. package/dist/lib/codegen/evaluatorGenerator.js +12 -11
  24. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
  25. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
  26. package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
  27. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
  28. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
  29. package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
  30. package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
  31. package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
  32. package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
  33. package/dist/lib/convertToArrow.d.ts +7 -2
  34. package/dist/lib/convertToArrow.d.ts.map +1 -1
  35. package/dist/lib/convertToArrow.js +499 -285
  36. package/dist/lib/defineOpContext.js +1 -1
  37. package/dist/lib/enumMetadata.d.ts +19 -0
  38. package/dist/lib/enumMetadata.d.ts.map +1 -0
  39. package/dist/lib/enumMetadata.js +86 -0
  40. package/dist/lib/flushScheduler.d.ts.map +1 -1
  41. package/dist/lib/flushScheduler.js +13 -4
  42. package/dist/lib/library.d.ts +16 -98
  43. package/dist/lib/library.d.ts.map +1 -1
  44. package/dist/lib/library.js +32 -525
  45. package/dist/lib/logBinding.d.ts +21 -27
  46. package/dist/lib/logBinding.d.ts.map +1 -1
  47. package/dist/lib/op.d.ts +30 -30
  48. package/dist/lib/op.d.ts.map +1 -1
  49. package/dist/lib/op.js +15 -22
  50. package/dist/lib/opContext/createOpGroup.d.ts +1 -1
  51. package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
  52. package/dist/lib/opContext/createOpGroup.js +22 -29
  53. package/dist/lib/opContext/defineOp.d.ts +4 -4
  54. package/dist/lib/opContext/defineOp.d.ts.map +1 -1
  55. package/dist/lib/opContext/defineOp.js +53 -10
  56. package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
  57. package/dist/lib/opContext/opTypes.d.ts +1 -1
  58. package/dist/lib/opContext/opTypes.d.ts.map +1 -1
  59. package/dist/lib/opContext/spanContextTypes.d.ts +33 -18
  60. package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
  61. package/dist/lib/opContext/types.d.ts +4 -4
  62. package/dist/lib/opContext/types.d.ts.map +1 -1
  63. package/dist/lib/physicalLayoutPlan.d.ts +89 -0
  64. package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
  65. package/dist/lib/physicalLayoutPlan.js +442 -0
  66. package/dist/lib/resolveMessage.d.ts +9 -0
  67. package/dist/lib/resolveMessage.d.ts.map +1 -0
  68. package/dist/lib/resolveMessage.js +63 -0
  69. package/dist/lib/result.d.ts +5 -7
  70. package/dist/lib/result.d.ts.map +1 -1
  71. package/dist/lib/result.js +19 -26
  72. package/dist/lib/runtimeHint.d.ts +35 -0
  73. package/dist/lib/runtimeHint.d.ts.map +1 -0
  74. package/dist/lib/runtimeHint.js +79 -0
  75. package/dist/lib/schema/typeGuards.d.ts +7 -47
  76. package/dist/lib/schema/typeGuards.d.ts.map +1 -1
  77. package/dist/lib/schema/typeGuards.js +7 -123
  78. package/dist/lib/schema/types.d.ts +1 -1
  79. package/dist/lib/schema/types.d.ts.map +1 -1
  80. package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
  81. package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
  82. package/dist/lib/span-buffer/aot/v1.js +24 -0
  83. package/dist/lib/spanBuffer.d.ts +33 -4
  84. package/dist/lib/spanBuffer.d.ts.map +1 -1
  85. package/dist/lib/spanBuffer.js +583 -91
  86. package/dist/lib/spanBufferStats.d.ts +1 -1
  87. package/dist/lib/spanBufferStats.d.ts.map +1 -1
  88. package/dist/lib/spanContext.d.ts +27 -51
  89. package/dist/lib/spanContext.d.ts.map +1 -1
  90. package/dist/lib/spanContext.js +822 -344
  91. package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
  92. package/dist/lib/sqlite/sqlite-common.js +20 -21
  93. package/dist/lib/testing/bun-harness.d.ts +8 -3
  94. package/dist/lib/testing/bun-harness.d.ts.map +1 -1
  95. package/dist/lib/testing/bun-harness.js +30 -18
  96. package/dist/lib/testing/extractFacts.d.ts +1 -1
  97. package/dist/lib/testing/extractFacts.d.ts.map +1 -1
  98. package/dist/lib/testing/extractFacts.js +55 -63
  99. package/dist/lib/testing/facts.d.ts +1 -1
  100. package/dist/lib/testing/facts.d.ts.map +1 -1
  101. package/dist/lib/testing/queryable-span.d.ts +1 -1
  102. package/dist/lib/testing/queryable-span.d.ts.map +1 -1
  103. package/dist/lib/testing/queryable-span.js +26 -28
  104. package/dist/lib/testing/span-query.d.ts.map +1 -1
  105. package/dist/lib/testing/span-query.js +19 -22
  106. package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
  107. package/dist/lib/testing/stdio-replay.js +19 -8
  108. package/dist/lib/threadId.d.ts.map +1 -1
  109. package/dist/lib/threadId.js +6 -3
  110. package/dist/lib/traceContext.d.ts.map +1 -1
  111. package/dist/lib/traceContext.js +1 -4
  112. package/dist/lib/traceRoot.d.ts +30 -8
  113. package/dist/lib/traceRoot.d.ts.map +1 -1
  114. package/dist/lib/traceRoot.es.d.ts +17 -15
  115. package/dist/lib/traceRoot.es.d.ts.map +1 -1
  116. package/dist/lib/traceRoot.es.js +68 -34
  117. package/dist/lib/traceRoot.js +11 -0
  118. package/dist/lib/traceRoot.node.d.ts +17 -19
  119. package/dist/lib/traceRoot.node.d.ts.map +1 -1
  120. package/dist/lib/traceRoot.node.js +66 -38
  121. package/dist/lib/traceTopology.d.ts +42 -0
  122. package/dist/lib/traceTopology.d.ts.map +1 -0
  123. package/dist/lib/traceTopology.js +260 -0
  124. package/dist/lib/tracer.d.ts +9 -5
  125. package/dist/lib/tracer.d.ts.map +1 -1
  126. package/dist/lib/tracer.js +65 -71
  127. package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
  128. package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
  129. package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
  130. package/dist/lib/tracers/StdioTracer.js +15 -13
  131. package/dist/lib/tracers/TestTracer.d.ts +4 -6
  132. package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
  133. package/dist/lib/tracers/TestTracer.js +6 -8
  134. package/dist/lib/types.d.ts +49 -32
  135. package/dist/lib/types.d.ts.map +1 -1
  136. package/dist/lib/vocabularyRegistry.d.ts +25 -0
  137. package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
  138. package/dist/lib/vocabularyRegistry.js +372 -0
  139. package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
  140. package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
  141. package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
  142. package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
  143. package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
  144. package/dist/lib/wasm/wasmAllocator.js +66 -44
  145. package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
  146. package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
  147. package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
  148. package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
  149. package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
  150. package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
  151. package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
  152. package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
  153. package/dist/lib/wasm/wasmTraceRoot.js +110 -71
  154. package/dist/vocabulary/register/v1.d.ts +2 -0
  155. package/dist/vocabulary/register/v1.d.ts.map +1 -0
  156. package/dist/vocabulary/register/v1.js +1 -0
  157. package/dist/wasm.d.ts +5 -0
  158. package/dist/wasm.d.ts.map +1 -0
  159. package/dist/wasm.js +4 -0
  160. package/package.json +54 -6
  161. package/src/index.ts +1 -0
  162. package/src/lib/JsBufferStrategy.ts +27 -9
  163. package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
  164. package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
  165. package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
  166. package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
  167. package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
  168. package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
  169. package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
  170. package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
  171. package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
  172. package/src/lib/__tests__/capability-span-context.test.ts +505 -0
  173. package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
  174. package/src/lib/__tests__/eager-columns.test.ts +345 -0
  175. package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
  176. package/src/lib/__tests__/enum-metadata.test.ts +177 -0
  177. package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
  178. package/src/lib/__tests__/flushScheduler.test.ts +5 -1
  179. package/src/lib/__tests__/identity-view.property.test.ts +179 -0
  180. package/src/lib/__tests__/library.test.ts +19 -235
  181. package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
  182. package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
  183. package/src/lib/__tests__/op-metadata.test.ts +1 -1
  184. package/src/lib/__tests__/op-type-safety.test.ts +5 -16
  185. package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
  186. package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
  187. package/src/lib/__tests__/root-context-construction.test.ts +414 -0
  188. package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
  189. package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
  190. package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
  191. package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
  192. package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
  193. package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
  194. package/src/lib/__tests__/test-helpers.ts +67 -12
  195. package/src/lib/__tests__/threadId.test.ts +62 -0
  196. package/src/lib/__tests__/timestamp.test.ts +221 -93
  197. package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
  198. package/src/lib/__tests__/type-narrowing.test.ts +63 -0
  199. package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
  200. package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
  201. package/src/lib/arrow/lease.ts +43 -0
  202. package/src/lib/arrow/utils.ts +10 -14
  203. package/src/lib/arrow/vocabularyDictionary.ts +123 -0
  204. package/src/lib/bufferStrategy.ts +9 -1
  205. package/src/lib/cloudflare/traceRows.ts +3 -2
  206. package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
  207. package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
  208. package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
  209. package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
  210. package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
  211. package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
  212. package/src/lib/codegen/evaluatorGenerator.ts +18 -13
  213. package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
  214. package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
  215. package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
  216. package/src/lib/convertToArrow.ts +598 -311
  217. package/src/lib/defineOpContext.ts +1 -1
  218. package/src/lib/enumMetadata.ts +121 -0
  219. package/src/lib/flushScheduler.ts +11 -5
  220. package/src/lib/library.ts +37 -595
  221. package/src/lib/logBinding.ts +21 -27
  222. package/src/lib/op.ts +75 -18
  223. package/src/lib/opContext/__tests__/retry.test.ts +27 -21
  224. package/src/lib/opContext/createOpGroup.ts +33 -31
  225. package/src/lib/opContext/defineOp.ts +88 -11
  226. package/src/lib/opContext/opGroupTypes.ts +2 -2
  227. package/src/lib/opContext/opTypes.ts +1 -1
  228. package/src/lib/opContext/spanContextTypes.ts +122 -24
  229. package/src/lib/opContext/types.ts +7 -3
  230. package/src/lib/physicalLayoutPlan.ts +598 -0
  231. package/src/lib/resolveMessage.ts +67 -0
  232. package/src/lib/result.ts +20 -33
  233. package/src/lib/runtimeHint.ts +98 -0
  234. package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
  235. package/src/lib/schema/builder.ts +1 -1
  236. package/src/lib/schema/typeGuards.ts +7 -151
  237. package/src/lib/schema/types.ts +1 -1
  238. package/src/lib/span-buffer/aot/v1.ts +26 -0
  239. package/src/lib/spanBuffer.ts +658 -92
  240. package/src/lib/spanBufferStats.ts +1 -1
  241. package/src/lib/spanContext.ts +1350 -861
  242. package/src/lib/sqlite/sqlite-common.ts +20 -31
  243. package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
  244. package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
  245. package/src/lib/testing/bun-harness.ts +94 -43
  246. package/src/lib/testing/extractFacts.ts +64 -78
  247. package/src/lib/testing/facts.ts +1 -1
  248. package/src/lib/testing/queryable-span.ts +23 -30
  249. package/src/lib/testing/span-query.ts +16 -20
  250. package/src/lib/testing/stdio-replay.ts +25 -8
  251. package/src/lib/testing/vitest-harness.ts +1 -1
  252. package/src/lib/threadId.ts +6 -3
  253. package/src/lib/traceContext.ts +1 -6
  254. package/src/lib/traceRoot.es.ts +77 -42
  255. package/src/lib/traceRoot.node.ts +75 -46
  256. package/src/lib/traceRoot.ts +41 -14
  257. package/src/lib/traceTopology.ts +279 -0
  258. package/src/lib/tracer.ts +109 -98
  259. package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
  260. package/src/lib/tracers/StdioTracer.ts +15 -13
  261. package/src/lib/tracers/TestTracer.ts +6 -8
  262. package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
  263. package/src/lib/tracers/__tests__/CompositeTracer.test.ts +150 -0
  264. package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
  265. package/src/lib/types.ts +64 -33
  266. package/src/lib/vocabularyRegistry.ts +439 -0
  267. package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
  268. package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
  269. package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
  270. package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
  271. package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
  272. package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
  273. package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
  274. package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
  275. package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
  276. package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
  277. package/src/lib/wasm/wasmAllocator.ts +131 -96
  278. package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
  279. package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
  280. package/src/lib/wasm/wasmTraceRoot.ts +140 -78
  281. package/src/vocabulary/register/v1.ts +1 -0
  282. package/src/wasm.ts +19 -0
  283. package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
  284. package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
  285. package/src/lib/wasm/allocator.zig +0 -948
package/README.md CHANGED
@@ -1,269 +1,269 @@
1
- # lmao
1
+ # @smoothbricks/lmao
2
2
 
3
- This library was generated with [Nx](https://nx.dev).
3
+ A high-performance, type-safe structured tracing and observability library for TypeScript.
4
4
 
5
- ## Building
5
+ Instrumented code writes spans directly into columnar [Apache Arrow](https://arrow.apache.org/) buffers — near-zero
6
+ hot-path overhead — and emits queryable Arrow tables that persist to SQLite (a local file, Node, or Cloudflare D1). A
7
+ headline feature is **trace-testing**: assert on the span tree your code emits instead of on return values.
6
8
 
7
- Run `nx build lmao` to build the library.
9
+ - **Type-safe by construction.** Your log schema drives the types of `ctx.tag`, `ctx.log`, feature flags, and results —
10
+ autocomplete everywhere, no casts.
11
+ - **Columnar & cheap.** Attributes are written to fixed buffer positions; string columns are dictionary-encoded. No
12
+ per-event object allocation on the hot path.
13
+ - **Arrow-native.** Convert a trace to an Arrow table and persist it to SQLite/D1, or analyze it with the companion
14
+ inspector.
8
15
 
9
- ## Trace Testing
16
+ > Part of the `smoothbricks` monorepo. Full documentation lives in [`targets/lmao-docs/`](../../targets/lmao-docs) (an Astro Starlight
17
+ > site). Runnable examples are in [`examples/`](./examples).
10
18
 
11
- LMAO provides a trace-testing system where each test creates queryable trace spans. Instead of testing return values
12
- directly, you execute code that emits trace facts and assert on WHAT happened.
19
+ ## Install
13
20
 
14
- ### Quick Start (bun:test)
15
-
16
- 1. Create a preload file:
17
-
18
- ```typescript
19
- // test-trace-setup.ts (preload)
20
- import * as bunTest from 'bun:test';
21
- import { mock } from 'bun:test';
22
- import { createBunTestMock, initTraceTestRun } from '@smoothbricks/lmao/testing/bun';
23
- import { myOpContext } from './src/opContext.js';
24
-
25
- initTraceTestRun(myOpContext, { sqlite: { dbPath: '.trace-results.db' } });
26
- mock.module('bun:test', () => createBunTestMock(bunTest));
21
+ ```bash
22
+ bun add @smoothbricks/lmao
27
23
  ```
28
24
 
29
- `mock.module` MUST be called from the preload file itself — bun only intercepts subsequent imports when the mock is
30
- registered from the entry module context.
31
-
32
- 2. Add to `bunfig.toml`:
25
+ ## Quick start
26
+
27
+ ```ts
28
+ import {
29
+ defineLogSchema,
30
+ defineOpContext,
31
+ JsBufferStrategy,
32
+ S,
33
+ StdioTracer,
34
+ } from '@smoothbricks/lmao';
35
+ import { createTraceRoot } from '@smoothbricks/lmao/node'; // or '/es' for browsers/Workers
36
+
37
+ // 1. Describe your columns. Pick a string strategy per field:
38
+ // S.enum (known set, 1 byte) · S.category (repeating, dictionary) · S.text (mostly unique)
39
+ const schema = defineLogSchema({
40
+ userId: S.category(),
41
+ operation: S.enum(['SELECT', 'INSERT', 'UPDATE', 'DELETE']),
42
+ duration: S.number(),
43
+ });
33
44
 
34
- ```toml
35
- [test]
36
- preload = ["./test-trace-setup.ts"]
37
- ```
45
+ // 2. Bundle the schema into an op context.
46
+ const opContext = defineOpContext({ logSchema: schema });
47
+ const { defineOp } = opContext;
38
48
 
39
- 3. Write tests import from `bun:test` as normal, `mock.module` intercepts transparently:
49
+ // 3. Define an op. Its body receives a typed SpanContext (`ctx`).
50
+ const createUser = defineOp('create-user', async (ctx, email: string) => {
51
+ ctx.tag.userId(email).operation('INSERT');
52
+ ctx.log.info('creating {{userId}}').userId(email); // {{field}} = template, value set via the chain
40
53
 
41
- ```typescript
42
- import { describe, it, expect } from 'bun:test';
43
- import { useTestSpan } from '@smoothbricks/lmao/testing/bun';
44
- import { querySpan, findSpan } from '@smoothbricks/lmao/testing';
45
-
46
- describe('Order Processing', () => {
47
- it('validates and saves order', async () => {
48
- const ctx = useTestSpan();
54
+ const validated = await ctx.span('validate', async (child) => {
55
+ child.tag.operation('SELECT');
56
+ return child.ok({ valid: true });
57
+ });
58
+ if (!validated.success) return ctx.err(new Error('validation failed'));
49
59
 
50
- await ctx.span('processOrder', async (child) => {
51
- child.tag.orderId('123');
52
- await child.span('validate', async (v) => v.ok(true));
53
- await child.span('save', async (s) => s.ok({ id: 'order-123' }));
54
- return child.ok({ status: 'saved' });
55
- });
60
+ return ctx.ok({ id: 'user-1', email }).with({ duration: 12 });
61
+ });
56
62
 
57
- // Query the trace tree
58
- const q = querySpan(ctx.buffer);
59
- expect(q.names()).toEqual(['processOrder', 'validate', 'save']);
60
- expect(q.find('validate')).toBeDefined();
61
- expect(findSpan(ctx.buffer, 'save')).toBeDefined();
62
- });
63
+ // 4. Build a tracer and run at the request boundary.
64
+ const { trace } = new StdioTracer(opContext, {
65
+ bufferStrategy: new JsBufferStrategy(),
66
+ createTraceRoot,
63
67
  });
68
+
69
+ const result = await trace('create-user', createUser, 'ada@example.com');
70
+ console.log(result.success ? result.value : result.error);
64
71
  ```
65
72
 
66
- Note: `describe`/`it`/`expect` are imported from `bun:test` as normal — `mock.module` intercepts transparently. Only
67
- `useTestSpan` comes from `@smoothbricks/lmao/testing/bun`.
73
+ ## Core API
74
+
75
+ ### Schema (`S` + `defineLogSchema`)
68
76
 
69
- ### Quick Start (vitest)
77
+ | Builder | Use |
78
+ |---|---|
79
+ | `S.enum([...])` | A fixed set of known values (stored as 1 byte). |
80
+ | `S.category()` | Repeating strings (dictionary-encoded). |
81
+ | `S.text()` | Mostly-unique strings (no dictionary). |
82
+ | `S.number()` | Numeric column. |
83
+ | `S.boolean()` | Boolean column (bit-packed). |
70
84
 
71
- 1. Configure vitest:
85
+ ### `defineOpContext`
72
86
 
73
- ```typescript
74
- // vitest.config.ts
75
- export default defineConfig({
76
- test: { setupFiles: ['./test-setup.ts'] },
87
+ ```ts
88
+ const opContext = defineOpContext({
89
+ logSchema, // required
90
+ flags, // optional: defineFeatureFlags(...).schema
91
+ deps, // optional: other op groups, wired with .prefix()/.mapColumns()
92
+ ctx: { // optional: user context carried on every span
93
+ requestId: undefined as string | undefined,
94
+ },
77
95
  });
96
+ const { defineOp, defineOps } = opContext;
78
97
  ```
79
98
 
80
- 2. Create the setup file with `vi.mock` for transparent interception:
99
+ `defineOp(name, fn)` creates a single op; `defineOps({ ... })` batches ops into a reusable group.
81
100
 
82
- ```typescript
83
- // test-setup.ts
84
- import { vi } from 'vitest';
85
- import { createNodeSQLiteDatabase } from '@smoothbricks/lmao/sqlite/node';
86
- import { myOpContext } from './src/opContext.js';
101
+ ### `SpanContext` (`ctx`)
87
102
 
88
- vi.mock('vitest', async (importOriginal) => {
89
- const [mod, { createVitestMock }] = await Promise.all([
90
- importOriginal(),
91
- import('@smoothbricks/lmao/testing/vitest'),
92
- ]);
93
- return createVitestMock(mod as Record<string, unknown>);
94
- });
103
+ The object every op body receives:
95
104
 
96
- import { initTraceTestRun } from '@smoothbricks/lmao/testing/vitest';
97
- initTraceTestRun(myOpContext, {
98
- sqlite: { dbPath: '.trace-results.db', createDatabase: createNodeSQLiteDatabase },
99
- });
100
- ```
105
+ | Member | What it does |
106
+ |---|---|
107
+ | `ctx.tag.field(value)` | Set span-start attributes (row 0). Chainable; `ctx.tag.with({...})` sets several. |
108
+ | `ctx.log.info/debug/warn/error(msg)` | Append a log event. `msg` is a `{{field}}` template; attach values via the chain. |
109
+ | `ctx.span(name, opOrFn, ...args)` | Open a child span; returns `Promise<Result>`. |
110
+ | `ctx.spanSync(name, fn)` | Open a **synchronous** child span; `fn` returns a `Result` directly (no `await`). |
111
+ | `ctx.ok(value)` / `ctx.err(error)` | Complete the span. Both chain `.with({...})` and `.message('...')`. |
112
+ | `ctx.setScope({...})` / `ctx.scope` | Set/read attributes inherited by all subsequent logs and child spans. |
113
+ | `ctx.ff` | Feature-flag access (present when `flags` is declared). |
114
+ | `ctx.deps` | Declared dependency op groups. |
115
+ | `ctx.buffer` | The underlying span buffer (used in tests and for Arrow conversion). |
116
+ | user context | Anything declared in `ctx: {...}` (e.g. `ctx.requestId`). |
101
117
 
102
- 3. Write tests import from `vitest` as normal, `vi.mock` intercepts transparently:
118
+ ### Results & typed errors
103
119
 
104
- ```typescript
105
- import { describe, it, expect } from 'vitest';
106
- import { useTestSpan } from '@smoothbricks/lmao/testing/vitest';
107
- import { querySpan, findSpan } from '@smoothbricks/lmao/testing';
120
+ Ops return a `Result` — check `result.success`, then read `result.value` or `result.error`. Error codes are typed
121
+ factories:
108
122
 
109
- describe('Order Processing', () => {
110
- it('validates and saves order', async () => {
111
- const ctx = useTestSpan();
123
+ ```ts
124
+ import { defineCodeError } from '@smoothbricks/lmao';
112
125
 
113
- await ctx.span('processOrder', async (child) => {
114
- child.tag.orderId('123');
115
- await child.span('validate', async (v) => v.ok(true));
116
- return child.ok({ status: 'saved' });
117
- });
126
+ const NOT_FOUND = defineCodeError('NOT_FOUND')<{ userId: string }>();
118
127
 
119
- const q = querySpan(ctx.buffer);
120
- expect(q.names()).toContain('validate');
121
- expect(findSpan(ctx.buffer, 'processOrder')).toBeDefined();
122
- });
128
+ const getUser = defineOp('get-user', async (ctx, id: string) => {
129
+ const user = await lookup(id);
130
+ return user ? ctx.ok(user) : ctx.err(NOT_FOUND({ userId: id }));
123
131
  });
132
+
133
+ const r = await trace('get-user', getUser, 'u1');
134
+ if (r.success) {
135
+ console.log(r.value);
136
+ } else {
137
+ console.log(r.error.code, r.error.userId); // 'NOT_FOUND' + the typed payload field
138
+ }
124
139
  ```
125
140
 
126
- Both bun:test and vitest use the same transparent interception pattern — tests import from their native test module as
127
- normal. Only `useTestSpan` (for accessing the it-local trace root) comes from the lmao testing module.
141
+ ## Tracers
142
+
143
+ Construct a tracer with `new SomeTracer(opContext, options)`, then destructure `trace`. Every tracer needs a
144
+ `bufferStrategy` (`new JsBufferStrategy()`) and a `createTraceRoot` (from `@smoothbricks/lmao/node` for Node, or `/es`
145
+ for browsers/Deno/Workers).
146
+
147
+ | Tracer | Use |
148
+ |---|---|
149
+ | `StdioTracer` | Print the span tree to the console. |
150
+ | `TestTracer` | Keep completed traces in memory (`tracer.rootBuffers`) for inspection/tests. |
151
+ | `ArrayQueueTracer` | Queue completed traces for batch processing (`tracer.drain()`). |
152
+ | `SQLiteTracer` / `SQLiteAsyncTracer` | Persist to a synchronous SQLite DB, or an async one (e.g. D1). |
153
+ | `CompositeTracer` | Fan out to several tracers. |
154
+ | `NoOpTracer` | Execute ops without emitting. |
155
+
156
+ ```ts
157
+ // trace() runs an op (or an inline fn) as the root span; overrides carry user-context values.
158
+ await trace('greet', greet);
159
+ await trace('greet', { requestId: 'req-1' }, greet, ...args);
160
+ ```
128
161
 
129
- #### Cloudflare Worker + Vitest notes
162
+ ## Feature flags
130
163
 
131
- - Keep the setup file wiring-only: call `setupVitestTestSuiteTracing(...)` and keep the `vi.mock('vitest', ...)` bridge
132
- with `createVitestMock(...)`.
133
- - Configure SQLite sink in the package-local vitest tracer module (not in test files) so worker suites flush to a
134
- worker-appropriate SQLite target (for example `d1://TRACE_RESULTS`).
135
- - Debug logging is harness-owned and toggled by `LMAO_VITEST_DEBUG`.
136
- - Verbose trace replay is toggled by `LMAO_TEST_TRACE_VERBOSE` (prints spans to stdout and still flushes SQLite).
137
- - In Worker tests, forward the debug env in `vitest.config.ts` via `define`, for example
138
- `globalThis.__LMAO_VITEST_DEBUG_ENV__`, and do the same for `globalThis.__LMAO_TEST_TRACE_VERBOSE_ENV__` when verbose
139
- replay is needed.
140
- - Enable debug for Cloudflare tests with:
164
+ Declare flags, pass the schema to `defineOpContext`, and supply an evaluator **to the tracer**:
141
165
 
142
- ```bash
143
- ```
166
+ ```ts
167
+ import { defineFeatureFlags, InMemoryFlagEvaluator, S } from '@smoothbricks/lmao';
144
168
 
145
- ### Setting Up Trace Testing for a New Package
169
+ const flags = defineFeatureFlags({
170
+ advancedValidation: S.boolean().default(false).sync(),
171
+ maxRetries: S.number().default(3).sync(),
172
+ });
146
173
 
147
- 1. Create the preload file (`test-trace-setup.ts`):
174
+ const opContext = defineOpContext({ logSchema: schema, flags: flags.schema });
148
175
 
149
- ```typescript
150
- import * as bunTest from 'bun:test';
151
- import { mock } from 'bun:test';
152
- import { createBunTestMock, initTraceTestRun } from '@smoothbricks/lmao/testing/bun';
153
- import { myOpContext } from './src/opContext.js';
176
+ const { trace } = new StdioTracer(opContext, {
177
+ bufferStrategy: new JsBufferStrategy(),
178
+ createTraceRoot,
179
+ flagEvaluator: new InMemoryFlagEvaluator(flags.schema, { advancedValidation: true, maxRetries: 5 }),
180
+ });
154
181
 
155
- initTraceTestRun(myOpContext, { sqlite: { dbPath: '.trace-results.db' } });
156
- mock.module('bun:test', () => createBunTestMock(bunTest));
182
+ // Inside an op sync flags are read as `ctx.ff.<name>?.value`:
183
+ if (ctx.ff.advancedValidation?.value) { /* ... */ }
157
184
  ```
158
185
 
159
- 2. Add `bunfig.toml`:
186
+ ## Persist & analyze
160
187
 
161
- ```toml
162
- [test]
163
- preload = ["./test-trace-setup.ts"]
164
- ```
188
+ Convert a completed trace to an Arrow table, then persist or query it:
165
189
 
166
- 3. Tests import `describe`/`it`/`expect` from `bun:test` as normal — the mock intercepts transparently.
190
+ ```ts
191
+ import { convertSpanTreeToArrowTable } from '@smoothbricks/lmao';
167
192
 
168
- 4. Add `.trace-results.db` to `.gitignore`.
193
+ const table = convertSpanTreeToArrowTable(tracer.rootBuffers[0]);
194
+ console.log(table.numRows, table.names);
195
+ ```
169
196
 
170
- ### Querying Trace Results
197
+ - **SQLite / D1** — use `SQLiteTracer`/`SQLiteAsyncTracer` with `createNodeSQLiteDatabase` (`@smoothbricks/lmao/sqlite/node`)
198
+ or `createD1SQLiteDatabase` (`@smoothbricks/lmao/sqlite`).
199
+ - **Query engine** — the companion package [`@smoothbricks/lmao-inspector`](../lmao-inspector) runs SQL over exported
200
+ Arrow data in the browser.
171
201
 
172
- After a test run, the trace database is written to the configured path. The `trace_id` is printed at the end:
202
+ ## Trace-testing
173
203
 
174
- ```
175
- [trace] trace_id: 550e8400-e29b-41d4-a716-446655440000 → .trace-results.db
176
- ```
204
+ Assert on **what your code did**, not just what it returned. Each test's ops emit a queryable span tree.
177
205
 
178
- The `trace_id` IS the run identifier — one root span per test run, with each `it()` as a child span.
206
+ ```ts
207
+ import { describe, it, expect } from 'bun:test';
208
+ import { useTestSpan } from '@smoothbricks/lmao/testing/bun';
209
+ import { querySpan, findSpan } from '@smoothbricks/lmao/testing';
179
210
 
180
- **SQLite CLI queries:**
211
+ describe('order processing', () => {
212
+ it('validates and saves', async () => {
213
+ const ctx = useTestSpan();
181
214
 
182
- ```bash
183
- # All spans for the latest trace (root span name = 'test-run')
184
- sqlite3 .trace-results.db "SELECT s0.message, s0.describe FROM spans s0 WHERE s0.row_index = 0 ORDER BY s0.timestamp_ns"
185
-
186
- # Find root span_id, then query it-level spans
187
- sqlite3 .trace-results.db "
188
- SELECT s0.message AS test_name, s0.describe,
189
- CASE WHEN s1.entry_type = 2 THEN 'ok'
190
- WHEN s1.entry_type = 3 THEN 'err'
191
- WHEN s1.entry_type = 4 THEN 'exception'
192
- ELSE 'running' END AS status,
193
- s1.timestamp_ns - s0.timestamp_ns AS duration_ns
194
- FROM spans s0
195
- LEFT JOIN spans s1 ON s1.trace_id = s0.trace_id AND s1.span_id = s0.span_id AND s1.row_index = 1
196
- WHERE s0.trace_id = (SELECT trace_id FROM spans WHERE parent_span_id = 0 AND row_index = 0 ORDER BY timestamp_ns DESC LIMIT 1)
197
- AND s0.parent_span_id = (SELECT span_id FROM spans WHERE parent_span_id = 0 AND row_index = 0 ORDER BY timestamp_ns DESC LIMIT 1)
198
- AND s0.row_index = 0
199
- ORDER BY s0.timestamp_ns"
200
-
201
- # All tests under a specific describe group
202
- sqlite3 .trace-results.db "SELECT message FROM spans WHERE describe = 'Order Processing > validation' AND row_index = 0"
203
-
204
- # Nested describe paths use ' > ' separator
205
- sqlite3 .trace-results.db "SELECT DISTINCT describe FROM spans WHERE describe IS NOT NULL AND row_index = 0"
206
- ```
215
+ await ctx.span('processOrder', async (child) => {
216
+ child.tag.orderId('123');
217
+ await child.span('validate', async (v) => v.ok(true));
218
+ await child.span('save', async (s) => s.ok({ id: 'order-123' }));
219
+ return child.ok({ status: 'saved' });
220
+ });
207
221
 
208
- **Schema:**
209
-
210
- | Column | Description |
211
- | ---------------- | ---------------------------------------------------------------- |
212
- | `trace_id` | Run identifier (= root span's trace_id) |
213
- | `span_id` | Unique span counter within trace |
214
- | `parent_span_id` | Parent span (0 = root, root's span_id = it-level) |
215
- | `row_index` | Row within span (0 = span-start, 1 = span-end, 2+ = log entries) |
216
- | `entry_type` | 1=span-start, 2=span-ok, 3=span-err, 4=span-exception |
217
- | `timestamp_ns` | Nanosecond timestamp |
218
- | `message` | Span name (row 0), log message (rows 2+) |
219
- | `describe` | `' > '`-separated describe path (user schema column) |
220
- | `...` | Additional user schema columns added dynamically via ALTER TABLE |
221
-
222
- Tree structure is encoded via `span_id` / `parent_span_id`. The root span (`parent_span_id = 0`) represents the entire
223
- test run. Each `it()` is a direct child of the root. User operations create deeper children.
224
-
225
- **TraceQuery API (programmatic access):**
226
-
227
- ```typescript
228
- import { Database } from 'bun:sqlite';
229
- import { TraceQuery } from '@smoothbricks/lmao/testing';
230
-
231
- const query = new TraceQuery(new Database('.trace-results.db'));
232
- query.failures(); // all failed tests
233
- query.slowest(undefined, 10); // 10 slowest tests
234
- query.findSpans('%validate%'); // spans matching pattern
235
- query.testTree('my-test'); // full span tree for a test
236
- query.close();
222
+ const q = querySpan(ctx.buffer);
223
+ expect(q.names()).toEqual(['processOrder', 'validate', 'save']);
224
+ expect(findSpan(ctx.buffer, 'save')).toBeDefined();
225
+ });
226
+ });
237
227
  ```
238
228
 
239
- ### Querying Span Results (in-test)
229
+ Setup is wiring-only: a preload/setup file calls `initTraceTestRun(opContext, { sqlite: { dbPath: '.trace-results.db' } })`
230
+ and installs a transparent mock so tests import `describe`/`it`/`expect` from their native runner as usual. Bun and
231
+ Vitest are both supported (`@smoothbricks/lmao/testing/bun` · `@smoothbricks/lmao/testing/vitest`). Traces flush to a
232
+ SQLite sink you can query with the `TraceQuery` API or the `sqlite3` CLI. See the docs for the full harness setup, the
233
+ SQLite schema, and query recipes.
240
234
 
241
- **QueryableSpan** wraps a SpanBuffer with ergonomic helpers:
235
+ ## Package exports
242
236
 
243
- ```typescript
244
- import { querySpan } from '@smoothbricks/lmao/testing';
237
+ | Import | Provides |
238
+ |---|---|
239
+ | `@smoothbricks/lmao` | Core API: `defineOpContext`, `defineLogSchema`, `defineFeatureFlags`, `S`, `JsBufferStrategy`, all tracers, Arrow conversion, results (`Ok`/`Err`/`defineCodeError`), `InMemoryFlagEvaluator`, entry-type constants. |
240
+ | `@smoothbricks/lmao/node` | `createTraceRoot` using `process.hrtime.bigint()`. |
241
+ | `@smoothbricks/lmao/es` | `createTraceRoot` using `performance.now()` (browser/Deno/Workers). |
242
+ | `@smoothbricks/lmao/sqlite`, `/sqlite/node` | SQLite/D1 tracers and database factories. |
243
+ | `@smoothbricks/lmao/cloudflare` | Cloudflare trace-sink adapters (`DiagnosticDrainTracer`, `ClassSplitTracer`, transports). *Partially implemented.* |
244
+ | `@smoothbricks/lmao/errors*` | `Transient`, `Blocked`, `defineCodeError`, backoff/retry helpers. |
245
+ | `@smoothbricks/lmao/testing`, `/testing/bun`, `/testing/vitest` | Trace-testing query API and runner harnesses. |
245
246
 
246
- const q = querySpan(tracer.rootBuffers[0]);
247
- q.name; // span name
248
- q.facts(); // all facts from this span tree
249
- q.find('validate'); // first child span by name
250
- q.findAll('db-query'); // all matching descendants
251
- q.children; // direct child QueryableSpans
252
- q.names(); // all descendant span names
253
- ```
247
+ ### Companion packages
254
248
 
255
- **Standalone functions** (tree-shakable):
249
+ - [`@smoothbricks/lmao-inspector`](../lmao-inspector) — client-side Arrow query engine and trace sources.
250
+ - [`@smoothbricks/lmao-transformer`](../lmao-transformer) — optional build-time TypeScript transformer (source-line
251
+ injection and `ctx.tag` inlining).
256
252
 
257
- ```typescript
258
- import { findSpan, extractFactsFor, spanNames } from '@smoothbricks/lmao/testing';
253
+ ## Examples
259
254
 
260
- const span = findSpan(rootBuffer, 'validate');
261
- const facts = extractFactsFor(rootBuffer, 'save');
262
- const names = spanNames(rootBuffer);
263
- ```
255
+ Runnable with `bun run examples/<name>.ts`:
264
256
 
265
- ### SQLite Persistence
257
+ | Example | Shows |
258
+ |---|---|
259
+ | `basic-usage.ts` | Schema, feature flags, user context, fluent tags, child spans. |
260
+ | `fluent-result-api.ts` | `ok`/`err` with `.with()`/`.message()`, typed error codes, exceptions. |
261
+ | `chaining-showcase.ts` | Tag/log fluent chaining patterns. |
262
+ | `middleware-pattern.ts` | Wrapping ops with cross-cutting behavior. |
263
+ | `library-integration.ts` | Composing op groups across packages with `.prefix()`/`.mapColumns()`. |
264
+ | `complete-example.ts` | An end-to-end request flow. |
265
+ | `arrow-export.ts` | Converting a trace to an Arrow table. |
266
266
 
267
- When configured, the trace database is written after all tests complete. Schema columns evolve automatically based on
268
- your LogSchema fields.
267
+ ## License
269
268
 
269
+ MIT
Binary file
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ export type { BaseSpanLogger, SpanLoggerImpl } from './lib/codegen/spanLoggerGen
20
20
  export { createSpanLogger, createSpanLoggerClass } from './lib/codegen/spanLoggerGenerator.js';
21
21
  export * from './lib/convertToArrow.js';
22
22
  export * from './lib/spanBuffer.js';
23
+ export * from './lib/traceTopology.js';
23
24
  export * from './lib/types.js';
24
25
  export * from './lib/flushScheduler.js';
25
26
  export type { BufferStrategy } from './lib/bufferStrategy.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,cAAc,0BAA0B,CAAC;AAGzC,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAMjC,OAAO,EAAE,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC1F,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACnF,OAAO,EAAE,eAAe,EAAE,GAAG,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAUzE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAMhG,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAM1E,YAAY,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAM7C,OAAO,EAEL,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,EAChB,gBAAgB,EAEhB,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EAEf,gBAAgB,EAChB,0BAA0B,EAC1B,0BAA0B,EAC1B,0BAA0B,EAC1B,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,wBAAwB,EAExB,yBAAyB,EAEzB,uBAAuB,EACvB,mBAAmB,EACnB,yBAAyB,EACzB,kBAAkB,EAElB,qBAAqB,EAErB,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EAErB,YAAY,GACb,MAAM,8BAA8B,CAAC;AAMtC,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAOvH,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,4BAA4B,CAAC;AAM3C,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,+CAA+C,CAAC;AACpG,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAC3F,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAM/F,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC;AAM/B,cAAc,yBAAyB,CAAC;AAMxC,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAM7D,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAEnE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,KAAK,aAAa,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAM7E,cAAc,kBAAkB,CAAC;AAMjC,cAAc,wBAAwB,CAAC;AAMvC,OAAO,EACL,cAAc,EACd,cAAc,EACd,WAAW,EACX,eAAe,EACf,0BAA0B,GAC3B,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,OAAO,GACb,MAAM,kBAAkB,CAAC;AAM1B,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAM7F,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -48,6 +48,7 @@ export { createSpanLogger, createSpanLoggerClass } from './lib/codegen/spanLogge
48
48
  // =============================================================================
49
49
  export * from './lib/convertToArrow.js';
50
50
  export * from './lib/spanBuffer.js';
51
+ export * from './lib/traceTopology.js';
51
52
  export * from './lib/types.js';
52
53
  // =============================================================================
53
54
  // Flush Scheduler
@@ -14,6 +14,7 @@ import type { Table } from '@uwdata/flechette';
14
14
  import type { BufferStrategy } from './bufferStrategy.js';
15
15
  import type { OpMetadata } from './opContext/opTypes.js';
16
16
  import type { LogSchema } from './schema/LogSchema.js';
17
+ import { type SpanBufferConstructor } from './spanBuffer.js';
17
18
  import type { ITraceRoot } from './traceRoot.js';
18
19
  import type { AnySpanBuffer, SpanBuffer } from './types.js';
19
20
  /**
@@ -40,10 +41,10 @@ export declare class JsBufferStrategy<T extends LogSchema = LogSchema> implement
40
41
  * Get or create SpanBuffer class for a schema.
41
42
  */
42
43
  private getSpanBufferClassForSchema;
43
- createSpanBuffer(schema: T, traceRoot: ITraceRoot, opMetadata: OpMetadata, capacity?: number): SpanBuffer<T>;
44
- createChildSpanBuffer(parentBuffer: SpanBuffer<T>, callsiteMetadata: OpMetadata, opMetadata: OpMetadata, capacity?: number, schema?: T): SpanBuffer<T>;
44
+ createSpanBuffer(schema: T, traceRoot: ITraceRoot, opMetadata: OpMetadata, capacity?: number, plannedClass?: SpanBufferConstructor<T>): SpanBuffer<T>;
45
+ createChildSpanBuffer(parentBuffer: SpanBuffer<T>, callsiteMetadata: OpMetadata, opMetadata: OpMetadata, capacity?: number, schema?: T, plannedClass?: SpanBufferConstructor<T>): SpanBuffer<T>;
45
46
  createOverflowBuffer(buffer: SpanBuffer<T>): SpanBuffer<T>;
46
47
  toArrowTable(buffer: AnySpanBuffer): Table;
47
- releaseBuffer(_buffer: AnySpanBuffer): void;
48
+ releaseBuffer(buffer: AnySpanBuffer): void;
48
49
  }
49
50
  //# sourceMappingURL=JsBufferStrategy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"JsBufferStrategy.d.ts","sourceRoot":"","sources":["../../src/lib/JsBufferStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAQvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS5D;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAgB,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,CAAE,YAAW,cAAc,CAAC,CAAC,CAAC;IACzF;;;OAGG;IACH,OAAO,CAAC,oBAAoB,CAAmD;IAE/E;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAYnC,gBAAgB,CAAC,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAE3G;IAED,qBAAqB,CACnB,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,EAC3B,gBAAgB,EAAE,UAAU,EAC5B,UAAU,EAAE,UAAU,EACtB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,CAAC,GACT,UAAU,CAAC,CAAC,CAAC,CAKf;IAED,oBAAoB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAEzD;IAED,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,KAAK,CAGzC;IAED,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAG1C;CACF"}
1
+ {"version":3,"file":"JsBufferStrategy.d.ts","sourceRoot":"","sources":["../../src/lib/JsBufferStrategy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAML,KAAK,qBAAqB,EAC3B,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS5D;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAgB,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,CAAE,YAAW,cAAc,CAAC,CAAC,CAAC;IACzF;;;OAGG;IACH,OAAO,CAAC,oBAAoB,CAAmD;IAE/E;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAYnC,gBAAgB,CACd,MAAM,EAAE,CAAC,EACT,SAAS,EAAE,UAAU,EACrB,UAAU,EAAE,UAAU,EACtB,QAAQ,CAAC,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACtC,UAAU,CAAC,CAAC,CAAC,CAEf;IAED,qBAAqB,CACnB,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,EAC3B,gBAAgB,EAAE,UAAU,EAC5B,UAAU,EAAE,UAAU,EACtB,QAAQ,CAAC,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,CAAC,EACV,YAAY,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACtC,UAAU,CAAC,CAAC,CAAC,CAgBf;IAED,oBAAoB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAEzD;IAED,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,KAAK,CAGzC;IAED,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAEzC;CACF"}
@@ -11,7 +11,7 @@
11
11
  * @module JsBufferStrategy
12
12
  */
13
13
  import { convertSpanTreeToArrowTable } from './convertToArrow.js';
14
- import { createChildSpanBuffer as createChildSpanBufferImpl, createOverflowBuffer as createOverflowBufferImpl, createSpanBuffer as createSpanBufferImpl, getSpanBufferClass, } from './spanBuffer.js';
14
+ import { createChildSpanBuffer as createChildSpanBufferImpl, createOverflowBuffer as createOverflowBufferImpl, createSpanBuffer as createSpanBufferImpl, getSpanBufferClass, resolveSpanBufferCapacity, } from './spanBuffer.js';
15
15
  function isSpanBufferConstructorForSchema(ctor, schema) {
16
16
  return ctor !== undefined && ctor.schema === schema;
17
17
  }
@@ -49,14 +49,22 @@ export class JsBufferStrategy {
49
49
  }
50
50
  return cached;
51
51
  }
52
- createSpanBuffer(schema, traceRoot, opMetadata, capacity) {
53
- return createSpanBufferImpl(schema, traceRoot, opMetadata, capacity);
52
+ createSpanBuffer(schema, traceRoot, opMetadata, capacity, plannedClass) {
53
+ return createSpanBufferImpl(schema, traceRoot, opMetadata, capacity, plannedClass);
54
54
  }
55
- createChildSpanBuffer(parentBuffer, callsiteMetadata, opMetadata, capacity, schema) {
56
- // Use provided schema (for cross-library calls) or parent's schema
57
- const childSchema = schema ?? parentBuffer._logSchema;
58
- const SpanBufferClass = this.getSpanBufferClassForSchema(childSchema);
59
- return createChildSpanBufferImpl(parentBuffer, SpanBufferClass, callsiteMetadata, opMetadata, capacity);
55
+ createChildSpanBuffer(parentBuffer, callsiteMetadata, opMetadata, capacity, schema, plannedClass) {
56
+ const targetSchema = schema ?? parentBuffer._logSchema;
57
+ const metadataSpanBufferClass = opMetadata._physicalLayoutPlan?.SpanBufferClass;
58
+ if (metadataSpanBufferClass !== undefined &&
59
+ !isSpanBufferConstructorForSchema(metadataSpanBufferClass, targetSchema)) {
60
+ throw new TypeError('Planned SpanBuffer class does not match schema');
61
+ }
62
+ const plannedSpanBufferClass = plannedClass ?? metadataSpanBufferClass;
63
+ const SpanBufferClass = plannedSpanBufferClass ?? this.getSpanBufferClassForSchema(targetSchema);
64
+ const actualCapacity = plannedSpanBufferClass === undefined
65
+ ? resolveSpanBufferCapacity(capacity, SpanBufferClass.stats.capacity)
66
+ : capacity;
67
+ return createChildSpanBufferImpl(parentBuffer, SpanBufferClass, callsiteMetadata, opMetadata, actualCapacity);
60
68
  }
61
69
  createOverflowBuffer(buffer) {
62
70
  return createOverflowBufferImpl(buffer);
@@ -65,8 +73,7 @@ export class JsBufferStrategy {
65
73
  // Uses existing tree conversion with shared dictionaries
66
74
  return convertSpanTreeToArrowTable(buffer);
67
75
  }
68
- releaseBuffer(_buffer) {
69
- // No-op for JS strategy - GC handles memory
70
- // The buffer will be collected when no references remain
76
+ releaseBuffer(buffer) {
77
+ buffer._traceRoot._topology.release();
71
78
  }
72
79
  }
@@ -0,0 +1,10 @@
1
+ import type { Table } from '@uwdata/flechette';
2
+ export interface ArrowLease {
3
+ readonly table: Table;
4
+ readonly released: boolean;
5
+ release(): void;
6
+ [Symbol.dispose](): void;
7
+ }
8
+ /** Internal constructor for a lease over borrowed Arrow source chunks. */
9
+ export declare function createArrowLease(table: Table, pinned: readonly unknown[], releases: readonly (() => void)[]): ArrowLease;
10
+ //# sourceMappingURL=lease.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease.d.ts","sourceRoot":"","sources":["../../../src/lib/arrow/lease.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,OAAO,IAAI,IAAI,CAAC;IAChB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;CAC1B;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,SAAS,OAAO,EAAE,EAC1B,QAAQ,EAAE,SAAS,CAAC,MAAM,IAAI,CAAC,EAAE,GAChC,UAAU,CA4BZ"}