@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
@@ -1,28 +1,57 @@
1
1
  import { describe, expect, it } from 'bun:test';
2
2
 
3
3
  import { Nanoseconds } from '@smoothbricks/arrow-builder';
4
- import { defineLogSchema } from '../schema/defineLogSchema.js';
5
- import type { AnySpanBuffer } from '../types.js';
6
- import { createBuffer } from './test-helpers.js';
4
+ import fc from 'fast-check';
5
+ import { JsBufferStrategy } from '../JsBufferStrategy.js';
6
+ import { resolveEntryType } from '../resolveMessage.js';
7
+ import { ENTRY_TYPE_INFO, ENTRY_TYPE_SPAN_OK, ENTRY_TYPE_SPAN_START } from '../schema/systemSchema.js';
8
+ import { createTraceId } from '../traceId.js';
9
+ import { createTraceRoot as createEsTraceRoot, TraceRoot as EsTraceRoot } from '../traceRoot.es.js';
10
+ import type { TracerLifecycleHooks } from '../traceRoot.js';
11
+ import { createTraceRoot as createNodeTraceRoot, TraceRoot as NodeTraceRoot } from '../traceRoot.node.js';
12
+ import type { SpanBuffer } from '../types.js';
13
+ import { createTestSpanBuffer } from './test-helpers.js';
14
+
15
+ const mockBuffer = createTestSpanBuffer({}).spanBuffer;
16
+ type MockLogSchema = (typeof mockBuffer)['_logSchema'];
17
+
18
+ function createMockSpanBuffer(): SpanBuffer<MockLogSchema> {
19
+ return createTestSpanBuffer({}).spanBuffer;
20
+ }
21
+
22
+ function createMockTracer(): TracerLifecycleHooks<MockLogSchema> {
23
+ return {
24
+ onTraceStart: () => {},
25
+ onTraceEnd: () => {},
26
+ onSpanStart: () => {},
27
+ onSpanEnd: () => {},
28
+ onStatsWillResetFor: () => {},
29
+ getFlagEvaluatorForContext: () => undefined,
30
+ bufferStrategy: new JsBufferStrategy<MockLogSchema>(),
31
+ };
32
+ }
33
+
34
+ function withPerformanceNow<T>(now: () => number, run: () => T): T {
35
+ const original = performance.now;
36
+ Object.defineProperty(performance, 'now', { configurable: true, value: now });
37
+ try {
38
+ return run();
39
+ } finally {
40
+ Object.defineProperty(performance, 'now', { configurable: true, value: original });
41
+ }
42
+ }
7
43
 
