@smoothbricks/lmao 0.1.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 (447) hide show
  1. package/README.md +269 -0
  2. package/dist/allocator.wasm +0 -0
  3. package/dist/bun/preload.d.ts +11 -0
  4. package/dist/bun/preload.d.ts.map +1 -0
  5. package/dist/bun/preload.js +10 -0
  6. package/dist/bun/trace-preload.d.ts +8 -0
  7. package/dist/bun/trace-preload.d.ts.map +1 -0
  8. package/dist/bun/trace-preload.js +12 -0
  9. package/dist/es.d.ts +8 -0
  10. package/dist/es.d.ts.map +1 -0
  11. package/dist/es.js +9 -0
  12. package/dist/index.d.ts +41 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +84 -0
  15. package/dist/lib/JsBufferStrategy.d.ts +49 -0
  16. package/dist/lib/JsBufferStrategy.d.ts.map +1 -0
  17. package/dist/lib/JsBufferStrategy.js +60 -0
  18. package/dist/lib/archive/chunkCompaction.d.ts +15 -0
  19. package/dist/lib/archive/chunkCompaction.d.ts.map +1 -0
  20. package/dist/lib/archive/chunkCompaction.js +24 -0
  21. package/dist/lib/archive/chunkEnvelope.d.ts +21 -0
  22. package/dist/lib/archive/chunkEnvelope.d.ts.map +1 -0
  23. package/dist/lib/archive/chunkEnvelope.js +55 -0
  24. package/dist/lib/archive/chunkRouting.d.ts +10 -0
  25. package/dist/lib/archive/chunkRouting.d.ts.map +1 -0
  26. package/dist/lib/archive/chunkRouting.js +47 -0
  27. package/dist/lib/archive/chunkStats.d.ts +12 -0
  28. package/dist/lib/archive/chunkStats.d.ts.map +1 -0
  29. package/dist/lib/archive/chunkStats.js +10 -0
  30. package/dist/lib/archive/index.d.ts +5 -0
  31. package/dist/lib/archive/index.d.ts.map +1 -0
  32. package/dist/lib/archive/index.js +4 -0
  33. package/dist/lib/arrow/capacityStats.d.ts +9 -0
  34. package/dist/lib/arrow/capacityStats.d.ts.map +1 -0
  35. package/dist/lib/arrow/capacityStats.js +231 -0
  36. package/dist/lib/arrow/dictionaries.d.ts +27 -0
  37. package/dist/lib/arrow/dictionaries.d.ts.map +1 -0
  38. package/dist/lib/arrow/dictionaries.js +135 -0
  39. package/dist/lib/arrow/flechette.d.ts +40 -0
  40. package/dist/lib/arrow/flechette.d.ts.map +1 -0
  41. package/dist/lib/arrow/flechette.js +67 -0
  42. package/dist/lib/arrow/utils.d.ts +38 -0
  43. package/dist/lib/arrow/utils.d.ts.map +1 -0
  44. package/dist/lib/arrow/utils.js +112 -0
  45. package/dist/lib/buffer/Nanoseconds.d.ts +109 -0
  46. package/dist/lib/buffer/Nanoseconds.d.ts.map +1 -0
  47. package/dist/lib/buffer/Nanoseconds.js +86 -0
  48. package/dist/lib/bufferStrategy.d.ts +95 -0
  49. package/dist/lib/bufferStrategy.d.ts.map +1 -0
  50. package/dist/lib/bufferStrategy.js +1 -0
  51. package/dist/lib/capacityTuning.d.ts +50 -0
  52. package/dist/lib/capacityTuning.d.ts.map +1 -0
  53. package/dist/lib/capacityTuning.js +65 -0
  54. package/dist/lib/codegen/evaluatorGenerator.d.ts +35 -0
  55. package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -0
  56. package/dist/lib/codegen/evaluatorGenerator.js +199 -0
  57. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +139 -0
  58. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -0
  59. package/dist/lib/codegen/fixedPositionWriterGenerator.js +289 -0
  60. package/dist/lib/codegen/spanLoggerGenerator.d.ts +115 -0
  61. package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -0
  62. package/dist/lib/codegen/spanLoggerGenerator.js +575 -0
  63. package/dist/lib/convertToArrow.d.ts +40 -0
  64. package/dist/lib/convertToArrow.d.ts.map +1 -0
  65. package/dist/lib/convertToArrow.js +1467 -0
  66. package/dist/lib/defineOpContext.d.ts +96 -0
  67. package/dist/lib/defineOpContext.d.ts.map +1 -0
  68. package/dist/lib/defineOpContext.js +227 -0
  69. package/dist/lib/errors/Blocked.d.ts +113 -0
  70. package/dist/lib/errors/Blocked.d.ts.map +1 -0
  71. package/dist/lib/errors/Blocked.js +68 -0
  72. package/dist/lib/errors/CodeError.d.ts +101 -0
  73. package/dist/lib/errors/CodeError.d.ts.map +1 -0
  74. package/dist/lib/errors/CodeError.js +42 -0
  75. package/dist/lib/errors/RetriesExhausted.d.ts +67 -0
  76. package/dist/lib/errors/RetriesExhausted.d.ts.map +1 -0
  77. package/dist/lib/errors/RetriesExhausted.js +31 -0
  78. package/dist/lib/errors/Transient.d.ts +115 -0
  79. package/dist/lib/errors/Transient.d.ts.map +1 -0
  80. package/dist/lib/errors/Transient.js +54 -0
  81. package/dist/lib/errors/index.d.ts +14 -0
  82. package/dist/lib/errors/index.d.ts.map +1 -0
  83. package/dist/lib/errors/index.js +16 -0
  84. package/dist/lib/errors/retry-policy.d.ts +60 -0
  85. package/dist/lib/errors/retry-policy.d.ts.map +1 -0
  86. package/dist/lib/errors/retry-policy.js +54 -0
  87. package/dist/lib/flushScheduler.d.ts +162 -0
  88. package/dist/lib/flushScheduler.d.ts.map +1 -0
  89. package/dist/lib/flushScheduler.js +388 -0
  90. package/dist/lib/library.d.ts +149 -0
  91. package/dist/lib/library.d.ts.map +1 -0
  92. package/dist/lib/library.js +588 -0
  93. package/dist/lib/logApi.d.ts +61 -0
  94. package/dist/lib/logApi.d.ts.map +1 -0
  95. package/dist/lib/logApi.js +12 -0
  96. package/dist/lib/logBinding.d.ts +63 -0
  97. package/dist/lib/logBinding.d.ts.map +1 -0
  98. package/dist/lib/logBinding.js +1 -0
  99. package/dist/lib/op.d.ts +105 -0
  100. package/dist/lib/op.d.ts.map +1 -0
  101. package/dist/lib/op.js +59 -0
  102. package/dist/lib/opContext/contextTypes.d.ts +88 -0
  103. package/dist/lib/opContext/contextTypes.d.ts.map +1 -0
  104. package/dist/lib/opContext/contextTypes.js +34 -0
  105. package/dist/lib/opContext/createOpGroup.d.ts +57 -0
  106. package/dist/lib/opContext/createOpGroup.d.ts.map +1 -0
  107. package/dist/lib/opContext/createOpGroup.js +341 -0
  108. package/dist/lib/opContext/defineOp.d.ts +83 -0
  109. package/dist/lib/opContext/defineOp.d.ts.map +1 -0
  110. package/dist/lib/opContext/defineOp.js +197 -0
  111. package/dist/lib/opContext/featureFlagTypes.d.ts +58 -0
  112. package/dist/lib/opContext/featureFlagTypes.d.ts.map +1 -0
  113. package/dist/lib/opContext/featureFlagTypes.js +1 -0
  114. package/dist/lib/opContext/index.d.ts +13 -0
  115. package/dist/lib/opContext/index.d.ts.map +1 -0
  116. package/dist/lib/opContext/index.js +15 -0
  117. package/dist/lib/opContext/opGroupTypes.d.ts +250 -0
  118. package/dist/lib/opContext/opGroupTypes.d.ts.map +1 -0
  119. package/dist/lib/opContext/opGroupTypes.js +31 -0
  120. package/dist/lib/opContext/opTypes.d.ts +48 -0
  121. package/dist/lib/opContext/opTypes.d.ts.map +1 -0
  122. package/dist/lib/opContext/opTypes.js +7 -0
  123. package/dist/lib/opContext/spanContextTypes.d.ts +347 -0
  124. package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -0
  125. package/dist/lib/opContext/spanContextTypes.js +1 -0
  126. package/dist/lib/opContext/types.d.ts +297 -0
  127. package/dist/lib/opContext/types.d.ts.map +1 -0
  128. package/dist/lib/opContext/types.js +16 -0
  129. package/dist/lib/result.d.ts +308 -0
  130. package/dist/lib/result.d.ts.map +1 -0
  131. package/dist/lib/result.js +359 -0
  132. package/dist/lib/schema/LogSchema.d.ts +62 -0
  133. package/dist/lib/schema/LogSchema.d.ts.map +1 -0
  134. package/dist/lib/schema/LogSchema.js +134 -0
  135. package/dist/lib/schema/builder.d.ts +12 -0
  136. package/dist/lib/schema/builder.d.ts.map +1 -0
  137. package/dist/lib/schema/builder.js +169 -0
  138. package/dist/lib/schema/defineFeatureFlags.d.ts +60 -0
  139. package/dist/lib/schema/defineFeatureFlags.d.ts.map +1 -0
  140. package/dist/lib/schema/defineFeatureFlags.js +29 -0
  141. package/dist/lib/schema/defineLogSchema.d.ts +87 -0
  142. package/dist/lib/schema/defineLogSchema.d.ts.map +1 -0
  143. package/dist/lib/schema/defineLogSchema.js +171 -0
  144. package/dist/lib/schema/evaluator.d.ts +267 -0
  145. package/dist/lib/schema/evaluator.d.ts.map +1 -0
  146. package/dist/lib/schema/evaluator.js +169 -0
  147. package/dist/lib/schema/extend.d.ts +14 -0
  148. package/dist/lib/schema/extend.d.ts.map +1 -0
  149. package/dist/lib/schema/extend.js +51 -0
  150. package/dist/lib/schema/systemSchema.d.ts +112 -0
  151. package/dist/lib/schema/systemSchema.d.ts.map +1 -0
  152. package/dist/lib/schema/systemSchema.js +260 -0
  153. package/dist/lib/schema/typeGuards.d.ts +52 -0
  154. package/dist/lib/schema/typeGuards.d.ts.map +1 -0
  155. package/dist/lib/schema/typeGuards.js +127 -0
  156. package/dist/lib/schema/types.d.ts +156 -0
  157. package/dist/lib/schema/types.d.ts.map +1 -0
  158. package/dist/lib/schema/types.js +4 -0
  159. package/dist/lib/spanBuffer.d.ts +133 -0
  160. package/dist/lib/spanBuffer.d.ts.map +1 -0
  161. package/dist/lib/spanBuffer.js +442 -0
  162. package/dist/lib/spanBufferHelpers.d.ts +53 -0
  163. package/dist/lib/spanBufferHelpers.d.ts.map +1 -0
  164. package/dist/lib/spanBufferHelpers.js +65 -0
  165. package/dist/lib/spanBufferStats.d.ts +38 -0
  166. package/dist/lib/spanBufferStats.d.ts.map +1 -0
  167. package/dist/lib/spanBufferStats.js +1 -0
  168. package/dist/lib/spanContext.d.ts +141 -0
  169. package/dist/lib/spanContext.d.ts.map +1 -0
  170. package/dist/lib/spanContext.js +763 -0
  171. package/dist/lib/sqlite/index.d.ts +14 -0
  172. package/dist/lib/sqlite/index.d.ts.map +1 -0
  173. package/dist/lib/sqlite/index.js +12 -0
  174. package/dist/lib/sqlite/sqlite-async-writer.d.ts +24 -0
  175. package/dist/lib/sqlite/sqlite-async-writer.d.ts.map +1 -0
  176. package/dist/lib/sqlite/sqlite-async-writer.js +65 -0
  177. package/dist/lib/sqlite/sqlite-common.d.ts +37 -0
  178. package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -0
  179. package/dist/lib/sqlite/sqlite-common.js +207 -0
  180. package/dist/lib/sqlite/sqlite-d1.d.ts +25 -0
  181. package/dist/lib/sqlite/sqlite-d1.d.ts.map +1 -0
  182. package/dist/lib/sqlite/sqlite-d1.js +67 -0
  183. package/dist/lib/sqlite/sqlite-db.d.ts +29 -0
  184. package/dist/lib/sqlite/sqlite-db.d.ts.map +1 -0
  185. package/dist/lib/sqlite/sqlite-db.js +1 -0
  186. package/dist/lib/sqlite/sqlite-node.d.ts +16 -0
  187. package/dist/lib/sqlite/sqlite-node.d.ts.map +1 -0
  188. package/dist/lib/sqlite/sqlite-node.js +68 -0
  189. package/dist/lib/sqlite/sqlite-writer.d.ts +39 -0
  190. package/dist/lib/sqlite/sqlite-writer.d.ts.map +1 -0
  191. package/dist/lib/sqlite/sqlite-writer.js +78 -0
  192. package/dist/lib/testing/bun-harness.d.ts +150 -0
  193. package/dist/lib/testing/bun-harness.d.ts.map +1 -0
  194. package/dist/lib/testing/bun-harness.js +729 -0
  195. package/dist/lib/testing/extractFacts.d.ts +73 -0
  196. package/dist/lib/testing/extractFacts.d.ts.map +1 -0
  197. package/dist/lib/testing/extractFacts.js +237 -0
  198. package/dist/lib/testing/facts.d.ts +235 -0
  199. package/dist/lib/testing/facts.d.ts.map +1 -0
  200. package/dist/lib/testing/facts.js +209 -0
  201. package/dist/lib/testing/index.d.ts +58 -0
  202. package/dist/lib/testing/index.d.ts.map +1 -0
  203. package/dist/lib/testing/index.js +74 -0
  204. package/dist/lib/testing/queryable-span.d.ts +39 -0
  205. package/dist/lib/testing/queryable-span.d.ts.map +1 -0
  206. package/dist/lib/testing/queryable-span.js +58 -0
  207. package/dist/lib/testing/span-query.d.ts +21 -0
  208. package/dist/lib/testing/span-query.d.ts.map +1 -0
  209. package/dist/lib/testing/span-query.js +47 -0
  210. package/dist/lib/testing/stdio-replay.d.ts +4 -0
  211. package/dist/lib/testing/stdio-replay.d.ts.map +1 -0
  212. package/dist/lib/testing/stdio-replay.js +42 -0
  213. package/dist/lib/testing/trace-query.d.ts +59 -0
  214. package/dist/lib/testing/trace-query.d.ts.map +1 -0
  215. package/dist/lib/testing/trace-query.js +462 -0
  216. package/dist/lib/testing/vitest-harness.d.ts +135 -0
  217. package/dist/lib/testing/vitest-harness.d.ts.map +1 -0
  218. package/dist/lib/testing/vitest-harness.js +486 -0
  219. package/dist/lib/threadId.d.ts +58 -0
  220. package/dist/lib/threadId.d.ts.map +1 -0
  221. package/dist/lib/threadId.js +123 -0
  222. package/dist/lib/traceContext.d.ts +116 -0
  223. package/dist/lib/traceContext.d.ts.map +1 -0
  224. package/dist/lib/traceContext.js +37 -0
  225. package/dist/lib/traceId.d.ts +78 -0
  226. package/dist/lib/traceId.d.ts.map +1 -0
  227. package/dist/lib/traceId.js +87 -0
  228. package/dist/lib/traceRoot.d.ts +133 -0
  229. package/dist/lib/traceRoot.d.ts.map +1 -0
  230. package/dist/lib/traceRoot.es.d.ts +75 -0
  231. package/dist/lib/traceRoot.es.d.ts.map +1 -0
  232. package/dist/lib/traceRoot.es.js +129 -0
  233. package/dist/lib/traceRoot.js +19 -0
  234. package/dist/lib/traceRoot.node.d.ts +77 -0
  235. package/dist/lib/traceRoot.node.d.ts.map +1 -0
  236. package/dist/lib/traceRoot.node.js +133 -0
  237. package/dist/lib/traceRoot.universal.d.ts +3 -0
  238. package/dist/lib/traceRoot.universal.d.ts.map +1 -0
  239. package/dist/lib/traceRoot.universal.js +17 -0
  240. package/dist/lib/tracer.d.ts +296 -0
  241. package/dist/lib/tracer.d.ts.map +1 -0
  242. package/dist/lib/tracer.js +346 -0
  243. package/dist/lib/tracers/ArrayQueueTracer.d.ts +56 -0
  244. package/dist/lib/tracers/ArrayQueueTracer.d.ts.map +1 -0
  245. package/dist/lib/tracers/ArrayQueueTracer.js +67 -0
  246. package/dist/lib/tracers/CompositeTracer.d.ts +24 -0
  247. package/dist/lib/tracers/CompositeTracer.d.ts.map +1 -0
  248. package/dist/lib/tracers/CompositeTracer.js +57 -0
  249. package/dist/lib/tracers/NoOpTracer.d.ts +58 -0
  250. package/dist/lib/tracers/NoOpTracer.d.ts.map +1 -0
  251. package/dist/lib/tracers/NoOpTracer.js +41 -0
  252. package/dist/lib/tracers/SQLiteTracer.d.ts +42 -0
  253. package/dist/lib/tracers/SQLiteTracer.d.ts.map +1 -0
  254. package/dist/lib/tracers/SQLiteTracer.js +84 -0
  255. package/dist/lib/tracers/StdioTracer.d.ts +83 -0
  256. package/dist/lib/tracers/StdioTracer.d.ts.map +1 -0
  257. package/dist/lib/tracers/StdioTracer.js +270 -0
  258. package/dist/lib/tracers/TestTracer.d.ts +95 -0
  259. package/dist/lib/tracers/TestTracer.d.ts.map +1 -0
  260. package/dist/lib/tracers/TestTracer.js +87 -0
  261. package/dist/lib/tracers/index.d.ts +12 -0
  262. package/dist/lib/tracers/index.d.ts.map +1 -0
  263. package/dist/lib/tracers/index.js +11 -0
  264. package/dist/lib/types.d.ts +366 -0
  265. package/dist/lib/types.d.ts.map +1 -0
  266. package/dist/lib/types.js +1 -0
  267. package/dist/lib/utf8Cache.d.ts +111 -0
  268. package/dist/lib/utf8Cache.d.ts.map +1 -0
  269. package/dist/lib/utf8Cache.js +177 -0
  270. package/dist/lib/wasm/WasmBufferStrategy.d.ts +88 -0
  271. package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -0
  272. package/dist/lib/wasm/WasmBufferStrategy.js +138 -0
  273. package/dist/lib/wasm/wasmAllocator.d.ts +109 -0
  274. package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -0
  275. package/dist/lib/wasm/wasmAllocator.js +227 -0
  276. package/dist/lib/wasm/wasmSpanBuffer.d.ts +123 -0
  277. package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -0
  278. package/dist/lib/wasm/wasmSpanBuffer.js +772 -0
  279. package/dist/lib/wasm/wasmTraceRoot.d.ts +167 -0
  280. package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -0
  281. package/dist/lib/wasm/wasmTraceRoot.js +264 -0
  282. package/dist/node.d.ts +7 -0
  283. package/dist/node.d.ts.map +1 -0
  284. package/dist/node.js +8 -0
  285. package/dist/testing.d.ts +18 -0
  286. package/dist/testing.d.ts.map +1 -0
  287. package/dist/testing.js +17 -0
  288. package/package.json +193 -0
  289. package/src/bun/preload.ts +11 -0
  290. package/src/bun/trace-preload.ts +14 -0
  291. package/src/es.ts +11 -0
  292. package/src/index.ts +194 -0
  293. package/src/lib/JsBufferStrategy.ts +102 -0
  294. package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +485 -0
  295. package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +390 -0
  296. package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +647 -0
  297. package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +292 -0
  298. package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +354 -0
  299. package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +127 -0
  300. package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +392 -0
  301. package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +389 -0
  302. package/src/lib/__tests__/arrow-conversion-algorithms.test.ts +54 -0
  303. package/src/lib/__tests__/arrow-test-helpers.ts +71 -0
  304. package/src/lib/__tests__/binary-e2e.test.ts +203 -0
  305. package/src/lib/__tests__/buffer-overflow-op-api.test.ts +608 -0
  306. package/src/lib/__tests__/buffer-overflow.test.ts +612 -0
  307. package/src/lib/__tests__/capacity-tuning.test.ts +544 -0
  308. package/src/lib/__tests__/effective-schema.test.ts +439 -0
  309. package/src/lib/__tests__/flechette.test.ts +42 -0
  310. package/src/lib/__tests__/flushScheduler.test.ts +537 -0
  311. package/src/lib/__tests__/integration.test.ts +600 -0
  312. package/src/lib/__tests__/library.test.ts +934 -0
  313. package/src/lib/__tests__/nested-library-tasks.test.ts +849 -0
  314. package/src/lib/__tests__/op-context-binding.test.ts +135 -0
  315. package/src/lib/__tests__/op-metadata.test.ts +198 -0
  316. package/src/lib/__tests__/op-type-safety.test.ts +71 -0
  317. package/src/lib/__tests__/package-exports.test.ts +57 -0
  318. package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +319 -0
  319. package/src/lib/__tests__/remapped-buffer-view.test.ts +635 -0
  320. package/src/lib/__tests__/scope-attributes.test.ts +348 -0
  321. package/src/lib/__tests__/span-lifecycle.test.ts +680 -0
  322. package/src/lib/__tests__/sync-async-trace.test.ts +435 -0
  323. package/src/lib/__tests__/test-helpers.ts +318 -0
  324. package/src/lib/__tests__/timestamp.test.ts +259 -0
  325. package/src/lib/__tests__/trace-archive-primitives.test.ts +98 -0
  326. package/src/lib/__tests__/traceContext-type-enforcement.test.ts +271 -0
  327. package/src/lib/__tests__/tracer.test.ts +211 -0
  328. package/src/lib/__tests__/type-narrowing.test.ts +137 -0
  329. package/src/lib/archive/chunkCompaction.ts +44 -0
  330. package/src/lib/archive/chunkEnvelope.ts +79 -0
  331. package/src/lib/archive/chunkRouting.ts +70 -0
  332. package/src/lib/archive/chunkStats.ts +25 -0
  333. package/src/lib/archive/index.ts +4 -0
  334. package/src/lib/arrow/capacityStats.ts +340 -0
  335. package/src/lib/arrow/dictionaries.ts +159 -0
  336. package/src/lib/arrow/flechette.ts +114 -0
  337. package/src/lib/arrow/utils.ts +126 -0
  338. package/src/lib/buffer/Nanoseconds.ts +131 -0
  339. package/src/lib/bufferStrategy.ts +106 -0
  340. package/src/lib/capacityTuning.ts +102 -0
  341. package/src/lib/codegen/__tests__/__snapshots__/evaluatorGenerator.test.ts.snap +160 -0
  342. package/src/lib/codegen/__tests__/__snapshots__/scopeGenerator.test.ts.snap +196 -0
  343. package/src/lib/codegen/__tests__/__snapshots__/spanLoggerGenerator.test.ts.snap +1965 -0
  344. package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +516 -0
  345. package/src/lib/codegen/__tests__/nullBitmap.test.ts +207 -0
  346. package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +237 -0
  347. package/src/lib/codegen/evaluatorGenerator.ts +309 -0
  348. package/src/lib/codegen/fixedPositionWriterGenerator.ts +444 -0
  349. package/src/lib/codegen/spanLoggerGenerator.ts +715 -0
  350. package/src/lib/convertToArrow.ts +1805 -0
  351. package/src/lib/defineOpContext.ts +398 -0
  352. package/src/lib/errors/Blocked.ts +165 -0
  353. package/src/lib/errors/CodeError.ts +132 -0
  354. package/src/lib/errors/RetriesExhausted.ts +78 -0
  355. package/src/lib/errors/Transient.ts +168 -0
  356. package/src/lib/errors/__tests__/Blocked-config.test.ts +152 -0
  357. package/src/lib/errors/__tests__/Transient.test.ts +129 -0
  358. package/src/lib/errors/__tests__/retry-policy.test.ts +85 -0
  359. package/src/lib/errors/index.ts +24 -0
  360. package/src/lib/errors/retry-policy.ts +87 -0
  361. package/src/lib/flushScheduler.ts +509 -0
  362. package/src/lib/library.ts +682 -0
  363. package/src/lib/logApi.ts +70 -0
  364. package/src/lib/logBinding.ts +67 -0
  365. package/src/lib/op.ts +103 -0
  366. package/src/lib/opContext/__tests__/retry.test.ts +764 -0
  367. package/src/lib/opContext/contextTypes.ts +130 -0
  368. package/src/lib/opContext/createOpGroup.ts +456 -0
  369. package/src/lib/opContext/defineOp.ts +281 -0
  370. package/src/lib/opContext/featureFlagTypes.ts +54 -0
  371. package/src/lib/opContext/index.ts +16 -0
  372. package/src/lib/opContext/opGroupTypes.ts +342 -0
  373. package/src/lib/opContext/opTypes.ts +80 -0
  374. package/src/lib/opContext/spanContextTypes.ts +398 -0
  375. package/src/lib/opContext/types.ts +403 -0
  376. package/src/lib/result.ts +550 -0
  377. package/src/lib/schema/LogSchema.ts +153 -0
  378. package/src/lib/schema/__tests__/defineLogSchema.test.ts +342 -0
  379. package/src/lib/schema/__tests__/featureFlags.test.ts +443 -0
  380. package/src/lib/schema/builder.ts +201 -0
  381. package/src/lib/schema/defineFeatureFlags.ts +91 -0
  382. package/src/lib/schema/defineLogSchema.ts +291 -0
  383. package/src/lib/schema/evaluator.ts +404 -0
  384. package/src/lib/schema/extend.ts +69 -0
  385. package/src/lib/schema/systemSchema.ts +339 -0
  386. package/src/lib/schema/typeGuards.ts +163 -0
  387. package/src/lib/schema/types.ts +265 -0
  388. package/src/lib/spanBuffer.ts +571 -0
  389. package/src/lib/spanBufferHelpers.ts +73 -0
  390. package/src/lib/spanBufferStats.ts +40 -0
  391. package/src/lib/spanContext.ts +1566 -0
  392. package/src/lib/sqlite/__tests__/sqlite-common.test.ts +89 -0
  393. package/src/lib/sqlite/index.ts +26 -0
  394. package/src/lib/sqlite/sqlite-async-writer.ts +101 -0
  395. package/src/lib/sqlite/sqlite-common.ts +309 -0
  396. package/src/lib/sqlite/sqlite-d1.ts +104 -0
  397. package/src/lib/sqlite/sqlite-db.ts +32 -0
  398. package/src/lib/sqlite/sqlite-node.ts +83 -0
  399. package/src/lib/sqlite/sqlite-writer.ts +128 -0
  400. package/src/lib/testing/TRACE-TESTING.md +100 -0
  401. package/src/lib/testing/__tests__/bun-harness.test.ts +108 -0
  402. package/src/lib/testing/__tests__/extractFacts.test.ts +279 -0
  403. package/src/lib/testing/__tests__/facts.test.ts +324 -0
  404. package/src/lib/testing/__tests__/vitest-harness.test.ts +32 -0
  405. package/src/lib/testing/bun-harness.ts +990 -0
  406. package/src/lib/testing/extractFacts.ts +362 -0
  407. package/src/lib/testing/facts.ts +470 -0
  408. package/src/lib/testing/index.ts +141 -0
  409. package/src/lib/testing/queryable-span.ts +108 -0
  410. package/src/lib/testing/span-query.ts +65 -0
  411. package/src/lib/testing/stdio-replay.ts +50 -0
  412. package/src/lib/testing/trace-query.ts +329 -0
  413. package/src/lib/testing/vitest-harness.ts +691 -0
  414. package/src/lib/threadId.ts +135 -0
  415. package/src/lib/traceContext.ts +182 -0
  416. package/src/lib/traceId.ts +142 -0
  417. package/src/lib/traceRoot.es.ts +157 -0
  418. package/src/lib/traceRoot.node.ts +170 -0
  419. package/src/lib/traceRoot.ts +154 -0
  420. package/src/lib/traceRoot.universal.ts +22 -0
  421. package/src/lib/tracer.ts +896 -0
  422. package/src/lib/tracers/ArrayQueueTracer.ts +76 -0
  423. package/src/lib/tracers/CompositeTracer.ts +76 -0
  424. package/src/lib/tracers/NoOpTracer.ts +73 -0
  425. package/src/lib/tracers/SQLiteTracer.ts +115 -0
  426. package/src/lib/tracers/StdioTracer.ts +380 -0
  427. package/src/lib/tracers/TestTracer.ts +146 -0
  428. package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +184 -0
  429. package/src/lib/tracers/__tests__/NoOpTracer.test.ts +204 -0
  430. package/src/lib/tracers/__tests__/StdioTracer.test.ts +313 -0
  431. package/src/lib/tracers/__tests__/TestTracer.test.ts +200 -0
  432. package/src/lib/tracers/index.ts +12 -0
  433. package/src/lib/types.ts +498 -0
  434. package/src/lib/utf8Cache.ts +201 -0
  435. package/src/lib/wasm/WasmBufferStrategy.ts +219 -0
  436. package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +256 -0
  437. package/src/lib/wasm/__tests__/wasm-integration.test.ts +476 -0
  438. package/src/lib/wasm/__tests__/wasmAllocator.test.ts +699 -0
  439. package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +449 -0
  440. package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +390 -0
  441. package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +444 -0
  442. package/src/lib/wasm/allocator.zig +945 -0
  443. package/src/lib/wasm/wasmAllocator.ts +469 -0
  444. package/src/lib/wasm/wasmSpanBuffer.ts +1014 -0
  445. package/src/lib/wasm/wasmTraceRoot.ts +315 -0
  446. package/src/node.ts +10 -0
  447. package/src/testing.ts +18 -0
