@smoothbricks/lmao 0.2.2 → 0.2.3

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 (276) hide show
  1. package/dist/allocator.wasm +0 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +1 -0
  5. package/dist/lib/JsBufferStrategy.d.ts +4 -3
  6. package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
  7. package/dist/lib/JsBufferStrategy.js +18 -11
  8. package/dist/lib/arrow/lease.d.ts +10 -0
  9. package/dist/lib/arrow/lease.d.ts.map +1 -0
  10. package/dist/lib/arrow/lease.js +33 -0
  11. package/dist/lib/arrow/utils.d.ts +3 -4
  12. package/dist/lib/arrow/utils.d.ts.map +1 -1
  13. package/dist/lib/arrow/utils.js +12 -13
  14. package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
  15. package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
  16. package/dist/lib/arrow/vocabularyDictionary.js +95 -0
  17. package/dist/lib/bufferStrategy.d.ts +3 -2
  18. package/dist/lib/bufferStrategy.d.ts.map +1 -1
  19. package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
  20. package/dist/lib/cloudflare/traceRows.js +3 -2
  21. package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
  22. package/dist/lib/codegen/evaluatorGenerator.js +12 -11
  23. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
  24. package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
  25. package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
  26. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
  27. package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
  28. package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
  29. package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
  30. package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
  31. package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
  32. package/dist/lib/convertToArrow.d.ts +7 -2
  33. package/dist/lib/convertToArrow.d.ts.map +1 -1
  34. package/dist/lib/convertToArrow.js +499 -285
  35. package/dist/lib/defineOpContext.js +1 -1
  36. package/dist/lib/enumMetadata.d.ts +19 -0
  37. package/dist/lib/enumMetadata.d.ts.map +1 -0
  38. package/dist/lib/enumMetadata.js +86 -0
  39. package/dist/lib/flushScheduler.d.ts.map +1 -1
  40. package/dist/lib/flushScheduler.js +13 -4
  41. package/dist/lib/library.d.ts +16 -98
  42. package/dist/lib/library.d.ts.map +1 -1
  43. package/dist/lib/library.js +32 -525
  44. package/dist/lib/logBinding.d.ts +21 -27
  45. package/dist/lib/logBinding.d.ts.map +1 -1
  46. package/dist/lib/op.d.ts +30 -30
  47. package/dist/lib/op.d.ts.map +1 -1
  48. package/dist/lib/op.js +15 -22
  49. package/dist/lib/opContext/createOpGroup.d.ts +1 -1
  50. package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
  51. package/dist/lib/opContext/createOpGroup.js +22 -29
  52. package/dist/lib/opContext/defineOp.d.ts +4 -4
  53. package/dist/lib/opContext/defineOp.d.ts.map +1 -1
  54. package/dist/lib/opContext/defineOp.js +53 -10
  55. package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
  56. package/dist/lib/opContext/opTypes.d.ts +1 -1
  57. package/dist/lib/opContext/opTypes.d.ts.map +1 -1
  58. package/dist/lib/opContext/spanContextTypes.d.ts +29 -14
  59. package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
  60. package/dist/lib/opContext/types.d.ts +4 -4
  61. package/dist/lib/opContext/types.d.ts.map +1 -1
  62. package/dist/lib/physicalLayoutPlan.d.ts +89 -0
  63. package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
  64. package/dist/lib/physicalLayoutPlan.js +442 -0
  65. package/dist/lib/resolveMessage.d.ts +9 -0
  66. package/dist/lib/resolveMessage.d.ts.map +1 -0
  67. package/dist/lib/resolveMessage.js +63 -0
  68. package/dist/lib/result.d.ts +5 -7
  69. package/dist/lib/result.d.ts.map +1 -1
  70. package/dist/lib/result.js +19 -26
  71. package/dist/lib/runtimeHint.d.ts +35 -0
  72. package/dist/lib/runtimeHint.d.ts.map +1 -0
  73. package/dist/lib/runtimeHint.js +79 -0
  74. package/dist/lib/schema/types.d.ts +1 -1
  75. package/dist/lib/schema/types.d.ts.map +1 -1
  76. package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
  77. package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
  78. package/dist/lib/span-buffer/aot/v1.js +24 -0
  79. package/dist/lib/spanBuffer.d.ts +33 -4
  80. package/dist/lib/spanBuffer.d.ts.map +1 -1
  81. package/dist/lib/spanBuffer.js +583 -91
  82. package/dist/lib/spanBufferStats.d.ts +1 -1
  83. package/dist/lib/spanBufferStats.d.ts.map +1 -1
  84. package/dist/lib/spanContext.d.ts +27 -51
  85. package/dist/lib/spanContext.d.ts.map +1 -1
  86. package/dist/lib/spanContext.js +822 -344
  87. package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
  88. package/dist/lib/sqlite/sqlite-common.js +20 -21
  89. package/dist/lib/testing/bun-harness.d.ts +8 -3
  90. package/dist/lib/testing/bun-harness.d.ts.map +1 -1
  91. package/dist/lib/testing/bun-harness.js +30 -18
  92. package/dist/lib/testing/extractFacts.d.ts +1 -1
  93. package/dist/lib/testing/extractFacts.d.ts.map +1 -1
  94. package/dist/lib/testing/extractFacts.js +55 -63
  95. package/dist/lib/testing/facts.d.ts +1 -1
  96. package/dist/lib/testing/facts.d.ts.map +1 -1
  97. package/dist/lib/testing/queryable-span.d.ts +1 -1
  98. package/dist/lib/testing/queryable-span.d.ts.map +1 -1
  99. package/dist/lib/testing/queryable-span.js +26 -28
  100. package/dist/lib/testing/span-query.d.ts.map +1 -1
  101. package/dist/lib/testing/span-query.js +19 -22
  102. package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
  103. package/dist/lib/testing/stdio-replay.js +19 -8
  104. package/dist/lib/threadId.d.ts.map +1 -1
  105. package/dist/lib/threadId.js +6 -3
  106. package/dist/lib/traceRoot.d.ts +30 -8
  107. package/dist/lib/traceRoot.d.ts.map +1 -1
  108. package/dist/lib/traceRoot.es.d.ts +17 -15
  109. package/dist/lib/traceRoot.es.d.ts.map +1 -1
  110. package/dist/lib/traceRoot.es.js +68 -34
  111. package/dist/lib/traceRoot.js +11 -0
  112. package/dist/lib/traceRoot.node.d.ts +17 -19
  113. package/dist/lib/traceRoot.node.d.ts.map +1 -1
  114. package/dist/lib/traceRoot.node.js +66 -38
  115. package/dist/lib/traceTopology.d.ts +42 -0
  116. package/dist/lib/traceTopology.d.ts.map +1 -0
  117. package/dist/lib/traceTopology.js +260 -0
  118. package/dist/lib/tracer.d.ts +9 -5
  119. package/dist/lib/tracer.d.ts.map +1 -1
  120. package/dist/lib/tracer.js +65 -71
  121. package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
  122. package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
  123. package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
  124. package/dist/lib/tracers/StdioTracer.js +15 -13
  125. package/dist/lib/tracers/TestTracer.d.ts +4 -6
  126. package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
  127. package/dist/lib/tracers/TestTracer.js +6 -8
  128. package/dist/lib/types.d.ts +49 -32
  129. package/dist/lib/types.d.ts.map +1 -1
  130. package/dist/lib/vocabularyRegistry.d.ts +25 -0
  131. package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
  132. package/dist/lib/vocabularyRegistry.js +372 -0
  133. package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
  134. package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
  135. package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
  136. package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
  137. package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
  138. package/dist/lib/wasm/wasmAllocator.js +66 -44
  139. package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
  140. package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
  141. package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
  142. package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
  143. package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
  144. package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
  145. package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
  146. package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
  147. package/dist/lib/wasm/wasmTraceRoot.js +110 -71
  148. package/dist/vocabulary/register/v1.d.ts +2 -0
  149. package/dist/vocabulary/register/v1.d.ts.map +1 -0
  150. package/dist/vocabulary/register/v1.js +1 -0
  151. package/dist/wasm.d.ts +5 -0
  152. package/dist/wasm.d.ts.map +1 -0
  153. package/dist/wasm.js +4 -0
  154. package/package.json +54 -6
  155. package/src/index.ts +1 -0
  156. package/src/lib/JsBufferStrategy.ts +27 -9
  157. package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
  158. package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
  159. package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
  160. package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
  161. package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
  162. package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
  163. package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
  164. package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
  165. package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
  166. package/src/lib/__tests__/capability-span-context.test.ts +505 -0
  167. package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
  168. package/src/lib/__tests__/eager-columns.test.ts +345 -0
  169. package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
  170. package/src/lib/__tests__/enum-metadata.test.ts +177 -0
  171. package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
  172. package/src/lib/__tests__/flushScheduler.test.ts +5 -1
  173. package/src/lib/__tests__/identity-view.property.test.ts +179 -0
  174. package/src/lib/__tests__/library.test.ts +19 -235
  175. package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
  176. package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
  177. package/src/lib/__tests__/op-metadata.test.ts +1 -1
  178. package/src/lib/__tests__/op-type-safety.test.ts +5 -16
  179. package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
  180. package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
  181. package/src/lib/__tests__/root-context-construction.test.ts +414 -0
  182. package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
  183. package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
  184. package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
  185. package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
  186. package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
  187. package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
  188. package/src/lib/__tests__/test-helpers.ts +67 -12
  189. package/src/lib/__tests__/threadId.test.ts +62 -0
  190. package/src/lib/__tests__/timestamp.test.ts +221 -93
  191. package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
  192. package/src/lib/__tests__/type-narrowing.test.ts +63 -0
  193. package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
  194. package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
  195. package/src/lib/arrow/lease.ts +43 -0
  196. package/src/lib/arrow/utils.ts +10 -14
  197. package/src/lib/arrow/vocabularyDictionary.ts +123 -0
  198. package/src/lib/bufferStrategy.ts +9 -1
  199. package/src/lib/cloudflare/traceRows.ts +3 -2
  200. package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
  201. package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
  202. package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
  203. package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
  204. package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
  205. package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
  206. package/src/lib/codegen/evaluatorGenerator.ts +18 -13
  207. package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
  208. package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
  209. package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
  210. package/src/lib/convertToArrow.ts +598 -311
  211. package/src/lib/defineOpContext.ts +1 -1
  212. package/src/lib/enumMetadata.ts +121 -0
  213. package/src/lib/flushScheduler.ts +11 -5
  214. package/src/lib/library.ts +37 -595
  215. package/src/lib/logBinding.ts +21 -27
  216. package/src/lib/op.ts +75 -18
  217. package/src/lib/opContext/__tests__/retry.test.ts +27 -21
  218. package/src/lib/opContext/createOpGroup.ts +33 -31
  219. package/src/lib/opContext/defineOp.ts +88 -11
  220. package/src/lib/opContext/opGroupTypes.ts +2 -2
  221. package/src/lib/opContext/opTypes.ts +1 -1
  222. package/src/lib/opContext/spanContextTypes.ts +98 -17
  223. package/src/lib/opContext/types.ts +7 -3
  224. package/src/lib/physicalLayoutPlan.ts +598 -0
  225. package/src/lib/resolveMessage.ts +67 -0
  226. package/src/lib/result.ts +20 -33
  227. package/src/lib/runtimeHint.ts +98 -0
  228. package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
  229. package/src/lib/schema/builder.ts +1 -1
  230. package/src/lib/schema/types.ts +1 -1
  231. package/src/lib/span-buffer/aot/v1.ts +26 -0
  232. package/src/lib/spanBuffer.ts +658 -92
  233. package/src/lib/spanBufferStats.ts +1 -1
  234. package/src/lib/spanContext.ts +1350 -861
  235. package/src/lib/sqlite/sqlite-common.ts +20 -31
  236. package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
  237. package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
  238. package/src/lib/testing/bun-harness.ts +94 -43
  239. package/src/lib/testing/extractFacts.ts +64 -78
  240. package/src/lib/testing/facts.ts +1 -1
  241. package/src/lib/testing/queryable-span.ts +23 -30
  242. package/src/lib/testing/span-query.ts +16 -20
  243. package/src/lib/testing/stdio-replay.ts +25 -8
  244. package/src/lib/testing/vitest-harness.ts +1 -1
  245. package/src/lib/threadId.ts +6 -3
  246. package/src/lib/traceRoot.es.ts +77 -42
  247. package/src/lib/traceRoot.node.ts +75 -46
  248. package/src/lib/traceRoot.ts +41 -14
  249. package/src/lib/traceTopology.ts +279 -0
  250. package/src/lib/tracer.ts +109 -98
  251. package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
  252. package/src/lib/tracers/StdioTracer.ts +15 -13
  253. package/src/lib/tracers/TestTracer.ts +6 -8
  254. package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
  255. package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
  256. package/src/lib/types.ts +64 -33
  257. package/src/lib/vocabularyRegistry.ts +439 -0
  258. package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
  259. package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
  260. package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
  261. package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
  262. package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
  263. package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
  264. package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
  265. package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
  266. package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
  267. package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
  268. package/src/lib/wasm/wasmAllocator.ts +131 -96
  269. package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
  270. package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
  271. package/src/lib/wasm/wasmTraceRoot.ts +140 -78
  272. package/src/vocabulary/register/v1.ts +1 -0
  273. package/src/wasm.ts +19 -0
  274. package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
  275. package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
  276. package/src/lib/wasm/allocator.zig +0 -948
