@cosmicdrift/kumiko-framework 0.133.0 → 0.134.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/package.json +2 -2
- package/src/engine/__tests__/boot-validator-dashboard.test.ts +136 -2
- package/src/engine/__tests__/boot-validator-located-timestamps.test.ts +3 -19
- package/src/engine/__tests__/factories-time.test.ts +2 -66
- package/src/engine/__tests__/{visual-tree-patterns.test.ts → tree-actions-patterns.test.ts} +4 -84
- package/src/engine/boot-validator/entity-handler.ts +5 -4
- package/src/engine/boot-validator/screens-nav.ts +112 -16
- package/src/engine/define-feature.ts +3 -17
- package/src/engine/factories.ts +2 -49
- package/src/engine/feature-ast/extractors/index.ts +1 -4
- package/src/engine/feature-ast/extractors/round6.ts +2 -36
- package/src/engine/feature-ast/parse.ts +1 -4
- package/src/engine/feature-ast/patch.ts +2 -5
- package/src/engine/feature-ast/patterns.ts +0 -14
- package/src/engine/feature-ast/render.ts +1 -9
- package/src/engine/index.ts +0 -1
- package/src/engine/pattern-library/__tests__/library.test.ts +0 -3
- package/src/engine/pattern-library/library.ts +0 -19
- package/src/engine/registry.ts +6 -16
- package/src/engine/types/feature.ts +3 -33
- package/src/engine/types/fields.ts +5 -4
- package/src/engine/types/index.ts +5 -0
- package/src/engine/types/screen.ts +64 -1
- package/src/engine/types/workspace.ts +0 -7
- package/src/errors/classes.ts +1 -1
- package/src/errors/field-issue.ts +0 -3
- package/src/errors/index.ts +0 -1
- package/src/i18n/required-surface-keys.ts +29 -10
- package/src/observability/__tests__/recording-tracer.test.ts +6 -4
- package/src/observability/noop-provider.ts +0 -9
- package/src/observability/recording-tracer.ts +0 -12
- package/src/observability/types/span.ts +0 -6
- package/src/time/tz-context.ts +1 -1
- package/src/ui-types/index.ts +5 -0
- package/src/bun-db/__tests__/bun-test-stack.ts +0 -6
- package/src/db/row-helpers.ts +0 -4
- package/src/engine/feature-ast/__tests__/visual-tree-parse.test.ts +0 -184
|
@@ -87,11 +87,13 @@ describe("RecordingTracer", () => {
|
|
|
87
87
|
expect(recorded).toHaveLength(1);
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
it("
|
|
90
|
+
it("startSpan with parent context continues an upstream trace", () => {
|
|
91
91
|
const { tracer, recorded } = makeTracer();
|
|
92
|
-
const span = tracer.
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
const span = tracer.startSpan("child", {
|
|
93
|
+
parent: {
|
|
94
|
+
traceId: "aabbccddeeff00112233445566778899",
|
|
95
|
+
spanId: "1122334455667788",
|
|
96
|
+
},
|
|
95
97
|
});
|
|
96
98
|
span.end();
|
|
97
99
|
expect(recorded[0]?.traceId).toBe("aabbccddeeff00112233445566778899");
|
|
@@ -5,7 +5,6 @@ import type {
|
|
|
5
5
|
Meter,
|
|
6
6
|
MetricDefinition,
|
|
7
7
|
ObservabilityProvider,
|
|
8
|
-
SerializedTraceContext,
|
|
9
8
|
Span,
|
|
10
9
|
SpanStatus,
|
|
11
10
|
StartSpanOptions,
|
|
@@ -68,14 +67,6 @@ class NoopTracer implements Tracer {
|
|
|
68
67
|
getActiveSpan(): Span | undefined {
|
|
69
68
|
return undefined;
|
|
70
69
|
}
|
|
71
|
-
|
|
72
|
-
startSpanFromContext(
|
|
73
|
-
name: string,
|
|
74
|
-
_context: SerializedTraceContext,
|
|
75
|
-
_options?: StartSpanOptions,
|
|
76
|
-
): Span {
|
|
77
|
-
return new NoopSpan(name, undefined);
|
|
78
|
-
}
|
|
79
70
|
}
|
|
80
71
|
|
|
81
72
|
class NoopCounter implements Counter {
|
|
@@ -175,18 +175,6 @@ export class RecordingTracer implements Tracer {
|
|
|
175
175
|
getActiveSpan(): Span | undefined {
|
|
176
176
|
return observabilityContext.getActiveSpan();
|
|
177
177
|
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* @deprecated Prefer `startSpan(name, { parent: context })`. Retained as a
|
|
181
|
-
* thin alias for call-sites that pre-date the unified StartSpanOptions.
|
|
182
|
-
*/
|
|
183
|
-
startSpanFromContext(
|
|
184
|
-
name: string,
|
|
185
|
-
context: SerializedTraceContext,
|
|
186
|
-
options?: StartSpanOptions,
|
|
187
|
-
): Span {
|
|
188
|
-
return this.startSpan(name, { ...options, parent: context });
|
|
189
|
-
}
|
|
190
178
|
}
|
|
191
179
|
|
|
192
180
|
// Helper to serialize an active Span into the cross-process format.
|
|
@@ -55,10 +55,4 @@ export interface Tracer {
|
|
|
55
55
|
): Promise<T>;
|
|
56
56
|
// Current active span from AsyncLocalStorage, or undefined.
|
|
57
57
|
getActiveSpan(): Span | undefined;
|
|
58
|
-
// @deprecated Prefer `startSpan(name, { parent: context })`.
|
|
59
|
-
startSpanFromContext(
|
|
60
|
-
name: string,
|
|
61
|
-
context: SerializedTraceContext,
|
|
62
|
-
options?: StartSpanOptions,
|
|
63
|
-
): Span;
|
|
64
58
|
}
|
package/src/time/tz-context.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import type { GeoAddress, GeoCoordinates, GeoTzProvider } from "./geo-tz";
|
|
18
18
|
import { ensureTemporalPolyfill, getTemporal } from "./polyfill";
|
|
19
19
|
|
|
20
|
-
// JSON-Form für Wall-Clock+TZ — siehe
|
|
20
|
+
// JSON-Form für Wall-Clock+TZ — siehe createLocatedTimestampField() in
|
|
21
21
|
// engine/factories.ts. Zwei Felder, idiotensicher.
|
|
22
22
|
export type LocatedTimestampJson = {
|
|
23
23
|
/** Wall-Clock-ISO ohne Offset, z.B. "2026-04-03T10:00:00" */
|
package/src/ui-types/index.ts
CHANGED
|
@@ -47,9 +47,14 @@ export type {
|
|
|
47
47
|
CustomScreenDefinition,
|
|
48
48
|
CustomScreenRoute,
|
|
49
49
|
DashboardChartPanel,
|
|
50
|
+
DashboardCustomPanel,
|
|
51
|
+
DashboardFeedPanel,
|
|
52
|
+
DashboardFilterDefinition,
|
|
50
53
|
DashboardListPanel,
|
|
51
54
|
DashboardPanelDefinition,
|
|
55
|
+
DashboardProgressListPanel,
|
|
52
56
|
DashboardScreenDefinition,
|
|
57
|
+
DashboardStatGroupPanel,
|
|
53
58
|
DashboardStatPanel,
|
|
54
59
|
EditExtensionSection,
|
|
55
60
|
EditFieldSpec,
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// Provider-agnostic Test-Stack — re-exported from stack/test-stack.ts.
|
|
2
|
-
// setupBunTestStack / BunTestStack sind Aliase für setupTestStack / TestStack.
|
|
3
|
-
// "Bun" ist historisch, jetzt provider-neutral (DB_PROVIDER env).
|
|
4
|
-
|
|
5
|
-
export type { TestStack as BunTestStack } from "../../stack/test-stack";
|
|
6
|
-
export { setupTestStack as setupBunTestStack } from "../../stack/test-stack";
|
package/src/db/row-helpers.ts
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
// AST round-trip tests for the Visual-Tree patterns. Each test feeds
|
|
2
|
-
// a minimal inline-feature into parseSourceFile and asserts the
|
|
3
|
-
// extracted Pattern shape + the editability classification.
|
|
4
|
-
//
|
|
5
|
-
// Why split from visual-tree-patterns.test.ts (engine-level): that suite
|
|
6
|
-
// covers the registrar+registry runtime path. This suite covers the
|
|
7
|
-
// AST extractor + the Designer/AI consumers (renderPattern,
|
|
8
|
-
// getEditability, PATTERN_LIBRARY). Both halves must agree on shape.
|
|
9
|
-
|
|
10
|
-
import { describe, expect, test } from "bun:test";
|
|
11
|
-
import { Project } from "ts-morph";
|
|
12
|
-
import { parseSourceFile } from "../parse";
|
|
13
|
-
import { getEditability } from "../patterns";
|
|
14
|
-
import { renderPattern } from "../render";
|
|
15
|
-
|
|
16
|
-
function parseInline(source: string) {
|
|
17
|
-
const project = new Project({ skipAddingFilesFromTsConfig: true, useInMemoryFileSystem: true });
|
|
18
|
-
const sourceFile = project.createSourceFile("feature.ts", source);
|
|
19
|
-
return parseSourceFile(sourceFile);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
describe("parseSourceFile — r.treeActions extraction", () => {
|
|
23
|
-
test("extracts a static treeActions pattern from an inline action-map", () => {
|
|
24
|
-
const result = parseInline(`
|
|
25
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
26
|
-
defineFeature("text-content", (r) => {
|
|
27
|
-
r.treeActions({
|
|
28
|
-
edit: { args: { slug: "" as string } },
|
|
29
|
-
list: {},
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
`);
|
|
33
|
-
|
|
34
|
-
expect(result.errors).toEqual([]);
|
|
35
|
-
const treeActions = result.patterns.find((p) => p.kind === "treeActions");
|
|
36
|
-
expect(treeActions).toBeDefined();
|
|
37
|
-
expect(treeActions?.kind).toBe("treeActions");
|
|
38
|
-
if (treeActions?.kind === "treeActions") {
|
|
39
|
-
expect(treeActions.definitions).toEqual({
|
|
40
|
-
edit: { args: { slug: "" } },
|
|
41
|
-
list: {},
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("treeActions pattern is classified as static (Designer renders form)", () => {
|
|
47
|
-
const result = parseInline(`
|
|
48
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
49
|
-
defineFeature("x", (r) => { r.treeActions({ list: {} }); });
|
|
50
|
-
`);
|
|
51
|
-
const treeActions = result.patterns.find((p) => p.kind === "treeActions");
|
|
52
|
-
expect(treeActions).toBeDefined();
|
|
53
|
-
if (treeActions !== undefined) {
|
|
54
|
-
expect(getEditability(treeActions)).toBe("static");
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("missing first argument produces a parse-error, not a pattern", () => {
|
|
59
|
-
const result = parseInline(`
|
|
60
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
61
|
-
defineFeature("x", (r) => { r.treeActions(); });
|
|
62
|
-
`);
|
|
63
|
-
expect(result.patterns.find((p) => p.kind === "treeActions")).toBeUndefined();
|
|
64
|
-
expect(result.errors.some((e) => e.methodName === "treeActions")).toBe(true);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
test("non-object first argument (identifier ref) produces a parse-error", () => {
|
|
68
|
-
const result = parseInline(`
|
|
69
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
70
|
-
const actions = { list: {} };
|
|
71
|
-
defineFeature("x", (r) => { r.treeActions(actions); });
|
|
72
|
-
`);
|
|
73
|
-
expect(result.patterns.find((p) => p.kind === "treeActions")).toBeUndefined();
|
|
74
|
-
expect(result.errors.some((e) => e.methodName === "treeActions")).toBe(true);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test("renderPattern round-trips back to a valid r.treeActions(...) call", () => {
|
|
78
|
-
const result = parseInline(`
|
|
79
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
80
|
-
defineFeature("x", (r) => {
|
|
81
|
-
r.treeActions({ edit: { args: { slug: "" } }, list: {} });
|
|
82
|
-
});
|
|
83
|
-
`);
|
|
84
|
-
const treeActions = result.patterns.find((p) => p.kind === "treeActions");
|
|
85
|
-
expect(treeActions).toBeDefined();
|
|
86
|
-
if (treeActions !== undefined) {
|
|
87
|
-
const rendered = renderPattern(treeActions);
|
|
88
|
-
expect(rendered).toMatch(/^r\.treeActions\(/);
|
|
89
|
-
// renderValue darf identifier-safe Keys unquoted ausgeben — beide
|
|
90
|
-
// Schreibweisen sind valide TypeScript-Source.
|
|
91
|
-
expect(rendered).toMatch(/(["])edit\1|edit\s*:/);
|
|
92
|
-
expect(rendered).toMatch(/(["])slug\1|slug\s*:/);
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe("parseSourceFile — r.tree extraction", () => {
|
|
98
|
-
test("extracts an opaque tree pattern with the provider body as SourceLocation", () => {
|
|
99
|
-
const result = parseInline(`
|
|
100
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
101
|
-
defineFeature("text-content", (r) => {
|
|
102
|
-
r.tree((ctx) => (emit) => {
|
|
103
|
-
emit([{ label: "Marketing" }]);
|
|
104
|
-
return () => {};
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
`);
|
|
108
|
-
|
|
109
|
-
expect(result.errors).toEqual([]);
|
|
110
|
-
const tree = result.patterns.find((p) => p.kind === "tree");
|
|
111
|
-
expect(tree).toBeDefined();
|
|
112
|
-
if (tree?.kind === "tree") {
|
|
113
|
-
expect(tree.providerBody.raw).toContain("emit");
|
|
114
|
-
expect(tree.providerBody.raw).toContain("Marketing");
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test("tree pattern is classified as opaque (Designer renders read-only code-block)", () => {
|
|
119
|
-
const result = parseInline(`
|
|
120
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
121
|
-
defineFeature("x", (r) => { r.tree((ctx) => (emit) => () => {}); });
|
|
122
|
-
`);
|
|
123
|
-
const tree = result.patterns.find((p) => p.kind === "tree");
|
|
124
|
-
expect(tree).toBeDefined();
|
|
125
|
-
if (tree !== undefined) {
|
|
126
|
-
expect(getEditability(tree)).toBe("opaque");
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test("missing first argument produces a parse-error, not a pattern", () => {
|
|
131
|
-
const result = parseInline(`
|
|
132
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
133
|
-
defineFeature("x", (r) => { r.tree(); });
|
|
134
|
-
`);
|
|
135
|
-
expect(result.patterns.find((p) => p.kind === "tree")).toBeUndefined();
|
|
136
|
-
expect(result.errors.some((e) => e.methodName === "tree")).toBe(true);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
test("non-function first argument (identifier ref) produces a parse-error", () => {
|
|
140
|
-
const result = parseInline(`
|
|
141
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
142
|
-
const provider = (ctx: unknown) => (emit: unknown) => () => {};
|
|
143
|
-
defineFeature("x", (r) => { r.tree(provider); });
|
|
144
|
-
`);
|
|
145
|
-
expect(result.patterns.find((p) => p.kind === "tree")).toBeUndefined();
|
|
146
|
-
expect(result.errors.some((e) => e.methodName === "tree")).toBe(true);
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test("renderPattern round-trips back to a valid r.tree(...) call with the body verbatim", () => {
|
|
150
|
-
const result = parseInline(`
|
|
151
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
152
|
-
defineFeature("x", (r) => {
|
|
153
|
-
r.tree((ctx) => (emit) => { emit([]); return () => {}; });
|
|
154
|
-
});
|
|
155
|
-
`);
|
|
156
|
-
const tree = result.patterns.find((p) => p.kind === "tree");
|
|
157
|
-
expect(tree).toBeDefined();
|
|
158
|
-
if (tree !== undefined) {
|
|
159
|
-
const rendered = renderPattern(tree);
|
|
160
|
-
expect(rendered).toMatch(/^r\.tree\(/);
|
|
161
|
-
expect(rendered).toContain("emit");
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
describe("Combined — feature with both r.treeActions and r.tree", () => {
|
|
167
|
-
test("both patterns coexist in the parse output, source-order preserved", () => {
|
|
168
|
-
const result = parseInline(`
|
|
169
|
-
import { defineFeature } from "@cosmicdrift/kumiko-framework/engine";
|
|
170
|
-
defineFeature("text-content", (r) => {
|
|
171
|
-
r.treeActions({ edit: { args: { slug: "" } } });
|
|
172
|
-
r.tree((ctx) => (emit) => { emit([{ label: "Marketing" }]); return () => {}; });
|
|
173
|
-
});
|
|
174
|
-
`);
|
|
175
|
-
|
|
176
|
-
expect(result.errors).toEqual([]);
|
|
177
|
-
const kinds = result.patterns.map((p) => p.kind);
|
|
178
|
-
const idxActions = kinds.indexOf("treeActions");
|
|
179
|
-
const idxTree = kinds.indexOf("tree");
|
|
180
|
-
expect(idxActions).toBeGreaterThanOrEqual(0);
|
|
181
|
-
expect(idxTree).toBeGreaterThanOrEqual(0);
|
|
182
|
-
expect(idxActions).toBeLessThan(idxTree);
|
|
183
|
-
});
|
|
184
|
-
});
|