@@ -0,0 +1,1467 @@
1
+ /**
2
+ * Zero-copy conversion from SpanBuffer to Flechette tables
3
+ *
4
+ * Per specs/lmao/01f_arrow_table_structure.md:
5
+ * - Enum columns: Dictionary with compile-time values
6
+ * - Category columns: Dictionary with runtime-built values
7
+ * - Text columns: Plain strings without dictionary
8
+ * - Zero-copy wrap TypedArrays as Arrow vectors
9
+ */
10
+ import { clearBitRange, compareStrings, createSortedDictionary, DictionaryBuilder, getMaskTransform, sortInPlace, } from '@smoothbricks/arrow-builder';
11
+ import { batchType, binary, bool, Column, dictionary, float64, int8, TimeUnit, tableFromColumns, timestamp, uint8, uint16, uint32, uint64, utf8, } from '@uwdata/flechette';
12
+ import { createCapacityStatsTable } from './arrow/capacityStats.js';
13
+ import { buildSortedCategoryDictionary, buildTextDictionary } from './arrow/dictionaries.js';
14
+ import { getArrowIndexArrayConstructorOr, getArrowIndexTypeOr, makeArrowColumn, } from './arrow/flechette.js';
15
+ import { calculateUtf8Offsets, concatenateFloat64Arrays, concatenateNullBitmaps, concatenateUint8Arrays, encodeUtf8Strings, getArrowFieldName, walkSpanTree, } from './arrow/utils.js';
16
+ import { ENTRY_TYPE_NAMES, SYSTEM_SCHEMA_FIELD_NAMES } from './schema/systemSchema.js';
17
+ import { getBinaryEncoder, getEnumUtf8, getEnumValues, getSchemaType } from './schema/typeGuards.js';
18
+ import { globalUtf8Cache } from './utf8Cache.js';
19
+ const DictBuilder = DictionaryBuilder;
20
+ const F64Array = Float64Array;
21
+ const EMPTY_VALIDITY = new Uint8Array(0);
22
+ const BINARY_TYPE = binary();
23
+ function buildData(data) {
24
+ return data;
25
+ }
26
+ function buildColumn(data) {
27
+ if (isDictionaryColumnBuildData(data)) {
28
+ const dictionaryData = {
29
+ type: data.type,
30
+ length: data.length,
31
+ nullCount: data.nullCount,
32
+ values: data.data,
33
+ validity: data.nullBitmap,
34
+ dictionary: data.dictionary,
35
+ };
36
+ return makeArrowColumn(dictionaryData);
37
+ }
38
+ if (isUtf8ColumnBuildData(data)) {
39
+ const utf8Data = {
40
+ type: data.type,
41
+ length: data.length,
42
+ nullCount: data.nullCount,
43
+ values: data.data,
44
+ validity: data.nullBitmap,
45
+ offsets: data.valueOffsets,
46
+ };
47
+ return makeArrowColumn(utf8Data);
48
+ }
49
+ const genericData = {
50
+ type: data.type,
51
+ length: data.length,
52
+ nullCount: data.nullCount,
53
+ values: data.data,
54
+ validity: data.nullBitmap,
55
+ };
56
+ return makeArrowColumn(genericData);
57
+ }
58
+ function isDictionaryColumnBuildData(data) {
59
+ return 'dictionary' in data && data.dictionary instanceof Column;
60
+ }
61
+ function isUtf8ColumnBuildData(data) {
62
+ return 'valueOffsets' in data && data.valueOffsets instanceof Int32Array;
63
+ }
64
+ function buildTable(fields, vectors) {
65
+ if (fields.length === 0)
66
+ return tableFromColumns({});
67
+ const columns = {};
68
+ for (let index = 0; index < fields.length; index++) {
69
+ columns[fields[index]] = vectors[index];
70
+ }
71
+ return tableFromColumns(columns);
72
+ }
73
+ function appendTables(base, extra) {
74
+ const columns = {};
75
+ for (let i = 0; i < base.numCols; i++) {
76
+ const name = base.names[i];
77
+ const left = base.getChildAt(i);
78
+ const right = extra.getChild(name);
79
+ if (!left || !right) {
80
+ throw new Error(`Cannot append tables: missing column '${name}'`);
81
+ }
82
+ columns[name] = new Column([...left.data, ...right.data]);
83
+ }
84
+ return tableFromColumns(columns);
85
+ }
86
+ function getAllocatedStringColumn(buffer, columnName) {
87
+ const column = buffer.getColumnIfAllocated(columnName);
88
+ if (!Array.isArray(column)) {
89
+ return undefined;
90
+ }
91
+ return isStringArray(column) ? column : undefined;
92
+ }
93
+ function getAllocatedBinaryColumn(buffer, columnName) {
94
+ const column = buffer.getColumnIfAllocated(columnName);
95
+ return Array.isArray(column) ? column : undefined;
96
+ }
97
+ function getStringScopeValue(buffer, fieldName) {
98
+ const value = buffer._scopeValues?.[fieldName];
99
+ return typeof value === 'string' ? value : undefined;
100
+ }
101
+ function getNumberScopeValue(buffer, fieldName) {
102
+ const value = buffer._scopeValues?.[fieldName];
103
+ return typeof value === 'number' ? value : undefined;
104
+ }
105
+ function getBooleanScopeValue(buffer, fieldName) {
106
+ const value = buffer._scopeValues?.[fieldName];
107
+ return typeof value === 'boolean' ? value : undefined;
108
+ }
109
+ function requireUint8Array(value, message) {
110
+ if (!(value instanceof Uint8Array)) {
111
+ throw new Error(message);
112
+ }
113
+ return value;
114
+ }
115
+ function isStringArray(value) {
116
+ return Array.isArray(value) && value.every((entry) => typeof entry === 'string' || entry == null);
117
+ }
118
+ function indexTypeForCount(count) {
119
+ if (count <= 255)
120
+ return uint8();
121
+ if (count <= 65535)
122
+ return uint16();
123
+ return uint32();
124
+ }
125
+ // ═══════════════════════════════════════════════════════════════════════════════
126
+ // Shared metadata column helpers (used by both buildMetadataColumnsWithFields
127
+ // and convertBuffersWithSharedDicts to avoid duplication)
128
+ // ═══════════════════════════════════════════════════════════════════════════════
129
+ /**
130
+ * Build non-dictionary identity columns: timestamp, thread_id, span_id, parent_thread_id, parent_span_id.
131
+ * These are identical in both single-batch and shared-dict paths.
132
+ *
133
+ * Callers are responsible for inserting trace_id (dictionary column) at the correct position
134
+ * and entry_type (dictionary column) after these columns.
135
+ */
136
+ function buildNonDictIdentityColumns(buffers, totalRows, fields, vectors) {
137
+ // thread_id (BigUint64Array, constant per buffer)
138
+ const threadIds = new BigUint64Array(totalRows);
139
+ let offset = 0;
140
+ for (const buf of buffers) {
141
+ threadIds.fill(buf.thread_id, offset, offset + buf._writeIndex);
142
+ offset += buf._writeIndex;
143
+ }
144
+ fields.push('thread_id');
145
+ vectors.push(buildColumn(buildData({ type: uint64(), offset: 0, length: totalRows, nullCount: 0, data: threadIds })));
146
+ // span_id (Uint32Array, constant per buffer)
147
+ const spanIds = new Uint32Array(totalRows);
148
+ offset = 0;
149
+ for (const buf of buffers) {
150
+ spanIds.fill(buf.span_id, offset, offset + buf._writeIndex);
151
+ offset += buf._writeIndex;
152
+ }
153
+ fields.push('span_id');
154
+ vectors.push(buildColumn(buildData({ type: uint32(), offset: 0, length: totalRows, nullCount: 0, data: spanIds })));
155
+ // parent_thread_id (nullable BigUint64Array)
156
+ const parentThreadIds = new BigUint64Array(totalRows);
157
+ const parentThreadIdNulls = new Uint8Array(Math.ceil(totalRows / 8));
158
+ parentThreadIdNulls.fill(0xff);
159
+ let parentThreadIdNullCount = 0;
160
+ offset = 0;
161
+ for (const buf of buffers) {
162
+ if (buf._parent) {
163
+ parentThreadIds.fill(buf.parent_thread_id, offset, offset + buf._writeIndex);
164
+ }
165
+ else {
166
+ clearBitRange(parentThreadIdNulls, offset, buf._writeIndex);
167
+ parentThreadIdNullCount += buf._writeIndex;
168
+ }
169
+ offset += buf._writeIndex;
170
+ }
171
+ fields.push('parent_thread_id');
172
+ vectors.push(buildColumn(buildData({
173
+ type: uint64(),
174
+ offset: 0,
175
+ length: totalRows,
176
+ nullCount: parentThreadIdNullCount,
177
+ data: parentThreadIds,
178
+ nullBitmap: parentThreadIdNullCount > 0 ? parentThreadIdNulls : undefined,
179
+ })));
180
+ // parent_span_id (nullable Uint32Array)
181
+ const parentSpanIds = new Uint32Array(totalRows);
182
+ const parentSpanIdNulls = new Uint8Array(Math.ceil(totalRows / 8));
183
+ parentSpanIdNulls.fill(0xff);
184
+ let parentSpanIdNullCount = 0;
185
+ offset = 0;
186
+ for (const buf of buffers) {
187
+ if (buf._hasParent) {
188
+ parentSpanIds.fill(buf.parent_span_id, offset, offset + buf._writeIndex);
189
+ }
190
+ else {
191
+ clearBitRange(parentSpanIdNulls, offset, buf._writeIndex);
192
+ parentSpanIdNullCount += buf._writeIndex;
193
+ }
194
+ offset += buf._writeIndex;
195
+ }
196
+ fields.push('parent_span_id');
197
+ vectors.push(buildColumn(buildData({
198
+ type: uint32(),
199
+ offset: 0,
200
+ length: totalRows,
201
+ nullCount: parentSpanIdNullCount,
202
+ data: parentSpanIds,
203
+ nullBitmap: parentSpanIdNullCount > 0 ? parentSpanIdNulls : undefined,
204
+ })));
205
+ }
206
+ /**
207
+ * Build timestamp column from buffers.
208
+ */
209
+ function buildTimestampColumn(buffers, totalRows, fields, vectors) {
210
+ const allTimestamps = new BigInt64Array(totalRows);
211
+ let offset = 0;
212
+ for (const buf of buffers) {
213
+ if (!buf.timestamp) {
214
+ throw new Error(`Buffer missing timestamps property (_writeIndex: ${buf._writeIndex})`);
215
+ }
216
+ allTimestamps.set(buf.timestamp.subarray(0, buf._writeIndex), offset);
217
+ offset += buf._writeIndex;
218
+ }
219
+ fields.push('timestamp');
220
+ vectors.push(buildColumn(buildData({
221
+ type: timestamp(TimeUnit.NANOSECOND),
222
+ offset: 0,
223
+ length: totalRows,
224
+ nullCount: 0,
225
+ data: allTimestamps,
226
+ })));
227
+ }
228
+ /**
229
+ * Build entry_type dictionary column.
230
+ */
231
+ function buildEntryTypeColumn(buffers, totalRows, fields, vectors, dictType) {
232
+ const entryTypeIndices = new Int8Array(totalRows);
233
+ let offset = 0;
234
+ for (const buf of buffers) {
235
+ if (!buf.entry_type) {
236
+ throw new Error(`Buffer missing operations property (_writeIndex: ${buf._writeIndex})`);
237
+ }
238
+ entryTypeIndices.set(buf.entry_type.subarray(0, buf._writeIndex), offset);
239
+ offset += buf._writeIndex;
240
+ }
241
+ const entryTypeDictData = buildData({
242
+ type: utf8(),
243
+ offset: 0,
244
+ length: ENTRY_TYPE_NAMES.length,
245
+ nullCount: 0,
246
+ valueOffsets: calculateUtf8Offsets(ENTRY_TYPE_NAMES),
247
+ data: encodeUtf8Strings(ENTRY_TYPE_NAMES),
248
+ });
249
+ fields.push('entry_type');
250
+ vectors.push(buildColumn(buildData({
251
+ type: dictType ?? dictionary(utf8(), int8()),
252
+ offset: 0,
253
+ length: totalRows,
254
+ nullCount: 0,
255
+ data: entryTypeIndices,
256
+ dictionary: buildColumn(entryTypeDictData),
257
+ })));
258
+ }
259
+ /**
260
+ * Build a per-buffer metadata dictionary column (package_name, package_file, git_sha).
261
+ * Row 0 uses callsiteMetadata, rows 1+ use opMetadata (per context flow spec).
262
+ */
263
+ function buildPerBufferDictColumn(buffers, totalRows, fieldName, metadataGetter, dictType, dictValues, dictMap, dictUtf8Offsets, dictUtf8Data, fields, vectors) {
264
+ const uniqueCount = dictValues.length;
265
+ const IndexArrayCtor = uniqueCount <= 255 ? Uint8Array : uniqueCount <= 65535 ? Uint16Array : Uint32Array;
266
+ const indices = new IndexArrayCtor(totalRows);
267
+ let offset = 0;
268
+ for (const buf of buffers) {
269
+ const callsiteValue = metadataGetter(buf._callsiteMetadata ?? buf._opMetadata);
270
+ const callsiteIdx = dictMap.get(callsiteValue) ?? 0;
271
+ const opIdx = dictMap.get(metadataGetter(buf._opMetadata)) ?? 0;
272
+ indices[offset] = callsiteIdx;
273
+ if (buf._writeIndex > 1) {
274
+ indices.fill(opIdx, offset + 1, offset + buf._writeIndex);
275
+ }
276
+ offset += buf._writeIndex;
277
+ }
278
+ fields.push(fieldName);
279
+ vectors.push(buildColumn(buildData({
280
+ type: dictType,
281
+ offset: 0,
282
+ length: totalRows,
283
+ nullCount: 0,
284
+ data: indices,
285
+ dictionary: buildColumn(buildData({
286
+ type: utf8(),
287
+ offset: 0,
288
+ length: dictValues.length,
289
+ nullCount: 0,
290
+ valueOffsets: dictUtf8Offsets,
291
+ data: dictUtf8Data,
292
+ })),
293
+ })));
294
+ }
295
+ /**
296
+ * Build a binary Arrow column from SpanBuffer data.
297
+ * Shared by both convertBuffersToTable and convertBuffersWithSharedDicts.
298
+ *
299
+ * Binary columns store arbitrary bytes (raw Uint8Array or encoder-encoded objects).
300
+ * At flush time, the encoder (if present) transforms stored values into Uint8Array.
301
+ */
302
+ function buildBinaryColumnFromBuffers(buffers, columnName, totalRows, fieldSchema) {
303
+ const encoder = getBinaryEncoder(fieldSchema);
304
+ // Collect all values from buffers, encode each if encoder is present
305
+ const allValues = [];
306
+ for (const buf of buffers) {
307
+ const col = getAllocatedBinaryColumn(buf, columnName);
308
+ const srcNulls = buf.getNullsIfAllocated(columnName);
309
+ for (let i = 0; i < buf._writeIndex; i++) {
310
+ if (srcNulls) {
311
+ const isValid = (srcNulls[i >>> 3] & (1 << (i & 7))) !== 0;
312
+ if (isValid && col) {
313
+ const raw = col[i];
314
+ allValues.push(encoder
315
+ ? encoder.encode(raw)
316
+ : requireUint8Array(raw, `Binary column '${columnName}' must store Uint8Array values`));
317
+ }
318
+ else {
319
+ allValues.push(null);
320
+ }
321
+ }
322
+ else if (col) {
323
+ // No null bitmap -- column allocated but check for undefined/null values
324
+ const raw = col[i];
325
+ if (raw != null) {
326
+ allValues.push(encoder
327
+ ? encoder.encode(raw)
328
+ : requireUint8Array(raw, `Binary column '${columnName}' must store Uint8Array values`));
329
+ }
330
+ else {
331
+ allValues.push(null);
332
+ }
333
+ }
334
+ else {
335
+ allValues.push(null);
336
+ }
337
+ }
338
+ }
339
+ // Build offsets and concatenated data buffer
340
+ const offsets = new Int32Array(totalRows + 1);
341
+ let dataLength = 0;
342
+ for (let i = 0; i < allValues.length; i++) {
343
+ offsets[i] = dataLength;
344
+ const value = allValues[i];
345
+ if (value !== null) {
346
+ dataLength += value.length;
347
+ }
348
+ }
349
+ offsets[allValues.length] = dataLength;
350
+ const data = new Uint8Array(dataLength);
351
+ let dataOffset = 0;
352
+ let nullCount = 0;
353
+ const nullBitmapSize = Math.ceil(totalRows / 8);
354
+ const nullBitmap = new Uint8Array(nullBitmapSize);
355
+ for (let i = 0; i < allValues.length; i++) {
356
+ const val = allValues[i];
357
+ if (val !== null) {
358
+ data.set(val, dataOffset);
359
+ dataOffset += val.length;
360
+ // Mark valid in null bitmap
361
+ nullBitmap[i >>> 3] |= 1 << (i & 7);
362
+ }
363
+ else {
364
+ nullCount++;
365
+ }
366
+ }
367
+ // Build Arrow Binary column via flechette
368
+ const batch = new (batchType(BINARY_TYPE))({
369
+ type: BINARY_TYPE,
370
+ length: totalRows,
371
+ nullCount,
372
+ validity: nullCount > 0 ? nullBitmap : EMPTY_VALIDITY,
373
+ offsets,
374
+ values: data,
375
+ });
376
+ return { column: new Column([batch]), nullCount };
377
+ }
378
+ /**
379
+ * Convert SpanBuffer (and its overflow chain) to an Arrow table.
380
+ *
381
+ * **Dictionary handling**: Each table batch has its own dictionary data.
382
+ * Dictionaries are built from the data in this batch only and are not shared
383
+ * with other batches, even when combined into a Table.
384
+ */
385
+ export function convertToTable(buffer, systemColumnBuilder) {
386
+ const buffers = [];
387
+ let currentBuffer = buffer;
388
+ while (currentBuffer) {
389
+ buffers.push(currentBuffer);
390
+ currentBuffer = currentBuffer._overflow;
391
+ }
392
+ return convertBuffersToTable(buffers, systemColumnBuilder);
393
+ }
394
+ /**
395
+ * Convert multiple buffers to a single table.
396
+ *
397
+ * **Dictionary handling**: Each table batch has its own dictionary data.
398
+ * Dictionaries are built from the data in this batch only and are not shared
399
+ * with other batches, even when combined into a Table.
400
+ */
401
+ function convertBuffersToTable(buffers, systemColumnBuilder) {
402
+ if (buffers.length === 0)
403
+ return tableFromColumns({});
404
+ const totalRows = buffers.reduce((sum, buf) => sum + buf._writeIndex, 0);
405
+ if (totalRows === 0)
406
+ return tableFromColumns({});
407
+ const schema = buffers[0]._logSchema;
408
+ // Build vectors first, then derive schema from them
409
+ // This ensures Field types and vector data types are identical (Arrow IPC requirement)
410
+ const fields = [];
411
+ const vectors = [];
412
+ if (systemColumnBuilder) {
413
+ const systemColumns = systemColumnBuilder(buffers[0], buffers, totalRows);
414
+ fields.push(...systemColumns.fields);
415
+ vectors.push(...systemColumns.vectors);
416
+ }
417
+ else {
418
+ // Build metadata columns - returns both fields and vectors with matching types
419
+ const metadataResult = buildMetadataColumnsWithFields(buffers, totalRows);
420
+ fields.push(...metadataResult.fields);
421
+ vectors.push(...metadataResult.vectors);
422
+ // System attribute column: message (eager category)
423
+ const maskTransform = undefined; // message has no masking
424
+ let { dictionary: dictValues, indices, arrowIndexType, nullBitmap, } = buildSortedCategoryDictionary(buffers, 'message', maskTransform);
425
+ // Ensure dictionary has at least one entry (empty string) if no messages were written
426
+ if (dictValues.length === 0) {
427
+ dictValues = [''];
428
+ }
429
+ // Ensure nullBitmap is all 1s (all valid) for eager column
430
+ if (!nullBitmap) {
431
+ const bitmapBytes = Math.ceil(totalRows / 8);
432
+ nullBitmap = new Uint8Array(bitmapBytes);
433
+ nullBitmap.fill(0xff);
434
+ }
435
+ // CRITICAL: Create ONE Dictionary type instance for field and batch data
436
+ // Arrow Schema validates that fields with same dictionary ID have identical type references
437
+ const messageDictType = dictionary(utf8(), arrowIndexType);
438
+ fields.push('message');
439
+ const { data: messageUtf8Data, offsets: messageUtf8Offsets } = globalUtf8Cache.encodeMany(dictValues);
440
+ const messageDictData = buildData({
441
+ type: utf8(),
442
+ offset: 0,
443
+ length: dictValues.length,
444
+ nullCount: 0,
445
+ valueOffsets: messageUtf8Offsets,
446
+ data: messageUtf8Data,
447
+ });
448
+ const messageData = buildData({
449
+ type: messageDictType,
450
+ offset: 0,
451
+ length: totalRows,
452
+ nullCount: 0, // message is eager, never null
453
+ data: indices,
454
+ nullBitmap, // Always include nullBitmap for message (even though nullCount is 0)
455
+ dictionary: buildColumn(messageDictData),
456
+ });
457
+ vectors.push(buildColumn(messageData));
458
+ }
459
+ // Build user attribute vectors
460
+ // Skip system schema fields - they are handled separately as system columns
461
+ // (message is handled above, line/error_code/exception_stack/ff_value/uint64_value below)
462
+ const userSchemaFields = schema._columns.filter(([fieldName]) => !SYSTEM_SCHEMA_FIELD_NAMES.has(fieldName));
463
+ for (const [fieldName, fieldSchema] of userSchemaFields) {
464
+ const lmaoType = getSchemaType(fieldSchema);
465
+ const arrowFieldName = getArrowFieldName(fieldName);
466
+ const columnName = fieldName; // User columns have no prefix
467
+ if (lmaoType === 'enum') {
468
+ const enumValues = getEnumValues(fieldSchema) || [];
469
+ const enumUtf8 = getEnumUtf8(fieldSchema);
470
+ // Get constructors from schema metadata
471
+ const indexArrayCtor = getArrowIndexArrayConstructorOr(fieldSchema);
472
+ const arrowIndexType = getArrowIndexTypeOr(fieldSchema, uint8());
473
+ // Collect value arrays - need to handle different TypedArray types
474
+ const valueArrays = [];
475
+ for (const buf of buffers) {
476
+ const column = buf.getColumnIfAllocated(columnName);
477
+ if (column && column instanceof indexArrayCtor) {
478
+ valueArrays.push(column.subarray(0, buf._writeIndex));
479
+ }
480
+ else {
481
+ valueArrays.push(new indexArrayCtor(buf._writeIndex));
482
+ }
483
+ }
484
+ // Concatenate arrays based on type
485
+ let allIndices;
486
+ if (indexArrayCtor === Uint8Array) {
487
+ const uint8ValueArrays = [];
488
+ for (const array of valueArrays) {
489
+ if (!(array instanceof Uint8Array)) {
490
+ throw new Error(`Enum column '${columnName}' expected Uint8Array chunks`);
491
+ }
492
+ uint8ValueArrays.push(array);
493
+ }
494
+ allIndices = concatenateUint8Arrays(uint8ValueArrays);
495
+ }
496
+ else {
497
+ const totalLength = valueArrays.reduce((sum, arr) => sum + arr.length, 0);
498
+ allIndices = new indexArrayCtor(totalLength);
499
+ let offset = 0;
500
+ for (const arr of valueArrays) {
501
+ allIndices.set(arr, offset);
502
+ offset += arr.length;
503
+ }
504
+ }
505
+ const { nullBitmap, nullCount } = concatenateNullBitmaps(buffers, columnName);
506
+ // CRITICAL: Create ONE Dictionary type instance for field and batch data
507
+ const enumDictType = dictionary(utf8(), arrowIndexType);
508
+ fields.push(arrowFieldName);
509
+ const enumDictData = buildData({
510
+ type: utf8(),
511
+ offset: 0,
512
+ length: enumValues.length,
513
+ nullCount: 0,
514
+ valueOffsets: enumUtf8?.offsets ?? calculateUtf8Offsets(enumValues),
515
+ data: enumUtf8?.concatenated ?? encodeUtf8Strings(enumValues),
516
+ });
517
+ const enumData = buildData({
518
+ type: enumDictType,
519
+ offset: 0,
520
+ length: totalRows,
521
+ nullCount,
522
+ data: allIndices,
523
+ nullBitmap,
524
+ dictionary: buildColumn(enumDictData),
525
+ });
526
+ vectors.push(buildColumn(enumData));
527
+ }
528
+ else if (lmaoType === 'category') {
529
+ // Get mask transform from schema metadata (if present)
530
+ const maskTransform = getMaskTransform(fieldSchema);
531
+ const { dictionary: dictValues, indices, arrowIndexType, nullBitmap, nullCount, } = buildSortedCategoryDictionary(buffers, columnName, maskTransform);
532
+ // CRITICAL: Create ONE Dictionary type instance for field and batch data
533
+ const categoryDictType = dictionary(utf8(), arrowIndexType);
534
+ fields.push(arrowFieldName);
535
+ const { data: categoryUtf8Data, offsets: categoryUtf8Offsets } = globalUtf8Cache.encodeMany(dictValues);
536
+ const categoryDictData = buildData({
537
+ type: utf8(),
538
+ offset: 0,
539
+ length: dictValues.length,
540
+ nullCount: 0,
541
+ valueOffsets: categoryUtf8Offsets,
542
+ data: categoryUtf8Data,
543
+ });
544
+ const categoryData = buildData({
545
+ type: categoryDictType,
546
+ offset: 0,
547
+ length: totalRows,
548
+ nullCount,
549
+ data: indices,
550
+ nullBitmap,
551
+ dictionary: buildColumn(categoryDictData),
552
+ });
553
+ vectors.push(buildColumn(categoryData));
554
+ }
555
+ else if (lmaoType === 'text') {
556
+ // Get mask transform from schema metadata (if present)
557
+ const maskTransform = getMaskTransform(fieldSchema);
558
+ const result = buildTextDictionary(buffers, columnName, maskTransform);
559
+ if (result) {
560
+ const { dictionary: dictValues, indices, arrowIndexType, nullBitmap, nullCount } = result;
561
+ // CRITICAL: Create ONE Dictionary type instance for field and batch data
562
+ const textDictType = dictionary(utf8(), arrowIndexType);
563
+ fields.push(arrowFieldName);
564
+ const { data: textUtf8Data, offsets: textUtf8Offsets } = globalUtf8Cache.encodeMany(dictValues);
565
+ const textDictData = buildData({
566
+ type: utf8(),
567
+ offset: 0,
568
+ length: dictValues.length,
569
+ nullCount: 0,
570
+ valueOffsets: textUtf8Offsets,
571
+ data: textUtf8Data,
572
+ });
573
+ const textData = buildData({
574
+ type: textDictType,
575
+ offset: 0,
576
+ length: totalRows,
577
+ nullCount,
578
+ data: indices,
579
+ nullBitmap,
580
+ dictionary: buildColumn(textDictData),
581
+ });
582
+ vectors.push(buildColumn(textData));
583
+ }
584
+ }
585
+ else if (lmaoType === 'number') {
586
+ const valueArrays = [];
587
+ for (const buf of buffers) {
588
+ const column = buf.getColumnIfAllocated(columnName);
589
+ if (column && column instanceof Float64Array) {
590
+ valueArrays.push(column.subarray(0, buf._writeIndex));
591
+ }
592
+ else {
593
+ valueArrays.push(new F64Array(buf._writeIndex));
594
+ }
595
+ }
596
+ const allValues = concatenateFloat64Arrays(valueArrays);
597
+ const { nullBitmap, nullCount } = concatenateNullBitmaps(buffers, columnName);
598
+ const numberType = float64();
599
+ fields.push(arrowFieldName);
600
+ const numberData = buildData({
601
+ type: numberType,
602
+ offset: 0,
603
+ length: totalRows,
604
+ nullCount,
605
+ data: allValues,
606
+ nullBitmap,
607
+ });
608
+ vectors.push(buildColumn(numberData));
609
+ }
610
+ else if (lmaoType === 'boolean') {
611
+ const valueArrays = [];
612
+ for (const buf of buffers) {
613
+ const column = buf.getColumnIfAllocated(columnName);
614
+ if (column && column instanceof Uint8Array) {
615
+ const requiredBytes = Math.ceil(buf._writeIndex / 8);
616
+ valueArrays.push(column.subarray(0, requiredBytes));
617
+ }
618
+ else {
619
+ const requiredBytes = Math.ceil(buf._writeIndex / 8);
620
+ valueArrays.push(new Uint8Array(requiredBytes));
621
+ }
622
+ }
623
+ const allValues = concatenateUint8Arrays(valueArrays);
624
+ const { nullBitmap, nullCount } = concatenateNullBitmaps(buffers, columnName);
625
+ const boolType = bool();
626
+ fields.push(arrowFieldName);
627
+ const boolData = buildData({
628
+ type: boolType,
629
+ offset: 0,
630
+ length: totalRows,
631
+ nullCount,
632
+ data: allValues,
633
+ nullBitmap,
634
+ });
635
+ vectors.push(buildColumn(boolData));
636
+ }
637
+ else if (lmaoType === 'binary') {
638
+ // Binary columns: raw Uint8Array or encoder-wrapped values (e.g. msgpack)
639
+ const { column } = buildBinaryColumnFromBuffers(buffers, columnName, totalRows, fieldSchema);
640
+ fields.push(arrowFieldName);
641
+ vectors.push(column);
642
+ }
643
+ }
644
+ return buildTable(fields, vectors);
645
+ }
646
+ /**
647
+ * Build metadata columns with matching Field definitions.
648
+ * Returns both fields and vectors with identical Dictionary type instances.
649
+ * This is required for Arrow IPC serialization - Schema validates that
650
+ * fields with same dictionary ID have identical type object references.
651
+ */
652
+ function buildMetadataColumnsWithFields(buffers, totalRows) {
653
+ const fields = [];
654
+ const vectors = [];
655
+ // Column order: timestamp, trace_id, thread_id, span_id, parent_thread_id, parent_span_id,
656
+ // entry_type, package_name, package_file, git_sha
657
+ // 1. Timestamp
658
+ buildTimestampColumn(buffers, totalRows, fields, vectors);
659
+ // 2. Trace ID dictionary (built inline from buffers)
660
+ const traceIdSet = new Set();
661
+ for (const buf of buffers)
662
+ traceIdSet.add(buf.trace_id);
663
+ const traceIdArray = Array.from(traceIdSet);
664
+ const traceIdMap = new Map(traceIdArray.map((id, idx) => [id, idx]));
665
+ const traceIdArrowIndexType = indexTypeForCount(traceIdArray.length);
666
+ const TraceIdIndexArrayCtor = traceIdArray.length <= 255 ? Uint8Array : traceIdArray.length <= 65535 ? Uint16Array : Uint32Array;
667
+ const traceIdIndices = new TraceIdIndexArrayCtor(totalRows);
668
+ let rowOffset = 0;
669
+ for (const buf of buffers) {
670
+ const traceIdIndex = traceIdMap.get(buf.trace_id);
671
+ if (traceIdIndex === undefined) {
672
+ throw new Error(`TraceId index not found for: ${buf.trace_id}`);
673
+ }
674
+ traceIdIndices.fill(traceIdIndex, rowOffset, rowOffset + buf._writeIndex);
675
+ rowOffset += buf._writeIndex;
676
+ }
677
+ const traceIdDictType = dictionary(utf8(), traceIdArrowIndexType);
678
+ fields.push('trace_id');
679
+ vectors.push(buildColumn(buildData({
680
+ type: traceIdDictType,
681
+ offset: 0,
682
+ length: totalRows,
683
+ nullCount: 0,
684
+ data: traceIdIndices,
685
+ dictionary: buildColumn(buildData({
686
+ type: utf8(),
687
+ offset: 0,
688
+ length: traceIdArray.length,
689
+ nullCount: 0,
690
+ valueOffsets: calculateUtf8Offsets(traceIdArray),
691
+ data: encodeUtf8Strings(traceIdArray),
692
+ })),
693
+ })));
694
+ // 3-6. thread_id, span_id, parent_thread_id, parent_span_id
695
+ buildNonDictIdentityColumns(buffers, totalRows, fields, vectors);
696
+ // 7. Entry type
697
+ buildEntryTypeColumn(buffers, totalRows, fields, vectors);
698
+ // 8-10. Per-buffer metadata columns (package_name, package_file, git_sha)
699
+ for (const [fieldName, metadataGetter] of [
700
+ ['package_name', (m) => m.package_name],
701
+ ['package_file', (m) => m.package_file],
702
+ ['git_sha', (m) => m.git_sha],
703
+ ]) {
704
+ const valueSet = new Set();
705
+ for (const buf of buffers) {
706
+ valueSet.add(metadataGetter(buf._opMetadata));
707
+ if (buf._callsiteMetadata)
708
+ valueSet.add(metadataGetter(buf._callsiteMetadata));
709
+ }
710
+ const dictValues = Array.from(valueSet);
711
+ const dictMap = new Map(dictValues.map((v, i) => [v, i]));
712
+ const arrowIndexType = indexTypeForCount(dictValues.length);
713
+ const dictType = dictionary(utf8(), arrowIndexType);
714
+ buildPerBufferDictColumn(buffers, totalRows, fieldName, metadataGetter, dictType, dictValues, dictMap, calculateUtf8Offsets(dictValues), encodeUtf8Strings(dictValues), fields, vectors);
715
+ }
716
+ return { fields, vectors };
717
+ }
718
+ /**
719
+ * Convert SpanBuffer (and its overflow chain) to Arrow Table
720
+ */
721
+ export function convertToArrowTable(buffer, systemColumnBuilder) {
722
+ const batch = convertToTable(buffer, systemColumnBuilder);
723
+ if (batch.numRows === 0)
724
+ return tableFromColumns({});
725
+ return batch;
726
+ }
727
+ // ═══════════════════════════════════════════════════════════════════════════════
728
+ // Tree Conversion with Shared Dictionaries
729
+ // ═══════════════════════════════════════════════════════════════════════════════
730
+ /**
731
+ * Convert SpanBuffer tree to Arrow Table
732
+ *
733
+ * Two-pass conversion with shared dictionaries:
734
+ * - Pass 1: Walk tree, build dictionaries (collect unique strings, cache UTF-8)
735
+ * - Pass 2: Walk tree, convert each buffer to a table using shared dictionaries
736
+ */
737
+ export function convertSpanTreeToArrowTable(rootBuffer, _systemColumnBuilder, modulesToLogStats, periodStartNs) {
738
+ // ═══════════════════════════════════════════════════════════════════════════
739
+ // PASS 0: Collect ALL unique schema fields from ALL buffers in the tree
740
+ // Per specs/lmao/01k_tree_walker_and_arrow_conversion.md - child spans may have different schemas
741
+ // (e.g., library prefixed schemas like db_query, http_status, etc.)
742
+ // ═══════════════════════════════════════════════════════════════════════════
743
+ const mergedSchemaFields = new Map();
744
+ walkSpanTree(rootBuffer, (buffer) => {
745
+ // Use buffer._columns directly - works for both SpanBuffer and RemappedBufferView
746
+ const fields = buffer._columns;
747
+ for (const [fieldName, fieldSchema] of fields) {
748
+ // Skip system schema fields - they are handled separately as system columns
749
+ // (message, line, error_code, exception_stack, ff_value, uint64_value)
750
+ if (SYSTEM_SCHEMA_FIELD_NAMES.has(fieldName)) {
751
+ continue;
752
+ }
753
+ // Only add if not already present (first buffer with this field wins)
754
+ if (!mergedSchemaFields.has(fieldName)) {
755
+ mergedSchemaFields.set(fieldName, fieldSchema);
756
+ }
757
+ }
758
+ });
759
+ // Convert merged schema fields to array format for iteration
760
+ const schemaFields = Array.from(mergedSchemaFields.entries());
761
+ // Create merged schema object from collected fields (for capacity stats and other uses)
762
+ const mergedSchema = Object.fromEntries(mergedSchemaFields);
763
+ // ═══════════════════════════════════════════════════════════════════════════
764
+ // PASS 1: Build dictionaries using DictionaryBuilder from arrow-builder
765
+ // ═══════════════════════════════════════════════════════════════════════════
766
+ const categoryBuilders = new Map();
767
+ const textBuilders = new Map();
768
+ // Store mask transforms and original->masked mappings per column
769
+ const categoryMaskTransforms = new Map();
770
+ const textMaskTransforms = new Map();
771
+ const categoryOriginalToMasked = new Map();
772
+ const textOriginalToMasked = new Map();
773
+ // Use cached schemaFields to filter out methods (extend, validate, parse, safeParse)
774
+ for (const [fieldName, fieldSchema] of schemaFields) {
775
+ const lmaoType = getSchemaType(fieldSchema);
776
+ if (lmaoType === 'category') {
777
+ categoryBuilders.set(fieldName, new DictBuilder(globalUtf8Cache));
778
+ categoryMaskTransforms.set(fieldName, getMaskTransform(fieldSchema));
779
+ categoryOriginalToMasked.set(fieldName, new Map());
780
+ }
781
+ if (lmaoType === 'text') {
782
+ textBuilders.set(fieldName, new DictBuilder(globalUtf8Cache));
783
+ textMaskTransforms.set(fieldName, getMaskTransform(fieldSchema));
784
+ textOriginalToMasked.set(fieldName, new Map());
785
+ }
786
+ }
787
+ // System attribute column: message (eager category, not in user schema)
788
+ // message is always present (eager allocation), so we need to handle it explicitly
789
+ categoryBuilders.set('message', new DictBuilder(globalUtf8Cache));
790
+ categoryMaskTransforms.set('message', undefined); // message has no masking
791
+ categoryOriginalToMasked.set('message', new Map());
792
+ // Metadata column dictionaries
793
+ // For traceId (metadata), use DictionaryBuilder (values not pre-encoded)
794
+ const traceIdBuilder = new DictBuilder(globalUtf8Cache);
795
+ // For package, modulePath, gitSha - collect pre-encoded entries for direct dictionary creation
796
+ // Use a Set to deduplicate by OpMetadata identity (same module = same entries)
797
+ const uniqueModules = new Set();
798
+ let spanRows = 0;
799
+ walkSpanTree(rootBuffer, (buffer) => {
800
+ spanRows += buffer._writeIndex;
801
+ traceIdBuilder.add(buffer.trace_id);
802
+ // Collect unique OpMetadata (for package_name, package_file, git_sha)
803
+ // Include both buffer._opMetadata (for rows 1+) and callsiteMetadata (for row 0) if present
804
+ uniqueModules.add(buffer._opMetadata);
805
+ if (buffer._callsiteMetadata) {
806
+ uniqueModules.add(buffer._callsiteMetadata);
807
+ }
808
+ for (const [fieldName, builder] of categoryBuilders) {
809
+ const col = getAllocatedStringColumn(buffer, fieldName);
810
+ const maskTransform = categoryMaskTransforms.get(fieldName);
811
+ const originalToMasked = categoryOriginalToMasked.get(fieldName);
812
+ if (!originalToMasked) {
813
+ throw new Error(`Category originalToMasked map not found for field: ${fieldName}`);
814
+ }
815
+ if (col) {
816
+ for (let i = 0; i < buffer._writeIndex; i++) {
817
+ const originalValue = col[i];
818
+ if (originalValue != null) {
819
+ let maskedValue = originalToMasked.get(originalValue);
820
+ if (maskedValue === undefined) {
821
+ maskedValue = maskTransform ? maskTransform(originalValue) : originalValue;
822
+ originalToMasked.set(originalValue, maskedValue);
823
+ }
824
+ builder.add(maskedValue);
825
+ }
826
+ }
827
+ }
828
+ // Also add scope values to dictionary (they may not be in columns)
829
+ // Per specs/lmao/01i_span_scope_attributes.md: scope values fill NULL cells at Arrow conversion
830
+ const scopeValue = getStringScopeValue(buffer, fieldName);
831
+ if (scopeValue !== undefined) {
832
+ let maskedScopeValue = originalToMasked.get(scopeValue);
833
+ if (maskedScopeValue === undefined) {
834
+ maskedScopeValue = maskTransform ? maskTransform(scopeValue) : scopeValue;
835
+ originalToMasked.set(scopeValue, maskedScopeValue);
836
+ }
837
+ builder.add(maskedScopeValue);
838
+ }
839
+ }
840
+ for (const [fieldName, builder] of textBuilders) {
841
+ const col = getAllocatedStringColumn(buffer, fieldName);
842
+ const maskTransform = textMaskTransforms.get(fieldName);
843
+ const originalToMasked = textOriginalToMasked.get(fieldName);
844
+ if (!originalToMasked) {
845
+ throw new Error(`Text originalToMasked map not found for field: ${fieldName}`);
846
+ }
847
+ if (col) {
848
+ for (let i = 0; i < buffer._writeIndex; i++) {
849
+ const originalValue = col[i];
850
+ if (originalValue != null) {
851
+ let maskedValue = originalToMasked.get(originalValue);
852
+ if (maskedValue === undefined) {
853
+ maskedValue = maskTransform ? maskTransform(originalValue) : originalValue;
854
+ originalToMasked.set(originalValue, maskedValue);
855
+ }
856
+ builder.add(maskedValue);
857
+ }
858
+ }
859
+ }
860
+ // Also add scope values to dictionary (they may not be in columns)
861
+ // Per specs/lmao/01i_span_scope_attributes.md: scope values fill NULL cells at Arrow conversion
862
+ const scopeValue = getStringScopeValue(buffer, fieldName);
863
+ if (scopeValue !== undefined) {
864
+ let maskedScopeValue = originalToMasked.get(scopeValue);
865
+ if (maskedScopeValue === undefined) {
866
+ maskedScopeValue = maskTransform ? maskTransform(scopeValue) : scopeValue;
867
+ originalToMasked.set(scopeValue, maskedScopeValue);
868
+ }
869
+ builder.add(maskedScopeValue);
870
+ }
871
+ // Scope values are now pre-filled in columns at allocation time
872
+ // (via lazy getters and _prefillScopedAttributes on overflow),
873
+ // so they'll be added to dictionary via the column iteration above
874
+ }
875
+ });
876
+ if (spanRows === 0 && (!modulesToLogStats || modulesToLogStats.length === 0)) {
877
+ return tableFromColumns({});
878
+ }
879
+ // Finalize dictionaries
880
+ const traceIdDict = traceIdBuilder.finalize(false);
881
+ // Build dictionaries from OpMetadata entries
882
+ // Use pre-encoded entries from OpMetadata (interned at Op definition time)
883
+ const moduleCount = uniqueModules.size;
884
+ const packageEntries = new Array(moduleCount);
885
+ const packagePathEntries = new Array(moduleCount);
886
+ const gitShaEntries = new Array(moduleCount);
887
+ let idx = 0;
888
+ for (const m of uniqueModules) {
889
+ packageEntries[idx] = m.package_name_entry;
890
+ packagePathEntries[idx] = m.package_file_entry;
891
+ gitShaEntries[idx] = m.git_sha_entry;
892
+ idx++;
893
+ }
894
+ const cmp = (a, b) => compareStrings(a.str, b.str);
895
+ const packageDict = createSortedDictionary(sortInPlace(packageEntries, cmp));
896
+ const packagePathDict = createSortedDictionary(sortInPlace(packagePathEntries, cmp));
897
+ const gitShaDict = createSortedDictionary(sortInPlace(gitShaEntries, cmp));
898
+ const categoryDicts = new Map();
899
+ const textDicts = new Map();
900
+ for (const [name, builder] of categoryBuilders) {
901
+ categoryDicts.set(name, builder.finalize(true)); // sorted for binary search
902
+ }
903
+ for (const [name, builder] of textBuilders) {
904
+ textDicts.set(name, builder.finalize(false)); // not sorted
905
+ }
906
+ // Get messageDict from categoryDicts (message is handled as a category column)
907
+ // If no messages were written, create an empty dictionary
908
+ let messageDict = categoryDicts.get('message');
909
+ if (!messageDict) {
910
+ const messageBuilder = new DictBuilder(globalUtf8Cache);
911
+ messageBuilder.add(''); // Single empty string entry
912
+ messageDict = messageBuilder.finalize(true); // sorted
913
+ }
914
+ // ═══════════════════════════════════════════════════════════════════════════
915
+ // PASS 2: Collect all buffers with non-zero rows
916
+ // ═══════════════════════════════════════════════════════════════════════════
917
+ const allBuffers = [];
918
+ walkSpanTree(rootBuffer, (buffer) => {
919
+ if (buffer._writeIndex > 0) {
920
+ allBuffers.push(buffer);
921
+ }
922
+ });
923
+ // Build a single table from all buffers
924
+ const batch = allBuffers.length > 0
925
+ ? convertBuffersWithSharedDicts(allBuffers, traceIdDict, packageDict, packagePathDict, gitShaDict, categoryDicts, textDicts, schemaFields, categoryOriginalToMasked, textOriginalToMasked)
926
+ : undefined;
927
+ // Create capacity stats table if needed
928
+ if (modulesToLogStats && modulesToLogStats.length > 0) {
929
+ // periodStartNs must be provided by the caller (from FlushScheduler's tracked period start)
930
+ // If not provided, use 0n as a fallback (indicates period tracking not enabled)
931
+ const effectivePeriodStartNs = periodStartNs ?? 0n;
932
+ const capacityStatsBatch = createCapacityStatsTable(modulesToLogStats, effectivePeriodStartNs, mergedSchema);
933
+ if (batch) {
934
+ return appendTables(batch, capacityStatsBatch);
935
+ }
936
+ return capacityStatsBatch;
937
+ }
938
+ if (batch) {
939
+ return batch;
940
+ }
941
+ return tableFromColumns({});
942
+ }
943
+ /**
944
+ * Convert multiple buffers to a single table using pre-built dictionaries.
945
+ *
946
+ * **Dictionary handling**: Each table batch has its own dictionary data.
947
+ * While dictionaries are built in a first pass from all buffers, they are used to create
948
+ * a single table. The resulting batches contain their own dictionary data and
949
+ * are not shared with other batches, even when combined into a Table.
950
+ */
951
+ function convertBuffersWithSharedDicts(buffers, traceIdDict, packageDict, packagePathDict, gitShaDict, categoryDicts, textDicts, schemaFields, categoryOriginalToMasked, textOriginalToMasked) {
952
+ const totalRows = buffers.reduce((sum, buf) => sum + buf._writeIndex, 0);
953
+ const fields = [];
954
+ const vectors = [];
955
+ // Dictionary types with explicit IDs for IPC serialization
956
+ const traceIdType = dictionary(utf8(), traceIdDict.arrowIndexType, false, 0);
957
+ const entryTypeDictType = dictionary(utf8(), int8(), false, 1);
958
+ const packageType = dictionary(utf8(), packageDict.arrowIndexType, false, 2);
959
+ const packagePathType = dictionary(utf8(), packagePathDict.arrowIndexType, false, 3);
960
+ const gitShaType = dictionary(utf8(), gitShaDict.arrowIndexType, false, 4);
961
+ // Column order: timestamp, trace_id, thread_id, span_id, parent_thread_id, parent_span_id,
962
+ // entry_type, package_name, package_file, git_sha
963
+ // 1. Timestamp
964
+ buildTimestampColumn(buffers, totalRows, fields, vectors);
965
+ // 2. Trace ID (using shared pre-built dictionary)
966
+ const traceIdIndices = new traceIdDict.indexArrayCtor(totalRows);
967
+ let offset = 0;
968
+ for (const buf of buffers) {
969
+ const idx = traceIdDict.indexMap.get(buf.trace_id) ?? 0;
970
+ traceIdIndices.fill(idx, offset, offset + buf._writeIndex);
971
+ offset += buf._writeIndex;
972
+ }
973
+ fields.push('trace_id');
974
+ vectors.push(buildColumn(buildData({
975
+ type: traceIdType,
976
+ offset: 0,
977
+ length: totalRows,
978
+ nullCount: 0,
979
+ data: traceIdIndices,
980
+ dictionary: buildColumn(buildData({
981
+ type: utf8(),
982
+ offset: 0,
983
+ length: traceIdDict.indexMap.size,
984
+ nullCount: 0,
985
+ valueOffsets: traceIdDict.offsets,
986
+ data: traceIdDict.data,
987
+ })),
988
+ })));
989
+ // 3-6. thread_id, span_id, parent_thread_id, parent_span_id
990
+ buildNonDictIdentityColumns(buffers, totalRows, fields, vectors);
991
+ // 7. Entry type (with explicit dictionary ID for IPC)
992
+ buildEntryTypeColumn(buffers, totalRows, fields, vectors, entryTypeDictType);
993
+ // 8-10. Per-buffer metadata columns using shared pre-built dictionaries
994
+ // Per specs/lmao/01c_context_flow_and_op_wrappers.md:
995
+ // - Row 0 (span-start): uses callsiteModule for gitSha/packageName/packagePath
996
+ // - Rows 1+ (logs, span-end): uses task._module
997
+ for (const [fieldName, metadataGetter, dictType, dict] of [
998
+ ['package_name', (m) => m.package_name, packageType, packageDict],
999
+ ['package_file', (m) => m.package_file, packagePathType, packagePathDict],
1000
+ ['git_sha', (m) => m.git_sha, gitShaType, gitShaDict],
1001
+ ]) {
1002
+ const dictValues = Array.from(dict.indexMap.keys());
1003
+ buildPerBufferDictColumn(buffers, totalRows, fieldName, metadataGetter, dictType, dictValues, dict.indexMap, dict.offsets, dict.data, fields, vectors);
1004
+ }
1005
+ // ═══════════════════════════════════════════════════════════════════════════
1006
+ // System attribute and user attribute columns - concatenate from all buffers
1007
+ // ═══════════════════════════════════════════════════════════════════════════
1008
+ // System attribute column: message (at fixed position 10, before user attributes)
1009
+ const messageDict = categoryDicts.get('message');
1010
+ const messageOriginalToMasked = categoryOriginalToMasked.get('message');
1011
+ if (!messageDict || !messageOriginalToMasked) {
1012
+ throw new Error('Message dictionary or mapping not found');
1013
+ }
1014
+ const messageFieldType = dictionary(utf8(), messageDict.arrowIndexType, false, 5);
1015
+ const messageIndices = new messageDict.indexArrayCtor(totalRows);
1016
+ const messageNullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
1017
+ let messageRowOffset = 0;
1018
+ for (const buf of buffers) {
1019
+ const col = getAllocatedStringColumn(buf, 'message');
1020
+ if (col) {
1021
+ for (let i = 0; i < buf._writeIndex; i++) {
1022
+ const v = col[i];
1023
+ const rowIdx = messageRowOffset + i;
1024
+ if (v != null) {
1025
+ const maskedValue = messageOriginalToMasked.get(v) ?? v;
1026
+ messageIndices[rowIdx] = messageDict.indexMap.get(maskedValue) ?? 0;
1027
+ messageNullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1028
+ }
1029
+ }
1030
+ }
1031
+ messageRowOffset += buf._writeIndex;
1032
+ }
1033
+ vectors.push(buildColumn(buildData({
1034
+ type: messageFieldType,
1035
+ offset: 0,
1036
+ length: totalRows,
1037
+ nullCount: 0, // message is eager, never null
1038
+ data: messageIndices,
1039
+ nullBitmap: messageNullBitmap,
1040
+ dictionary: buildColumn(buildData({
1041
+ type: utf8(),
1042
+ offset: 0,
1043
+ length: messageDict.indexMap.size,
1044
+ nullCount: 0,
1045
+ valueOffsets: messageDict.offsets,
1046
+ data: messageDict.data,
1047
+ })),
1048
+ })));
1049
+ fields.push('message');
1050
+ // System attribute column: uint64_value (for buffer metrics - op durations, counts, etc.)
1051
+ // For span data, this is all null - only buffer metrics use it
1052
+ const uint64ValueNullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
1053
+ // All zeros = all null (Arrow null bitmap: 1 = valid, 0 = null)
1054
+ vectors.push(buildColumn(buildData({
1055
+ type: uint64(),
1056
+ offset: 0,
1057
+ length: totalRows,
1058
+ nullCount: totalRows,
1059
+ data: new BigUint64Array(totalRows),
1060
+ nullBitmap: uint64ValueNullBitmap,
1061
+ })));
1062
+ fields.push('uint64_value');
1063
+ for (const [fieldName, fieldSchema] of schemaFields) {
1064
+ const lmaoType = getSchemaType(fieldSchema);
1065
+ const columnName = fieldName; // User columns have no prefix
1066
+ const arrowFieldName = getArrowFieldName(fieldName);
1067
+ if (lmaoType === 'category') {
1068
+ const dict = categoryDicts.get(fieldName);
1069
+ const originalToMasked = categoryOriginalToMasked.get(fieldName);
1070
+ if (!dict || !originalToMasked) {
1071
+ throw new Error(`Category dictionary or mapping not found for field: ${fieldName}`);
1072
+ }
1073
+ const indices = new dict.indexArrayCtor(totalRows);
1074
+ const nullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
1075
+ let nullCount = 0;
1076
+ let rowOffset = 0;
1077
+ // Per specs/lmao/01i_span_scope_attributes.md: scope values fill NULL cells at Arrow conversion
1078
+ for (const buf of buffers) {
1079
+ const col = getAllocatedStringColumn(buf, columnName);
1080
+ // Check if this buffer has a scope value for this field
1081
+ const scopeValue = getStringScopeValue(buf, fieldName);
1082
+ let scopeEncodedValue;
1083
+ if (scopeValue !== undefined) {
1084
+ const maskedScopeValue = originalToMasked.get(scopeValue) ?? scopeValue;
1085
+ scopeEncodedValue = dict.indexMap.get(maskedScopeValue);
1086
+ }
1087
+ if (col) {
1088
+ for (let i = 0; i < buf._writeIndex; i++) {
1089
+ const v = col[i];
1090
+ const rowIdx = rowOffset + i;
1091
+ if (v != null) {
1092
+ // Direct write wins
1093
+ const maskedValue = originalToMasked.get(v) ?? v;
1094
+ indices[rowIdx] = dict.indexMap.get(maskedValue) ?? 0;
1095
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1096
+ }
1097
+ else if (scopeEncodedValue !== undefined) {
1098
+ // No direct write, but have scope value - use it
1099
+ indices[rowIdx] = scopeEncodedValue;
1100
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1101
+ }
1102
+ else {
1103
+ nullCount++;
1104
+ }
1105
+ }
1106
+ }
1107
+ else if (scopeEncodedValue !== undefined) {
1108
+ // Column not allocated but we have scope - fill all rows with scope value
1109
+ for (let i = 0; i < buf._writeIndex; i++) {
1110
+ const rowIdx = rowOffset + i;
1111
+ indices[rowIdx] = scopeEncodedValue;
1112
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1113
+ }
1114
+ }
1115
+ else {
1116
+ // No column and no scope - all nulls
1117
+ nullCount += buf._writeIndex;
1118
+ }
1119
+ rowOffset += buf._writeIndex;
1120
+ }
1121
+ vectors.push(buildColumn(buildData({
1122
+ type: dictionary(utf8(), dict.arrowIndexType),
1123
+ offset: 0,
1124
+ length: totalRows,
1125
+ nullCount,
1126
+ data: indices,
1127
+ nullBitmap: nullCount > 0 ? nullBitmap : undefined,
1128
+ dictionary: buildColumn(buildData({
1129
+ type: utf8(),
1130
+ offset: 0,
1131
+ length: dict.indexMap.size,
1132
+ nullCount: 0,
1133
+ valueOffsets: dict.offsets,
1134
+ data: dict.data,
1135
+ })),
1136
+ })));
1137
+ fields.push(arrowFieldName);
1138
+ }
1139
+ else if (lmaoType === 'text') {
1140
+ const dict = textDicts.get(fieldName);
1141
+ const originalToMasked = textOriginalToMasked.get(fieldName);
1142
+ if (!dict || !originalToMasked) {
1143
+ throw new Error(`Text dictionary or mapping not found for field: ${fieldName}`);
1144
+ }
1145
+ const indices = new dict.indexArrayCtor(totalRows);
1146
+ const nullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
1147
+ let nullCount = 0;
1148
+ let rowOffset = 0;
1149
+ for (const buf of buffers) {
1150
+ const col = getAllocatedStringColumn(buf, columnName);
1151
+ // Check if this buffer has a scope value for this field
1152
+ const scopeValue = getStringScopeValue(buf, fieldName);
1153
+ let scopeEncodedValue;
1154
+ if (scopeValue !== undefined) {
1155
+ const maskedScopeValue = originalToMasked.get(scopeValue) ?? scopeValue;
1156
+ scopeEncodedValue = dict.indexMap.get(maskedScopeValue);
1157
+ }
1158
+ if (col) {
1159
+ for (let i = 0; i < buf._writeIndex; i++) {
1160
+ const v = col[i];
1161
+ const rowIdx = rowOffset + i;
1162
+ if (v != null) {
1163
+ // Direct write wins - look up the masked value
1164
+ const maskedValue = originalToMasked.get(v) ?? v;
1165
+ indices[rowIdx] = dict.indexMap.get(maskedValue) ?? 0;
1166
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1167
+ }
1168
+ else if (scopeEncodedValue !== undefined) {
1169
+ // No direct write, but have scope value - use it
1170
+ indices[rowIdx] = scopeEncodedValue;
1171
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1172
+ }
1173
+ else {
1174
+ nullCount++;
1175
+ }
1176
+ }
1177
+ }
1178
+ else if (scopeEncodedValue !== undefined) {
1179
+ // Column not allocated but we have scope - fill all rows with scope value
1180
+ for (let i = 0; i < buf._writeIndex; i++) {
1181
+ const rowIdx = rowOffset + i;
1182
+ indices[rowIdx] = scopeEncodedValue;
1183
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1184
+ }
1185
+ }
1186
+ else {
1187
+ // No column and no scope - all nulls
1188
+ nullCount += buf._writeIndex;
1189
+ }
1190
+ rowOffset += buf._writeIndex;
1191
+ }
1192
+ vectors.push(buildColumn(buildData({
1193
+ type: dictionary(utf8(), dict.arrowIndexType),
1194
+ offset: 0,
1195
+ length: totalRows,
1196
+ nullCount,
1197
+ data: indices,
1198
+ nullBitmap: nullCount > 0 ? nullBitmap : undefined,
1199
+ dictionary: buildColumn(buildData({
1200
+ type: utf8(),
1201
+ offset: 0,
1202
+ length: dict.indexMap.size,
1203
+ nullCount: 0,
1204
+ valueOffsets: dict.offsets,
1205
+ data: dict.data,
1206
+ })),
1207
+ })));
1208
+ fields.push(arrowFieldName);
1209
+ }
1210
+ else if (lmaoType === 'number') {
1211
+ const allValues = new F64Array(totalRows);
1212
+ const nullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
1213
+ // Start with all nulls (bits cleared) - we'll set bits as we find values
1214
+ let nullCount = 0;
1215
+ let rowOffset = 0;
1216
+ for (const buf of buffers) {
1217
+ const col = buf.getColumnIfAllocated(columnName);
1218
+ const srcNulls = buf.getNullsIfAllocated(columnName);
1219
+ // Check if this buffer has a scope value for this field
1220
+ const scopeValue = getNumberScopeValue(buf, fieldName);
1221
+ if (col instanceof Float64Array) {
1222
+ allValues.set(col.subarray(0, buf._writeIndex), rowOffset);
1223
+ if (srcNulls) {
1224
+ // Process each row - direct write wins, then scope, then null
1225
+ for (let i = 0; i < buf._writeIndex; i++) {
1226
+ const srcByte = i >>> 3;
1227
+ const srcBit = i & 7;
1228
+ const isValid = (srcNulls[srcByte] & (1 << srcBit)) !== 0;
1229
+ const rowIdx = rowOffset + i;
1230
+ if (isValid) {
1231
+ // Direct write - mark as valid
1232
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1233
+ }
1234
+ else if (scopeValue !== undefined) {
1235
+ // No direct write, but have scope value - use it
1236
+ allValues[rowIdx] = scopeValue;
1237
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1238
+ }
1239
+ else {
1240
+ // No direct write and no scope - null
1241
+ nullCount++;
1242
+ }
1243
+ }
1244
+ }
1245
+ else {
1246
+ // No null bitmap means column was allocated but no writes - check scope
1247
+ for (let i = 0; i < buf._writeIndex; i++) {
1248
+ const rowIdx = rowOffset + i;
1249
+ if (scopeValue !== undefined) {
1250
+ allValues[rowIdx] = scopeValue;
1251
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1252
+ }
1253
+ else {
1254
+ nullCount++;
1255
+ }
1256
+ }
1257
+ }
1258
+ }
1259
+ else if (scopeValue !== undefined) {
1260
+ // Column not allocated but we have scope - fill all rows with scope value
1261
+ for (let i = 0; i < buf._writeIndex; i++) {
1262
+ const rowIdx = rowOffset + i;
1263
+ allValues[rowIdx] = scopeValue;
1264
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1265
+ }
1266
+ }
1267
+ else {
1268
+ // Column doesn't exist for this buffer and no scope - all nulls
1269
+ nullCount += buf._writeIndex;
1270
+ }
1271
+ rowOffset += buf._writeIndex;
1272
+ }
1273
+ vectors.push(buildColumn(buildData({
1274
+ type: float64(),
1275
+ offset: 0,
1276
+ length: totalRows,
1277
+ nullCount,
1278
+ data: allValues,
1279
+ nullBitmap: nullCount > 0 ? nullBitmap : undefined,
1280
+ })));
1281
+ fields.push(arrowFieldName);
1282
+ }
1283
+ else if (lmaoType === 'boolean') {
1284
+ const requiredBytes = Math.ceil(totalRows / 8);
1285
+ const allValues = new Uint8Array(requiredBytes);
1286
+ const nullBitmap = new Uint8Array(requiredBytes);
1287
+ // Start with all nulls (bits cleared) - we'll set bits as we find values
1288
+ let nullCount = 0;
1289
+ let rowOffset = 0;
1290
+ for (const buf of buffers) {
1291
+ const col = buf.getColumnIfAllocated(columnName);
1292
+ const srcNulls = buf.getNullsIfAllocated(columnName);
1293
+ // Check if this buffer has a scope value for this field
1294
+ const scopeValue = getBooleanScopeValue(buf, fieldName);
1295
+ if (col instanceof Uint8Array) {
1296
+ // Copy boolean values bit by bit - can't avoid loop for bit-level operations
1297
+ for (let i = 0; i < buf._writeIndex; i++) {
1298
+ const srcByte = i >>> 3;
1299
+ const srcBit = i & 7;
1300
+ const rowIdx = rowOffset + i;
1301
+ if (srcNulls) {
1302
+ const isValid = (srcNulls[srcByte] & (1 << srcBit)) !== 0;
1303
+ if (isValid) {
1304
+ // Direct write - copy the value
1305
+ const value = (col[srcByte] & (1 << srcBit)) !== 0;
1306
+ if (value) {
1307
+ allValues[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1308
+ }
1309
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1310
+ }
1311
+ else if (scopeValue !== undefined) {
1312
+ // No direct write, but have scope value - use it
1313
+ if (scopeValue) {
1314
+ allValues[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1315
+ }
1316
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1317
+ }
1318
+ else {
1319
+ // No direct write and no scope - null
1320
+ nullCount++;
1321
+ }
1322
+ }
1323
+ else {
1324
+ // No null bitmap - check scope
1325
+ if (scopeValue !== undefined) {
1326
+ if (scopeValue) {
1327
+ allValues[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1328
+ }
1329
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1330
+ }
1331
+ else {
1332
+ nullCount++;
1333
+ }
1334
+ }
1335
+ }
1336
+ }
1337
+ else if (scopeValue !== undefined) {
1338
+ // Column not allocated but we have scope - fill all rows with scope value
1339
+ for (let i = 0; i < buf._writeIndex; i++) {
1340
+ const rowIdx = rowOffset + i;
1341
+ if (scopeValue) {
1342
+ allValues[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1343
+ }
1344
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1345
+ }
1346
+ }
1347
+ else {
1348
+ // Column doesn't exist for this buffer and no scope - all nulls
1349
+ nullCount += buf._writeIndex;
1350
+ }
1351
+ rowOffset += buf._writeIndex;
1352
+ }
1353
+ vectors.push(buildColumn(buildData({
1354
+ type: bool(),
1355
+ offset: 0,
1356
+ length: totalRows,
1357
+ nullCount,
1358
+ data: allValues,
1359
+ nullBitmap: nullCount > 0 ? nullBitmap : undefined,
1360
+ })));
1361
+ fields.push(arrowFieldName);
1362
+ }
1363
+ else if (lmaoType === 'enum') {
1364
+ const enumValues = getEnumValues(fieldSchema) || [];
1365
+ const enumUtf8 = getEnumUtf8(fieldSchema);
1366
+ // Get constructors from schema metadata
1367
+ const indexArrayCtor = getArrowIndexArrayConstructorOr(fieldSchema);
1368
+ const arrowIndexType = getArrowIndexTypeOr(fieldSchema, uint8());
1369
+ const allIndices = new indexArrayCtor(totalRows);
1370
+ const nullBitmap = new Uint8Array(Math.ceil(totalRows / 8));
1371
+ // Start with all nulls (bits cleared) - we'll set bits as we find values
1372
+ let nullCount = 0;
1373
+ let rowOffset = 0;
1374
+ // Build enum value to index mapping for scope lookup
1375
+ const enumValueToIndex = new Map();
1376
+ for (let i = 0; i < enumValues.length; i++) {
1377
+ enumValueToIndex.set(enumValues[i], i);
1378
+ }
1379
+ for (const buf of buffers) {
1380
+ const col = buf.getColumnIfAllocated(columnName);
1381
+ const srcNulls = buf.getNullsIfAllocated(columnName);
1382
+ // Check if this buffer has a scope value for this field
1383
+ const scopeValue = getStringScopeValue(buf, fieldName);
1384
+ let scopeEncodedValue;
1385
+ if (scopeValue !== undefined) {
1386
+ scopeEncodedValue = enumValueToIndex.get(scopeValue);
1387
+ }
1388
+ if (col instanceof indexArrayCtor) {
1389
+ allIndices.set(col.subarray(0, buf._writeIndex), rowOffset);
1390
+ if (srcNulls) {
1391
+ for (let i = 0; i < buf._writeIndex; i++) {
1392
+ const srcByte = i >>> 3;
1393
+ const srcBit = i & 7;
1394
+ const isValid = (srcNulls[srcByte] & (1 << srcBit)) !== 0;
1395
+ const rowIdx = rowOffset + i;
1396
+ if (isValid) {
1397
+ // Direct write - mark as valid
1398
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1399
+ }
1400
+ else if (scopeEncodedValue !== undefined) {
1401
+ // No direct write, but have scope value - use it
1402
+ allIndices[rowIdx] = scopeEncodedValue;
1403
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1404
+ }
1405
+ else {
1406
+ // No direct write and no scope - null
1407
+ nullCount++;
1408
+ }
1409
+ }
1410
+ }
1411
+ else {
1412
+ // No null bitmap - check scope for each row
1413
+ for (let i = 0; i < buf._writeIndex; i++) {
1414
+ const rowIdx = rowOffset + i;
1415
+ if (scopeEncodedValue !== undefined) {
1416
+ allIndices[rowIdx] = scopeEncodedValue;
1417
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1418
+ }
1419
+ else {
1420
+ nullCount++;
1421
+ }
1422
+ }
1423
+ }
1424
+ }
1425
+ else if (scopeEncodedValue !== undefined) {
1426
+ // Column not allocated but we have scope - fill all rows with scope value
1427
+ for (let i = 0; i < buf._writeIndex; i++) {
1428
+ const rowIdx = rowOffset + i;
1429
+ allIndices[rowIdx] = scopeEncodedValue;
1430
+ nullBitmap[rowIdx >>> 3] |= 1 << (rowIdx & 7);
1431
+ }
1432
+ }
1433
+ else {
1434
+ // Column doesn't exist for this buffer and no scope - all nulls
1435
+ nullCount += buf._writeIndex;
1436
+ }
1437
+ rowOffset += buf._writeIndex;
1438
+ }
1439
+ const enumDictData = buildData({
1440
+ type: utf8(),
1441
+ offset: 0,
1442
+ length: enumValues.length,
1443
+ nullCount: 0,
1444
+ valueOffsets: enumUtf8?.offsets ?? calculateUtf8Offsets(enumValues),
1445
+ data: enumUtf8?.concatenated ?? encodeUtf8Strings(enumValues),
1446
+ });
1447
+ vectors.push(buildColumn(buildData({
1448
+ type: dictionary(utf8(), arrowIndexType),
1449
+ offset: 0,
1450
+ length: totalRows,
1451
+ nullCount,
1452
+ data: allIndices,
1453
+ nullBitmap: nullCount > 0 ? nullBitmap : undefined,
1454
+ dictionary: buildColumn(enumDictData),
1455
+ })));
1456
+ fields.push(arrowFieldName);
1457
+ }
1458
+ else if (lmaoType === 'binary') {
1459
+ // Binary columns: raw Uint8Array or encoder-wrapped values (e.g. msgpack)
1460
+ // Binary columns don't use dictionaries and are not scope-fillable
1461
+ const { column } = buildBinaryColumnFromBuffers(buffers, columnName, totalRows, fieldSchema);
1462
+ fields.push(arrowFieldName);
1463
+ vectors.push(column);
1464
+ }
1465
+ }
1466
+ return buildTable(fields, vectors);
1467
+ }