@smoothbricks/lmao 0.2.2 → 0.3.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 +206 -206
- package/dist/allocator.wasm +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/JsBufferStrategy.d.ts +4 -3
- package/dist/lib/JsBufferStrategy.d.ts.map +1 -1
- package/dist/lib/JsBufferStrategy.js +18 -11
- package/dist/lib/arrow/lease.d.ts +10 -0
- package/dist/lib/arrow/lease.d.ts.map +1 -0
- package/dist/lib/arrow/lease.js +33 -0
- package/dist/lib/arrow/utils.d.ts +3 -4
- package/dist/lib/arrow/utils.d.ts.map +1 -1
- package/dist/lib/arrow/utils.js +12 -13
- package/dist/lib/arrow/vocabularyDictionary.d.ts +21 -0
- package/dist/lib/arrow/vocabularyDictionary.d.ts.map +1 -0
- package/dist/lib/arrow/vocabularyDictionary.js +95 -0
- package/dist/lib/bufferStrategy.d.ts +3 -2
- package/dist/lib/bufferStrategy.d.ts.map +1 -1
- package/dist/lib/cloudflare/traceRows.d.ts.map +1 -1
- package/dist/lib/cloudflare/traceRows.js +3 -2
- package/dist/lib/codegen/evaluatorGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/evaluatorGenerator.js +12 -11
- package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts +44 -82
- package/dist/lib/codegen/fixedPositionWriterGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/fixedPositionWriterGenerator.js +223 -162
- package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts +63 -0
- package/dist/lib/codegen/spanLoggerClosureMaterializer.d.ts.map +1 -0
- package/dist/lib/codegen/spanLoggerClosureMaterializer.js +447 -0
- package/dist/lib/codegen/spanLoggerGenerator.d.ts +36 -19
- package/dist/lib/codegen/spanLoggerGenerator.d.ts.map +1 -1
- package/dist/lib/codegen/spanLoggerGenerator.js +164 -158
- package/dist/lib/convertToArrow.d.ts +7 -2
- package/dist/lib/convertToArrow.d.ts.map +1 -1
- package/dist/lib/convertToArrow.js +499 -285
- package/dist/lib/defineOpContext.js +1 -1
- package/dist/lib/enumMetadata.d.ts +19 -0
- package/dist/lib/enumMetadata.d.ts.map +1 -0
- package/dist/lib/enumMetadata.js +86 -0
- package/dist/lib/flushScheduler.d.ts.map +1 -1
- package/dist/lib/flushScheduler.js +13 -4
- package/dist/lib/library.d.ts +16 -98
- package/dist/lib/library.d.ts.map +1 -1
- package/dist/lib/library.js +32 -525
- package/dist/lib/logBinding.d.ts +21 -27
- package/dist/lib/logBinding.d.ts.map +1 -1
- package/dist/lib/op.d.ts +30 -30
- package/dist/lib/op.d.ts.map +1 -1
- package/dist/lib/op.js +15 -22
- package/dist/lib/opContext/createOpGroup.d.ts +1 -1
- package/dist/lib/opContext/createOpGroup.d.ts.map +1 -1
- package/dist/lib/opContext/createOpGroup.js +22 -29
- package/dist/lib/opContext/defineOp.d.ts +4 -4
- package/dist/lib/opContext/defineOp.d.ts.map +1 -1
- package/dist/lib/opContext/defineOp.js +53 -10
- package/dist/lib/opContext/opGroupTypes.d.ts +2 -2
- package/dist/lib/opContext/opTypes.d.ts +1 -1
- package/dist/lib/opContext/opTypes.d.ts.map +1 -1
- package/dist/lib/opContext/spanContextTypes.d.ts +33 -18
- package/dist/lib/opContext/spanContextTypes.d.ts.map +1 -1
- package/dist/lib/opContext/types.d.ts +4 -4
- package/dist/lib/opContext/types.d.ts.map +1 -1
- package/dist/lib/physicalLayoutPlan.d.ts +89 -0
- package/dist/lib/physicalLayoutPlan.d.ts.map +1 -0
- package/dist/lib/physicalLayoutPlan.js +442 -0
- package/dist/lib/resolveMessage.d.ts +9 -0
- package/dist/lib/resolveMessage.d.ts.map +1 -0
- package/dist/lib/resolveMessage.js +63 -0
- package/dist/lib/result.d.ts +5 -7
- package/dist/lib/result.d.ts.map +1 -1
- package/dist/lib/result.js +19 -26
- package/dist/lib/runtimeHint.d.ts +35 -0
- package/dist/lib/runtimeHint.d.ts.map +1 -0
- package/dist/lib/runtimeHint.js +79 -0
- package/dist/lib/schema/typeGuards.d.ts +7 -47
- package/dist/lib/schema/typeGuards.d.ts.map +1 -1
- package/dist/lib/schema/typeGuards.js +7 -123
- package/dist/lib/schema/types.d.ts +1 -1
- package/dist/lib/schema/types.d.ts.map +1 -1
- package/dist/lib/span-buffer/aot/v1.d.ts +2 -0
- package/dist/lib/span-buffer/aot/v1.d.ts.map +1 -0
- package/dist/lib/span-buffer/aot/v1.js +24 -0
- package/dist/lib/spanBuffer.d.ts +33 -4
- package/dist/lib/spanBuffer.d.ts.map +1 -1
- package/dist/lib/spanBuffer.js +583 -91
- package/dist/lib/spanBufferStats.d.ts +1 -1
- package/dist/lib/spanBufferStats.d.ts.map +1 -1
- package/dist/lib/spanContext.d.ts +27 -51
- package/dist/lib/spanContext.d.ts.map +1 -1
- package/dist/lib/spanContext.js +822 -344
- package/dist/lib/sqlite/sqlite-common.d.ts.map +1 -1
- package/dist/lib/sqlite/sqlite-common.js +20 -21
- package/dist/lib/testing/bun-harness.d.ts +8 -3
- package/dist/lib/testing/bun-harness.d.ts.map +1 -1
- package/dist/lib/testing/bun-harness.js +30 -18
- package/dist/lib/testing/extractFacts.d.ts +1 -1
- package/dist/lib/testing/extractFacts.d.ts.map +1 -1
- package/dist/lib/testing/extractFacts.js +55 -63
- package/dist/lib/testing/facts.d.ts +1 -1
- package/dist/lib/testing/facts.d.ts.map +1 -1
- package/dist/lib/testing/queryable-span.d.ts +1 -1
- package/dist/lib/testing/queryable-span.d.ts.map +1 -1
- package/dist/lib/testing/queryable-span.js +26 -28
- package/dist/lib/testing/span-query.d.ts.map +1 -1
- package/dist/lib/testing/span-query.js +19 -22
- package/dist/lib/testing/stdio-replay.d.ts.map +1 -1
- package/dist/lib/testing/stdio-replay.js +19 -8
- package/dist/lib/threadId.d.ts.map +1 -1
- package/dist/lib/threadId.js +6 -3
- package/dist/lib/traceContext.d.ts.map +1 -1
- package/dist/lib/traceContext.js +1 -4
- package/dist/lib/traceRoot.d.ts +30 -8
- package/dist/lib/traceRoot.d.ts.map +1 -1
- package/dist/lib/traceRoot.es.d.ts +17 -15
- package/dist/lib/traceRoot.es.d.ts.map +1 -1
- package/dist/lib/traceRoot.es.js +68 -34
- package/dist/lib/traceRoot.js +11 -0
- package/dist/lib/traceRoot.node.d.ts +17 -19
- package/dist/lib/traceRoot.node.d.ts.map +1 -1
- package/dist/lib/traceRoot.node.js +66 -38
- package/dist/lib/traceTopology.d.ts +42 -0
- package/dist/lib/traceTopology.d.ts.map +1 -0
- package/dist/lib/traceTopology.js +260 -0
- package/dist/lib/tracer.d.ts +9 -5
- package/dist/lib/tracer.d.ts.map +1 -1
- package/dist/lib/tracer.js +65 -71
- package/dist/lib/tracers/ArrayQueueTracer.d.ts +1 -1
- package/dist/lib/tracers/ArrayQueueTracer.js +1 -1
- package/dist/lib/tracers/StdioTracer.d.ts.map +1 -1
- package/dist/lib/tracers/StdioTracer.js +15 -13
- package/dist/lib/tracers/TestTracer.d.ts +4 -6
- package/dist/lib/tracers/TestTracer.d.ts.map +1 -1
- package/dist/lib/tracers/TestTracer.js +6 -8
- package/dist/lib/types.d.ts +49 -32
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/vocabularyRegistry.d.ts +25 -0
- package/dist/lib/vocabularyRegistry.d.ts.map +1 -0
- package/dist/lib/vocabularyRegistry.js +372 -0
- package/dist/lib/wasm/WasmBufferStrategy.d.ts +6 -10
- package/dist/lib/wasm/WasmBufferStrategy.d.ts.map +1 -1
- package/dist/lib/wasm/WasmBufferStrategy.js +44 -37
- package/dist/lib/wasm/wasmAllocator.d.ts +27 -22
- package/dist/lib/wasm/wasmAllocator.d.ts.map +1 -1
- package/dist/lib/wasm/wasmAllocator.js +66 -44
- package/dist/lib/wasm/wasmPhysicalLayout.d.ts +67 -0
- package/dist/lib/wasm/wasmPhysicalLayout.d.ts.map +1 -0
- package/dist/lib/wasm/wasmPhysicalLayout.js +179 -0
- package/dist/lib/wasm/wasmSpanBuffer.d.ts +79 -31
- package/dist/lib/wasm/wasmSpanBuffer.d.ts.map +1 -1
- package/dist/lib/wasm/wasmSpanBuffer.js +442 -272
- package/dist/lib/wasm/wasmTraceRoot.d.ts +24 -22
- package/dist/lib/wasm/wasmTraceRoot.d.ts.map +1 -1
- package/dist/lib/wasm/wasmTraceRoot.js +110 -71
- package/dist/vocabulary/register/v1.d.ts +2 -0
- package/dist/vocabulary/register/v1.d.ts.map +1 -0
- package/dist/vocabulary/register/v1.js +1 -0
- package/dist/wasm.d.ts +5 -0
- package/dist/wasm.d.ts.map +1 -0
- package/dist/wasm.js +4 -0
- package/package.json +54 -6
- package/src/index.ts +1 -0
- package/src/lib/JsBufferStrategy.ts +27 -9
- package/src/lib/__tests__/arrow-builder-integration/arrow-conversion.test.ts +335 -37
- package/src/lib/__tests__/arrow-builder-integration/binary-arrow-conversion.test.ts +97 -26
- package/src/lib/__tests__/arrow-builder-integration/binary-comparison.test.ts +75 -15
- package/src/lib/__tests__/arrow-builder-integration/binary-format-compliance.test.ts +30 -6
- package/src/lib/__tests__/arrow-builder-integration/buffer-chaining.test.ts +18 -21
- package/src/lib/__tests__/arrow-builder-integration/foundation.test.ts +5 -2
- package/src/lib/__tests__/arrow-builder-integration/integration.test.ts +25 -7
- package/src/lib/__tests__/arrow-builder-integration/lazy-columns.test.ts +3 -2
- package/src/lib/__tests__/buffer-overflow.test.ts +24 -18
- package/src/lib/__tests__/capability-span-context.test.ts +505 -0
- package/src/lib/__tests__/capacity-tuning.test.ts +5 -3
- package/src/lib/__tests__/eager-columns.test.ts +345 -0
- package/src/lib/__tests__/enum-metadata-aot.test.ts +153 -0
- package/src/lib/__tests__/enum-metadata.test.ts +177 -0
- package/src/lib/__tests__/fixtures/empty-vocabulary-runtime.fixture.ts +15 -0
- package/src/lib/__tests__/flushScheduler.test.ts +5 -1
- package/src/lib/__tests__/identity-view.property.test.ts +179 -0
- package/src/lib/__tests__/library.test.ts +19 -235
- package/src/lib/__tests__/message-buffer-families.test.ts +878 -0
- package/src/lib/__tests__/nested-library-tasks.test.ts +14 -15
- package/src/lib/__tests__/op-metadata.test.ts +1 -1
- package/src/lib/__tests__/op-type-safety.test.ts +5 -16
- package/src/lib/__tests__/physical-layout-plan.test.ts +333 -0
- package/src/lib/__tests__/remap-descriptor-integration.test.ts +381 -0
- package/src/lib/__tests__/root-context-construction.test.ts +414 -0
- package/src/lib/__tests__/span-auto-runtime.test.ts +386 -0
- package/src/lib/__tests__/span-buffer-segment-stats.test.ts +221 -0
- package/src/lib/__tests__/span-lifecycle.test.ts +53 -25
- package/src/lib/__tests__/spanbuffer-materializer-parity.test.ts +266 -0
- package/src/lib/__tests__/sync-async-trace.test.ts +24 -23
- package/src/lib/__tests__/tag-writer-aot.test.ts +214 -0
- package/src/lib/__tests__/test-helpers.ts +67 -12
- package/src/lib/__tests__/threadId.test.ts +62 -0
- package/src/lib/__tests__/timestamp.test.ts +221 -93
- package/src/lib/__tests__/traceTopology.property.test.ts +383 -0
- package/src/lib/__tests__/type-narrowing.test.ts +63 -0
- package/src/lib/__tests__/vocabulary-dense-decoding.test.ts +405 -0
- package/src/lib/__tests__/vocabularyRegistry.test.ts +313 -0
- package/src/lib/arrow/lease.ts +43 -0
- package/src/lib/arrow/utils.ts +10 -14
- package/src/lib/arrow/vocabularyDictionary.ts +123 -0
- package/src/lib/bufferStrategy.ts +9 -1
- package/src/lib/cloudflare/traceRows.ts +3 -2
- package/src/lib/codegen/__tests__/evaluatorGenerator.test.ts +21 -141
- package/src/lib/codegen/__tests__/fixedPositionWriter-parity.test.ts +273 -0
- package/src/lib/codegen/__tests__/fixedPositionWriter-uint64.test.ts +61 -34
- package/src/lib/codegen/__tests__/nullBitmap.test.ts +33 -37
- package/src/lib/codegen/__tests__/spanLoggerGenerator.test.ts +34 -18
- package/src/lib/codegen/__tests__/spanLoggerMaterializerParity.test.ts +503 -0
- package/src/lib/codegen/evaluatorGenerator.ts +18 -13
- package/src/lib/codegen/fixedPositionWriterGenerator.ts +329 -245
- package/src/lib/codegen/spanLoggerClosureMaterializer.ts +598 -0
- package/src/lib/codegen/spanLoggerGenerator.ts +241 -177
- package/src/lib/convertToArrow.ts +598 -311
- package/src/lib/defineOpContext.ts +1 -1
- package/src/lib/enumMetadata.ts +121 -0
- package/src/lib/flushScheduler.ts +11 -5
- package/src/lib/library.ts +37 -595
- package/src/lib/logBinding.ts +21 -27
- package/src/lib/op.ts +75 -18
- package/src/lib/opContext/__tests__/retry.test.ts +27 -21
- package/src/lib/opContext/createOpGroup.ts +33 -31
- package/src/lib/opContext/defineOp.ts +88 -11
- package/src/lib/opContext/opGroupTypes.ts +2 -2
- package/src/lib/opContext/opTypes.ts +1 -1
- package/src/lib/opContext/spanContextTypes.ts +122 -24
- package/src/lib/opContext/types.ts +7 -3
- package/src/lib/physicalLayoutPlan.ts +598 -0
- package/src/lib/resolveMessage.ts +67 -0
- package/src/lib/result.ts +20 -33
- package/src/lib/runtimeHint.ts +98 -0
- package/src/lib/schema/__tests__/featureFlags.test.ts +2 -1
- package/src/lib/schema/builder.ts +1 -1
- package/src/lib/schema/typeGuards.ts +7 -151
- package/src/lib/schema/types.ts +1 -1
- package/src/lib/span-buffer/aot/v1.ts +26 -0
- package/src/lib/spanBuffer.ts +658 -92
- package/src/lib/spanBufferStats.ts +1 -1
- package/src/lib/spanContext.ts +1350 -861
- package/src/lib/sqlite/sqlite-common.ts +20 -31
- package/src/lib/testing/__tests__/topology-traversal.test.ts +174 -0
- package/src/lib/testing/__tests__/vitest-harness.test.ts +2 -1
- package/src/lib/testing/bun-harness.ts +94 -43
- package/src/lib/testing/extractFacts.ts +64 -78
- package/src/lib/testing/facts.ts +1 -1
- package/src/lib/testing/queryable-span.ts +23 -30
- package/src/lib/testing/span-query.ts +16 -20
- package/src/lib/testing/stdio-replay.ts +25 -8
- package/src/lib/testing/vitest-harness.ts +1 -1
- package/src/lib/threadId.ts +6 -3
- package/src/lib/traceContext.ts +1 -6
- package/src/lib/traceRoot.es.ts +77 -42
- package/src/lib/traceRoot.node.ts +75 -46
- package/src/lib/traceRoot.ts +41 -14
- package/src/lib/traceTopology.ts +279 -0
- package/src/lib/tracer.ts +109 -98
- package/src/lib/tracers/ArrayQueueTracer.ts +1 -1
- package/src/lib/tracers/StdioTracer.ts +15 -13
- package/src/lib/tracers/TestTracer.ts +6 -8
- package/src/lib/tracers/__tests__/ArrayQueueTracer.test.ts +15 -10
- package/src/lib/tracers/__tests__/CompositeTracer.test.ts +150 -0
- package/src/lib/tracers/__tests__/TestTracer.test.ts +23 -13
- package/src/lib/types.ts +64 -33
- package/src/lib/vocabularyRegistry.ts +439 -0
- package/src/lib/wasm/WasmBufferStrategy.ts +56 -48
- package/src/lib/wasm/__tests__/WasmBufferStrategy.test.ts +215 -11
- package/src/lib/wasm/__tests__/allocatorFreeBlockClamp.test.ts +86 -0
- package/src/lib/wasm/__tests__/wasm-identity-view.test.ts +311 -0
- package/src/lib/wasm/__tests__/wasm-integration.test.ts +417 -44
- package/src/lib/wasm/__tests__/wasm-message-buffer-families.test.ts +588 -0
- package/src/lib/wasm/__tests__/wasmAllocator.test.ts +100 -668
- package/src/lib/wasm/__tests__/wasmSpanBuffer.test.ts +419 -63
- package/src/lib/wasm/__tests__/wasmTraceRoot.test.ts +24 -29
- package/src/lib/wasm/__tests__/wasmTracer.test.ts.disabled +2 -2
- package/src/lib/wasm/wasmAllocator.ts +131 -96
- package/src/lib/wasm/wasmPhysicalLayout.ts +309 -0
- package/src/lib/wasm/wasmSpanBuffer.ts +597 -341
- package/src/lib/wasm/wasmTraceRoot.ts +140 -78
- package/src/vocabulary/register/v1.ts +1 -0
- package/src/wasm.ts +19 -0
- package/src/lib/__tests__/remapped-buffer-view-integration.test.ts +0 -319
- package/src/lib/__tests__/remapped-buffer-view.test.ts +0 -635
- package/src/lib/wasm/allocator.zig +0 -948
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
import fc from 'fast-check';
|
|
3
|
+
import { convertSpanTreeToArrowTable } from '../convertToArrow.js';
|
|
4
|
+
import { defineOpContext } from '../defineOpContext.js';
|
|
5
|
+
import { JsBufferStrategy } from '../JsBufferStrategy.js';
|
|
6
|
+
import { defineLogSchema } from '../schema/defineLogSchema.js';
|
|
7
|
+
import { extractFacts } from '../testing/extractFacts.js';
|
|
8
|
+
import { querySpan } from '../testing/queryable-span.js';
|
|
9
|
+
import { createTraceRoot } from '../traceRoot.node.js';
|
|
10
|
+
import { ArrayQueueTracer } from '../tracers/ArrayQueueTracer.js';
|
|
11
|
+
import { iterateSpanChildren, iterateSpanTree, NO_NODE, TraceTopology, walkSpanTree } from '../traceTopology.js';
|
|
12
|
+
|
|
13
|
+
const topologyContext = defineOpContext({ logSchema: defineLogSchema({}) });
|
|
14
|
+
|
|
15
|
+
function createTracer() {
|
|
16
|
+
return new ArrayQueueTracer(topologyContext, {
|
|
17
|
+
bufferStrategy: new JsBufferStrategy(),
|
|
18
|
+
createTraceRoot,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function createRuntimeRoot(name = 'root') {
|
|
23
|
+
const tracer = createTracer();
|
|
24
|
+
tracer.trace(name, (ctx) => ctx.ok(null));
|
|
25
|
+
const root = tracer.queue[0];
|
|
26
|
+
if (!root) throw new Error(`Expected traced root '${name}'`);
|
|
27
|
+
return { root, tracer };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function addChild(runtime: ReturnType<typeof createRuntimeRoot>, parent: ReturnType<typeof createRuntimeRoot>['root']) {
|
|
31
|
+
return runtime.tracer.bufferStrategy.createChildSpanBuffer(parent, parent._opMetadata, parent._opMetadata, 8);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function collectWalk(root: Parameters<typeof walkSpanTree>[0]) {
|
|
35
|
+
const visited: Parameters<typeof walkSpanTree>[0][] = [];
|
|
36
|
+
walkSpanTree(root, (buffer) => visited.push(buffer));
|
|
37
|
+
return visited;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function expectNoChildrenArray(buffer: Parameters<typeof walkSpanTree>[0]): void {
|
|
41
|
+
expect(Object.hasOwn(buffer, '_children')).toBe(false);
|
|
42
|
+
expect(Array.isArray(Reflect.get(buffer, '_children'))).toBe(false);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function requireColumn(table: ReturnType<typeof convertSpanTreeToArrowTable>, name: string) {
|
|
46
|
+
const column = table.getChild(name);
|
|
47
|
+
if (!column) throw new Error(`Expected Arrow column '${name}'`);
|
|
48
|
+
return column;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function spanStartNames(table: ReturnType<typeof convertSpanTreeToArrowTable>): unknown[] {
|
|
52
|
+
const entryTypes = requireColumn(table, 'entry_type');
|
|
53
|
+
const messages = requireColumn(table, 'message');
|
|
54
|
+
const names: unknown[] = [];
|
|
55
|
+
for (let row = 0; row < table.numRows; row++) {
|
|
56
|
+
if (entryTypes.get(row) === 'span-start') names.push(messages.get(row));
|
|
57
|
+
}
|
|
58
|
+
return names;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe('trace topology arena properties', () => {
|
|
62
|
+
it('registers a root, children, and grandchild in insertion order without per-span child arrays', () => {
|
|
63
|
+
const runtime = createRuntimeRoot();
|
|
64
|
+
const { root } = runtime;
|
|
65
|
+
const firstChild = addChild(runtime, root);
|
|
66
|
+
const secondChild = addChild(runtime, root);
|
|
67
|
+
const grandchild = addChild(runtime, firstChild);
|
|
68
|
+
const topology = root._traceRoot._topology;
|
|
69
|
+
|
|
70
|
+
expect(topology).toBeInstanceOf(TraceTopology);
|
|
71
|
+
expect(topology.root).toBe(0);
|
|
72
|
+
expect(topology.count).toBe(4);
|
|
73
|
+
expect([root._nodeIndex, firstChild._nodeIndex, secondChild._nodeIndex, grandchild._nodeIndex]).toEqual([
|
|
74
|
+
0, 1, 2, 3,
|
|
75
|
+
]);
|
|
76
|
+
expect(topology.buffers.slice(0, topology.count)).toEqual([root, firstChild, secondChild, grandchild]);
|
|
77
|
+
|
|
78
|
+
expect(topology.firstChild[root._nodeIndex]).toBe(firstChild._nodeIndex);
|
|
79
|
+
expect(topology.lastChild[root._nodeIndex]).toBe(secondChild._nodeIndex);
|
|
80
|
+
expect(topology.nextSibling[firstChild._nodeIndex]).toBe(secondChild._nodeIndex);
|
|
81
|
+
expect(topology.nextSibling[secondChild._nodeIndex]).toBe(NO_NODE);
|
|
82
|
+
expect(topology.firstChild[firstChild._nodeIndex]).toBe(grandchild._nodeIndex);
|
|
83
|
+
expect(topology.lastChild[firstChild._nodeIndex]).toBe(grandchild._nodeIndex);
|
|
84
|
+
expect(topology.nextSibling[grandchild._nodeIndex]).toBe(NO_NODE);
|
|
85
|
+
expect(topology.firstChild[secondChild._nodeIndex]).toBe(NO_NODE);
|
|
86
|
+
expect(topology.lastChild[secondChild._nodeIndex]).toBe(NO_NODE);
|
|
87
|
+
|
|
88
|
+
expect(Array.from(iterateSpanChildren(root))).toEqual([firstChild, secondChild]);
|
|
89
|
+
expect(Array.from(iterateSpanChildren(firstChild))).toEqual([grandchild]);
|
|
90
|
+
expect(collectWalk(root)).toEqual([root, firstChild, grandchild, secondChild]);
|
|
91
|
+
expect(Array.from(iterateSpanTree(root))).toEqual([root, firstChild, grandchild, secondChild]);
|
|
92
|
+
|
|
93
|
+
for (const buffer of [root, firstChild, secondChild, grandchild]) {
|
|
94
|
+
topology.assertLive(buffer);
|
|
95
|
+
expect(buffer._topologyGeneration).toBe(topology.generation);
|
|
96
|
+
expectNoChildrenArray(buffer);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('grows every arena lane together and preserves arbitrary sibling insertion order', () => {
|
|
101
|
+
fc.assert(
|
|
102
|
+
fc.property(fc.integer({ min: 9, max: 384 }), (siblingCount) => {
|
|
103
|
+
const runtime = createRuntimeRoot(`siblings-${siblingCount}`);
|
|
104
|
+
const { root } = runtime;
|
|
105
|
+
const siblings = [];
|
|
106
|
+
for (let index = 0; index < siblingCount; index++) siblings.push(addChild(runtime, root));
|
|
107
|
+
const topology = root._traceRoot._topology;
|
|
108
|
+
|
|
109
|
+
expect(topology.count).toBe(siblingCount + 1);
|
|
110
|
+
expect(topology.root).toBe(root._nodeIndex);
|
|
111
|
+
expect(topology.buffers.length).toBeGreaterThanOrEqual(topology.count);
|
|
112
|
+
expect(topology.buffers.length & (topology.buffers.length - 1)).toBe(0);
|
|
113
|
+
expect(topology.firstChild).toHaveLength(topology.buffers.length);
|
|
114
|
+
expect(topology.lastChild).toHaveLength(topology.buffers.length);
|
|
115
|
+
expect(topology.nextSibling).toHaveLength(topology.buffers.length);
|
|
116
|
+
expect(topology.firstChild[root._nodeIndex]).toBe(1);
|
|
117
|
+
expect(topology.lastChild[root._nodeIndex]).toBe(siblingCount);
|
|
118
|
+
|
|
119
|
+
for (let index = 0; index < siblings.length; index++) {
|
|
120
|
+
const sibling = siblings[index];
|
|
121
|
+
if (!sibling) throw new Error(`Missing sibling ${index}`);
|
|
122
|
+
const nodeIndex = index + 1;
|
|
123
|
+
expect(sibling._nodeIndex).toBe(nodeIndex);
|
|
124
|
+
expect(topology.buffers[nodeIndex]).toBe(sibling);
|
|
125
|
+
expect(topology.firstChild[nodeIndex]).toBe(NO_NODE);
|
|
126
|
+
expect(topology.lastChild[nodeIndex]).toBe(NO_NODE);
|
|
127
|
+
expect(topology.nextSibling[nodeIndex]).toBe(index + 1 < siblingCount ? nodeIndex + 1 : NO_NODE);
|
|
128
|
+
expectNoChildrenArray(sibling);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
expect(Array.from(iterateSpanChildren(root))).toEqual(siblings);
|
|
132
|
+
expect(collectWalk(root)).toEqual([root, ...siblings]);
|
|
133
|
+
expectNoChildrenArray(root);
|
|
134
|
+
topology.release();
|
|
135
|
+
}),
|
|
136
|
+
{ numRuns: 60 },
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('walks a 20,000-edge chain iteratively without consuming the JavaScript call stack', () => {
|
|
141
|
+
const runtime = createRuntimeRoot('deep-root');
|
|
142
|
+
const { root } = runtime;
|
|
143
|
+
const nodes = [root];
|
|
144
|
+
let parent = root;
|
|
145
|
+
const edgeCount = 20_000;
|
|
146
|
+
|
|
147
|
+
for (let depth = 0; depth < edgeCount; depth++) {
|
|
148
|
+
const child = addChild(runtime, parent);
|
|
149
|
+
nodes.push(child);
|
|
150
|
+
parent = child;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let visited = 0;
|
|
154
|
+
walkSpanTree(root, (buffer) => {
|
|
155
|
+
if (buffer !== nodes[visited]) throw new Error(`Preorder mismatch at depth ${visited}`);
|
|
156
|
+
visited++;
|
|
157
|
+
});
|
|
158
|
+
expect(visited).toBe(edgeCount + 1);
|
|
159
|
+
|
|
160
|
+
let iterated = 0;
|
|
161
|
+
for (const buffer of iterateSpanTree(root)) {
|
|
162
|
+
if (buffer !== nodes[iterated]) throw new Error(`Iterator preorder mismatch at depth ${iterated}`);
|
|
163
|
+
iterated++;
|
|
164
|
+
}
|
|
165
|
+
expect(iterated).toBe(edgeCount + 1);
|
|
166
|
+
|
|
167
|
+
const topology = root._traceRoot._topology;
|
|
168
|
+
for (let depth = 0; depth < nodes.length; depth++) {
|
|
169
|
+
const buffer = nodes[depth];
|
|
170
|
+
if (!buffer) throw new Error(`Missing buffer at depth ${depth}`);
|
|
171
|
+
expectNoChildrenArray(buffer);
|
|
172
|
+
expect(topology.nextSibling[buffer._nodeIndex]).toBe(NO_NODE);
|
|
173
|
+
const expectedChild = depth < edgeCount ? depth + 1 : NO_NODE;
|
|
174
|
+
expect(topology.firstChild[buffer._nodeIndex]).toBe(expectedChild);
|
|
175
|
+
expect(topology.lastChild[buffer._nodeIndex]).toBe(expectedChild);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('matches iterative model preorder and lane links for arbitrary trees', () => {
|
|
180
|
+
fc.assert(
|
|
181
|
+
fc.property(fc.array(fc.nat(), { maxLength: 192 }), (parentSeeds) => {
|
|
182
|
+
const runtime = createRuntimeRoot('property-root');
|
|
183
|
+
const { root } = runtime;
|
|
184
|
+
const buffers = [root];
|
|
185
|
+
const modelChildren: number[][] = [[]];
|
|
186
|
+
|
|
187
|
+
for (let offset = 0; offset < parentSeeds.length; offset++) {
|
|
188
|
+
const seed = parentSeeds[offset];
|
|
189
|
+
if (seed === undefined) throw new Error(`Missing parent seed ${offset}`);
|
|
190
|
+
const childNode = offset + 1;
|
|
191
|
+
const parentNode = seed % childNode;
|
|
192
|
+
const parentBuffer = buffers[parentNode];
|
|
193
|
+
const siblings = modelChildren[parentNode];
|
|
194
|
+
if (!parentBuffer || !siblings) throw new Error(`Missing generated parent ${parentNode}`);
|
|
195
|
+
const child = addChild(runtime, parentBuffer);
|
|
196
|
+
buffers.push(child);
|
|
197
|
+
siblings.push(childNode);
|
|
198
|
+
modelChildren.push([]);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const expectedPreorder: number[] = [];
|
|
202
|
+
const pending = [0];
|
|
203
|
+
while (pending.length > 0) {
|
|
204
|
+
const node = pending.pop();
|
|
205
|
+
if (node === undefined) throw new Error('Pending preorder node disappeared');
|
|
206
|
+
expectedPreorder.push(node);
|
|
207
|
+
const children = modelChildren[node];
|
|
208
|
+
if (!children) throw new Error(`Missing model lane ${node}`);
|
|
209
|
+
for (let index = children.length - 1; index >= 0; index--) {
|
|
210
|
+
const child = children[index];
|
|
211
|
+
if (child === undefined) throw new Error(`Missing modeled child ${index} of ${node}`);
|
|
212
|
+
pending.push(child);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const topology = root._traceRoot._topology;
|
|
217
|
+
expect(topology.count).toBe(buffers.length);
|
|
218
|
+
expect(collectWalk(root).map((buffer) => buffer._nodeIndex)).toEqual(expectedPreorder);
|
|
219
|
+
expect(Array.from(iterateSpanTree(root), (buffer) => buffer._nodeIndex)).toEqual(expectedPreorder);
|
|
220
|
+
|
|
221
|
+
for (let node = 0; node < buffers.length; node++) {
|
|
222
|
+
const buffer = buffers[node];
|
|
223
|
+
const children = modelChildren[node];
|
|
224
|
+
if (!buffer || !children) throw new Error(`Missing generated node ${node}`);
|
|
225
|
+
const first = children[0] ?? NO_NODE;
|
|
226
|
+
const last = children[children.length - 1] ?? NO_NODE;
|
|
227
|
+
expect(buffer._nodeIndex).toBe(node);
|
|
228
|
+
expect(topology.buffers[node]).toBe(buffer);
|
|
229
|
+
expect(topology.firstChild[node]).toBe(first);
|
|
230
|
+
expect(topology.lastChild[node]).toBe(last);
|
|
231
|
+
expect(Array.from(iterateSpanChildren(buffer), (child) => child._nodeIndex)).toEqual(children);
|
|
232
|
+
expectNoChildrenArray(buffer);
|
|
233
|
+
|
|
234
|
+
for (let position = 0; position < children.length; position++) {
|
|
235
|
+
const child = children[position];
|
|
236
|
+
if (child === undefined) throw new Error(`Missing child ${position} of ${node}`);
|
|
237
|
+
expect(topology.nextSibling[child]).toBe(children[position + 1] ?? NO_NODE);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
topology.release();
|
|
242
|
+
}),
|
|
243
|
+
{ numRuns: 100 },
|
|
244
|
+
);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('keeps every overflow chain contiguous on its logical node without arena registration', () => {
|
|
248
|
+
const runtime = createRuntimeRoot('overflow-root');
|
|
249
|
+
const { root } = runtime;
|
|
250
|
+
const rootOverflow = runtime.tracer.bufferStrategy.createOverflowBuffer(root);
|
|
251
|
+
const rootOverflowTail = runtime.tracer.bufferStrategy.createOverflowBuffer(rootOverflow);
|
|
252
|
+
const firstChild = addChild(runtime, root);
|
|
253
|
+
const secondChild = addChild(runtime, root);
|
|
254
|
+
const grandchild = addChild(runtime, firstChild);
|
|
255
|
+
const childOverflow = runtime.tracer.bufferStrategy.createOverflowBuffer(firstChild);
|
|
256
|
+
const grandchildOverflow = runtime.tracer.bufferStrategy.createOverflowBuffer(grandchild);
|
|
257
|
+
const topology = root._traceRoot._topology;
|
|
258
|
+
|
|
259
|
+
expect(topology.count).toBe(4);
|
|
260
|
+
expect(rootOverflow._nodeIndex).toBe(root._nodeIndex);
|
|
261
|
+
expect(rootOverflowTail._nodeIndex).toBe(root._nodeIndex);
|
|
262
|
+
expect(childOverflow._nodeIndex).toBe(firstChild._nodeIndex);
|
|
263
|
+
expect(grandchildOverflow._nodeIndex).toBe(grandchild._nodeIndex);
|
|
264
|
+
expect(topology.buffers[root._nodeIndex]).toBe(root);
|
|
265
|
+
expect(topology.buffers[firstChild._nodeIndex]).toBe(firstChild);
|
|
266
|
+
expect(topology.buffers[grandchild._nodeIndex]).toBe(grandchild);
|
|
267
|
+
expect(topology.buffers.slice(0, topology.count)).toEqual([root, firstChild, secondChild, grandchild]);
|
|
268
|
+
expect(Array.from(iterateSpanChildren(root))).toEqual([firstChild, secondChild]);
|
|
269
|
+
expect(collectWalk(root)).toEqual([
|
|
270
|
+
root,
|
|
271
|
+
rootOverflow,
|
|
272
|
+
rootOverflowTail,
|
|
273
|
+
firstChild,
|
|
274
|
+
childOverflow,
|
|
275
|
+
grandchild,
|
|
276
|
+
grandchildOverflow,
|
|
277
|
+
secondChild,
|
|
278
|
+
]);
|
|
279
|
+
|
|
280
|
+
for (const buffer of [rootOverflow, rootOverflowTail, childOverflow, grandchildOverflow]) {
|
|
281
|
+
topology.assertLive(buffer);
|
|
282
|
+
expect(buffer._topologyGeneration).toBe(topology.generation);
|
|
283
|
+
expectNoChildrenArray(buffer);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('clears the arena on release, rejects every stale handle, and registers a fresh generation', () => {
|
|
288
|
+
const runtime = createRuntimeRoot('release-root');
|
|
289
|
+
const { root } = runtime;
|
|
290
|
+
const child = addChild(runtime, root);
|
|
291
|
+
const overflow = runtime.tracer.bufferStrategy.createOverflowBuffer(child);
|
|
292
|
+
const topology = root._traceRoot._topology;
|
|
293
|
+
const laneCapacity = topology.buffers.length;
|
|
294
|
+
const releasedGeneration = topology.generation;
|
|
295
|
+
|
|
296
|
+
topology.release();
|
|
297
|
+
|
|
298
|
+
expect(topology.count).toBe(0);
|
|
299
|
+
expect(topology.root).toBe(NO_NODE);
|
|
300
|
+
expect(topology.generation).toBe(releasedGeneration + 1);
|
|
301
|
+
expect(topology.buffers).toHaveLength(laneCapacity);
|
|
302
|
+
for (let index = 0; index < laneCapacity; index++) {
|
|
303
|
+
expect(topology.buffers[index]).toBeUndefined();
|
|
304
|
+
expect(topology.firstChild[index]).toBe(NO_NODE);
|
|
305
|
+
expect(topology.lastChild[index]).toBe(NO_NODE);
|
|
306
|
+
expect(topology.nextSibling[index]).toBe(NO_NODE);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
expect(() => topology.assertLive(root)).toThrow('stale');
|
|
310
|
+
expect(() => topology.assertLive(child)).toThrow('stale');
|
|
311
|
+
expect(() => topology.assertLive(overflow)).toThrow('stale');
|
|
312
|
+
expect(() => topology.registerChild(root, child)).toThrow('stale');
|
|
313
|
+
expect(() => topology.adoptOverflow(root, overflow)).toThrow('stale');
|
|
314
|
+
expect(() => walkSpanTree(root, () => undefined)).toThrow('stale');
|
|
315
|
+
expect(() => iterateSpanChildren(root).next()).toThrow('stale');
|
|
316
|
+
expect(() => iterateSpanTree(root).next()).toThrow('stale');
|
|
317
|
+
|
|
318
|
+
const freshRoot = runtime.tracer.bufferStrategy.createSpanBuffer(
|
|
319
|
+
root._logSchema,
|
|
320
|
+
root._traceRoot,
|
|
321
|
+
root._opMetadata,
|
|
322
|
+
8,
|
|
323
|
+
);
|
|
324
|
+
expect(freshRoot._nodeIndex).toBe(0);
|
|
325
|
+
expect(freshRoot._topologyGeneration).toBe(releasedGeneration + 1);
|
|
326
|
+
expect(topology.root).toBe(0);
|
|
327
|
+
expect(topology.count).toBe(1);
|
|
328
|
+
expect(topology.buffers[0]).toBe(freshRoot);
|
|
329
|
+
topology.assertLive(freshRoot);
|
|
330
|
+
|
|
331
|
+
const freshChild = addChild(runtime, freshRoot);
|
|
332
|
+
expect(freshChild._nodeIndex).toBe(1);
|
|
333
|
+
expect(topology.firstChild[0]).toBe(1);
|
|
334
|
+
expect(topology.lastChild[0]).toBe(1);
|
|
335
|
+
expect(topology.nextSibling[1]).toBe(NO_NODE);
|
|
336
|
+
expect(() => topology.registerRoot(freshChild)).toThrow('already registered');
|
|
337
|
+
expect(() => topology.assertLive(root)).toThrow('stale');
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('keeps Arrow, facts, and queryable spans in the real traced arena preorder', async () => {
|
|
341
|
+
const tracer = createTracer();
|
|
342
|
+
await tracer.trace('root', async (root) => {
|
|
343
|
+
root.log.info('root-event');
|
|
344
|
+
await root.span('child-a', async (child) => {
|
|
345
|
+
child.log.info('child-a-event');
|
|
346
|
+
await child.span('grandchild', (grandchild) => {
|
|
347
|
+
grandchild.log.info('grandchild-event');
|
|
348
|
+
return grandchild.ok(null);
|
|
349
|
+
});
|
|
350
|
+
return child.ok(null);
|
|
351
|
+
});
|
|
352
|
+
await root.span('child-b', (child) => {
|
|
353
|
+
child.log.info('child-b-event');
|
|
354
|
+
return child.ok(null);
|
|
355
|
+
});
|
|
356
|
+
return root.ok(null);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
const root = tracer.queue[0];
|
|
360
|
+
if (!root) throw new Error('Expected completed traced root');
|
|
361
|
+
expect(collectWalk(root).map((buffer) => buffer._nodeIndex)).toEqual([0, 1, 2, 3]);
|
|
362
|
+
for (const buffer of collectWalk(root)) expectNoChildrenArray(buffer);
|
|
363
|
+
|
|
364
|
+
const table = convertSpanTreeToArrowTable(root);
|
|
365
|
+
expect(spanStartNames(table)).toEqual(['root', 'child-a', 'grandchild', 'child-b']);
|
|
366
|
+
|
|
367
|
+
const startedFacts = Array.from(extractFacts(root, { includeMetrics: false })).filter((fact) =>
|
|
368
|
+
fact.endsWith(': started'),
|
|
369
|
+
);
|
|
370
|
+
expect(startedFacts).toEqual([
|
|
371
|
+
'span:root: started',
|
|
372
|
+
'span:child-a: started',
|
|
373
|
+
'span:grandchild: started',
|
|
374
|
+
'span:child-b: started',
|
|
375
|
+
]);
|
|
376
|
+
|
|
377
|
+
const queryable = querySpan(root);
|
|
378
|
+
expect(queryable.name).toBe('root');
|
|
379
|
+
expect(queryable.children.map((child) => child.name)).toEqual(['child-a', 'child-b']);
|
|
380
|
+
expect(queryable.names()).toEqual(['child-a', 'grandchild', 'child-b']);
|
|
381
|
+
expect(queryable.find('grandchild')?.name).toBe('grandchild');
|
|
382
|
+
});
|
|
383
|
+
});
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { describe, expect, it } from 'bun:test';
|
|
7
|
+
import type { TagWriter } from '../codegen/fixedPositionWriterGenerator.js';
|
|
7
8
|
import { defineOpContext } from '../defineOpContext.js';
|
|
8
9
|
import { defineCodeError } from '../result.js';
|
|
9
10
|
import { S } from '../schema/builder.js';
|
|
10
11
|
import { defineLogSchema } from '../schema/defineLogSchema.js';
|
|
12
|
+
import type { InferSchema } from '../schema/types.js';
|
|
13
|
+
import type { FluentLogEntry } from '../spanContext.js';
|
|
11
14
|
import { TestTracer } from '../tracers/TestTracer.js';
|
|
12
15
|
import { createTestTracerOptions } from './test-helpers.js';
|
|
13
16
|
|
|
@@ -20,6 +23,36 @@ const testSchema = defineLogSchema({
|
|
|
20
23
|
customField: S.category(),
|
|
21
24
|
});
|
|
22
25
|
|
|
26
|
+
const inlineEnumSchema = defineLogSchema({
|
|
27
|
+
outcome: S.enum(['failure', 'success']),
|
|
28
|
+
category: S.category(),
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
type InlineEnumOutcome = InferSchema<typeof inlineEnumSchema>['outcome'];
|
|
32
|
+
|
|
33
|
+
function assertInlineEnumInference(
|
|
34
|
+
outcome: InlineEnumOutcome,
|
|
35
|
+
category: string,
|
|
36
|
+
tag: TagWriter<typeof inlineEnumSchema>,
|
|
37
|
+
log: FluentLogEntry<typeof inlineEnumSchema>,
|
|
38
|
+
): void {
|
|
39
|
+
const exactOutcome: 'failure' | 'success' = outcome;
|
|
40
|
+
|
|
41
|
+
tag.outcome('failure').outcome('success');
|
|
42
|
+
log.outcome('failure').outcome('success');
|
|
43
|
+
tag.category(category);
|
|
44
|
+
log.category(category);
|
|
45
|
+
|
|
46
|
+
// @ts-expect-error - enum setters must reject values outside the inferred literal union
|
|
47
|
+
tag.outcome('pending');
|
|
48
|
+
// @ts-expect-error - enum setters must reject values outside the inferred literal union
|
|
49
|
+
log.outcome('pending');
|
|
50
|
+
|
|
51
|
+
void exactOutcome;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void assertInlineEnumInference;
|
|
55
|
+
|
|
23
56
|
// Create op context factory
|
|
24
57
|
const opContext = defineOpContext({
|
|
25
58
|
logSchema: testSchema,
|
|
@@ -134,4 +167,34 @@ describe('Type Narrowing with FluentResult', () => {
|
|
|
134
167
|
expect(output.value).toBe('VALIDATION_ERROR');
|
|
135
168
|
}
|
|
136
169
|
});
|
|
170
|
+
it('preserves schema-specific writer and result inference without casts', async () => {
|
|
171
|
+
const { trace } = createTestTracer();
|
|
172
|
+
|
|
173
|
+
const testOp = defineOp('writerInference', (ctx) => {
|
|
174
|
+
const tag = ctx.tag.userId('tag-user').customField('tag-custom');
|
|
175
|
+
tag.userId('tag-user-updated');
|
|
176
|
+
|
|
177
|
+
const log = ctx.log.info('inferred log').userId('log-user').customField('log-custom');
|
|
178
|
+
log.warn('inferred warning');
|
|
179
|
+
|
|
180
|
+
const ok = ctx.ok({ id: 789 }).with({ userId: 'result-user' }).message('Result succeeded');
|
|
181
|
+
if (!ok.success) throw new Error('expected inferred Ok');
|
|
182
|
+
const id: number = ok.value.id;
|
|
183
|
+
|
|
184
|
+
const err = ctx
|
|
185
|
+
.err(TEST_ERROR({ field: 'writer', reason: 'expected' }))
|
|
186
|
+
.with({ customField: 'result-error' })
|
|
187
|
+
.message('Result failed');
|
|
188
|
+
if (err.success) throw new Error('expected inferred Err');
|
|
189
|
+
const code: 'TEST_ERROR' = err.error.code;
|
|
190
|
+
const field: string = err.error.field;
|
|
191
|
+
|
|
192
|
+
return ctx.ok({ id, code, field });
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const output = await trace('writerInference', testOp);
|
|
196
|
+
expect(output.success).toBe(true);
|
|
197
|
+
if (!output.success) throw new Error('expected writer inference operation to succeed');
|
|
198
|
+
expect(output.value).toEqual({ id: 789, code: 'TEST_ERROR', field: 'writer' });
|
|
199
|
+
});
|
|
137
200
|
});
|