@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,443 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
// Must import test-helpers first to initialize timestamp implementation
|
|
3
|
+
import '../../__tests__/test-helpers.js';
|
|
4
|
+
import { createTestTracerOptions } from '../../__tests__/test-helpers.js';
|
|
5
|
+
import { defineOpContext } from '../../defineOpContext.js';
|
|
6
|
+
import { TestTracer } from '../../tracers/TestTracer.js';
|
|
7
|
+
import type { AnySpanBuffer } from '../../types.js';
|
|
8
|
+
import { S } from '../builder.js';
|
|
9
|
+
import { defineFeatureFlags } from '../defineFeatureFlags.js';
|
|
10
|
+
import { defineLogSchema } from '../defineLogSchema.js';
|
|
11
|
+
import { InMemoryFlagEvaluator } from '../evaluator.js';
|
|
12
|
+
import { ENTRY_TYPE_FF_ACCESS, ENTRY_TYPE_FF_USAGE } from '../systemSchema.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Helper to count entries of a specific type in the buffer
|
|
16
|
+
*/
|
|
17
|
+
function countEntryType(buffer: AnySpanBuffer, entryType: number): number {
|
|
18
|
+
let count = 0;
|
|
19
|
+
let current: AnySpanBuffer | undefined = buffer;
|
|
20
|
+
while (current) {
|
|
21
|
+
const writeIndex = current._writeIndex;
|
|
22
|
+
for (let i = 0; i < writeIndex; i++) {
|
|
23
|
+
if (current.entry_type[i] === entryType) {
|
|
24
|
+
count++;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
current = current._overflow;
|
|
28
|
+
}
|
|
29
|
+
return count;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('Feature Flags', () => {
|
|
33
|
+
// Define a minimal log schema for tests
|
|
34
|
+
const testLogSchema = defineLogSchema({});
|
|
35
|
+
|
|
36
|
+
test('defines feature flags with sync/async markers', () => {
|
|
37
|
+
const flags = defineFeatureFlags({
|
|
38
|
+
debugMode: S.boolean().default(false).sync(),
|
|
39
|
+
maxRetries: S.number().default(3).sync(),
|
|
40
|
+
userSpecificLimit: S.number().default(100).async(),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(flags.schema).toBeDefined();
|
|
44
|
+
expect(flags.syncFlags).toContain('debugMode');
|
|
45
|
+
expect(flags.syncFlags).toContain('maxRetries');
|
|
46
|
+
expect(flags.asyncFlags).toContain('userSpecificLimit');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('evaluator returns FlagContext for truthy flags', async () => {
|
|
50
|
+
const flags = defineFeatureFlags({
|
|
51
|
+
debugMode: S.boolean().default(false).sync(),
|
|
52
|
+
maxRetries: S.number().default(3).sync(),
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const ctx = defineOpContext({
|
|
56
|
+
logSchema: testLogSchema,
|
|
57
|
+
flags: flags.schema,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, {
|
|
61
|
+
debugMode: true,
|
|
62
|
+
maxRetries: 5,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const { trace } = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
66
|
+
const result = await trace('test-span', async (ctx) => {
|
|
67
|
+
const ff = ctx.ff;
|
|
68
|
+
|
|
69
|
+
expect(ff.debugMode).toBeDefined();
|
|
70
|
+
expect(ff.debugMode?.value).toBe(true);
|
|
71
|
+
expect(typeof ff.debugMode?.track).toBe('function');
|
|
72
|
+
|
|
73
|
+
expect(ff.maxRetries).toBeDefined();
|
|
74
|
+
expect(ff.maxRetries?.value).toBe(5);
|
|
75
|
+
expect(typeof ff.maxRetries?.track).toBe('function');
|
|
76
|
+
|
|
77
|
+
return ctx.ok(null);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(result.success).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('feature-flag runtime stays worker-safe', async () => {
|
|
84
|
+
const flags = defineFeatureFlags({
|
|
85
|
+
debugMode: S.boolean().default(false).sync(),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const ctx = defineOpContext({
|
|
89
|
+
logSchema: testLogSchema,
|
|
90
|
+
flags: flags.schema,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, { debugMode: true });
|
|
94
|
+
const tracer = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
95
|
+
|
|
96
|
+
await tracer.trace('worker-safe-evaluator', async (spanCtx) => {
|
|
97
|
+
expect(spanCtx.ff.debugMode?.value).toBe(true);
|
|
98
|
+
expect(spanCtx.ff.constructor.toString()).not.toContain('new Function');
|
|
99
|
+
return spanCtx.ok(null);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('evaluator returns undefined for falsy flags', async () => {
|
|
104
|
+
const flags = defineFeatureFlags({
|
|
105
|
+
debugMode: S.boolean().default(false).sync(),
|
|
106
|
+
userLimit: S.number().default(100).async(),
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const ctx = defineOpContext({
|
|
110
|
+
logSchema: testLogSchema,
|
|
111
|
+
flags: flags.schema,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, {}); // No flags set → null values
|
|
115
|
+
|
|
116
|
+
const { trace } = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
117
|
+
await trace('test-span', async (ctx) => {
|
|
118
|
+
const ff = ctx.ff;
|
|
119
|
+
expect(ff.debugMode).toBeUndefined();
|
|
120
|
+
return ctx.ok(null);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test('async flags return FlagContext via get method', async () => {
|
|
125
|
+
const flags = defineFeatureFlags({
|
|
126
|
+
userSpecificLimit: S.number().default(100).async(),
|
|
127
|
+
dynamicProvider: S.enum(['stripe', 'paypal']).default('stripe').async(),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const ctx = defineOpContext({
|
|
131
|
+
logSchema: testLogSchema,
|
|
132
|
+
flags: flags.schema,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, {
|
|
136
|
+
userSpecificLimit: 200,
|
|
137
|
+
dynamicProvider: 'paypal',
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const { trace } = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
141
|
+
await trace('test-span', async (ctx) => {
|
|
142
|
+
// Async flags accessed via get() return FlagContext
|
|
143
|
+
const limit = await ctx.ff.get('userSpecificLimit');
|
|
144
|
+
expect(limit).toBeDefined();
|
|
145
|
+
expect(limit?.value).toBe(200);
|
|
146
|
+
|
|
147
|
+
const provider = await ctx.ff.get('dynamicProvider');
|
|
148
|
+
expect(provider).toBeDefined();
|
|
149
|
+
expect(provider?.value).toBe('paypal');
|
|
150
|
+
|
|
151
|
+
return ctx.ok(null);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('track() on FlagContext logs usage events', async () => {
|
|
156
|
+
const flags = defineFeatureFlags({
|
|
157
|
+
advancedValidation: S.boolean().default(false).sync(),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const ctx = defineOpContext({
|
|
161
|
+
logSchema: testLogSchema,
|
|
162
|
+
flags: flags.schema,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, {
|
|
166
|
+
advancedValidation: true,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const { trace } = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
170
|
+
await trace('test-span', async (ctx) => {
|
|
171
|
+
const flag = ctx.ff.advancedValidation;
|
|
172
|
+
|
|
173
|
+
// track() returns fluent log entry so additional fields can be tagged
|
|
174
|
+
flag?.track({ action: 'validation_performed', outcome: 'success' }).ff_value('used').line(123);
|
|
175
|
+
|
|
176
|
+
// Check buffer for ff-usage entry
|
|
177
|
+
const usageCount = countEntryType(ctx.buffer, ENTRY_TYPE_FF_USAGE);
|
|
178
|
+
expect(usageCount).toBe(1);
|
|
179
|
+
|
|
180
|
+
return ctx.ok(null);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test('sync flag access is logged only once per span', async () => {
|
|
185
|
+
const flags = defineFeatureFlags({
|
|
186
|
+
debugMode: S.boolean().default(false).sync(),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const ctx = defineOpContext({
|
|
190
|
+
logSchema: testLogSchema,
|
|
191
|
+
flags: flags.schema,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, { debugMode: true });
|
|
195
|
+
|
|
196
|
+
const { trace } = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
197
|
+
await trace('test-span', async (ctx) => {
|
|
198
|
+
// Access the flag multiple times
|
|
199
|
+
const value1 = ctx.ff.debugMode;
|
|
200
|
+
const value2 = ctx.ff.debugMode;
|
|
201
|
+
const value3 = ctx.ff.debugMode;
|
|
202
|
+
|
|
203
|
+
// All accesses should return same value (flag is truthy)
|
|
204
|
+
expect(value1?.value).toBe(true);
|
|
205
|
+
expect(value2?.value).toBe(true);
|
|
206
|
+
expect(value3?.value).toBe(true);
|
|
207
|
+
|
|
208
|
+
// Only ONE ff-access log should be written (deduplication via buffer scan)
|
|
209
|
+
const accessCount = countEntryType(ctx.buffer, ENTRY_TYPE_FF_ACCESS);
|
|
210
|
+
expect(accessCount).toBe(1);
|
|
211
|
+
|
|
212
|
+
return ctx.ok(null);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test('async flag access is logged', async () => {
|
|
217
|
+
const flags = defineFeatureFlags({
|
|
218
|
+
userLimit: S.number().default(100).async(),
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const ctx = defineOpContext({
|
|
222
|
+
logSchema: testLogSchema,
|
|
223
|
+
flags: flags.schema,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, { userLimit: 200 });
|
|
227
|
+
|
|
228
|
+
const { trace } = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
229
|
+
await trace('test-span', async (ctx) => {
|
|
230
|
+
const value = await ctx.ff.get('userLimit');
|
|
231
|
+
expect(value?.value).toBe(200);
|
|
232
|
+
|
|
233
|
+
// Check buffer for ff-access entry
|
|
234
|
+
const accessCount = countEntryType(ctx.buffer, ENTRY_TYPE_FF_ACCESS);
|
|
235
|
+
expect(accessCount).toBe(1);
|
|
236
|
+
|
|
237
|
+
return ctx.ok(null);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('S.enum validates enum values', () => {
|
|
242
|
+
const schema = defineFeatureFlags({
|
|
243
|
+
environment: S.enum(['dev', 'staging', 'prod'] as const)
|
|
244
|
+
.default('dev')
|
|
245
|
+
.sync(),
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
expect(schema.schema.environment).toBeDefined();
|
|
249
|
+
expect(schema.schema.environment.defaultValue).toBe('dev');
|
|
250
|
+
expect(schema.schema.environment.evaluationType).toBe('sync');
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
test('S.enum throws on empty values', () => {
|
|
254
|
+
expect(() => {
|
|
255
|
+
S.enum([]);
|
|
256
|
+
}).toThrow('Enum must have at least one value');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('multiple sync and async flags work together', async () => {
|
|
260
|
+
const flags = defineFeatureFlags({
|
|
261
|
+
// Sync flags
|
|
262
|
+
enableFeatureX: S.boolean().default(false).sync(),
|
|
263
|
+
maxConnectionPool: S.number().default(10).sync(),
|
|
264
|
+
logLevel: S.enum(['debug', 'info', 'warn', 'error'] as const)
|
|
265
|
+
.default('info')
|
|
266
|
+
.sync(),
|
|
267
|
+
|
|
268
|
+
// Async flags
|
|
269
|
+
userTier: S.category().default('free').async(),
|
|
270
|
+
customLimit: S.number().default(100).async(),
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const ctx = defineOpContext({
|
|
274
|
+
logSchema: testLogSchema,
|
|
275
|
+
flags: flags.schema,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, {
|
|
279
|
+
enableFeatureX: true,
|
|
280
|
+
maxConnectionPool: 20,
|
|
281
|
+
logLevel: 'debug',
|
|
282
|
+
userTier: 'premium',
|
|
283
|
+
customLimit: 500,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const { trace } = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
287
|
+
await trace('test-span', async (ctx) => {
|
|
288
|
+
// Test sync flags
|
|
289
|
+
expect(ctx.ff.enableFeatureX?.value).toBe(true);
|
|
290
|
+
expect(ctx.ff.maxConnectionPool?.value).toBe(20);
|
|
291
|
+
expect(ctx.ff.logLevel?.value).toBe('debug');
|
|
292
|
+
|
|
293
|
+
// Test async flags
|
|
294
|
+
const userTier = await ctx.ff.get('userTier');
|
|
295
|
+
expect(userTier?.value).toBe('premium');
|
|
296
|
+
|
|
297
|
+
const customLimit = await ctx.ff.get('customLimit');
|
|
298
|
+
expect(customLimit?.value).toBe(500);
|
|
299
|
+
|
|
300
|
+
return ctx.ok(null);
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test('InMemoryFlagEvaluator setFlag updates values', async () => {
|
|
305
|
+
const schema = defineFeatureFlags({
|
|
306
|
+
testFlag: S.category().default('initial').sync(),
|
|
307
|
+
});
|
|
308
|
+
const evaluator = new InMemoryFlagEvaluator(schema.schema, {
|
|
309
|
+
testFlag: 'initial',
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// getSync receives ctx as first param (can be empty object for simple evaluator)
|
|
313
|
+
const { trace } = new TestTracer(
|
|
314
|
+
defineOpContext({
|
|
315
|
+
logSchema: testLogSchema,
|
|
316
|
+
flags: schema.schema,
|
|
317
|
+
}),
|
|
318
|
+
{ ...createTestTracerOptions(), flagEvaluator: evaluator },
|
|
319
|
+
);
|
|
320
|
+
await trace('sync-read-initial', async (ctx) => {
|
|
321
|
+
expect(evaluator.getSync(ctx, 'testFlag')).toBe('initial');
|
|
322
|
+
return ctx.ok(null);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
evaluator.setFlag('testFlag', 'updated');
|
|
326
|
+
|
|
327
|
+
await trace('sync-read-updated', async (ctx) => {
|
|
328
|
+
expect(evaluator.getSync(ctx, 'testFlag')).toBe('updated');
|
|
329
|
+
return ctx.ok(null);
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
test('InMemoryFlagEvaluator works with async', async () => {
|
|
334
|
+
const schema = defineFeatureFlags({
|
|
335
|
+
asyncFlag: S.number().default(0).async(),
|
|
336
|
+
});
|
|
337
|
+
const evaluator = new InMemoryFlagEvaluator(schema.schema, {
|
|
338
|
+
asyncFlag: 42,
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const { trace } = new TestTracer(
|
|
342
|
+
defineOpContext({
|
|
343
|
+
logSchema: testLogSchema,
|
|
344
|
+
flags: schema.schema,
|
|
345
|
+
}),
|
|
346
|
+
{ ...createTestTracerOptions(), flagEvaluator: evaluator },
|
|
347
|
+
);
|
|
348
|
+
await trace('async-read', async (ctx) => {
|
|
349
|
+
expect(await evaluator.getAsync(ctx, 'asyncFlag')).toBe(42);
|
|
350
|
+
return ctx.ok(null);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
test('forContext creates child evaluator bound to child SpanContext', async () => {
|
|
355
|
+
const flags = defineFeatureFlags({
|
|
356
|
+
debugMode: S.boolean().default(false).sync(),
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
const ctx = defineOpContext({
|
|
360
|
+
logSchema: testLogSchema,
|
|
361
|
+
flags: flags.schema,
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const flagEvaluator = new InMemoryFlagEvaluator(flags.schema, { debugMode: true });
|
|
365
|
+
|
|
366
|
+
const { trace } = new TestTracer(ctx, { ...createTestTracerOptions(), flagEvaluator });
|
|
367
|
+
await trace('parent-span', async (parentCtx) => {
|
|
368
|
+
// Access flag in parent
|
|
369
|
+
expect(parentCtx.ff.debugMode?.value).toBe(true);
|
|
370
|
+
|
|
371
|
+
const parentAccessCount = countEntryType(parentCtx.buffer, ENTRY_TYPE_FF_ACCESS);
|
|
372
|
+
expect(parentAccessCount).toBe(1);
|
|
373
|
+
|
|
374
|
+
// Create child span - child gets its own ff evaluator via forContext
|
|
375
|
+
await parentCtx.span('child-span', async (childCtx) => {
|
|
376
|
+
expect(childCtx.ff.debugMode?.value).toBe(true);
|
|
377
|
+
|
|
378
|
+
// Access in child should log to child buffer
|
|
379
|
+
const childAccessCount = countEntryType(childCtx.buffer, ENTRY_TYPE_FF_ACCESS);
|
|
380
|
+
expect(childAccessCount).toBe(1);
|
|
381
|
+
|
|
382
|
+
return childCtx.ok(null);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
return parentCtx.ok(null);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
test('usage example from spec: undefined/truthy pattern', async () => {
|
|
390
|
+
const flags = defineFeatureFlags({
|
|
391
|
+
darkMode: S.boolean().default(false).sync(),
|
|
392
|
+
advancedSearch: S.boolean().default(false).sync(),
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
// Scenario 1: darkMode is enabled
|
|
396
|
+
const enabledCtx = defineOpContext({
|
|
397
|
+
logSchema: testLogSchema,
|
|
398
|
+
flags: flags.schema,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
const enabledFlagEvaluator = new InMemoryFlagEvaluator(flags.schema, { darkMode: true });
|
|
402
|
+
const { trace: enabledTrace } = new TestTracer(enabledCtx, {
|
|
403
|
+
...createTestTracerOptions(),
|
|
404
|
+
flagEvaluator: enabledFlagEvaluator,
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
await enabledTrace('test-enabled', async (ctx) => {
|
|
408
|
+
const darkMode = ctx.ff.darkMode;
|
|
409
|
+
|
|
410
|
+
// Truthy check works naturally with undefined/truthy semantics
|
|
411
|
+
if (darkMode) {
|
|
412
|
+
expect(darkMode.value).toBe(true);
|
|
413
|
+
darkMode.track({ action: 'applied' });
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return ctx.ok(null);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Scenario 2: darkMode is disabled
|
|
420
|
+
const disabledCtx = defineOpContext({
|
|
421
|
+
logSchema: testLogSchema,
|
|
422
|
+
flags: flags.schema,
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
const disabledFlagEvaluator = new InMemoryFlagEvaluator(flags.schema, { darkMode: false });
|
|
426
|
+
const { trace: disabledTrace } = new TestTracer(disabledCtx, {
|
|
427
|
+
...createTestTracerOptions(),
|
|
428
|
+
flagEvaluator: disabledFlagEvaluator,
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
await disabledTrace('test-disabled', async (ctx) => {
|
|
432
|
+
const darkModeDisabled = ctx.ff.darkMode;
|
|
433
|
+
|
|
434
|
+
// Falsy check works - undefined is falsy
|
|
435
|
+
expect(darkModeDisabled).toBeUndefined();
|
|
436
|
+
if (!darkModeDisabled) {
|
|
437
|
+
expect(true).toBe(true);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return ctx.ok(null);
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
});
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema builder for lmao - extends arrow-builder's schema builder with feature flags, masking, and binary sugar
|
|
3
|
+
*
|
|
4
|
+
* This module re-exports the S object from arrow-builder and adds:
|
|
5
|
+
* - Feature flag support via .default().sync()/.async() pattern
|
|
6
|
+
* - Masking transformations for sensitive data
|
|
7
|
+
* - S.unknown() and S.object<T>() sugar for msgpack-encoded binary columns
|
|
8
|
+
* - S.binary() passthrough to arrow-builder's S.binary()
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { encode } from '@msgpack/msgpack';
|
|
12
|
+
import {
|
|
13
|
+
S as ArrowS,
|
|
14
|
+
type BinaryEncoder,
|
|
15
|
+
type LazyBinarySchema,
|
|
16
|
+
type LazyCategorySchema,
|
|
17
|
+
type LazyEnumSchema,
|
|
18
|
+
type LazyTextSchema,
|
|
19
|
+
type Schema,
|
|
20
|
+
} from '@smoothbricks/arrow-builder';
|
|
21
|
+
import type { FeatureFlagDefinition, FlagBuilderWithDefault, SchemaBuilder, SchemaOrFlagBuilder } from './types.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Msgpack encoder singleton -- per-value, synchronous.
|
|
25
|
+
* Encodes at flush time (cold path), not on the hot write path.
|
|
26
|
+
* @msgpack/msgpack already handles most types; functions/symbols become undefined (dropped silently).
|
|
27
|
+
*
|
|
28
|
+
* Both wrap @msgpack/msgpack's encode(). This encoder is private to the schema builder;
|
|
29
|
+
*/
|
|
30
|
+
const msgpackEncoder: BinaryEncoder = {
|
|
31
|
+
encode(value: unknown): Uint8Array {
|
|
32
|
+
return encode(value) as Uint8Array;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create a flag builder that wraps a schema object
|
|
38
|
+
* This allows schemas to be used for both tag attributes and feature flags
|
|
39
|
+
*/
|
|
40
|
+
type SchemaWithFlagBuilder<TSchema extends Schema<Value>, Value> = TSchema & SchemaOrFlagBuilder<Value>;
|
|
41
|
+
|
|
42
|
+
function createSchemaWithFlagBuilder<Value, TSchema extends Schema<Value>>(
|
|
43
|
+
schema: TSchema,
|
|
44
|
+
): SchemaWithFlagBuilder<TSchema, Value> {
|
|
45
|
+
const schemaWithBuilder: SchemaWithFlagBuilder<TSchema, Value> = Object.assign(schema, {
|
|
46
|
+
default(defaultValue: Value): FlagBuilderWithDefault<Value> {
|
|
47
|
+
return {
|
|
48
|
+
sync(): FeatureFlagDefinition<Value, 'sync'> {
|
|
49
|
+
return {
|
|
50
|
+
schema,
|
|
51
|
+
defaultValue,
|
|
52
|
+
evaluationType: 'sync' as const,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
async(): FeatureFlagDefinition<Value, 'async'> {
|
|
56
|
+
return {
|
|
57
|
+
schema,
|
|
58
|
+
defaultValue,
|
|
59
|
+
evaluationType: 'async' as const,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return schemaWithBuilder;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Schema builder that wraps arrow-builder's S with feature flag support
|
|
71
|
+
*
|
|
72
|
+
* STRING TYPE SYSTEM (See specs/lmao/01a_trace_schema_system.md):
|
|
73
|
+
* Three distinct string types, each with different storage strategies:
|
|
74
|
+
* - S.enum(['A', 'B', 'C']) - Known values at compile time (Uint8Array, 1 byte)
|
|
75
|
+
* - S.category() - Repeated values (raw string storage, dictionary built at Arrow conversion)
|
|
76
|
+
* - S.text() - Unique values (no dictionary overhead)
|
|
77
|
+
*/
|
|
78
|
+
const schemaBuilderImpl: SchemaBuilder = {
|
|
79
|
+
/**
|
|
80
|
+
* Create number schema
|
|
81
|
+
*
|
|
82
|
+
* Usage:
|
|
83
|
+
* - S.number() - any number for tag attributes
|
|
84
|
+
* - S.number().default(0).sync() - feature flag
|
|
85
|
+
*/
|
|
86
|
+
number: () => {
|
|
87
|
+
const schema = ArrowS.number();
|
|
88
|
+
return createSchemaWithFlagBuilder(schema);
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Create boolean schema
|
|
93
|
+
*
|
|
94
|
+
* Usage:
|
|
95
|
+
* - S.boolean() - for tag attributes
|
|
96
|
+
* - S.boolean().default(false).sync() - feature flag
|
|
97
|
+
*/
|
|
98
|
+
boolean: () => {
|
|
99
|
+
const schema = ArrowS.boolean();
|
|
100
|
+
return createSchemaWithFlagBuilder(schema);
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Wrap schema to make it optional
|
|
105
|
+
*
|
|
106
|
+
* Usage:
|
|
107
|
+
* - SchemaBuilder.optional(SchemaBuilder.string()) - string | undefined
|
|
108
|
+
*/
|
|
109
|
+
optional: <T>(schema: Schema<T>): Schema<T | undefined, T | undefined> => {
|
|
110
|
+
return ArrowS.optional(schema);
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create union of multiple schemas
|
|
115
|
+
*
|
|
116
|
+
* Usage:
|
|
117
|
+
* - SchemaBuilder.union([SchemaBuilder.string(), SchemaBuilder.number()]) - string | number
|
|
118
|
+
*/
|
|
119
|
+
union: <T extends readonly [Schema, ...Schema[]]>(schemas: T) => {
|
|
120
|
+
return ArrowS.union(schemas);
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Enum - Known values at compile time
|
|
125
|
+
*
|
|
126
|
+
* Storage: Uint8Array (1 byte) with compile-time mapping
|
|
127
|
+
* Arrow: Dictionary with pre-defined values (UTF-8 pre-computed at definition time)
|
|
128
|
+
* Use for: Operations, HTTP methods, entry types, status enums
|
|
129
|
+
*
|
|
130
|
+
* Usage:
|
|
131
|
+
* - S.enum(['CREATE', 'READ', 'UPDATE', 'DELETE']) - for tag attributes
|
|
132
|
+
* - S.enum(['dev', 'staging', 'prod']).default('dev').sync() - feature flag
|
|
133
|
+
*/
|
|
134
|
+
enum: <T extends readonly string[]>(values: T): SchemaOrFlagBuilder<T[number]> & LazyEnumSchema<T[number]> => {
|
|
135
|
+
const schema = ArrowS.enum(values);
|
|
136
|
+
return createSchemaWithFlagBuilder(schema);
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Category - Values that often repeat (limited cardinality)
|
|
141
|
+
*
|
|
142
|
+
* Storage: Raw strings (no hot-path interning)
|
|
143
|
+
* Arrow: Dictionary built dynamically from values at Arrow conversion
|
|
144
|
+
* Use for: userIds, sessionIds, moduleNames, spanNames, table names
|
|
145
|
+
*/
|
|
146
|
+
category: (): SchemaOrFlagBuilder<string> & LazyCategorySchema => {
|
|
147
|
+
const schema = ArrowS.category();
|
|
148
|
+
return createSchemaWithFlagBuilder(schema);
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Text - Unique values that rarely repeat
|
|
153
|
+
*
|
|
154
|
+
* Storage: Raw strings without interning
|
|
155
|
+
* Arrow: Plain string column (no dictionary overhead)
|
|
156
|
+
* Use for: Unique error messages, URLs, request bodies, masked queries
|
|
157
|
+
*/
|
|
158
|
+
text: (): SchemaOrFlagBuilder<string> & LazyTextSchema => {
|
|
159
|
+
const schema = ArrowS.text();
|
|
160
|
+
return createSchemaWithFlagBuilder(schema);
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Binary - Raw bytes or encoder-wrapped values
|
|
165
|
+
*
|
|
166
|
+
* Passthrough to arrow-builder's S.binary().
|
|
167
|
+
* Without encoder: accepts Uint8Array (raw binary).
|
|
168
|
+
* With encoder: accepts any value T (encoded to bytes at flush time).
|
|
169
|
+
*/
|
|
170
|
+
binary: ((options?: { encoder: BinaryEncoder }): LazyBinarySchema => {
|
|
171
|
+
if (options?.encoder) {
|
|
172
|
+
return ArrowS.binary(options);
|
|
173
|
+
}
|
|
174
|
+
return ArrowS.binary();
|
|
175
|
+
}) as SchemaBuilder['binary'],
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Unknown - accepts any value, msgpack-encoded at flush time
|
|
179
|
+
*
|
|
180
|
+
* Sugar for S.binary({ encoder: msgpackEncoder }).
|
|
181
|
+
* Use for: arbitrary objects, request bodies, error context, unknown-shape data.
|
|
182
|
+
* Hot path stores frozen object reference; flush path encodes via @msgpack/msgpack.
|
|
183
|
+
*/
|
|
184
|
+
unknown: (): LazyBinarySchema<unknown> => {
|
|
185
|
+
return ArrowS.binary({ encoder: msgpackEncoder });
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Object<T> - typed variant of unknown, same underlying binary storage with msgpack encoding
|
|
190
|
+
*
|
|
191
|
+
* TypeScript enforces shape at compile time; no runtime validation on hot path.
|
|
192
|
+
* Sugar for S.binary<T>({ encoder: msgpackEncoder }).
|
|
193
|
+
*/
|
|
194
|
+
object: <T extends object>(): LazyBinarySchema<T> => {
|
|
195
|
+
return ArrowS.binary<T>({ encoder: msgpackEncoder });
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Export as S for convenience
|
|
200
|
+
// Note: The SchemaBuilder type is exported from types.ts
|
|
201
|
+
export const S = schemaBuilderImpl;
|