@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.
- package/README.md +269 -0
- package/dist/allocator.wasm +0 -0
- package/dist/bun/preload.d.ts +11 -0
- package/dist/bun/preload.d.ts.map +1 -0
- package/dist/bun/preload.js +10 -0
- package/dist/bun/trace-preload.d.ts +8 -0
- package/dist/bun/trace-preload.d.ts.map +1 -0
- package/dist/bun/trace-preload.js +12 -0
- package/dist/es.d.ts +8 -0
- package/dist/es.d.ts.map +1 -0
- package/dist/es.js +9 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +84 -0
- package/dist/lib/JsBufferStrategy.d.ts +49 -0
- package/dist/lib/JsBufferStrategy.d.ts.map +1 -0
- package/dist/lib/JsBufferStrategy.js +60 -0
- package/dist/lib/archive/chunkCompaction.d.ts +15 -0
- package/dist/lib/archive/chunkCompaction.d.ts.map +1 -0
- package/dist/lib/archive/chunkCompaction.js +24 -0
- package/dist/lib/archive/chunkEnvelope.d.ts +21 -0
- package/dist/lib/archive/chunkEnvelope.d.ts.map +1 -0
- package/dist/lib/archive/chunkEnvelope.js +55 -0
- package/dist/lib/archive/chunkRouting.d.ts +10 -0
- package/dist/lib/archive/chunkRouting.d.ts.map +1 -0
- package/dist/lib/archive/chunkRouting.js +47 -0
- package/dist/lib/archive/chunkStats.d.ts +12 -0
- package/dist/lib/archive/chunkStats.d.ts.map +1 -0
- package/dist/lib/archive/chunkStats.js +10 -0
- package/dist/lib/archive/index.d.ts +5 -0
- package/dist/lib/archive/index.d.ts.map +1 -0
- package/dist/lib/archive/index.js +4 -0
- package/dist/lib/arrow/capacityStats.d.ts +9 -0
- package/dist/lib/arrow/capacityStats.d.ts.map +1 -0
- package/dist/lib/arrow/capacityStats.js +231 -0
- package/dist/lib/arrow/dictionaries.d.ts +27 -0
- package/dist/lib/arrow/dictionaries.d.ts.map +1 -0
- package/dist/lib/arrow/dictionaries.js +135 -0
- package/dist/lib/arrow/flechette.d.ts +40 -0
- package/dist/lib/arrow/flechette.d.ts.map +1 -0
- package/dist/lib/arrow/flechette.js +67 -0
- package/dist/lib/arrow/utils.d.ts +38 -0
- package/dist/lib/arrow/utils.d.ts.map +1 -0
- package/dist/lib/arrow/utils.js +112 -0
- package/dist/lib/buffer/Nanoseconds.d.ts +109 -0
- package/dist/lib/buffer/Nanoseconds.d.ts.map +1 -0
- package/dist/lib/buffer/Nanoseconds.js +86 -0
- package/dist/lib/bufferStrategy.d.ts +95 -0
- package/dist/lib/bufferStrategy.d.ts.map +1 -0
- package/dist/lib/bufferStrategy.js +1 -0
- package/dist/lib/capacityTuning.d.ts +50 -0
- package/dist/lib/capacityTuning.d.ts.map +1 -0
- package/dist/lib/capacityTuning.js +65 -0
- package/dist/lib/codegen/evaluatorGenerator.d.ts +35 -0
- package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -0
- package/dist/lib/codegen/evaluatorGenerator.js +199 -0
- package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +139 -0
- package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -0
- package/dist/lib/codegen/fixedPositionWriterGenerator.js +289 -0
- package/dist/lib/codegen/spanLoggerGenerator.d.ts +115 -0
- package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -0
- package/dist/lib/codegen/spanLoggerGenerator.js +575 -0
- package/dist/lib/convertToArrow.d.ts +40 -0
- package/dist/lib/convertToArrow.d.ts.map +1 -0
- package/dist/lib/convertToArrow.js +1467 -0
- package/dist/lib/defineOpContext.d.ts +96 -0
- package/dist/lib/defineOpContext.d.ts.map +1 -0
- package/dist/lib/defineOpContext.js +227 -0
- package/dist/lib/errors/Blocked.d.ts +113 -0
- package/dist/lib/errors/Blocked.d.ts.map +1 -0
- package/dist/lib/errors/Blocked.js +68 -0
- package/dist/lib/errors/CodeError.d.ts +101 -0
- package/dist/lib/errors/CodeError.d.ts.map +1 -0
- package/dist/lib/errors/CodeError.js +42 -0
- package/dist/lib/errors/RetriesExhausted.d.ts +67 -0
- package/dist/lib/errors/RetriesExhausted.d.ts.map +1 -0
- package/dist/lib/errors/RetriesExhausted.js +31 -0
- package/dist/lib/errors/Transient.d.ts +115 -0
- package/dist/lib/errors/Transient.d.ts.map +1 -0
- package/dist/lib/errors/Transient.js +54 -0
- package/dist/lib/errors/index.d.ts +14 -0
- package/dist/lib/errors/index.d.ts.map +1 -0
- package/dist/lib/errors/index.js +16 -0
- package/dist/lib/errors/retry-policy.d.ts +60 -0
- package/dist/lib/errors/retry-policy.d.ts.map +1 -0
- package/dist/lib/errors/retry-policy.js +54 -0
- package/dist/lib/flushScheduler.d.ts +162 -0
- package/dist/lib/flushScheduler.d.ts.map +1 -0
- package/dist/lib/flushScheduler.js +388 -0
- package/dist/lib/library.d.ts +149 -0
- package/dist/lib/library.d.ts.map +1 -0
- package/dist/lib/library.js +588 -0
- package/dist/lib/logApi.d.ts +61 -0
- package/dist/lib/logApi.d.ts.map +1 -0
- package/dist/lib/logApi.js +12 -0
- package/dist/lib/logBinding.d.ts +63 -0
- package/dist/lib/logBinding.d.ts.map +1 -0
- package/dist/lib/logBinding.js +1 -0
- package/dist/lib/op.d.ts +105 -0
- package/dist/lib/op.d.ts.map +1 -0
- package/dist/lib/op.js +59 -0
- package/dist/lib/opContext/contextTypes.d.ts +88 -0
- package/dist/lib/opContext/contextTypes.d.ts.map +1 -0
- package/dist/lib/opContext/contextTypes.js +34 -0
- package/dist/lib/opContext/createOpGroup.d.ts +57 -0
- package/dist/lib/opContext/createOpGroup.d.ts.map +1 -0
- package/dist/lib/opContext/createOpGroup.js +341 -0
- package/dist/lib/opContext/defineOp.d.ts +83 -0
- package/dist/lib/opContext/defineOp.d.ts.map +1 -0
- package/dist/lib/opContext/defineOp.js +197 -0
- package/dist/lib/opContext/featureFlagTypes.d.ts +58 -0
- package/dist/lib/opContext/featureFlagTypes.d.ts.map +1 -0
- package/dist/lib/opContext/featureFlagTypes.js +1 -0
- package/dist/lib/opContext/index.d.ts +13 -0
- package/dist/lib/opContext/index.d.ts.map +1 -0
- package/dist/lib/opContext/index.js +15 -0
- package/dist/lib/opContext/opGroupTypes.d.ts +250 -0
- package/dist/lib/opContext/opGroupTypes.d.ts.map +1 -0
- package/dist/lib/opContext/opGroupTypes.js +31 -0
- package/dist/lib/opContext/opTypes.d.ts +48 -0
- package/dist/lib/opContext/opTypes.d.ts.map +1 -0
- package/dist/lib/opContext/opTypes.js +7 -0
- package/dist/lib/opContext/spanContextTypes.d.ts +347 -0
- package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -0
- package/dist/lib/opContext/spanContextTypes.js +1 -0
- package/dist/lib/opContext/types.d.ts +297 -0
- package/dist/lib/opContext/types.d.ts.map +1 -0
- package/dist/lib/opContext/types.js +16 -0
- package/dist/lib/result.d.ts +308 -0
- package/dist/lib/result.d.ts.map +1 -0
- package/dist/lib/result.js +359 -0
- package/dist/lib/schema/LogSchema.d.ts +62 -0
- package/dist/lib/schema/LogSchema.d.ts.map +1 -0
- package/dist/lib/schema/LogSchema.js +134 -0
- package/dist/lib/schema/builder.d.ts +12 -0
- package/dist/lib/schema/builder.d.ts.map +1 -0
- package/dist/lib/schema/builder.js +169 -0
- package/dist/lib/schema/defineFeatureFlags.d.ts +60 -0
- package/dist/lib/schema/defineFeatureFlags.d.ts.map +1 -0
- package/dist/lib/schema/defineFeatureFlags.js +29 -0
- package/dist/lib/schema/defineLogSchema.d.ts +87 -0
- package/dist/lib/schema/defineLogSchema.d.ts.map +1 -0
- package/dist/lib/schema/defineLogSchema.js +171 -0
- package/dist/lib/schema/evaluator.d.ts +267 -0
- package/dist/lib/schema/evaluator.d.ts.map +1 -0
- package/dist/lib/schema/evaluator.js +169 -0
- package/dist/lib/schema/extend.d.ts +14 -0
- package/dist/lib/schema/extend.d.ts.map +1 -0
- package/dist/lib/schema/extend.js +51 -0
- package/dist/lib/schema/systemSchema.d.ts +112 -0
- package/dist/lib/schema/systemSchema.d.ts.map +1 -0
- package/dist/lib/schema/systemSchema.js +260 -0
- package/dist/lib/schema/typeGuards.d.ts +52 -0
- package/dist/lib/schema/typeGuards.d.ts.map +1 -0
- package/dist/lib/schema/typeGuards.js +127 -0
- package/dist/lib/schema/types.d.ts +156 -0
- package/dist/lib/schema/types.d.ts.map +1 -0
- package/dist/lib/schema/types.js +4 -0
- package/dist/lib/spanBuffer.d.ts +133 -0
- package/dist/lib/spanBuffer.d.ts.map +1 -0
- package/dist/lib/spanBuffer.js +442 -0
- package/dist/lib/spanBufferHelpers.d.ts +53 -0
- package/dist/lib/spanBufferHelpers.d.ts.map +1 -0
- package/dist/lib/spanBufferHelpers.js +65 -0
- package/dist/lib/spanBufferStats.d.ts +38 -0
- package/dist/lib/spanBufferStats.d.ts.map +1 -0
- package/dist/lib/spanBufferStats.js +1 -0
- package/dist/lib/spanContext.d.ts +141 -0
- package/dist/lib/spanContext.d.ts.map +1 -0
- package/dist/lib/spanContext.js +763 -0
- package/dist/lib/sqlite/index.d.ts +14 -0
- package/dist/lib/sqlite/index.d.ts.map +1 -0
- package/dist/lib/sqlite/index.js +12 -0
- package/dist/lib/sqlite/sqlite-async-writer.d.ts +24 -0
- package/dist/lib/sqlite/sqlite-async-writer.d.ts.map +1 -0
- package/dist/lib/sqlite/sqlite-async-writer.js +65 -0
- package/dist/lib/sqlite/sqlite-common.d.ts +37 -0
- package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -0
- package/dist/lib/sqlite/sqlite-common.js +207 -0
- package/dist/lib/sqlite/sqlite-d1.d.ts +25 -0
- package/dist/lib/sqlite/sqlite-d1.d.ts.map +1 -0
- package/dist/lib/sqlite/sqlite-d1.js +67 -0
- package/dist/lib/sqlite/sqlite-db.d.ts +29 -0
- package/dist/lib/sqlite/sqlite-db.d.ts.map +1 -0
- package/dist/lib/sqlite/sqlite-db.js +1 -0
- package/dist/lib/sqlite/sqlite-node.d.ts +16 -0
- package/dist/lib/sqlite/sqlite-node.d.ts.map +1 -0
- package/dist/lib/sqlite/sqlite-node.js +68 -0
- package/dist/lib/sqlite/sqlite-writer.d.ts +39 -0
- package/dist/lib/sqlite/sqlite-writer.d.ts.map +1 -0
- package/dist/lib/sqlite/sqlite-writer.js +78 -0
- package/dist/lib/testing/bun-harness.d.ts +150 -0
- package/dist/lib/testing/bun-harness.d.ts.map +1 -0
- package/dist/lib/testing/bun-harness.js +729 -0
- package/dist/lib/testing/extractFacts.d.ts +73 -0
- package/dist/lib/testing/extractFacts.d.ts.map +1 -0
- package/dist/lib/testing/extractFacts.js +237 -0
- package/dist/lib/testing/facts.d.ts +235 -0
- package/dist/lib/testing/facts.d.ts.map +1 -0
- package/dist/lib/testing/facts.js +209 -0
- package/dist/lib/testing/index.d.ts +58 -0
- package/dist/lib/testing/index.d.ts.map +1 -0
- package/dist/lib/testing/index.js +74 -0
- package/dist/lib/testing/queryable-span.d.ts +39 -0
- package/dist/lib/testing/queryable-span.d.ts.map +1 -0
- package/dist/lib/testing/queryable-span.js +58 -0
- package/dist/lib/testing/span-query.d.ts +21 -0
- package/dist/lib/testing/span-query.d.ts.map +1 -0
- package/dist/lib/testing/span-query.js +47 -0
- package/dist/lib/testing/stdio-replay.d.ts +4 -0
- package/dist/lib/testing/stdio-replay.d.ts.map +1 -0
- package/dist/lib/testing/stdio-replay.js +42 -0
- package/dist/lib/testing/trace-query.d.ts +59 -0
- package/dist/lib/testing/trace-query.d.ts.map +1 -0
- package/dist/lib/testing/trace-query.js +462 -0
- package/dist/lib/testing/vitest-harness.d.ts +135 -0
- package/dist/lib/testing/vitest-harness.d.ts.map +1 -0
- package/dist/lib/testing/vitest-harness.js +486 -0
- package/dist/lib/threadId.d.ts +58 -0
- package/dist/lib/threadId.d.ts.map +1 -0
- package/dist/lib/threadId.js +123 -0
- package/dist/lib/traceContext.d.ts +116 -0
- package/dist/lib/traceContext.d.ts.map +1 -0
- package/dist/lib/traceContext.js +37 -0
- package/dist/lib/traceId.d.ts +78 -0
- package/dist/lib/traceId.d.ts.map +1 -0
- package/dist/lib/traceId.js +87 -0
- package/dist/lib/traceRoot.d.ts +133 -0
- package/dist/lib/traceRoot.d.ts.map +1 -0
- package/dist/lib/traceRoot.es.d.ts +75 -0
- package/dist/lib/traceRoot.es.d.ts.map +1 -0
- package/dist/lib/traceRoot.es.js +129 -0
- package/dist/lib/traceRoot.js +19 -0
- package/dist/lib/traceRoot.node.d.ts +77 -0
- package/dist/lib/traceRoot.node.d.ts.map +1 -0
- package/dist/lib/traceRoot.node.js +133 -0
- package/dist/lib/traceRoot.universal.d.ts +3 -0
- package/dist/lib/traceRoot.universal.d.ts.map +1 -0
- package/dist/lib/traceRoot.universal.js +17 -0
- package/dist/lib/tracer.d.ts +296 -0
- package/dist/lib/tracer.d.ts.map +1 -0
- package/dist/lib/tracer.js +346 -0
- package/dist/lib/tracers/ArrayQueueTracer.d.ts +56 -0
- package/dist/lib/tracers/ArrayQueueTracer.d.ts.map +1 -0
- package/dist/lib/tracers/ArrayQueueTracer.js +67 -0
- package/dist/lib/tracers/CompositeTracer.d.ts +24 -0
- package/dist/lib/tracers/CompositeTracer.d.ts.map +1 -0
- package/dist/lib/tracers/CompositeTracer.js +57 -0
- package/dist/lib/tracers/NoOpTracer.d.ts +58 -0
- package/dist/lib/tracers/NoOpTracer.d.ts.map +1 -0
- package/dist/lib/tracers/NoOpTracer.js +41 -0
- package/dist/lib/tracers/SQLiteTracer.d.ts +42 -0
- package/dist/lib/tracers/SQLiteTracer.d.ts.map +1 -0
- package/dist/lib/tracers/SQLiteTracer.js +84 -0
- package/dist/lib/tracers/StdioTracer.d.ts +83 -0
- package/dist/lib/tracers/StdioTracer.d.ts.map +1 -0
- package/dist/lib/tracers/StdioTracer.js +270 -0
- package/dist/lib/tracers/TestTracer.d.ts +95 -0
- package/dist/lib/tracers/TestTracer.d.ts.map +1 -0
- package/dist/lib/tracers/TestTracer.js +87 -0
- package/dist/lib/tracers/index.d.ts +12 -0
- package/dist/lib/tracers/index.d.ts.map +1 -0
- package/dist/lib/tracers/index.js +11 -0
- package/dist/lib/types.d.ts +366 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +1 -0
- package/dist/lib/utf8Cache.d.ts +111 -0
- package/dist/lib/utf8Cache.d.ts.map +1 -0
- package/dist/lib/utf8Cache.js +177 -0
- package/dist/lib/wasm/WasmBufferStrategy.d.ts +88 -0
- package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -0
- package/dist/lib/wasm/WasmBufferStrategy.js +138 -0
- package/dist/lib/wasm/wasmAllocator.d.ts +109 -0
- package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -0
- package/dist/lib/wasm/wasmAllocator.js +227 -0
- package/dist/lib/wasm/wasmSpanBuffer.d.ts +123 -0
- package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -0
- package/dist/lib/wasm/wasmSpanBuffer.js +772 -0
- package/dist/lib/wasm/wasmTraceRoot.d.ts +167 -0
- package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -0
- package/dist/lib/wasm/wasmTraceRoot.js +264 -0
- package/dist/node.d.ts +7 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +8 -0
- package/dist/testing.d.ts +18 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +17 -0
- package/package.json +193 -0
- package/src/bun/preload.ts +11 -0
- package/src/bun/trace-preload.ts +14 -0
- package/src/es.ts +11 -0
- package/src/index.ts +194 -0
- package/src/lib/JsBufferStrategy.ts +102 -0
- package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +485 -0
- package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +390 -0
- package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +647 -0
- package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +292 -0
- package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +354 -0
- package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +127 -0
- package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +392 -0
- package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +389 -0
- package/src/lib/__tests__/arrow-conversion-algorithms.test.ts +54 -0
- package/src/lib/__tests__/arrow-test-helpers.ts +71 -0
- package/src/lib/__tests__/binary-e2e.test.ts +203 -0
- package/src/lib/__tests__/buffer-overflow-op-api.test.ts +608 -0
- package/src/lib/__tests__/buffer-overflow.test.ts +612 -0
- package/src/lib/__tests__/capacity-tuning.test.ts +544 -0
- package/src/lib/__tests__/effective-schema.test.ts +439 -0
- package/src/lib/__tests__/flechette.test.ts +42 -0
- package/src/lib/__tests__/flushScheduler.test.ts +537 -0
- package/src/lib/__tests__/integration.test.ts +600 -0
- package/src/lib/__tests__/library.test.ts +934 -0
- package/src/lib/__tests__/nested-library-tasks.test.ts +849 -0
- package/src/lib/__tests__/op-context-binding.test.ts +135 -0
- package/src/lib/__tests__/op-metadata.test.ts +198 -0
- package/src/lib/__tests__/op-type-safety.test.ts +71 -0
- package/src/lib/__tests__/package-exports.test.ts +57 -0
- package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +319 -0
- package/src/lib/__tests__/remapped-buffer-view.test.ts +635 -0
- package/src/lib/__tests__/scope-attributes.test.ts +348 -0
- package/src/lib/__tests__/span-lifecycle.test.ts +680 -0
- package/src/lib/__tests__/sync-async-trace.test.ts +435 -0
- package/src/lib/__tests__/test-helpers.ts +318 -0
- package/src/lib/__tests__/timestamp.test.ts +259 -0
- package/src/lib/__tests__/trace-archive-primitives.test.ts +98 -0
- package/src/lib/__tests__/traceContext-type-enforcement.test.ts +271 -0
- package/src/lib/__tests__/tracer.test.ts +211 -0
- package/src/lib/__tests__/type-narrowing.test.ts +137 -0
- package/src/lib/archive/chunkCompaction.ts +44 -0
- package/src/lib/archive/chunkEnvelope.ts +79 -0
- package/src/lib/archive/chunkRouting.ts +70 -0
- package/src/lib/archive/chunkStats.ts +25 -0
- package/src/lib/archive/index.ts +4 -0
- package/src/lib/arrow/capacityStats.ts +340 -0
- package/src/lib/arrow/dictionaries.ts +159 -0
- package/src/lib/arrow/flechette.ts +114 -0
- package/src/lib/arrow/utils.ts +126 -0
- package/src/lib/buffer/Nanoseconds.ts +131 -0
- package/src/lib/bufferStrategy.ts +106 -0
- package/src/lib/capacityTuning.ts +102 -0
- package/src/lib/codegen/__tests__/__snapshots__/evaluatorGenerator.test.ts.snap +160 -0
- package/src/lib/codegen/__tests__/__snapshots__/scopeGenerator.test.ts.snap +196 -0
- package/src/lib/codegen/__tests__/__snapshots__/spanLoggerGenerator.test.ts.snap +1965 -0
- package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +516 -0
- package/src/lib/codegen/__tests__/nullBitmap.test.ts +207 -0
- package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +237 -0
- package/src/lib/codegen/evaluatorGenerator.ts +309 -0
- package/src/lib/codegen/fixedPositionWriterGenerator.ts +444 -0
- package/src/lib/codegen/spanLoggerGenerator.ts +715 -0
- package/src/lib/convertToArrow.ts +1805 -0
- package/src/lib/defineOpContext.ts +398 -0
- package/src/lib/errors/Blocked.ts +165 -0
- package/src/lib/errors/CodeError.ts +132 -0
- package/src/lib/errors/RetriesExhausted.ts +78 -0
- package/src/lib/errors/Transient.ts +168 -0
- package/src/lib/errors/__tests__/Blocked-config.test.ts +152 -0
- package/src/lib/errors/__tests__/Transient.test.ts +129 -0
- package/src/lib/errors/__tests__/retry-policy.test.ts +85 -0
- package/src/lib/errors/index.ts +24 -0
- package/src/lib/errors/retry-policy.ts +87 -0
- package/src/lib/flushScheduler.ts +509 -0
- package/src/lib/library.ts +682 -0
- package/src/lib/logApi.ts +70 -0
- package/src/lib/logBinding.ts +67 -0
- package/src/lib/op.ts +103 -0
- package/src/lib/opContext/__tests__/retry.test.ts +764 -0
- package/src/lib/opContext/contextTypes.ts +130 -0
- package/src/lib/opContext/createOpGroup.ts +456 -0
- package/src/lib/opContext/defineOp.ts +281 -0
- package/src/lib/opContext/featureFlagTypes.ts +54 -0
- package/src/lib/opContext/index.ts +16 -0
- package/src/lib/opContext/opGroupTypes.ts +342 -0
- package/src/lib/opContext/opTypes.ts +80 -0
- package/src/lib/opContext/spanContextTypes.ts +398 -0
- package/src/lib/opContext/types.ts +403 -0
- package/src/lib/result.ts +550 -0
- package/src/lib/schema/LogSchema.ts +153 -0
- package/src/lib/schema/__tests__/defineLogSchema.test.ts +342 -0
- package/src/lib/schema/__tests__/featureFlags.test.ts +443 -0
- package/src/lib/schema/builder.ts +201 -0
- package/src/lib/schema/defineFeatureFlags.ts +91 -0
- package/src/lib/schema/defineLogSchema.ts +291 -0
- package/src/lib/schema/evaluator.ts +404 -0
- package/src/lib/schema/extend.ts +69 -0
- package/src/lib/schema/systemSchema.ts +339 -0
- package/src/lib/schema/typeGuards.ts +163 -0
- package/src/lib/schema/types.ts +265 -0
- package/src/lib/spanBuffer.ts +571 -0
- package/src/lib/spanBufferHelpers.ts +73 -0
- package/src/lib/spanBufferStats.ts +40 -0
- package/src/lib/spanContext.ts +1566 -0
- package/src/lib/sqlite/__tests__/sqlite-common.test.ts +89 -0
- package/src/lib/sqlite/index.ts +26 -0
- package/src/lib/sqlite/sqlite-async-writer.ts +101 -0
- package/src/lib/sqlite/sqlite-common.ts +309 -0
- package/src/lib/sqlite/sqlite-d1.ts +104 -0
- package/src/lib/sqlite/sqlite-db.ts +32 -0
- package/src/lib/sqlite/sqlite-node.ts +83 -0
- package/src/lib/sqlite/sqlite-writer.ts +128 -0
- package/src/lib/testing/TRACE-TESTING.md +100 -0
- package/src/lib/testing/__tests__/bun-harness.test.ts +108 -0
- package/src/lib/testing/__tests__/extractFacts.test.ts +279 -0
- package/src/lib/testing/__tests__/facts.test.ts +324 -0
- package/src/lib/testing/__tests__/vitest-harness.test.ts +32 -0
- package/src/lib/testing/bun-harness.ts +990 -0
- package/src/lib/testing/extractFacts.ts +362 -0
- package/src/lib/testing/facts.ts +470 -0
- package/src/lib/testing/index.ts +141 -0
- package/src/lib/testing/queryable-span.ts +108 -0
- package/src/lib/testing/span-query.ts +65 -0
- package/src/lib/testing/stdio-replay.ts +50 -0
- package/src/lib/testing/trace-query.ts +329 -0
- package/src/lib/testing/vitest-harness.ts +691 -0
- package/src/lib/threadId.ts +135 -0
- package/src/lib/traceContext.ts +182 -0
- package/src/lib/traceId.ts +142 -0
- package/src/lib/traceRoot.es.ts +157 -0
- package/src/lib/traceRoot.node.ts +170 -0
- package/src/lib/traceRoot.ts +154 -0
- package/src/lib/traceRoot.universal.ts +22 -0
- package/src/lib/tracer.ts +896 -0
- package/src/lib/tracers/ArrayQueueTracer.ts +76 -0
- package/src/lib/tracers/CompositeTracer.ts +76 -0
- package/src/lib/tracers/NoOpTracer.ts +73 -0
- package/src/lib/tracers/SQLiteTracer.ts +115 -0
- package/src/lib/tracers/StdioTracer.ts +380 -0
- package/src/lib/tracers/TestTracer.ts +146 -0
- package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +184 -0
- package/src/lib/tracers/__tests__/NoOpTracer.test.ts +204 -0
- package/src/lib/tracers/__tests__/StdioTracer.test.ts +313 -0
- package/src/lib/tracers/__tests__/TestTracer.test.ts +200 -0
- package/src/lib/tracers/index.ts +12 -0
- package/src/lib/types.ts +498 -0
- package/src/lib/utf8Cache.ts +201 -0
- package/src/lib/wasm/WasmBufferStrategy.ts +219 -0
- package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +256 -0
- package/src/lib/wasm/__tests__/wasm-integration.test.ts +476 -0
- package/src/lib/wasm/__tests__/wasmAllocator.test.ts +699 -0
- package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +449 -0
- package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +390 -0
- package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +444 -0
- package/src/lib/wasm/allocator.zig +945 -0
- package/src/lib/wasm/wasmAllocator.ts +469 -0
- package/src/lib/wasm/wasmSpanBuffer.ts +1014 -0
- package/src/lib/wasm/wasmTraceRoot.ts +315 -0
- package/src/node.ts +10 -0
- package/src/testing.ts +18 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
import type {
|
|
5
|
+
AsyncSQLiteDatabase,
|
|
6
|
+
AsyncSQLiteStatement,
|
|
7
|
+
SyncSQLiteDatabase,
|
|
8
|
+
SyncSQLiteStatement,
|
|
9
|
+
} from './sqlite-db.js';
|
|
10
|
+
|
|
11
|
+
function toSyncStatement(statement: {
|
|
12
|
+
run(...params: unknown[]): unknown;
|
|
13
|
+
all(...params: unknown[]): unknown[];
|
|
14
|
+
get(...params: unknown[]): unknown;
|
|
15
|
+
}): SyncSQLiteStatement {
|
|
16
|
+
return {
|
|
17
|
+
run(...params: unknown[]): void {
|
|
18
|
+
statement.run(...params);
|
|
19
|
+
},
|
|
20
|
+
all(...params: unknown[]): unknown[] {
|
|
21
|
+
return statement.all(...params);
|
|
22
|
+
},
|
|
23
|
+
get(...params: unknown[]): unknown {
|
|
24
|
+
return statement.get(...params);
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create a Node built-in sqlite database adapter.
|
|
31
|
+
*
|
|
32
|
+
* Use this in Node Vitest setup when you want trace output persisted
|
|
33
|
+
* to a deterministic file path.
|
|
34
|
+
*/
|
|
35
|
+
export function createNodeSQLiteDatabase(dbPath: string): SyncSQLiteDatabase {
|
|
36
|
+
const db = new DatabaseSync(dbPath);
|
|
37
|
+
return {
|
|
38
|
+
exec(sql: string): void {
|
|
39
|
+
db.exec(sql);
|
|
40
|
+
},
|
|
41
|
+
prepare(sql: string): SyncSQLiteStatement {
|
|
42
|
+
return toSyncStatement(db.prepare(sql));
|
|
43
|
+
},
|
|
44
|
+
close(): void {
|
|
45
|
+
db.close();
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function toAsyncStatement(statement: SyncSQLiteStatement): AsyncSQLiteStatement {
|
|
51
|
+
return {
|
|
52
|
+
async run(...params: unknown[]): Promise<void> {
|
|
53
|
+
statement.run(...params);
|
|
54
|
+
},
|
|
55
|
+
async all(...params: unknown[]): Promise<unknown[]> {
|
|
56
|
+
return statement.all(...params);
|
|
57
|
+
},
|
|
58
|
+
async get(...params: unknown[]): Promise<unknown> {
|
|
59
|
+
return statement.get(...params);
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create an async adapter around Node built-in sqlite.
|
|
66
|
+
*
|
|
67
|
+
* Useful when wiring into `createAsyncDatabase` callbacks while still
|
|
68
|
+
* writing to a deterministic file path on Node.
|
|
69
|
+
*/
|
|
70
|
+
export function createNodeSQLiteAsyncDatabase(dbPath: string): AsyncSQLiteDatabase {
|
|
71
|
+
const syncDb = createNodeSQLiteDatabase(dbPath);
|
|
72
|
+
return {
|
|
73
|
+
async exec(sql: string): Promise<void> {
|
|
74
|
+
syncDb.exec(sql);
|
|
75
|
+
},
|
|
76
|
+
prepare(sql: string): AsyncSQLiteStatement {
|
|
77
|
+
return toAsyncStatement(syncDb.prepare(sql));
|
|
78
|
+
},
|
|
79
|
+
async close(): Promise<void> {
|
|
80
|
+
syncDb.close();
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLiteTraceWriter - General-purpose writer that persists span buffer trees to SQLite.
|
|
3
|
+
*
|
|
4
|
+
* Accepts a SyncSQLiteDatabase instance (from bun:sqlite or better-sqlite3)
|
|
5
|
+
* and persists the full span tree as a flat `spans` table with dynamic column
|
|
6
|
+
* evolution based on the LogSchema fields found at flush time.
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Single `spans` table — no runs/log_entries decomposition
|
|
10
|
+
* - trace_id IS the run identifier (one root span per trace)
|
|
11
|
+
* - Tree structure via span_id / parent_span_id (no depth column)
|
|
12
|
+
* - User schema columns added dynamically via ALTER TABLE
|
|
13
|
+
* - Per-buffer ensureColumns for cross-library schema merging
|
|
14
|
+
*
|
|
15
|
+
* @module sqlite-writer
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { LogSchema } from '../schema/LogSchema.js';
|
|
19
|
+
import type { AnySpanBuffer } from '../types.js';
|
|
20
|
+
import {
|
|
21
|
+
buildAddColumnSql,
|
|
22
|
+
buildInsertParams,
|
|
23
|
+
buildInsertSql,
|
|
24
|
+
extractSqliteColumnsFromTableInfo,
|
|
25
|
+
getActiveUserFields,
|
|
26
|
+
getInsertStatementCacheKey,
|
|
27
|
+
getMissingSchemaColumns,
|
|
28
|
+
isSqliteDuplicateColumnError,
|
|
29
|
+
parseSqliteTableInfoRows,
|
|
30
|
+
SPANS_TABLE_INFO_SQL,
|
|
31
|
+
SPANS_TABLE_INIT_SQL,
|
|
32
|
+
type SpanSegment,
|
|
33
|
+
walkSpanSegments,
|
|
34
|
+
} from './sqlite-common.js';
|
|
35
|
+
import type { SyncSQLiteDatabase, SyncSQLiteStatement } from './sqlite-db.js';
|
|
36
|
+
|
|
37
|
+
export interface SQLiteWriterConfig {
|
|
38
|
+
/** Path to SQLite file. Default: '.trace-results.db' */
|
|
39
|
+
dbPath?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export class SQLiteTraceWriter {
|
|
43
|
+
private knownColumns = new Set<string>();
|
|
44
|
+
private insertStmtCache = new Map<string, SyncSQLiteStatement>();
|
|
45
|
+
|
|
46
|
+
constructor(private db: SyncSQLiteDatabase) {
|
|
47
|
+
this.init();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private init(): void {
|
|
51
|
+
// Parallel Bun test workers share one trace DB, so wait for short SQLite writer locks instead of failing setup.
|
|
52
|
+
this.db.exec('PRAGMA busy_timeout = 10000');
|
|
53
|
+
this.db.exec(SPANS_TABLE_INIT_SQL);
|
|
54
|
+
|
|
55
|
+
this.refreshKnownColumns();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private refreshKnownColumns(): void {
|
|
59
|
+
this.knownColumns.clear();
|
|
60
|
+
// WHY: PRAGMA row shape changes would make later ALTER/INSERT logic drift silently, so validate here before
|
|
61
|
+
// mutating the writer's cached schema view.
|
|
62
|
+
const rows = parseSqliteTableInfoRows(this.db.prepare(SPANS_TABLE_INFO_SQL).all());
|
|
63
|
+
for (const column of extractSqliteColumnsFromTableInfo(rows)) {
|
|
64
|
+
this.knownColumns.add(column.name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Ensure user-defined schema columns exist in the spans table */
|
|
69
|
+
private ensureColumns(schema: LogSchema): void {
|
|
70
|
+
for (const column of getMissingSchemaColumns(schema, this.knownColumns)) {
|
|
71
|
+
try {
|
|
72
|
+
this.db.exec(buildAddColumnSql(column));
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (!isSqliteDuplicateColumnError(error, column.name)) {
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
this.refreshKnownColumns();
|
|
80
|
+
this.knownColumns.add(column.name);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private writeSegmentRows(segment: SpanSegment): void {
|
|
85
|
+
this.ensureColumns(segment.buffer._logSchema);
|
|
86
|
+
|
|
87
|
+
const activeUserFields = getActiveUserFields(segment.buffer._logSchema, this.knownColumns);
|
|
88
|
+
const insertStmt = this.getInsertStatement(activeUserFields);
|
|
89
|
+
|
|
90
|
+
for (let row = 0; row < segment.buffer._writeIndex; row++) {
|
|
91
|
+
insertStmt.run(...buildInsertParams(segment, row, activeUserFields));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private flushAllSegments(rootBuffer: AnySpanBuffer): void {
|
|
96
|
+
for (const segment of walkSpanSegments(rootBuffer)) {
|
|
97
|
+
this.writeSegmentRows(segment);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private getInsertStatement(activeUserFields: readonly string[]): SyncSQLiteStatement {
|
|
102
|
+
const key = getInsertStatementCacheKey(activeUserFields);
|
|
103
|
+
const cached = this.insertStmtCache.get(key);
|
|
104
|
+
if (cached) {
|
|
105
|
+
return cached;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const stmt = this.db.prepare(buildInsertSql(activeUserFields));
|
|
109
|
+
this.insertStmtCache.set(key, stmt);
|
|
110
|
+
return stmt;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Write a root SpanBuffer tree to the database */
|
|
114
|
+
flush(rootBuffer: AnySpanBuffer): void {
|
|
115
|
+
this.db.exec('BEGIN IMMEDIATE');
|
|
116
|
+
try {
|
|
117
|
+
this.flushAllSegments(rootBuffer);
|
|
118
|
+
this.db.exec('COMMIT');
|
|
119
|
+
} catch (error) {
|
|
120
|
+
this.db.exec('ROLLBACK');
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
close(): void {
|
|
126
|
+
this.db.close();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Trace-Testing with LMAO
|
|
2
|
+
|
|
3
|
+
> Based on Akkartik's "tracing tests": https://akkartik.name/post/tracing-tests
|
|
4
|
+
|
|
5
|
+
## Core Principle
|
|
6
|
+
|
|
7
|
+
**Test WHAT happened (domain facts), not HOW (implementation details).**
|
|
8
|
+
|
|
9
|
+
Traditional tests couple to internal structure:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
const result = await myOp(args);
|
|
13
|
+
expect(result.status).toBe('success'); // Brittle - breaks on refactor
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Trace-tests assert on facts emitted during execution:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
await trace('my-op', myOp);
|
|
20
|
+
expect(facts.has(spanOk('my-op'))).toBe(true); // Robust - survives refactoring
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## LMAO Fact Types
|
|
24
|
+
|
|
25
|
+
Facts are strongly-typed template literals. Invalid facts = compile errors.
|
|
26
|
+
|
|
27
|
+
| Type | Format | Example |
|
|
28
|
+
| ----------- | ------------------------ | -------------------------- |
|
|
29
|
+
| `SpanFact` | `span:${name}: ${state}` | `span:fetch-user: ok` |
|
|
30
|
+
| `LogFact` | `log:${level}: ${msg}` | `log:info: Processing` |
|
|
31
|
+
| `TagFact` | `tag:${key}: ${value}` | `tag:userId: 123` |
|
|
32
|
+
| `ScopeFact` | `scope:${key}: ${value}` | `scope:requestId: req-abc` |
|
|
33
|
+
| `FFFact` | `ff:${flag}: ${value}` | `ff:darkMode: true` |
|
|
34
|
+
|
|
35
|
+
Span states: `started`, `ok`, `err(CODE)`, `exception(msg)`
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { TestTracer, defineOpContext } from '@smoothbricks/lmao';
|
|
41
|
+
import { extractFacts, spanStarted, spanOk, spanErr, tagFact, logInfo } from '@smoothbricks/lmao/testing';
|
|
42
|
+
|
|
43
|
+
// 1. Run traced code
|
|
44
|
+
const tracer = new TestTracer(opContext);
|
|
45
|
+
await tracer.trace('process-order', async (ctx) => {
|
|
46
|
+
ctx.tag.orderId('ord-123');
|
|
47
|
+
await ctx.span('validate', async (c) => c.ok(null));
|
|
48
|
+
await ctx.span('charge', async (c) => c.ok(null));
|
|
49
|
+
return ctx.ok('done');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// 2. Extract facts from buffer tree
|
|
53
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
54
|
+
|
|
55
|
+
// 3. Assert on WHAT happened
|
|
56
|
+
expect(facts.has(spanOk('process-order'))).toBe(true);
|
|
57
|
+
expect(facts.has(tagFact('orderId', 'ord-123'))).toBe(true);
|
|
58
|
+
expect(facts.hasInOrder([spanStarted('validate'), spanOk('validate'), spanStarted('charge'), spanOk('charge')])).toBe(
|
|
59
|
+
true
|
|
60
|
+
);
|
|
61
|
+
expect(facts.hasMatch('span:*: err(*)')).toBe(false);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## FactArray API
|
|
65
|
+
|
|
66
|
+
| Method | Purpose |
|
|
67
|
+
| ------------------------------- | -------------------------------------- |
|
|
68
|
+
| `has(fact)` | Exact match |
|
|
69
|
+
| `hasMatch(pattern)` | Glob match (`*` = any non-colon chars) |
|
|
70
|
+
| `hasInOrder([...])` | Facts appear in order (not adjacent) |
|
|
71
|
+
| `byNamespace('span')` | Filter to namespace |
|
|
72
|
+
| `spans()` / `logs()` / `tags()` | Typed filters |
|
|
73
|
+
| `match(pattern)` | Return matching facts |
|
|
74
|
+
|
|
75
|
+
## Buffer Layout (Why This Works)
|
|
76
|
+
|
|
77
|
+
Per `specs/lmao/01h_entry_types_and_logging_primitives.md`:
|
|
78
|
+
|
|
79
|
+
- **Row 0**: `span-start` + tag writes (`ctx.tag.*` overwrites here)
|
|
80
|
+
- **Row 1**: Completion (`span-ok`/`span-err`/`span-exception`)
|
|
81
|
+
- **Row 2+**: Log entries (`ctx.log.*` appends here)
|
|
82
|
+
|
|
83
|
+
`extractFacts()` walks the buffer tree depth-first, emitting facts in execution order.
|
|
84
|
+
|
|
85
|
+
## When to Use Trace-Testing
|
|
86
|
+
|
|
87
|
+
✅ **Use for**: Operation ordering, error handling, tag/scope propagation, multi-span workflows ❌ **Don't use for**:
|
|
88
|
+
Return value validation, performance benchmarks, schema validation
|
|
89
|
+
|
|
90
|
+
## Key Insight
|
|
91
|
+
|
|
92
|
+
> "Tests no longer need call fine-grained helpers directly... The trace checks that the program correctly computed a
|
|
93
|
+
> specific _fact_, while remaining oblivious about _how_ it was computed." — Akkartik
|
|
94
|
+
|
|
95
|
+
This makes tests resilient to:
|
|
96
|
+
|
|
97
|
+
- Function boundary changes
|
|
98
|
+
- Sync → async refactoring
|
|
99
|
+
- Internal restructuring
|
|
100
|
+
- Adding/removing intermediate steps
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
import { defineOpContext } from '../../defineOpContext.js';
|
|
3
|
+
import { S } from '../../schema/builder.js';
|
|
4
|
+
import { defineLogSchema } from '../../schema/defineLogSchema.js';
|
|
5
|
+
import { TestTracer } from '../../tracers/TestTracer.js';
|
|
6
|
+
import { type BunTestModuleShape, makeBunTestSuiteTracer, makeTestTracer } from '../bun-harness.js';
|
|
7
|
+
|
|
8
|
+
type BunTestModuleLike = BunTestModuleShape;
|
|
9
|
+
|
|
10
|
+
function createImmediateTestFn(): BunTestModuleLike['it'] {
|
|
11
|
+
const runBase = (_name: string, fn: () => unknown | Promise<unknown>) => fn();
|
|
12
|
+
return Object.assign(runBase, it, {
|
|
13
|
+
only: runBase,
|
|
14
|
+
skipIf: (condition: boolean) => (condition ? it.skip : runBase),
|
|
15
|
+
if: (condition: boolean) => (condition ? runBase : it.skip),
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createImmediateDescribeFn(): BunTestModuleLike['describe'] {
|
|
20
|
+
const runBase = (_name: string, fn: () => void) => fn();
|
|
21
|
+
return Object.assign(runBase, describe, {
|
|
22
|
+
only: runBase,
|
|
23
|
+
skipIf: (condition: boolean) => (condition ? describe.skip : runBase),
|
|
24
|
+
if: (condition: boolean) => (condition ? runBase : describe.skip),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createImmediateIt() {
|
|
29
|
+
return createImmediateTestFn();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function createImmediateDescribe() {
|
|
33
|
+
return createImmediateDescribeFn();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createImmediateBunTestModule(): BunTestModuleLike {
|
|
37
|
+
const itFn = createImmediateIt();
|
|
38
|
+
return {
|
|
39
|
+
it: itFn,
|
|
40
|
+
describe: createImmediateDescribe(),
|
|
41
|
+
test: itFn,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const baseBinding = defineOpContext({
|
|
46
|
+
logSchema: defineLogSchema({ base_field: S.category() }),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const suiteWithExtension = makeBunTestSuiteTracer(baseBinding, {
|
|
50
|
+
extraTestColumns: {
|
|
51
|
+
test_metric: S.number(),
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
type ExtendedSpan = ReturnType<typeof suiteWithExtension.useTestSpan>;
|
|
56
|
+
type HasExtendedTag = ExtendedSpan['tag'] extends { test_metric: (value: number) => unknown } ? true : false;
|
|
57
|
+
type HasExtendedLog =
|
|
58
|
+
ReturnType<ExtendedSpan['log']['info']> extends { test_metric: (value: number) => unknown } ? true : false;
|
|
59
|
+
const hasExtendedTag: HasExtendedTag = true;
|
|
60
|
+
const hasExtendedLog: HasExtendedLog = true;
|
|
61
|
+
|
|
62
|
+
describe('bun harness test log schema extension', () => {
|
|
63
|
+
it('includes extension fields in suite span typing', () => {
|
|
64
|
+
expect(hasExtendedTag).toBe(true);
|
|
65
|
+
expect(hasExtendedLog).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('writes extension fields through tag and log APIs', async () => {
|
|
69
|
+
const tracer = makeTestTracer(baseBinding, {
|
|
70
|
+
extraTestColumns: {
|
|
71
|
+
test_metric: S.number(),
|
|
72
|
+
test_note: S.text(),
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
tracer.setup();
|
|
76
|
+
|
|
77
|
+
const wrappedModule = tracer.createBunTestMock(createImmediateBunTestModule());
|
|
78
|
+
await wrappedModule.it('writes test-only fields', async () => {
|
|
79
|
+
const span = tracer.useTestSpan();
|
|
80
|
+
span.tag.test_metric(123);
|
|
81
|
+
span.log.info('row-1').test_metric(456).test_note('hello');
|
|
82
|
+
|
|
83
|
+
const buffer = span.buffer;
|
|
84
|
+
expect(buffer.test_metric_values[0]).toBe(123);
|
|
85
|
+
expect(buffer.test_metric_values[2]).toBe(456);
|
|
86
|
+
expect(buffer.test_note_values[2]).toBe('hello');
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('defaults to an in-memory TestTracer when sqlite and verbose are off', () => {
|
|
91
|
+
const tracer = makeTestTracer(baseBinding);
|
|
92
|
+
tracer.setup();
|
|
93
|
+
|
|
94
|
+
expect(tracer.getTracer()).toBeInstanceOf(TestTracer);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('rejects duplicate extra test columns instead of silently erasing them', () => {
|
|
98
|
+
const tracer = makeTestTracer(baseBinding, {
|
|
99
|
+
extraTestColumns: {
|
|
100
|
+
base_field: S.category(),
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
expect(() => tracer.setup()).toThrow(
|
|
105
|
+
"Test harness schema column 'base_field' already exists in the bound log schema",
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for extractFacts - the bridge between buffers and facts.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'bun:test';
|
|
6
|
+
import { createTestTracerOptions } from '../../__tests__/test-helpers.js';
|
|
7
|
+
import { defineOpContext } from '../../defineOpContext.js';
|
|
8
|
+
import { defineCodeError } from '../../result.js';
|
|
9
|
+
import { S } from '../../schema/builder.js';
|
|
10
|
+
import { defineFeatureFlags } from '../../schema/defineFeatureFlags.js';
|
|
11
|
+
import { defineLogSchema } from '../../schema/defineLogSchema.js';
|
|
12
|
+
import { InMemoryFlagEvaluator } from '../../schema/evaluator.js';
|
|
13
|
+
import { TestTracer } from '../../tracers/TestTracer.js';
|
|
14
|
+
import { extractFacts } from '../extractFacts.js';
|
|
15
|
+
import { ffFact, logInfo, logWarn, spanErr, spanOk, spanStarted, tagFact } from '../facts.js';
|
|
16
|
+
|
|
17
|
+
// Define a test error for ctx.err tests
|
|
18
|
+
const NOT_FOUND = defineCodeError('NOT_FOUND')<{ detail: string }>();
|
|
19
|
+
|
|
20
|
+
describe('extractFacts', () => {
|
|
21
|
+
// Create a test schema
|
|
22
|
+
const testSchema = defineLogSchema({
|
|
23
|
+
userId: S.category(),
|
|
24
|
+
orderId: S.category(),
|
|
25
|
+
amount: S.number(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const opContext = defineOpContext({ logSchema: testSchema });
|
|
29
|
+
const featureFlags = defineFeatureFlags({
|
|
30
|
+
advancedValidation: S.boolean().default(false).sync(),
|
|
31
|
+
});
|
|
32
|
+
const opContextWithFlags = defineOpContext({
|
|
33
|
+
logSchema: testSchema,
|
|
34
|
+
flags: featureFlags.schema,
|
|
35
|
+
});
|
|
36
|
+
const flagEvaluator = new InMemoryFlagEvaluator(featureFlags.schema, {
|
|
37
|
+
advancedValidation: true,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('extracts span lifecycle facts from a simple trace', async () => {
|
|
41
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
42
|
+
|
|
43
|
+
await tracer.trace('my-operation', async (ctx) => {
|
|
44
|
+
return ctx.ok('done');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(tracer.rootBuffers).toHaveLength(1);
|
|
48
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
49
|
+
|
|
50
|
+
// Should have started and ok facts
|
|
51
|
+
expect(facts.has(spanStarted('my-operation'))).toBe(true);
|
|
52
|
+
expect(facts.has(spanOk('my-operation'))).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('extracts log facts', async () => {
|
|
56
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
57
|
+
|
|
58
|
+
await tracer.trace('with-logs', async (ctx) => {
|
|
59
|
+
ctx.log.info('Starting process');
|
|
60
|
+
ctx.log.warn('Something to note');
|
|
61
|
+
return ctx.ok('done');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
65
|
+
|
|
66
|
+
expect(facts.has(logInfo('Starting process'))).toBe(true);
|
|
67
|
+
expect(facts.has(logWarn('Something to note'))).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('extracts tag facts from row 0', async () => {
|
|
71
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
72
|
+
|
|
73
|
+
await tracer.trace('with-tags', async (ctx) => {
|
|
74
|
+
ctx.tag.userId('user-123').orderId('order-456');
|
|
75
|
+
return ctx.ok('done');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
79
|
+
|
|
80
|
+
expect(facts.has(tagFact('userId', 'user-123'))).toBe(true);
|
|
81
|
+
expect(facts.has(tagFact('orderId', 'order-456'))).toBe(true);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('extracts facts from nested spans in order', async () => {
|
|
85
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
86
|
+
|
|
87
|
+
await tracer.trace('parent', async (ctx) => {
|
|
88
|
+
await ctx.span('child-1', async (childCtx) => {
|
|
89
|
+
return childCtx.ok('child-1 done');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await ctx.span('child-2', async (childCtx) => {
|
|
93
|
+
return childCtx.ok('child-2 done');
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return ctx.ok('parent done');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
100
|
+
|
|
101
|
+
// Check order: parent starts, child-1 complete, child-2 complete, parent completes
|
|
102
|
+
expect(
|
|
103
|
+
facts.hasInOrder([
|
|
104
|
+
spanStarted('parent'),
|
|
105
|
+
spanStarted('child-1'),
|
|
106
|
+
spanOk('child-1'),
|
|
107
|
+
spanStarted('child-2'),
|
|
108
|
+
spanOk('child-2'),
|
|
109
|
+
spanOk('parent'),
|
|
110
|
+
]),
|
|
111
|
+
).toBe(true);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('extracts error facts from span:err', async () => {
|
|
115
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
116
|
+
|
|
117
|
+
await tracer.trace('failing-op', async (ctx) => {
|
|
118
|
+
return ctx.err(NOT_FOUND({ detail: 'Resource missing' }));
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
122
|
+
|
|
123
|
+
expect(facts.has(spanStarted('failing-op'))).toBe(true);
|
|
124
|
+
expect(facts.has(spanErr('failing-op', 'NOT_FOUND'))).toBe(true);
|
|
125
|
+
expect(facts.has(spanOk('failing-op'))).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('extracts feature flag access facts from system columns', async () => {
|
|
129
|
+
const tracer = new TestTracer(opContextWithFlags, {
|
|
130
|
+
...createTestTracerOptions(),
|
|
131
|
+
flagEvaluator,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
await tracer.trace('with-ff', async (ctx) => {
|
|
135
|
+
const validationFlag = ctx.ff.advancedValidation;
|
|
136
|
+
expect(validationFlag?.value).toBe(true);
|
|
137
|
+
return ctx.ok('done');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
141
|
+
|
|
142
|
+
expect(facts.has(ffFact('advancedValidation', 'true'))).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('filters facts by namespace', async () => {
|
|
146
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
147
|
+
|
|
148
|
+
await tracer.trace('mixed', async (ctx) => {
|
|
149
|
+
ctx.log.info('A log message');
|
|
150
|
+
ctx.tag.userId('user-1');
|
|
151
|
+
return ctx.ok('done');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
155
|
+
|
|
156
|
+
// Filter to just span facts
|
|
157
|
+
const spanFacts = facts.byNamespace('span');
|
|
158
|
+
expect(spanFacts.length).toBe(2); // started + ok
|
|
159
|
+
|
|
160
|
+
// Filter to just log facts
|
|
161
|
+
const logFacts = facts.byNamespace('log');
|
|
162
|
+
expect(logFacts.length).toBe(1);
|
|
163
|
+
|
|
164
|
+
// Filter to just tag facts
|
|
165
|
+
const tagFacts = facts.byNamespace('tag');
|
|
166
|
+
expect(tagFacts.length).toBe(1);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('supports pattern matching', async () => {
|
|
170
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
171
|
+
|
|
172
|
+
await tracer.trace('fetch-user', async (ctx) => {
|
|
173
|
+
await ctx.span('fetch-profile', async (c) => c.ok(null));
|
|
174
|
+
await ctx.span('fetch-orders', async (c) => c.ok(null));
|
|
175
|
+
return ctx.ok('done');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
179
|
+
|
|
180
|
+
// Match any fetch-* span that started
|
|
181
|
+
expect(facts.hasMatch('span:fetch-*: started')).toBe(true);
|
|
182
|
+
|
|
183
|
+
// Match any span that completed ok
|
|
184
|
+
expect(facts.hasMatch('span:*: ok')).toBe(true);
|
|
185
|
+
|
|
186
|
+
// Should match multiple
|
|
187
|
+
const fetchStarts = facts.match('span:fetch-*: started');
|
|
188
|
+
expect(fetchStarts.length).toBe(3); // fetch-user, fetch-profile, fetch-orders
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('handles deeply nested spans', async () => {
|
|
192
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
193
|
+
|
|
194
|
+
await tracer.trace('level-0', async (ctx) => {
|
|
195
|
+
await ctx.span('level-1', async (c1) => {
|
|
196
|
+
await c1.span('level-2', async (c2) => {
|
|
197
|
+
await c2.span('level-3', async (c3) => {
|
|
198
|
+
return c3.ok('deepest');
|
|
199
|
+
});
|
|
200
|
+
return c2.ok('l2');
|
|
201
|
+
});
|
|
202
|
+
return c1.ok('l1');
|
|
203
|
+
});
|
|
204
|
+
return ctx.ok('l0');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
208
|
+
|
|
209
|
+
// All levels should appear
|
|
210
|
+
expect(facts.has(spanStarted('level-0'))).toBe(true);
|
|
211
|
+
expect(facts.has(spanStarted('level-1'))).toBe(true);
|
|
212
|
+
expect(facts.has(spanStarted('level-2'))).toBe(true);
|
|
213
|
+
expect(facts.has(spanStarted('level-3'))).toBe(true);
|
|
214
|
+
|
|
215
|
+
// Inner spans complete before outer
|
|
216
|
+
expect(facts.hasInOrder([spanOk('level-3'), spanOk('level-2'), spanOk('level-1'), spanOk('level-0')])).toBe(true);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe('trace-testing patterns', () => {
|
|
221
|
+
const testSchema = defineLogSchema({
|
|
222
|
+
sku: S.category(),
|
|
223
|
+
quantity: S.number(),
|
|
224
|
+
reservationId: S.category(),
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const opContext = defineOpContext({ logSchema: testSchema });
|
|
228
|
+
|
|
229
|
+
it('example: verify operation order without implementation details', async () => {
|
|
230
|
+
const tracer = new TestTracer(opContext, { ...createTestTracerOptions() });
|
|
231
|
+
|
|
232
|
+
// Simulate an order processing workflow
|
|
233
|
+
await tracer.trace('process-order', async (ctx) => {
|
|
234
|
+
ctx.tag.sku('SKU-A').quantity(5);
|
|
235
|
+
|
|
236
|
+
// Validate
|
|
237
|
+
await ctx.span('validate', async (c) => {
|
|
238
|
+
c.log.info('Validating order');
|
|
239
|
+
return c.ok({ valid: true });
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Reserve inventory
|
|
243
|
+
await ctx.span('reserve-inventory', async (c) => {
|
|
244
|
+
c.tag.reservationId('res-123');
|
|
245
|
+
return c.ok({ reserved: true });
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// Charge payment
|
|
249
|
+
await ctx.span('charge-payment', async (c) => {
|
|
250
|
+
c.log.info('Charging $49.99');
|
|
251
|
+
return c.ok({ charged: true });
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
return ctx.ok('Order processed');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
const facts = extractFacts(tracer.rootBuffers[0]);
|
|
258
|
+
|
|
259
|
+
// Test WHAT happened, not HOW
|
|
260
|
+
|
|
261
|
+
// 1. Order was processed successfully
|
|
262
|
+
expect(facts.has(spanOk('process-order'))).toBe(true);
|
|
263
|
+
|
|
264
|
+
// 2. Validation happened before inventory reservation
|
|
265
|
+
expect(facts.hasInOrder([spanOk('validate'), spanStarted('reserve-inventory')])).toBe(true);
|
|
266
|
+
|
|
267
|
+
// 3. Inventory was reserved before payment was charged
|
|
268
|
+
expect(facts.hasInOrder([spanOk('reserve-inventory'), spanStarted('charge-payment')])).toBe(true);
|
|
269
|
+
|
|
270
|
+
// 4. Expected tags were set
|
|
271
|
+
expect(facts.has(tagFact('sku', 'SKU-A'))).toBe(true);
|
|
272
|
+
expect(facts.has(tagFact('quantity', 5))).toBe(true);
|
|
273
|
+
expect(facts.has(tagFact('reservationId', 'res-123'))).toBe(true);
|
|
274
|
+
|
|
275
|
+
// 5. No errors occurred
|
|
276
|
+
expect(facts.hasMatch('span:*: err(*)')).toBe(false);
|
|
277
|
+
expect(facts.hasMatch('log:error: *')).toBe(false);
|
|
278
|
+
});
|
|
279
|
+
});
|