@@ -17,11 +17,18 @@
17
17
  */
18
18
 
19
19
  import {
20
+ activeMaterializerMode,
20
21
  type ColumnEntry,
21
- type ColumnWriter,
22
22
  type ColumnWriterExtension,
23
- getColumnWriterClass,
23
+ generateColumnWriterClass,
24
24
  } from '@smoothbricks/arrow-builder';
25
+ import {
26
+ type EnumLookupDescriptor,
27
+ resolveEnumLookupDescriptor,
28
+ type SchemaEnumLookupDescriptor,
29
+ } from '../enumMetadata.js';
30
+ import { decodeVocabularyMessage } from '../resolveMessage.js';
31
+ import type { MessageLayoutFamily, MessagePhysicalLayout } from '../runtimeHint.js';
25
32
  import {
26
33
  ENTRY_TYPE_DEBUG,
27
34
  ENTRY_TYPE_ERROR,
@@ -31,10 +38,16 @@ import {
31
38
  ENTRY_TYPE_TRACE,
32
39
  ENTRY_TYPE_WARN,
33
40
  } from '../schema/systemSchema.js';
34
- import { getEnumValues, getSchemaType } from '../schema/typeGuards.js';
41
+ import { getSchemaType } from '../schema/typeGuards.js';
35
42
  import type { InferSchema, LogSchema } from '../schema/types.js';
36
-
37
- import type { AnySpanBuffer, SpanBuffer } from '../types.js';
43
+ import type { AnySpanBuffer } from '../types.js';
44
+ import type { VocabularyGeneration } from '../vocabularyRegistry.js';
45
+ import type { WriterState } from './fixedPositionWriterGenerator.js';
46
+ import {
47
+ materializeSpanLoggerClass,
48
+ type SpanLoggerColumnMode,
49
+ type SpanLoggerPlan,
50
+ } from './spanLoggerClosureMaterializer.js';
38
51
 
39
52
  // =============================================================================
40
53
  // SINGLETON HELPERS OBJECT
@@ -47,10 +60,17 @@ import type { AnySpanBuffer, SpanBuffer } from '../types.js';
47
60
  * Singleton - same object shared by all generated SpanLogger classes.
48
61
  */
49
62
  export const SPAN_LOGGER_HELPERS: {
63
+ normalizeOperationalTemplate: (template: string) => string;
50
64
  setNullBit: (bitmap: Uint8Array, idx: number) => void;
65
+ decodeVocabularyMessage: (generation: VocabularyGeneration, denseIndex: number) => string;
51
66
  fillNullBitmapRange: (bitmap: Uint8Array, startIdx: number, endIdx: number) => void;
52
67
  fillBooleanBitmapRange: (bitmap: Uint8Array, startIdx: number, endIdx: number, value: boolean) => void;
53
68
  } = {
69
+ normalizeOperationalTemplate: (template: string) => {
70
+ if (template.indexOf('{{') === -1 && template.indexOf('}}') === -1) return template;
71
+ return template.replaceAll('{{', '{').replaceAll('}}', '}');
72
+ },
73
+ decodeVocabularyMessage,
54
74
  setNullBit: (bitmap: Uint8Array, idx: number) => {
55
75
  bitmap[idx >>> 3] |= 1 << (idx & 7);
56
76
  },
@@ -156,12 +176,17 @@ export const SPAN_LOGGER_HELPERS: {
156
176
  export interface BaseSpanLogger<T extends LogSchema> {
157
177
  /** Log info-level message */
158
178
  info(message: string): FluentLogEntry<T>;
179
+ info(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
159
180
  /** Log debug-level message */
160
181
  debug(message: string): FluentLogEntry<T>;
161
182
  /** Log warning message */
162
183
  warn(message: string): FluentLogEntry<T>;
184
+ warn(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
163
185
  /** Log error message */
164
186
  error(message: string): FluentLogEntry<T>;
187
+ error(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
188
+ /** Log trace-level message */
189
+ trace(message: string): FluentLogEntry<T>;
165
190
  }
166
191
 
167
192
  /**
@@ -188,9 +213,12 @@ export type FluentLogEntry<T extends LogSchema> = {
188
213
 
189
214
  // Logging methods for continued chaining
190
215
  info(message: string): FluentLogEntry<T>;
216
+ info(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
191
217
  debug(message: string): FluentLogEntry<T>;
192
218
  warn(message: string): FluentLogEntry<T>;
219
+ warn(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
193
220
  error(message: string): FluentLogEntry<T>;
221
+ error(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
194
222
  trace(message: string): FluentLogEntry<T>;
195
223
  } & {
196
224
  [K in keyof InferSchema<T>]: (value: InferSchema<T>[K]) => FluentLogEntry<T>;
@@ -207,52 +235,50 @@ export type FluentLogEntry<T extends LogSchema> = {
207
235
  * This is the FULL type returned by createSpanLogger().
208
236
  * Users see SpanLogger<T> which hides internal methods.
209
237
  */
210
- export type SpanLoggerImpl<T extends LogSchema> = ColumnWriter<T> & {
238
+ export type SpanLoggerImpl<T extends LogSchema> = {
211
239
  info(message: string): FluentLogEntry<T>;
240
+ info(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
212
241
  debug(message: string): FluentLogEntry<T>;
213
242
  warn(message: string): FluentLogEntry<T>;
243
+ warn(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
214
244
  error(message: string): FluentLogEntry<T>;
245
+ error(template: string, fields: Partial<InferSchema<T>>): FluentLogEntry<T>;
215
246
  trace(message: string): FluentLogEntry<T>;
247
+ _infoTemplate(vocabularyIndex: number): FluentLogEntry<T>;
248
+ _debugTemplate(vocabularyIndex: number): FluentLogEntry<T>;
249
+ _warnTemplate(vocabularyIndex: number): FluentLogEntry<T>;
250
+ _errorTemplate(vocabularyIndex: number): FluentLogEntry<T>;
251
+ _traceTemplate(vocabularyIndex: number): FluentLogEntry<T>;
216
252
  readonly scope: Readonly<Record<string, unknown>>;
217
253
  _setScope(attributes: ScopeUpdate<T>): void;
254
+ _prefillScopedAttributesOn(buffer: AnySpanBuffer): void;
255
+ } & {
256
+ [K in keyof InferSchema<T>]: (value: InferSchema<T>[K]) => FluentLogEntry<T>;
218
257
  };
219
258
 
259
+ export type SpanLoggerConstructor<T extends LogSchema> = new (state: WriterState) => SpanLoggerImpl<T>;
260
+
220
261
  export type ScopeUpdate<T extends LogSchema> = {
221
262
  [K in keyof InferSchema<T>]?: InferSchema<T>[K] | null;
222
263
  };
223
264
 
224
- /**
225
- * Generate enum value mapping code
226
- * Creates a switch-case statement for compile-time enum mapping
227
- */
228
- function generateEnumMapping(fieldName: string, enumValues: readonly string[]): string {
229
- const cases = enumValues.map((value, index) => ` case ${JSON.stringify(value)}: return ${index};`).join('\n');
230
-
231
- return `
232
- function getEnumIndex_${fieldName}(value) {
233
- switch(value) {
234
- ${cases}
235
- default: return 0;
236
- }
237
- }`;
238
- }
239
-
240
265
  /**
241
266
  * Generate override fluent setters for enum fields.
242
267
  * These convert string values to numeric indices before writing to the buffer.
243
268
  * The buffer expects numeric indices (after the enum map removal change).
244
269
  */
245
- function generateEnumFluentSetters(enumFieldNames: Set<string>): string {
270
+ function generateEnumFluentSetters(
271
+ enumFields: readonly EnumLookupDescriptor[],
272
+ enumEncoderNames: Readonly<Record<string, string>>,
273
+ ): string {
246
274
  const setters: string[] = [];
247
275
 
248
- for (const fieldName of enumFieldNames) {
276
+ for (const { fieldName } of enumFields) {
277
+ const encoderName = enumEncoderNames[fieldName];
249
278
  setters.push(`
250
- /**
251
- * Override fluent setter for ${fieldName} to convert string → index.
252
- * Buffer expects numeric index, not string value.
253
- */
279
+ /** Convert the declared enum string to its schema-order index. */
254
280
  ${fieldName}(value) {
255
- const idx = getEnumIndex_${fieldName}(value);
281
+ const idx = ${encoderName}(value);
256
282
  this._buffer.${fieldName}(this._writeIndex, idx);
257
283
  return this;
258
284
  }`);
@@ -302,7 +328,7 @@ function generateSetScopeMethod(): string {
302
328
  */
303
329
  function generatePrefillScopedAttributesMethod(
304
330
  schemaFields: readonly ColumnEntry[],
305
- enumFieldNames: Set<string>,
331
+ enumEncoderNames: Readonly<Record<string, string>>,
306
332
  ): string {
307
333
  const columnFills = schemaFields.map(([fieldName, fieldSchema]) => {
308
334
  const columnName = fieldName;
@@ -327,8 +353,9 @@ function generatePrefillScopedAttributesMethod(
327
353
 
328
354
  // Value processing based on type
329
355
  let valueExpr = 'scopeValue';
330
- if (lmaoType === 'enum' && enumFieldNames.has(fieldName)) {
331
- valueExpr = `getEnumIndex_${fieldName}(scopeValue)`;
356
+ const enumEncoderName = enumEncoderNames[fieldName];
357
+ if (lmaoType === 'enum' && enumEncoderName !== undefined) {
358
+ valueExpr = `${enumEncoderName}(scopeValue)`;
332
359
  }
333
360
 
334
361
  // For string arrays (category/text), use manual loop instead of fill()
@@ -372,30 +399,45 @@ function generatePrefillScopedAttributesMethod(
372
399
  /**
373
400
  * Build the extension for SpanLogger that extends ColumnWriter
374
401
  */
375
- function buildSpanLoggerExtension(schema: LogSchema): ColumnWriterExtension {
402
+ function buildSpanLoggerExtension(
403
+ schema: LogSchema,
404
+ messageLayoutFamily: MessageLayoutFamily,
405
+ messagePhysicalLayout: MessagePhysicalLayout,
406
+ eagerColumns: readonly string[],
407
+ enumLookup: SchemaEnumLookupDescriptor,
408
+ ): ColumnWriterExtension {
376
409
  const schemaFields = schema._columns;
377
410
 
378
- // Collect enum mappings
379
- const enumMappings: string[] = [];
380
- const enumFieldNames = new Set<string>();
381
-
382
- for (const [fieldName, fieldSchema] of schemaFields) {
383
- const lmaoType = getSchemaType(fieldSchema);
384
- const enumValues = getEnumValues(fieldSchema);
385
-
386
- if (lmaoType === 'enum' && enumValues) {
387
- enumMappings.push(generateEnumMapping(fieldName, enumValues));
388
- enumFieldNames.add(fieldName);
389
- }
390
- }
411
+ const enumEncoderNames: Record<string, string> = Object.create(null);
412
+ const enumEncoderBindings = enumLookup.ordered.map(({ fieldName }, index) => {
413
+ const encoderName = `encodeEnum${index}`;
414
+ enumEncoderNames[fieldName] = encoderName;
415
+ return ` const ${encoderName} = enumLookup.byField[${JSON.stringify(fieldName)}].encode;`;
416
+ });
391
417
 
392
418
  // Generate methods
393
419
  const setScopeMethod = generateSetScopeMethod();
394
- const prefillMethod = generatePrefillScopedAttributesMethod(schemaFields, enumFieldNames);
395
- const enumFluentSetters = generateEnumFluentSetters(enumFieldNames);
420
+ const prefillMethod = generatePrefillScopedAttributesMethod(schemaFields, enumEncoderNames);
421
+ const enumFluentSetters = generateEnumFluentSetters(enumLookup.ordered, enumEncoderNames);
422
+ const staticMessageWrite = (entryType: number): string => {
423
+ switch (messagePhysicalLayout) {
424
+ case 'current':
425
+ return `const localMessageId = this._state._physicalLayoutPlan.encodeLocalMessage(vocabularyIndex);
426
+ if (localMessageId === 0) {
427
+ this._buffer.message_values[idx] = helpers.decodeVocabularyMessage(this._buffer._vocabularyGeneration, vocabularyIndex);
428
+ } else {
429
+ this._buffer._messageIds[idx] = localMessageId;
430
+ }`;
431
+ case 'specialized':
432
+ return 'this._buffer._logHeaders[idx] = vocabularyIndex + 1;';
433
+ case 'packed':
434
+ return `if (vocabularyIndex > 0x00fffffe) throw new RangeError('Packed message dense index exceeds 0xFFFFFE');
435
+ this._buffer._rowHeaders[idx] = ((((vocabularyIndex + 1) << 8) | ${entryType}) >>> 0);`;
436
+ }
437
+ };
396
438
 
397
439
  return {
398
- constructorParams: '',
440
+ preallocatedColumns: eagerColumns,
399
441
 
400
442
  // Entry type constants (inlined from lmao.ts)
401
443
  classPreamble: `
@@ -406,109 +448,88 @@ function buildSpanLoggerExtension(schema: LogSchema): ColumnWriterExtension {
406
448
  const ENTRY_TYPE_TRACE = ${ENTRY_TYPE_TRACE};
407
449
  const ENTRY_TYPE_FF_ACCESS = ${ENTRY_TYPE_FF_ACCESS};
408
450
  const ENTRY_TYPE_FF_USAGE = ${ENTRY_TYPE_FF_USAGE};
409
-
410
- ${enumMappings.join('\n')}
411
- `,
412
-
413
- // SpanLogger starts at writeIndex 1, so first nextRow() makes it 2
414
- // (Rows 0 and 1 are reserved for span-start and span-end)
415
- // Sync buffer's writeIndex - needed for Arrow conversion
416
- constructorCode: `
417
- this._writeIndex = 1;
418
- this._buffer._writeIndex = 2;
451
+ ${enumEncoderBindings.join('\n')}
419
452
  `,
420
453
 
421
- // Check for overflow before writing, switch to overflow buffer if needed.
422
- // Overflow when _writeIndex >= capacity (buffer is full, no room for this write).
423
- // Buffer.getOrCreateOverflow() handles: stats notification, capacity tuning, buffer creation.
424
- // We just need to switch this._buffer and prefill scope on the new buffer.
425
454
  methods:
426
- `_checkOverflow() {
427
- if (this._buffer._writeIndex >= this._buffer._capacity) {
428
- this._buffer = this._buffer.getOrCreateOverflow();
429
- this._prefillScopedAttributesOn(this._buffer);
455
+ // The optional fields argument is the untransformed fallback. JavaScript evaluates
456
+ // the receiver, template, and object initializers before this method runs. Lowered
457
+ // calls use _infoTemplate/_warnTemplate/_errorTemplate plus direct setters instead.
458
+ // Context-owned append advances the shared active buffer and returns the literal row.
459
+ `info(message, fields) {
460
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_INFO);
461
+ ${messageLayoutFamily === 'static-only' ? `throw new TypeError('Dynamic log write reached a static-only callsite plan');` : 'this._buffer.message_values[idx] = helpers.normalizeOperationalTemplate(message);'}
462
+ if (fields !== undefined) {
463
+ this.with(fields);
430
464
  }
465
+ return this;
431
466
  }
432
467
 
433
- ` +
434
- // Write an info log entry.
435
- // writeLogEntry bumps buffer._writeIndex, writes timestamp+entry_type, returns idx.
436
- // We sync this._writeIndex so fluent setters write at correct row.
437
- `info(message) {
438
- this._checkOverflow();
439
- const idx = this._buffer._traceRoot.writeLogEntry(this._buffer, ENTRY_TYPE_INFO);
440
- this._writeIndex = idx;
441
- if (this._buffer.message_values) {
442
- this._buffer.message_values[idx] = message;
443
- if (this._buffer.message_nulls) {
444
- helpers.setNullBit(this._buffer.message_nulls, idx);
445
- }
446
- }
447
- this._buffer.constructor.stats.totalWrites++;
468
+ _infoTemplate(vocabularyIndex) {
469
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_INFO);
470
+ ${messageLayoutFamily === 'dynamic-only' ? `throw new TypeError('Static log write reached a dynamic-only callsite plan');` : staticMessageWrite(ENTRY_TYPE_INFO)}
448
471
  return this;
449
472
  }
450
473
 
451
474
  ` +
452
475
  // Write a debug log entry.
453
476
  `debug(message) {
454
- this._checkOverflow();
455
- const idx = this._buffer._traceRoot.writeLogEntry(this._buffer, ENTRY_TYPE_DEBUG);
456
- this._writeIndex = idx;
457
- if (this._buffer.message_values) {
458
- this._buffer.message_values[idx] = message;
459
- if (this._buffer.message_nulls) {
460
- helpers.setNullBit(this._buffer.message_nulls, idx);
461
- }
462
- }
463
- this._buffer.constructor.stats.totalWrites++;
477
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_DEBUG);
478
+ ${messageLayoutFamily === 'static-only' ? `throw new TypeError('Dynamic log write reached a static-only callsite plan');` : 'this._buffer.message_values[idx] = message;'}
479
+ return this;
480
+ }
481
+
482
+ _debugTemplate(vocabularyIndex) {
483
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_DEBUG);
484
+ ${messageLayoutFamily === 'dynamic-only' ? `throw new TypeError('Static log write reached a dynamic-only callsite plan');` : staticMessageWrite(ENTRY_TYPE_DEBUG)}
464
485
  return this;
465
486
  }
466
487
 
467
488
  ` +
468
489
  // Write a warn log entry.
469
- `warn(message) {
470
- this._checkOverflow();
471
- const idx = this._buffer._traceRoot.writeLogEntry(this._buffer, ENTRY_TYPE_WARN);
472
- this._writeIndex = idx;
473
- if (this._buffer.message_values) {
474
- this._buffer.message_values[idx] = message;
475
- if (this._buffer.message_nulls) {
476
- helpers.setNullBit(this._buffer.message_nulls, idx);
477
- }
490
+ `warn(message, fields) {
491
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_WARN);
492
+ ${messageLayoutFamily === 'static-only' ? `throw new TypeError('Dynamic log write reached a static-only callsite plan');` : 'this._buffer.message_values[idx] = helpers.normalizeOperationalTemplate(message);'}
493
+ if (fields !== undefined) {
494
+ this.with(fields);
478
495
  }
479
- this._buffer.constructor.stats.totalWrites++;
496
+ return this;
497
+ }
498
+
499
+ _warnTemplate(vocabularyIndex) {
500
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_WARN);
501
+ ${messageLayoutFamily === 'dynamic-only' ? `throw new TypeError('Static log write reached a dynamic-only callsite plan');` : staticMessageWrite(ENTRY_TYPE_WARN)}
480
502
  return this;
481
503
  }
482
504
 
483
505
  ` +
484
506
  // Write an error log entry.
485
- `error(message) {
486
- this._checkOverflow();
487
- const idx = this._buffer._traceRoot.writeLogEntry(this._buffer, ENTRY_TYPE_ERROR);
488
- this._writeIndex = idx;
489
- if (this._buffer.message_values) {
490
- this._buffer.message_values[idx] = message;
491
- if (this._buffer.message_nulls) {
492
- helpers.setNullBit(this._buffer.message_nulls, idx);
493
- }
507
+ `error(message, fields) {
508
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_ERROR);
509
+ ${messageLayoutFamily === 'static-only' ? `throw new TypeError('Dynamic log write reached a static-only callsite plan');` : 'this._buffer.message_values[idx] = helpers.normalizeOperationalTemplate(message);'}
510
+ if (fields !== undefined) {
511
+ this.with(fields);
494
512
  }
495
- this._buffer.constructor.stats.totalWrites++;
513
+ return this;
514
+ }
515
+
516
+ _errorTemplate(vocabularyIndex) {
517
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_ERROR);
518
+ ${messageLayoutFamily === 'dynamic-only' ? `throw new TypeError('Static log write reached a dynamic-only callsite plan');` : staticMessageWrite(ENTRY_TYPE_ERROR)}
496
519
  return this;
497
520
  }
498
521
 
499
522
  ` +
500
523
  // Write a trace log entry.
501
524
  `trace(message) {
502
- this._checkOverflow();
503
- const idx = this._buffer._traceRoot.writeLogEntry(this._buffer, ENTRY_TYPE_TRACE);
504
- this._writeIndex = idx;
505
- if (this._buffer.message_values) {
506
- this._buffer.message_values[idx] = message;
507
- if (this._buffer.message_nulls) {
508
- helpers.setNullBit(this._buffer.message_nulls, idx);
509
- }
510
- }
511
- this._buffer.constructor.stats.totalWrites++;
525
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_TRACE);
526
+ ${messageLayoutFamily === 'static-only' ? `throw new TypeError('Dynamic log write reached a static-only callsite plan');` : 'this._buffer.message_values[idx] = message;'}
527
+ return this;
528
+ }
529
+
530
+ _traceTemplate(vocabularyIndex) {
531
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_TRACE);
532
+ ${messageLayoutFamily === 'dynamic-only' ? `throw new TypeError('Static log write reached a dynamic-only callsite plan');` : staticMessageWrite(ENTRY_TYPE_TRACE)}
512
533
  return this;
513
534
  }
514
535
 
@@ -532,15 +553,8 @@ function buildSpanLoggerExtension(schema: LogSchema): ColumnWriterExtension {
532
553
  // Write a feature flag access entry (internal method, not on public type).
533
554
  // Called by FeatureFlagEvaluator to log flag access.
534
555
  `ffAccess(flagName, value) {
535
- this._checkOverflow();
536
- const idx = this._buffer._traceRoot.writeLogEntry(this._buffer, ENTRY_TYPE_FF_ACCESS);
537
- this._writeIndex = idx;
538
- if (this._buffer.message_values) {
539
- this._buffer.message_values[idx] = flagName;
540
- if (this._buffer.message_nulls) {
541
- helpers.setNullBit(this._buffer.message_nulls, idx);
542
- }
543
- }
556
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_FF_ACCESS);
557
+ ${messageLayoutFamily === 'static-only' ? `throw new TypeError('Feature flag write reached a static-only callsite plan');` : 'this._buffer.message_values[idx] = flagName;'}
544
558
  if (this._buffer.ff_value_values) {
545
559
  const strValue = value === null || value === undefined ? 'null' : String(value);
546
560
  this._buffer.ff_value_values[idx] = strValue;
@@ -548,23 +562,14 @@ function buildSpanLoggerExtension(schema: LogSchema): ColumnWriterExtension {
548
562
  helpers.setNullBit(this._buffer.ff_value_nulls, idx);
549
563
  }
550
564
  }
551
- this._buffer.constructor.stats.totalWrites++;
552
565
  }
553
566
 
554
567
  ` +
555
568
  // Write a feature flag usage entry (internal method, not on public type).
556
569
  // Called by FeatureFlagEvaluator to log flag usage.
557
570
  `ffUsage(flagName, context) {
558
- this._checkOverflow();
559
- const idx = this._buffer._traceRoot.writeLogEntry(this._buffer, ENTRY_TYPE_FF_USAGE);
560
- this._writeIndex = idx;
561
- if (this._buffer.message_values) {
562
- this._buffer.message_values[idx] = flagName;
563
- if (this._buffer.message_nulls) {
564
- helpers.setNullBit(this._buffer.message_nulls, idx);
565
- }
566
- }
567
- this._buffer.constructor.stats.totalWrites++;
571
+ const idx = this._state._appendWriterEntry(ENTRY_TYPE_FF_USAGE);
572
+ ${messageLayoutFamily === 'static-only' ? `throw new TypeError('Feature flag write reached a static-only callsite plan');` : 'this._buffer.message_values[idx] = flagName;'}
568
573
  if (context) {
569
574
  this.with(context);
570
575
  }
@@ -648,6 +653,7 @@ function buildSpanLoggerExtension(schema: LogSchema): ColumnWriterExtension {
648
653
  // Use singleton helpers object (created once at module load)
649
654
  dependencies: {
650
655
  helpers: SPAN_LOGGER_HELPERS,
656
+ enumLookup,
651
657
  },
652
658
  };
653
659
  }
@@ -655,48 +661,112 @@ function buildSpanLoggerExtension(schema: LogSchema): ColumnWriterExtension {
655
661
  /**
656
662
  * Cache for generated SpanLogger classes per schema.
657
663
  */
658
- const spanLoggerClassCache = new WeakMap<LogSchema, unknown>();
664
+ const spanLoggerClassCache = new WeakMap<LogSchema, Map<string, unknown>>();
659
665
 
660
- function isSpanLoggerConstructor<T extends LogSchema>(
661
- value: unknown,
662
- ): value is new (
663
- buffer: AnySpanBuffer,
664
- ) => SpanLoggerImpl<T> {
666
+ function isSpanLoggerConstructor<T extends LogSchema>(value: unknown): value is SpanLoggerConstructor<T> {
665
667
  return typeof value === 'function';
666
668
  }
667
669
 
670
+ function generateStateBoundSpanLoggerClass(schema: LogSchema, extension: ColumnWriterExtension): string {
671
+ const source = generateColumnWriterClass(schema, 'GeneratedSpanLogger', extension);
672
+ const constructorStart = source.indexOf(' constructor(buffer) {');
673
+ const firstSetter = schema._columnNames[0];
674
+ const methodsStart = source.indexOf(
675
+ firstSetter === undefined ? '\n info(message, fields) {' : `\n ${firstSetter}(value) {`,
676
+ constructorStart,
677
+ );
678
+ if (constructorStart < 0 || methodsStart < 0) {
679
+ throw new Error('Failed to locate generated SpanLogger class boundaries');
680
+ }
681
+ const stateConstructor = ' constructor(state) {\n this._state = state;\n }\n';
682
+ return (source.slice(0, constructorStart) + stateConstructor + source.slice(methodsStart + 1))
683
+ .replaceAll('this._buffer', 'this._state._buffer')
684
+ .replaceAll('this._writeIndex', '(this._state._buffer._writeIndex - 1)');
685
+ }
686
+
687
+ /** Compiled materializer: render class source and evaluate it with `new Function`. */
688
+ function compileSpanLoggerClass(
689
+ schema: LogSchema,
690
+ messageLayoutFamily: MessageLayoutFamily,
691
+ messagePhysicalLayout: MessagePhysicalLayout,
692
+ eagerColumns: readonly string[],
693
+ enumLookup: SchemaEnumLookupDescriptor,
694
+ ): unknown {
695
+ const extension = buildSpanLoggerExtension(
696
+ schema,
697
+ messageLayoutFamily,
698
+ messagePhysicalLayout,
699
+ eagerColumns,
700
+ enumLookup,
701
+ );
702
+ const classCode = generateStateBoundSpanLoggerClass(schema, extension).trim();
703
+ return new Function('helpers', 'enumLookup', classCode)(SPAN_LOGGER_HELPERS, enumLookup);
704
+ }
705
+
668
706
  /**
669
- * Create SpanLogger class constructor from schema.
670
- * This is the cold-path function called at module creation time.
671
- *
672
- * SpanLogger extends ColumnWriter and adds:
673
- * - info(), debug(), warn(), error() methods for log entries
674
- * - _setScope() for setting scoped attributes
675
- * - _getNextBuffer() override for SpanBuffer creation on overflow
707
+ * Schema/config -> pure-data plan consumed by the closure-composed (no-eval)
708
+ * materializer. Mirrors the inputs the compiled renderer bakes into source:
709
+ * per-column access mode (arrow-builder's buildColumnAccessorPlan semantics),
710
+ * layout family/physical layout, and the injected singleton dependencies.
711
+ */
712
+ function buildSpanLoggerPlan(
713
+ schema: LogSchema,
714
+ messageLayoutFamily: MessageLayoutFamily,
715
+ messagePhysicalLayout: MessagePhysicalLayout,
716
+ eagerColumns: readonly string[],
717
+ enumLookup: SchemaEnumLookupDescriptor,
718
+ ): SpanLoggerPlan {
719
+ const preallocated = new Set(eagerColumns);
720
+ const columns = schema._columns.map(([fieldName, fieldSchema]) => {
721
+ const isEager =
722
+ typeof fieldSchema === 'object' && fieldSchema !== null && Reflect.get(fieldSchema, '__eager') === true;
723
+ const mode: SpanLoggerColumnMode = isEager ? 'eager' : preallocated.has(fieldName) ? 'preallocated' : 'lazy';
724
+ return { name: fieldName, schemaType: getSchemaType(fieldSchema), mode };
725
+ });
726
+ return {
727
+ columns,
728
+ messageLayoutFamily,
729
+ messagePhysicalLayout,
730
+ helpers: SPAN_LOGGER_HELPERS,
731
+ enumLookup,
732
+ };
733
+ }
734
+
735
+ /**
736
+ * Create the state-only SpanLogger constructor selected for one schema/layout family.
676
737
  *
677
- * Note: Fluent attribute setters are inherited from ColumnWriter and write at _writeIndex.
738
+ * Selects the materializer via activeMaterializerMode(): the compiled renderer
739
+ * (string codegen) where `new Function` is allowed, the closure-composed
740
+ * materializer where it is forbidden (e.g. workerd). Cache keys are
741
+ * mode-prefixed so a forced override never returns the other mode's class.
678
742
  */
679
743
  export function createSpanLoggerClass<T extends LogSchema>(
680
744
  schema: T,
681
- ): new (
682
- buffer: AnySpanBuffer,
683
- ) => SpanLoggerImpl<T> {
684
- // Check cache first
685
- let SpanLoggerClass = spanLoggerClassCache.get(schema);
745
+ messageLayoutFamily: MessageLayoutFamily = 'mixed',
746
+ messagePhysicalLayout: MessagePhysicalLayout = 'current',
747
+ eagerColumns: readonly string[] = [],
748
+ enumLookup: SchemaEnumLookupDescriptor = resolveEnumLookupDescriptor(schema),
749
+ ): SpanLoggerConstructor<T> {
750
+ const mode = activeMaterializerMode();
751
+ const cacheKey = `${mode}:${messageLayoutFamily}:${messagePhysicalLayout}:${eagerColumns.join('\u0000')}`;
752
+ let familyClasses = spanLoggerClassCache.get(schema);
753
+ let SpanLoggerClass = familyClasses?.get(cacheKey);
686
754
 
687
755
  if (!SpanLoggerClass) {
688
- const extension = buildSpanLoggerExtension(schema);
689
-
690
- // Use arrow-builder's getColumnWriterClass with our extension
691
- const WriterClass = getColumnWriterClass(schema, extension);
692
-
693
- SpanLoggerClass = WriterClass;
756
+ SpanLoggerClass =
757
+ mode === 'compiled'
758
+ ? compileSpanLoggerClass(schema, messageLayoutFamily, messagePhysicalLayout, eagerColumns, enumLookup)
759
+ : materializeSpanLoggerClass(
760
+ buildSpanLoggerPlan(schema, messageLayoutFamily, messagePhysicalLayout, eagerColumns, enumLookup),
761
+ );
694
762
 
695
763
  if (!isSpanLoggerConstructor<LogSchema>(SpanLoggerClass)) {
696
764
  throw new Error('Failed to generate SpanLogger constructor');
697
765
  }
698
766
 
699
- spanLoggerClassCache.set(schema, SpanLoggerClass);
767
+ familyClasses ??= new Map();
768
+ familyClasses.set(cacheKey, SpanLoggerClass);
769
+ spanLoggerClassCache.set(schema, familyClasses);
700
770
  }
701
771
 
702
772
  if (!isSpanLoggerConstructor<T>(SpanLoggerClass)) {
@@ -706,14 +776,8 @@ export function createSpanLoggerClass<T extends LogSchema>(
706
776
  return SpanLoggerClass;
707
777
  }
708
778
 
709
- /**
710
- * Create a SpanLogger instance for the given buffer.
711
- *
712
- * @param schema - Tag attribute schema
713
- * @param buffer - SpanBuffer to write to
714
- */
715
- export function createSpanLogger<T extends LogSchema>(schema: T, buffer: SpanBuffer<T>): SpanLoggerImpl<T> {
716
- const SpanLoggerClass = createSpanLoggerClass(schema);
717
- return new SpanLoggerClass(buffer);
779
+ /** Create a SpanLogger bound to an existing SpanContext writer state. */
780
+ export function createSpanLogger<T extends LogSchema>(schema: T, state: WriterState): SpanLoggerImpl<T> {
781
+ return new (createSpanLoggerClass(schema))(state);
718
782
  }
719
783
  //#endregion smoo/lmao!n/codegen-spanlogger