8
- function createMockSpanBuffer(): AnySpanBuffer {
9
- return createBuffer(defineLogSchema({}));
44
+ function appendLifecycle(root: NodeTraceRoot | EsTraceRoot, buffer: SpanBuffer<MockLogSchema>): void {
45
+ root._writeSpanStart(root, buffer, 'timestamp-contract');
46
+ root._appendLogEntry(root, buffer, ENTRY_TYPE_INFO);
47
+ root._appendLogEntry(root, buffer, ENTRY_TYPE_INFO);
48
+ root._writeSpanEnd(root, buffer, ENTRY_TYPE_SPAN_OK);
10
49
  }
11
50
 
12
51
  describe('Node.js TraceRoot Timestamps (process.hrtime.bigint)', () => {
13
52
  it('should return a bigint from getTimestampNanos()', async () => {
14
53
  const { createTraceRoot } = await import('../traceRoot.node.js');
15
- const mockTracer = {
16
- onTraceStart: () => {},
17
- onTraceEnd: () => {},
18
- onSpanStart: () => {},
19
- onSpanEnd: () => {},
20
- onStatsWillResetFor: () => {},
21
- bufferStrategy: {
22
- createChildSpanBuffer: createMockSpanBuffer,
23
- createOverflowBuffer: createMockSpanBuffer,
24
- },
25
- };
54
+ const mockTracer = createMockTracer();
26
55
  const traceRoot = createTraceRoot('test-trace', mockTracer);
27
56
 
28
57
  const ts = traceRoot.getTimestampNanos();
@@ -31,17 +60,7 @@ describe('Node.js TraceRoot Timestamps (process.hrtime.bigint)', () => {
31
60
 
32
61
  it('should return increasing timestamps', async () => {
33
62
  const { createTraceRoot } = await import('../traceRoot.node.js');
34
- const mockTracer = {
35
- onTraceStart: () => {},
36
- onTraceEnd: () => {},
37
- onSpanStart: () => {},
38
- onSpanEnd: () => {},
39
- onStatsWillResetFor: () => {},
40
- bufferStrategy: {
41
- createChildSpanBuffer: createMockSpanBuffer,
42
- createOverflowBuffer: createMockSpanBuffer,
43
- },
44
- };
63
+ const mockTracer = createMockTracer();
45
64
  const traceRoot = createTraceRoot('test-trace', mockTracer);
46
65
 
47
66
  const ts1 = traceRoot.getTimestampNanos();
@@ -57,17 +76,7 @@ describe('Node.js TraceRoot Timestamps (process.hrtime.bigint)', () => {
57
76
 
58
77
  it('should be within 1ms of Date.now()', async () => {
59
78
  const { createTraceRoot } = await import('../traceRoot.node.js');
60
- const mockTracer = {
61
- onTraceStart: () => {},
62
- onTraceEnd: () => {},
63
- onSpanStart: () => {},
64
- onSpanEnd: () => {},
65
- onStatsWillResetFor: () => {},
66
- bufferStrategy: {
67
- createChildSpanBuffer: createMockSpanBuffer,
68
- createOverflowBuffer: createMockSpanBuffer,
69
- },
70
- };
79
+ const mockTracer = createMockTracer();
71
80
 
72
81
  // Sample multiple times and check they're all close
73
82
  for (let i = 0; i < 10; i++) {
@@ -83,17 +92,7 @@ describe('Node.js TraceRoot Timestamps (process.hrtime.bigint)', () => {
83
92
 
84
93
  it('should have sub-millisecond precision (true nanoseconds)', async () => {
85
94
  const { createTraceRoot } = await import('../traceRoot.node.js');
86
- const mockTracer = {
87
- onTraceStart: () => {},
88
- onTraceEnd: () => {},
89
- onSpanStart: () => {},
90
- onSpanEnd: () => {},
91
- onStatsWillResetFor: () => {},
92
- bufferStrategy: {
93
- createChildSpanBuffer: createMockSpanBuffer,
94
- createOverflowBuffer: createMockSpanBuffer,
95
- },
96
- };
95
+ const mockTracer = createMockTracer();
97
96
  const traceRoot = createTraceRoot('test-trace', mockTracer);
98
97
  const timestamps: bigint[] = [];
99
98
 
@@ -124,17 +123,7 @@ describe('Node.js TraceRoot Timestamps (process.hrtime.bigint)', () => {
124
123
 
125
124
  try {
126
125
  const { createTraceRoot } = await import('../traceRoot.node.js');
127
- const mockTracer = {
128
- onTraceStart: () => {},
129
- onTraceEnd: () => {},
130
- onSpanStart: () => {},
131
- onSpanEnd: () => {},
132
- onStatsWillResetFor: () => {},
133
- bufferStrategy: {
134
- createChildSpanBuffer: createMockSpanBuffer,
135
- createOverflowBuffer: createMockSpanBuffer,
136
- },
137
- };
126
+ const mockTracer = createMockTracer();
138
127
 
139
128
  const traceRoot = createTraceRoot('test-trace', mockTracer);
140
129
  const ts0 = traceRoot.getTimestampNanos();
@@ -150,17 +139,7 @@ describe('Node.js TraceRoot Timestamps (process.hrtime.bigint)', () => {
150
139
  describe('Browser TraceRoot Timestamps (performance.now)', () => {
151
140
  it('should return a bigint from getTimestampNanos()', async () => {
152
141
  const { createTraceRoot } = await import('../traceRoot.es.js');
153
- const mockTracer = {
154
- onTraceStart: () => {},
155
- onTraceEnd: () => {},
156
- onSpanStart: () => {},
157
- onSpanEnd: () => {},
158
- onStatsWillResetFor: () => {},
159
- bufferStrategy: {
160
- createChildSpanBuffer: createMockSpanBuffer,
161
- createOverflowBuffer: createMockSpanBuffer,
162
- },
163
- };
142
+ const mockTracer = createMockTracer();
164
143
  const traceRoot = createTraceRoot('test-trace', mockTracer);
165
144
 
166
145
  const ts = traceRoot.getTimestampNanos();
@@ -169,17 +148,7 @@ describe('Browser TraceRoot Timestamps (performance.now)', () => {
169
148
 
170
149
  it('should return increasing timestamps', async () => {
171
150
  const { createTraceRoot } = await import('../traceRoot.es.js');
172
- const mockTracer = {
173
- onTraceStart: () => {},
174
- onTraceEnd: () => {},
175
- onSpanStart: () => {},
176
- onSpanEnd: () => {},
177
- onStatsWillResetFor: () => {},
178
- bufferStrategy: {
179
- createChildSpanBuffer: createMockSpanBuffer,
180
- createOverflowBuffer: createMockSpanBuffer,
181
- },
182
- };
151
+ const mockTracer = createMockTracer();
183
152
  const traceRoot = createTraceRoot('test-trace', mockTracer);
184
153
 
185
154
  const ts1 = traceRoot.getTimestampNanos();
@@ -195,17 +164,7 @@ describe('Browser TraceRoot Timestamps (performance.now)', () => {
195
164
 
196
165
  it('should be within 1ms of Date.now()', async () => {
197
166
  const { createTraceRoot } = await import('../traceRoot.es.js');
198
- const mockTracer = {
199
- onTraceStart: () => {},
200
- onTraceEnd: () => {},
201
- onSpanStart: () => {},
202
- onSpanEnd: () => {},
203
- onStatsWillResetFor: () => {},
204
- bufferStrategy: {
205
- createChildSpanBuffer: createMockSpanBuffer,
206
- createOverflowBuffer: createMockSpanBuffer,
207
- },
208
- };
167
+ const mockTracer = createMockTracer();
209
168
 
210
169
  // Sample multiple times and check they're all close
211
170
  for (let i = 0; i < 10; i++) {
@@ -221,6 +180,175 @@ describe('Browser TraceRoot Timestamps (performance.now)', () => {
221
180
  });
222
181
  });
223
182
 
183
+ describe('Platform timestamp append contract', () => {
184
+ it('anchors public Node and ES factories to the Unix epoch without exact wall-clock equality', () => {
185
+ const before = BigInt(Date.now()) * 1_000_000n;
186
+ const node = createNodeTraceRoot('node-epoch', createMockTracer());
187
+ const es = createEsTraceRoot('es-epoch', createMockTracer());
188
+ const after = BigInt(Date.now()) * 1_000_000n;
189
+ const tolerance = 50_000_000n;
190
+
191
+ for (const root of [node, es]) {
192
+ const buffer = createMockSpanBuffer();
193
+ root._writeSpanStart(root, buffer, 'epoch');
194
+ expect(buffer.timestamp[0]).toBeGreaterThanOrEqual(before - tolerance);
195
+ expect(buffer.timestamp[0]).toBeLessThanOrEqual(after + tolerance);
196
+ }
197
+ });
198
+
199
+ it('keeps lifecycle appends strictly monotonic when the wrapped clock stalls or rolls back', () => {
200
+ const epoch = 1_700_000_000_000_000_000n;
201
+ const anchor = 10_000_000n;
202
+ const ticks = [anchor, anchor, anchor - 50n, anchor + 1n, anchor - 1_000n];
203
+ const buffer = createMockSpanBuffer();
204
+ let index = 0;
205
+ const original = process.hrtime.bigint;
206
+ process.hrtime.bigint = () => ticks[index++] ?? ticks[ticks.length - 1];
207
+
208
+ try {
209
+ const root = new NodeTraceRoot(createTraceId('rollback'), epoch, Number(anchor), anchor, createMockTracer());
210
+ appendLifecycle(root, buffer);
211
+ const chronological = [buffer.timestamp[0], buffer.timestamp[2], buffer.timestamp[3], buffer.timestamp[1]];
212
+ for (let i = 1; i < chronological.length; i++) {
213
+ expect(chronological[i]).toBeGreaterThan(chronological[i - 1]);
214
+ }
215
+ } finally {
216
+ process.hrtime.bigint = original;
217
+ }
218
+ });
219
+
220
+ it('advances ES lifecycle appends by one microsecond when performance.now stalls or rolls back', () => {
221
+ const epoch = 1_700_000_000_000_000_000n;
222
+ const buffer = createMockSpanBuffer();
223
+ const ticks = [10, 10, 9, 10.0001];
224
+ let index = 0;
225
+ const root = new EsTraceRoot(createTraceId('es-rollback'), epoch, 10, createMockTracer());
226
+
227
+ withPerformanceNow(
228
+ () => ticks[index++] ?? ticks[ticks.length - 1],
229
+ () => appendLifecycle(root, buffer),
230
+ );
231
+
232
+ const chronological = [buffer.timestamp[0], buffer.timestamp[2], buffer.timestamp[3], buffer.timestamp[1]];
233
+ expect(chronological[0]).toBe(epoch);
234
+ for (let i = 1; i < chronological.length; i++) {
235
+ expect(chronological[i] - chronological[i - 1]).toBe(1_000n);
236
+ }
237
+ });
238
+
239
+ it('preserves exact nanosecond deltas after a long Node monotonic-clock gap', () => {
240
+ const epoch = 1_700_000_000_000_000_000n;
241
+ const anchor = 9_007_199_254_740_993n;
242
+ const gap = 365n * 24n * 60n * 60n * 1_000_000_000n;
243
+ const ticks = [anchor + gap, anchor + gap + 1n, anchor + gap + 2n, anchor + gap + 3n];
244
+ const buffer = createMockSpanBuffer();
245
+ let index = 0;
246
+ const original = process.hrtime.bigint;
247
+ process.hrtime.bigint = () => ticks[index++] ?? ticks[ticks.length - 1];
248
+
249
+ try {
250
+ const root = new NodeTraceRoot(createTraceId('long-gap'), epoch, Number(anchor), anchor, createMockTracer());
251
+ appendLifecycle(root, buffer);
252
+ expect(buffer.timestamp[0]).toBe(epoch + gap);
253
+ expect(buffer.timestamp[2] - buffer.timestamp[0]).toBe(1n);
254
+ expect(buffer.timestamp[3] - buffer.timestamp[2]).toBe(1n);
255
+ expect(buffer.timestamp[1] - buffer.timestamp[3]).toBe(1n);
256
+ } finally {
257
+ process.hrtime.bigint = original;
258
+ }
259
+ });
260
+
261
+ it('re-anchors each new trace while an existing trace ignores wall-clock rollback', () => {
262
+ const originalDateNow = Date.now;
263
+ const originalHrtime = process.hrtime.bigint;
264
+ const wallTimes = [1_700_000_000_000, 1_699_999_000_000];
265
+ const ticks = [100n, 110n, 200n, 220n, 120n];
266
+ const firstStart = createMockSpanBuffer();
267
+ const secondStart = createMockSpanBuffer();
268
+ let wallIndex = 0;
269
+ let tickIndex = 0;
270
+ Date.now = () => wallTimes[wallIndex++] ?? wallTimes[wallTimes.length - 1];
271
+ process.hrtime.bigint = () => ticks[tickIndex++] ?? ticks[ticks.length - 1];
272
+
273
+ try {
274
+ const first = createNodeTraceRoot('first-anchor', createMockTracer());
275
+ first._writeSpanStart(first, firstStart, 'first');
276
+ const second = createNodeTraceRoot('second-anchor', createMockTracer());
277
+ second._writeSpanStart(second, secondStart, 'second');
278
+ const firstLater = first._timestampNow(first);
279
+
280
+ expect(firstStart.timestamp[0]).toBe(BigInt(wallTimes[0]) * 1_000_000n + 10n);
281
+ expect(secondStart.timestamp[0]).toBe(BigInt(wallTimes[1]) * 1_000_000n + 20n);
282
+ expect(firstLater).toBeGreaterThan(firstStart.timestamp[0]);
283
+ } finally {
284
+ Date.now = originalDateNow;
285
+ process.hrtime.bigint = originalHrtime;
286
+ }
287
+ });
288
+
289
+ it('keeps Node and ES lifecycle output equivalent at shared microsecond ticks', () => {
290
+ const epoch = 1_700_000_000_000_000_000n;
291
+ const nodeAnchor = 5_000_000n;
292
+ const elapsedMicros = [0, 1, 2, 3];
293
+ const nodeBuffer = createMockSpanBuffer();
294
+ const esBuffer = createMockSpanBuffer();
295
+ let nodeIndex = 0;
296
+ const original = process.hrtime.bigint;
297
+ process.hrtime.bigint = () => nodeAnchor + BigInt(elapsedMicros[nodeIndex++] ?? 3) * 1_000n;
298
+
299
+ try {
300
+ const node = new NodeTraceRoot(
301
+ createTraceId('node-parity'),
302
+ epoch,
303
+ Number(nodeAnchor),
304
+ nodeAnchor,
305
+ createMockTracer(),
306
+ );
307
+ let esIndex = 0;
308
+ const es = new EsTraceRoot(createTraceId('es-parity'), epoch, 10, createMockTracer());
309
+ appendLifecycle(node, nodeBuffer);
310
+ withPerformanceNow(
311
+ () => 10 + (elapsedMicros[esIndex++] ?? 3) / 1_000,
312
+ () => appendLifecycle(es, esBuffer),
313
+ );
314
+
315
+ expect(Array.from({ length: 4 }, (_, row) => resolveEntryType(esBuffer, row))).toEqual(
316
+ Array.from({ length: 4 }, (_, row) => resolveEntryType(nodeBuffer, row)),
317
+ );
318
+ expect(Array.from(esBuffer.timestamp.slice(0, 4))).toEqual(Array.from(nodeBuffer.timestamp.slice(0, 4)));
319
+ expect(resolveEntryType(nodeBuffer, 0)).toBe(ENTRY_TYPE_SPAN_START);
320
+ expect(resolveEntryType(nodeBuffer, 1)).toBe(ENTRY_TYPE_SPAN_OK);
321
+ } finally {
322
+ process.hrtime.bigint = original;
323
+ }
324
+ });
325
+
326
+ it('keeps generated rapid-write sequences strictly monotonic through the real append primitive', () => {
327
+ fc.assert(
328
+ fc.property(fc.array(fc.integer({ min: -5, max: 5 }), { minLength: 4, maxLength: 40 }), (steps) => {
329
+ const epoch = 1_700_000_000_000_000_000n;
330
+ const anchor = 1_000_000n;
331
+ let tick = anchor;
332
+ let index = 0;
333
+ const ticks = steps.map((step) => (tick += BigInt(step)));
334
+ const buffer = createMockSpanBuffer();
335
+ const original = process.hrtime.bigint;
336
+ process.hrtime.bigint = () => ticks[index++] ?? ticks[ticks.length - 1];
337
+ try {
338
+ const root = new NodeTraceRoot(createTraceId('property'), epoch, Number(anchor), anchor, createMockTracer());
339
+ root._writeSpanStart(root, buffer, 'property');
340
+ for (let i = 1; i < steps.length; i++) root._appendLogEntry(root, buffer, ENTRY_TYPE_INFO);
341
+ const written = Array.from(buffer.timestamp.slice(0, buffer._writeIndex)).filter((value) => value !== 0n);
342
+ for (let i = 1; i < written.length; i++) expect(written[i]).toBeGreaterThan(written[i - 1]);
343
+ } finally {
344
+ process.hrtime.bigint = original;
345
+ }
346
+ }),
347
+ { numRuns: 80 },
348
+ );
349
+ });
350
+ });
351
+
224
352
  describe('Nanoseconds utilities', () => {
225
353
  it('fromMillis converts correctly', () => {
226
354
  const ns = Nanoseconds.fromMillis(1000);