@uptimizr/metrics 0.0.0 → 0.2.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/AGENTS.md +129 -0
- package/README.md +43 -21
- package/dist/envelopes.d.ts +280 -0
- package/dist/envelopes.d.ts.map +1 -0
- package/dist/envelopes.js +289 -0
- package/dist/envelopes.js.map +1 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/dist/narrative.d.ts +164 -0
- package/dist/narrative.d.ts.map +1 -0
- package/dist/narrative.js +150 -0
- package/dist/narrative.js.map +1 -0
- package/dist/panelSpec.d.ts +145 -0
- package/dist/panelSpec.d.ts.map +1 -0
- package/dist/panelSpec.js +286 -0
- package/dist/panelSpec.js.map +1 -0
- package/dist/query.d.ts +192 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +461 -0
- package/dist/query.js.map +1 -0
- package/dist/registry.d.ts +948 -98
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +954 -13
- package/dist/registry.js.map +1 -1
- package/llms.txt +12 -3
- package/package.json +4 -4
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The **session narrative** contract (ADR 0051 §7, design sketch §G.2).
|
|
3
|
+
*
|
|
4
|
+
* A narrative is an ordered, compacted account of what one session did — scene
|
|
5
|
+
* changes, mesh dwell, interactions, performance dips, errors and the reason it
|
|
6
|
+
* ended — with every timestamp relative to the session's first event. It exists
|
|
7
|
+
* because the two things an agent could otherwise ask for are both useless to
|
|
8
|
+
* it: the aggregate metrics say nothing about *one* session, and the raw NDJSON
|
|
9
|
+
* stream is tens of thousands of lines of sampled telemetry.
|
|
10
|
+
*
|
|
11
|
+
* Only the **shapes and bounds** live here, in the dependency-free registry
|
|
12
|
+
* package, because three packages need them and none of them may depend on the
|
|
13
|
+
* others:
|
|
14
|
+
*
|
|
15
|
+
* - `@uptimizr/db` computes a narrative from `AnyEvent[]` (`src/narrative/`);
|
|
16
|
+
* - the collector serves it on `GET /api/v1/sessions/:id/narrative` and bounds
|
|
17
|
+
* its querystring with the same numbers;
|
|
18
|
+
* - the registry entry below it (`session_narrative`) advertises the row schema
|
|
19
|
+
* to OpenAPI, the agent tool catalog and the docs tables.
|
|
20
|
+
*
|
|
21
|
+
* **Privacy (ADR 0003).** A narrative is derived from raw per-session events, so
|
|
22
|
+
* it is reachable only on a collector with `ENABLE_RAW_SESSION_RETENTION` and
|
|
23
|
+
* only with a key holding `query:raw`. Even then it is a *projection*: an entry
|
|
24
|
+
* carries a relative timestamp, a templated one-line summary and at most a mesh
|
|
25
|
+
* name, a scene id and a custom-event name. It never carries the visitor hash,
|
|
26
|
+
* the page URL, `pageMeta`, positions, rays, or anything from the `device` block
|
|
27
|
+
* beyond the engine/graphics API. Custom-event **property values** are excluded
|
|
28
|
+
* unless the caller explicitly asks for them; the property *keys* are always
|
|
29
|
+
* safe to show because they are developer-chosen field names.
|
|
30
|
+
*/
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
/**
|
|
33
|
+
* What one narrative entry is about.
|
|
34
|
+
*
|
|
35
|
+
* - `scene` — the session entered a scene (`session_start` or `scene_change`).
|
|
36
|
+
* - `dwell` — a mesh held the viewer's attention for at least `minDwellMs`,
|
|
37
|
+
* aggregated across the session from `mesh_visibility` / `hover_dwell`.
|
|
38
|
+
* - `interaction` — a discrete act: a mesh interaction, a click that hit a mesh,
|
|
39
|
+
* a named input action, or a custom event.
|
|
40
|
+
* - `perf_dip` — a run of consecutive `frame_perf` samples below `fpsThreshold`,
|
|
41
|
+
* collapsed into one entry with the run's duration and sample count.
|
|
42
|
+
* - `error` — a `runtime_error`, message truncated.
|
|
43
|
+
* - `diagnostic` — a `graphics_diagnostic`, by category and severity.
|
|
44
|
+
* - `capability` — a `capability_change` (quality drop, tracking loss, backend
|
|
45
|
+
* fallback).
|
|
46
|
+
* - `xr` — entering/leaving immersive input, and a boundary-proximity summary.
|
|
47
|
+
* - `end` — how the session finished (`session_end` reason), when it reported.
|
|
48
|
+
* - `summary` — the single closing entry carrying the session's totals.
|
|
49
|
+
*/
|
|
50
|
+
export const NARRATIVE_ENTRY_KINDS = [
|
|
51
|
+
"scene",
|
|
52
|
+
"dwell",
|
|
53
|
+
"interaction",
|
|
54
|
+
"perf_dip",
|
|
55
|
+
"error",
|
|
56
|
+
"diagnostic",
|
|
57
|
+
"capability",
|
|
58
|
+
"xr",
|
|
59
|
+
"end",
|
|
60
|
+
"summary",
|
|
61
|
+
];
|
|
62
|
+
/** {@link NARRATIVE_ENTRY_KINDS} as a Zod enum. */
|
|
63
|
+
export const narrativeEntryKindSchema = z.enum(NARRATIVE_ENTRY_KINDS);
|
|
64
|
+
/**
|
|
65
|
+
* The named things an entry points at. Deliberately only three, and all three
|
|
66
|
+
* are developer-assigned identifiers rather than anything about a person: the
|
|
67
|
+
* mesh/object name, the scene id, and the name of a custom event or input
|
|
68
|
+
* action.
|
|
69
|
+
*/
|
|
70
|
+
export const narrativeRefsSchema = z.object({
|
|
71
|
+
mesh: z.string().optional(),
|
|
72
|
+
scene: z.string().optional(),
|
|
73
|
+
name: z.string().optional(),
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* Session-wide totals, carried on the closing `summary` entry so a reader that
|
|
77
|
+
* only keeps the last line still knows the shape of what it just read.
|
|
78
|
+
*/
|
|
79
|
+
export const sessionNarrativeTotalsSchema = z.object({
|
|
80
|
+
/** Events the narrative was compacted from (every type, before filtering). */
|
|
81
|
+
events: z.number().int().nonnegative(),
|
|
82
|
+
/** Wall-clock span of the session, first to last event. */
|
|
83
|
+
durationMs: z.number().int().nonnegative(),
|
|
84
|
+
/** Distinct scene ids visited. */
|
|
85
|
+
scenes: z.number().int().nonnegative(),
|
|
86
|
+
/** Distinct mesh names the session touched or dwelled on. */
|
|
87
|
+
meshes: z.number().int().nonnegative(),
|
|
88
|
+
/** Interaction entries (mesh interactions, clicks, input actions, customs). */
|
|
89
|
+
interactions: z.number().int().nonnegative(),
|
|
90
|
+
/** Performance dips detected. */
|
|
91
|
+
dips: z.number().int().nonnegative(),
|
|
92
|
+
/** Runtime errors plus `error`/`fatal` graphics diagnostics. */
|
|
93
|
+
errors: z.number().int().nonnegative(),
|
|
94
|
+
});
|
|
95
|
+
/**
|
|
96
|
+
* One line of the narrative.
|
|
97
|
+
*
|
|
98
|
+
* `summary` is a **templated** one-line sentence composed from the fields
|
|
99
|
+
* already on the entry — never free text copied out of an event payload — so
|
|
100
|
+
* that what an LLM reads cannot contain anything the structured fields do not.
|
|
101
|
+
*/
|
|
102
|
+
export const sessionNarrativeEntrySchema = z.object({
|
|
103
|
+
/** Milliseconds since the session's first event. Never a wall-clock time. */
|
|
104
|
+
tMs: z.number().int().nonnegative(),
|
|
105
|
+
kind: narrativeEntryKindSchema,
|
|
106
|
+
/** One templated line of prose describing the entry. */
|
|
107
|
+
summary: z.string(),
|
|
108
|
+
refs: narrativeRefsSchema,
|
|
109
|
+
/** How long the entry spans, for the kinds that cover a stretch of time. */
|
|
110
|
+
durationMs: z.number().int().nonnegative().optional(),
|
|
111
|
+
/** How many source events the entry collapses (dwell samples, dip frames, …). */
|
|
112
|
+
count: z.number().int().nonnegative().optional(),
|
|
113
|
+
/** Session totals. Present on the closing `summary` entry only. */
|
|
114
|
+
totals: sessionNarrativeTotalsSchema.optional(),
|
|
115
|
+
/**
|
|
116
|
+
* Whether entries were dropped to honour `maxEntries`. Present on the closing
|
|
117
|
+
* `summary` entry only, so the bound is always visible to whoever reads the
|
|
118
|
+
* last line.
|
|
119
|
+
*/
|
|
120
|
+
truncated: z.boolean().optional(),
|
|
121
|
+
});
|
|
122
|
+
/**
|
|
123
|
+
* The bounds and defaults every consumer shares. The collector's querystring
|
|
124
|
+
* schema, the generated tool's input schema and the compaction function all read
|
|
125
|
+
* them from here, so "the default dwell floor" is one number rather than three.
|
|
126
|
+
*/
|
|
127
|
+
export const NARRATIVE_LIMITS = {
|
|
128
|
+
/** Default dwell floor: below this a mesh is a glance, not attention. */
|
|
129
|
+
defaultMinDwellMs: 1_000,
|
|
130
|
+
/** Largest dwell floor a caller may ask for (one hour). */
|
|
131
|
+
maxMinDwellMs: 3_600_000,
|
|
132
|
+
/** Default FPS floor below which a frame sample counts towards a dip. */
|
|
133
|
+
defaultFpsThreshold: 30,
|
|
134
|
+
/** Largest FPS floor a caller may ask for. */
|
|
135
|
+
maxFpsThreshold: 240,
|
|
136
|
+
/**
|
|
137
|
+
* Consecutive sub-threshold `frame_perf` samples before a dip is reported.
|
|
138
|
+
* Two, so a single unlucky sample (a tab switch, a GC pause) is not a story.
|
|
139
|
+
*/
|
|
140
|
+
dipMinSamples: 2,
|
|
141
|
+
/** Default entry cap — the "under 200 lines" bound issue #314 asks for. */
|
|
142
|
+
defaultMaxEntries: 200,
|
|
143
|
+
/** Hard cap: no caller can ask for an unbounded narrative (ADR 0051 §9). */
|
|
144
|
+
maxMaxEntries: 1_000,
|
|
145
|
+
/** Error/diagnostic messages are truncated to this many characters. */
|
|
146
|
+
maxMessageLength: 200,
|
|
147
|
+
/** At most this many custom-event property **keys** are listed per entry. */
|
|
148
|
+
maxCustomPropKeys: 12,
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=narrative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narrative.js","sourceRoot":"","sources":["../src/narrative.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,OAAO;IACP,OAAO;IACP,aAAa;IACb,UAAU;IACV,OAAO;IACP,YAAY;IACZ,YAAY;IACZ,IAAI;IACJ,KAAK;IACL,SAAS;CACD,CAAC;AAKX,mDAAmD;AACnD,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAKH;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IACnD,8EAA8E;IAC9E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACtC,2DAA2D;IAC3D,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC1C,kCAAkC;IAClC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACtC,6DAA6D;IAC7D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACtC,+EAA+E;IAC/E,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IAC5C,iCAAiC;IACjC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACpC,gEAAgE;IAChE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;CACvC,CAAC,CAAC;AAKH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAClD,6EAA6E;IAC7E,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE;IACnC,IAAI,EAAE,wBAAwB;IAC9B,wDAAwD;IACxD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,IAAI,EAAE,mBAAmB;IACzB,4EAA4E;IAC5E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IACrD,iFAAiF;IACjF,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,QAAQ,EAAE;IAChD,mEAAmE;IACnE,MAAM,EAAE,4BAA4B,CAAC,QAAQ,EAAE;IAC/C;;;;OAIG;IACH,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAC;AAKH;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,yEAAyE;IACzE,iBAAiB,EAAE,KAAK;IACxB,2DAA2D;IAC3D,aAAa,EAAE,SAAS;IACxB,yEAAyE;IACzE,mBAAmB,EAAE,EAAE;IACvB,8CAA8C;IAC9C,eAAe,EAAE,GAAG;IACpB;;;OAGG;IACH,aAAa,EAAE,CAAC;IAChB,2EAA2E;IAC3E,iBAAiB,EAAE,GAAG;IACtB,4EAA4E;IAC5E,aAAa,EAAE,KAAK;IACpB,uEAAuE;IACvE,gBAAgB,EAAE,GAAG;IACrB,6EAA6E;IAC7E,iBAAiB,EAAE,EAAE;CACb,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Registry validation for declarative panel specs** (ADR 0051 §7, sketch §G.3).
|
|
3
|
+
*
|
|
4
|
+
* The same split the query DSL makes, one level up. `@uptimizr/schema`'s
|
|
5
|
+
* `panelSpecV1Schema` answers "is this a well-formed spec?" — a known chart
|
|
6
|
+
* name, bounded strings, a closed query grammar. It cannot answer the question
|
|
7
|
+
* that actually decides whether the panel will *draw anything*: does this chart
|
|
8
|
+
* suit this metric's grain, and do these encoding columns exist in its result.
|
|
9
|
+
* Those are questions about the vocabulary, and the vocabulary is this package.
|
|
10
|
+
*
|
|
11
|
+
* So {@link validatePanelSpec} runs `validateQuery` over the spec's query and
|
|
12
|
+
* then adds the two checks only the registry can make. It returns objections as
|
|
13
|
+
* data in exactly the {@link QueryIssue} shape the DSL already uses, so the
|
|
14
|
+
* collector turns a bad spec into one `400` with the same body a bad query
|
|
15
|
+
* gets, and a test can assert on codes rather than prose.
|
|
16
|
+
*
|
|
17
|
+
* ## Why the chart is checked at all
|
|
18
|
+
*
|
|
19
|
+
* Because a pinned panel is read much later than it is written. A `line` over
|
|
20
|
+
* `top_meshes` is not a crash — it is a chart with no axis to walk along, which
|
|
21
|
+
* renders as *something*, and a week later somebody reads that something as a
|
|
22
|
+
* trend. Refusing it at pin time is the only moment anybody is paying attention.
|
|
23
|
+
*
|
|
24
|
+
* ## The compatibility rules, in words
|
|
25
|
+
*
|
|
26
|
+
* - `table` — every metric. Rows are rows; this is the honest fallback and the
|
|
27
|
+
* reason no metric is unpinnable.
|
|
28
|
+
* - `stat` — a metric whose result *is* one row: `project` grain with nothing
|
|
29
|
+
* keying the rows. One number, big. A `stat` over a ranked list would show
|
|
30
|
+
* the first row and silently hide the rest.
|
|
31
|
+
* - `bar` — a label to name each bar and a measure to size it, over a grain
|
|
32
|
+
* that is a *list* rather than a grid: the ranked grains (`mesh`, `scene`,
|
|
33
|
+
* `session`, `row`) plus `bucket`, which is what a histogram or a funnel
|
|
34
|
+
* already is. A spatial grid's key is a coordinate, and bars of coordinates
|
|
35
|
+
* say nothing.
|
|
36
|
+
* - `line` / `area` — an **ordered axis** to walk along: a column the registry
|
|
37
|
+
* marks `axis`, which it guarantees is exactly the `bucket`-grain metrics
|
|
38
|
+
* (`registry.test.ts` pins that). Everything else has an order chosen by the
|
|
39
|
+
* query, and a line drawn through a ranking is a lie about continuity.
|
|
40
|
+
* - `heatmap2d` — a `bin` grain: the metric already bins its input into a grid,
|
|
41
|
+
* which is the only thing the 2D heatmap canvas can paint.
|
|
42
|
+
* - `world3d` — a `voxel` grain, for the same reason in three dimensions.
|
|
43
|
+
*/
|
|
44
|
+
import type { PanelChartKind, PanelSpecV1, QueryV1 } from "@uptimizr/schema";
|
|
45
|
+
import { type MetricDefinition, type MetricId } from "./registry.js";
|
|
46
|
+
import { type QueryIssue, type QueryTier } from "./query.js";
|
|
47
|
+
/** Why a panel spec was rejected. Extends the DSL's codes rather than replacing them. */
|
|
48
|
+
export type PanelSpecIssueCode =
|
|
49
|
+
/** The `chart` cannot draw this metric's grain. */
|
|
50
|
+
"chart_grain_mismatch"
|
|
51
|
+
/** An `encoding` column the metric's result does not contain. */
|
|
52
|
+
| "unknown_encoding_column";
|
|
53
|
+
/** One objection to a panel spec: a DSL issue, or one of the two above. */
|
|
54
|
+
export type PanelSpecIssue = Omit<QueryIssue, "code"> & {
|
|
55
|
+
code: QueryIssue["code"] | PanelSpecIssueCode;
|
|
56
|
+
};
|
|
57
|
+
/** The outcome of validating a panel spec against the registry. */
|
|
58
|
+
export interface PanelSpecValidation {
|
|
59
|
+
/** Empty when the spec can be stored and rendered. */
|
|
60
|
+
issues: readonly PanelSpecIssue[];
|
|
61
|
+
/** The resolved metric, when the spec's query named one it could compile. */
|
|
62
|
+
metric?: MetricDefinition;
|
|
63
|
+
/** The tier the spec's query runs on, when it resolved. */
|
|
64
|
+
tier?: QueryTier;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* One row of the chart/grain compatibility table: which chart, what it needs,
|
|
68
|
+
* and the predicate that decides it.
|
|
69
|
+
*
|
|
70
|
+
* Declared as data rather than as a `switch` so the docs table, the validator
|
|
71
|
+
* and the `suggestChart` fallback all read from one place. `docs/` renders
|
|
72
|
+
* {@link PANEL_CHART_RULES} and `src/__tests__/panelSpec.test.ts` pins the
|
|
73
|
+
* rendering, so the published table cannot drift from the code that enforces it.
|
|
74
|
+
*/
|
|
75
|
+
export interface PanelChartRule {
|
|
76
|
+
chart: PanelChartKind;
|
|
77
|
+
/** What the chart needs from the metric, in words, for the error and the docs. */
|
|
78
|
+
requires: string;
|
|
79
|
+
/** Whether this metric can be drawn this way. */
|
|
80
|
+
accepts: (metric: MetricDefinition) => boolean;
|
|
81
|
+
}
|
|
82
|
+
/** The metric's ordered axis column, when it has one (only `bucket` grains do). */
|
|
83
|
+
export declare function axisColumn(metric: MetricDefinition): string | undefined;
|
|
84
|
+
/** The metric's row-naming column, when it has one. */
|
|
85
|
+
export declare function labelColumn(metric: MetricDefinition): string | undefined;
|
|
86
|
+
/** The metric's headline measure column, when it has one. */
|
|
87
|
+
export declare function measureColumn(metric: MetricDefinition): string | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* The chart/grain compatibility table. The single source of truth for the
|
|
90
|
+
* validator, the docs and the `suggestChart` fallback.
|
|
91
|
+
*/
|
|
92
|
+
export declare const PANEL_CHART_RULES: readonly PanelChartRule[];
|
|
93
|
+
/** Whether `chart` can draw `metric`. The predicate behind the table above. */
|
|
94
|
+
export declare function chartSuitsMetric(chart: PanelChartKind, metric: MetricDefinition): boolean;
|
|
95
|
+
/** Every chart that can draw this metric, in the table's order. */
|
|
96
|
+
export declare function chartsForMetric(metric: MetricDefinition): readonly PanelChartKind[];
|
|
97
|
+
/**
|
|
98
|
+
* The columns one row of this query's result carries.
|
|
99
|
+
*
|
|
100
|
+
* On the delegated tier that is the metric's declared `row` shape, unchanged —
|
|
101
|
+
* the canned builder runs and returns exactly what it always did. On the
|
|
102
|
+
* generic tier the builder projects the grouped dimensions plus the metric's
|
|
103
|
+
* declared measures instead, so the encoding has to be checked against *those*:
|
|
104
|
+
* a regrouped `top_meshes` has no `mesh` column when it was grouped by `source`.
|
|
105
|
+
*/
|
|
106
|
+
export declare function resultColumns(metric: MetricDefinition, query: QueryV1): readonly string[];
|
|
107
|
+
/**
|
|
108
|
+
* Check a structurally-valid panel spec against the registry.
|
|
109
|
+
*
|
|
110
|
+
* Runs the DSL's own validation first — a spec whose query cannot be answered
|
|
111
|
+
* is not a panel, whatever chart it asks for — and stops there if the metric
|
|
112
|
+
* did not resolve, because every remaining check is about that metric. Chart
|
|
113
|
+
* and encoding objections are then collected together, so an agent that got
|
|
114
|
+
* both wrong learns both in one round trip.
|
|
115
|
+
*/
|
|
116
|
+
export declare function validatePanelSpec(spec: PanelSpecV1): PanelSpecValidation;
|
|
117
|
+
/**
|
|
118
|
+
* The chart to pre-fill when an agent pins an answer it just computed.
|
|
119
|
+
*
|
|
120
|
+
* Pure, registry-only and deliberately unambitious: it reads the grain and
|
|
121
|
+
* picks the drawing that grain *is*. A voxelised metric is a world heatmap, a
|
|
122
|
+
* binned one is a 2D heatmap, a bucketed one is a line, a single record is a
|
|
123
|
+
* stat, a ranked list is bars — and anything left over is a table, which can
|
|
124
|
+
* always be drawn. The result always satisfies {@link chartSuitsMetric}, so the
|
|
125
|
+
* assistant's "Pin as panel" never proposes a spec the collector would refuse.
|
|
126
|
+
*
|
|
127
|
+
* `query` is taken so a *regrouped* metric is suggested on the shape it will
|
|
128
|
+
* actually return: `top_meshes` grouped by `source` is still a ranked list, but
|
|
129
|
+
* a generic-tier query that drops the metric's own label column should not be
|
|
130
|
+
* offered a bar it cannot name.
|
|
131
|
+
*/
|
|
132
|
+
export declare function suggestChart(metric: MetricDefinition | MetricId, query: QueryV1): PanelChartKind;
|
|
133
|
+
/**
|
|
134
|
+
* The default encoding for a chart over a metric: the metric's own axis or
|
|
135
|
+
* label on `x`, its headline measure on `y`.
|
|
136
|
+
*
|
|
137
|
+
* Shared by the assistant's pre-fill and by the renderer's fallback when a spec
|
|
138
|
+
* carries no `encoding` at all, so "what does this panel draw when nobody said"
|
|
139
|
+
* has exactly one answer.
|
|
140
|
+
*/
|
|
141
|
+
export declare function defaultEncoding(metric: MetricDefinition, chart: PanelChartKind): {
|
|
142
|
+
x?: string;
|
|
143
|
+
y?: string;
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=panelSpec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panelSpec.d.ts","sourceRoot":"","sources":["../src/panelSpec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAGL,KAAK,gBAAgB,EAErB,KAAK,QAAQ,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,YAAY,CAAC;AAiBpB,yFAAyF;AACzF,MAAM,MAAM,kBAAkB;AAC5B,mDAAmD;AACjD,sBAAsB;AACxB,iEAAiE;GAC/D,yBAAyB,CAAC;AAE9B,2EAA2E;AAC3E,MAAM,MAAM,cAAc,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG;IACtD,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG,kBAAkB,CAAC;CAC/C,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAClC,6EAA6E;IAC7E,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,2DAA2D;IAC3D,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,cAAc,CAAC;IACtB,kFAAkF;IAClF,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,OAAO,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,OAAO,CAAC;CAChD;AAOD,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAExE;AAED,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,GAAG,SAAS,CAE1E;AAED;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,cAAc,EAuCtD,CAAC;AAMF,+EAA+E;AAC/E,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAEzF;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,cAAc,EAAE,CAEnF;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAYzF;AA2BD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,mBAAmB,CAuCxE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,QAAQ,EAAE,KAAK,EAAE,OAAO,GAAG,cAAc,CA8BhG;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,EACxB,KAAK,EAAE,cAAc,GACpB;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAU5B"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Registry validation for declarative panel specs** (ADR 0051 §7, sketch §G.3).
|
|
3
|
+
*
|
|
4
|
+
* The same split the query DSL makes, one level up. `@uptimizr/schema`'s
|
|
5
|
+
* `panelSpecV1Schema` answers "is this a well-formed spec?" — a known chart
|
|
6
|
+
* name, bounded strings, a closed query grammar. It cannot answer the question
|
|
7
|
+
* that actually decides whether the panel will *draw anything*: does this chart
|
|
8
|
+
* suit this metric's grain, and do these encoding columns exist in its result.
|
|
9
|
+
* Those are questions about the vocabulary, and the vocabulary is this package.
|
|
10
|
+
*
|
|
11
|
+
* So {@link validatePanelSpec} runs `validateQuery` over the spec's query and
|
|
12
|
+
* then adds the two checks only the registry can make. It returns objections as
|
|
13
|
+
* data in exactly the {@link QueryIssue} shape the DSL already uses, so the
|
|
14
|
+
* collector turns a bad spec into one `400` with the same body a bad query
|
|
15
|
+
* gets, and a test can assert on codes rather than prose.
|
|
16
|
+
*
|
|
17
|
+
* ## Why the chart is checked at all
|
|
18
|
+
*
|
|
19
|
+
* Because a pinned panel is read much later than it is written. A `line` over
|
|
20
|
+
* `top_meshes` is not a crash — it is a chart with no axis to walk along, which
|
|
21
|
+
* renders as *something*, and a week later somebody reads that something as a
|
|
22
|
+
* trend. Refusing it at pin time is the only moment anybody is paying attention.
|
|
23
|
+
*
|
|
24
|
+
* ## The compatibility rules, in words
|
|
25
|
+
*
|
|
26
|
+
* - `table` — every metric. Rows are rows; this is the honest fallback and the
|
|
27
|
+
* reason no metric is unpinnable.
|
|
28
|
+
* - `stat` — a metric whose result *is* one row: `project` grain with nothing
|
|
29
|
+
* keying the rows. One number, big. A `stat` over a ranked list would show
|
|
30
|
+
* the first row and silently hide the rest.
|
|
31
|
+
* - `bar` — a label to name each bar and a measure to size it, over a grain
|
|
32
|
+
* that is a *list* rather than a grid: the ranked grains (`mesh`, `scene`,
|
|
33
|
+
* `session`, `row`) plus `bucket`, which is what a histogram or a funnel
|
|
34
|
+
* already is. A spatial grid's key is a coordinate, and bars of coordinates
|
|
35
|
+
* say nothing.
|
|
36
|
+
* - `line` / `area` — an **ordered axis** to walk along: a column the registry
|
|
37
|
+
* marks `axis`, which it guarantees is exactly the `bucket`-grain metrics
|
|
38
|
+
* (`registry.test.ts` pins that). Everything else has an order chosen by the
|
|
39
|
+
* query, and a line drawn through a ranking is a lie about continuity.
|
|
40
|
+
* - `heatmap2d` — a `bin` grain: the metric already bins its input into a grid,
|
|
41
|
+
* which is the only thing the 2D heatmap canvas can paint.
|
|
42
|
+
* - `world3d` — a `voxel` grain, for the same reason in three dimensions.
|
|
43
|
+
*/
|
|
44
|
+
import { getMetric, } from "./registry.js";
|
|
45
|
+
import { dimensionColumn, nativeDimensions, queryTier, validateQuery, } from "./query.js";
|
|
46
|
+
/**
|
|
47
|
+
* Grains whose result is a **list of named things** — the shapes a bar chart
|
|
48
|
+
* can rank. Deliberately the same set the DSL calls orderable, plus `bucket`:
|
|
49
|
+
* a histogram, a funnel and a daily count are all drawn as bars, and the DSL
|
|
50
|
+
* excludes `bucket` from *reordering* for a different reason (its order is the
|
|
51
|
+
* axis, and re-sorting it would destroy the thing being shown).
|
|
52
|
+
*/
|
|
53
|
+
const BAR_GRAINS = new Set([
|
|
54
|
+
"mesh",
|
|
55
|
+
"scene",
|
|
56
|
+
"session",
|
|
57
|
+
"row",
|
|
58
|
+
"bucket",
|
|
59
|
+
]);
|
|
60
|
+
/** Whether the metric's result is a single record rather than a list of rows. */
|
|
61
|
+
function isSingleRecord(metric) {
|
|
62
|
+
return metric.grain === "project" && nativeDimensions(metric).length === 0;
|
|
63
|
+
}
|
|
64
|
+
/** The metric's ordered axis column, when it has one (only `bucket` grains do). */
|
|
65
|
+
export function axisColumn(metric) {
|
|
66
|
+
return Object.entries(metric.columns).find(([, semantics]) => semantics.axis === true)?.[0];
|
|
67
|
+
}
|
|
68
|
+
/** The metric's row-naming column, when it has one. */
|
|
69
|
+
export function labelColumn(metric) {
|
|
70
|
+
return Object.entries(metric.columns).find(([, semantics]) => semantics.label === true)?.[0];
|
|
71
|
+
}
|
|
72
|
+
/** The metric's headline measure column, when it has one. */
|
|
73
|
+
export function measureColumn(metric) {
|
|
74
|
+
return Object.entries(metric.columns).find(([, semantics]) => semantics.measure === true)?.[0];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The chart/grain compatibility table. The single source of truth for the
|
|
78
|
+
* validator, the docs and the `suggestChart` fallback.
|
|
79
|
+
*/
|
|
80
|
+
export const PANEL_CHART_RULES = [
|
|
81
|
+
{
|
|
82
|
+
chart: "table",
|
|
83
|
+
requires: "nothing — any metric's rows can be listed",
|
|
84
|
+
accepts: () => true,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
chart: "stat",
|
|
88
|
+
requires: "a single-record result (a `project`-grain metric with no grain dimensions)",
|
|
89
|
+
accepts: isSingleRecord,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
chart: "bar",
|
|
93
|
+
requires: "a label column, a measure column, and a ranked or bucketed grain " +
|
|
94
|
+
"(`mesh`, `scene`, `session`, `row`, `bucket`)",
|
|
95
|
+
accepts: (metric) => BAR_GRAINS.has(metric.grain) && labelColumn(metric) != null && measureColumn(metric) != null,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
chart: "line",
|
|
99
|
+
requires: "an ordered axis column — in practice a `bucket`-grain metric",
|
|
100
|
+
accepts: (metric) => axisColumn(metric) != null,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
chart: "area",
|
|
104
|
+
requires: "an ordered axis column — in practice a `bucket`-grain metric",
|
|
105
|
+
accepts: (metric) => axisColumn(metric) != null,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
chart: "heatmap2d",
|
|
109
|
+
requires: "a `bin` grain (the metric already bins its input into a grid)",
|
|
110
|
+
accepts: (metric) => metric.grain === "bin",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
chart: "world3d",
|
|
114
|
+
requires: "a `voxel` grain (the metric already bins its input into world-space cells)",
|
|
115
|
+
accepts: (metric) => metric.grain === "voxel",
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
const RULE_BY_CHART = new Map(PANEL_CHART_RULES.map((rule) => [rule.chart, rule]));
|
|
119
|
+
/** Whether `chart` can draw `metric`. The predicate behind the table above. */
|
|
120
|
+
export function chartSuitsMetric(chart, metric) {
|
|
121
|
+
return RULE_BY_CHART.get(chart)?.accepts(metric) ?? false;
|
|
122
|
+
}
|
|
123
|
+
/** Every chart that can draw this metric, in the table's order. */
|
|
124
|
+
export function chartsForMetric(metric) {
|
|
125
|
+
return PANEL_CHART_RULES.filter((rule) => rule.accepts(metric)).map((rule) => rule.chart);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* The columns one row of this query's result carries.
|
|
129
|
+
*
|
|
130
|
+
* On the delegated tier that is the metric's declared `row` shape, unchanged —
|
|
131
|
+
* the canned builder runs and returns exactly what it always did. On the
|
|
132
|
+
* generic tier the builder projects the grouped dimensions plus the metric's
|
|
133
|
+
* declared measures instead, so the encoding has to be checked against *those*:
|
|
134
|
+
* a regrouped `top_meshes` has no `mesh` column when it was grouped by `source`.
|
|
135
|
+
*/
|
|
136
|
+
export function resultColumns(metric, query) {
|
|
137
|
+
const tier = queryTier(metric, query);
|
|
138
|
+
if (tier === "delegated")
|
|
139
|
+
return Object.keys(metric.row.shape);
|
|
140
|
+
// `query.dimensions` is bounded-identifier-typed by the schema (the grammar
|
|
141
|
+
// cannot know the registry's union); `validateQuery` has already rejected any
|
|
142
|
+
// that is not one of the metric's declared dimensions by the time a caller
|
|
143
|
+
// reaches here through `validatePanelSpec`.
|
|
144
|
+
const dimensions = query.dimensions ?? nativeDimensions(metric);
|
|
145
|
+
const grouped = dimensions.map((dimension) => dimensionColumn(metric, dimension));
|
|
146
|
+
const measures = (metric.genericGroupBy?.measures ?? []).map((measure) => measure.column);
|
|
147
|
+
return [...new Set([...grouped, ...measures])];
|
|
148
|
+
}
|
|
149
|
+
/** `` `a`, `b` `` — for a message listing what would have been accepted. */
|
|
150
|
+
function list(values) {
|
|
151
|
+
return values.length === 0 ? "none" : values.map((value) => `\`${value}\``).join(", ");
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The query a spec runs, as a `queryV1` the DSL validator understands.
|
|
155
|
+
*
|
|
156
|
+
* `range: "inherit"` is the host's business, not the registry's: whichever
|
|
157
|
+
* window is substituted, it is a window, and nothing `validateQuery` checks
|
|
158
|
+
* depends on which. Substituting a placeholder here keeps the spec validator
|
|
159
|
+
* from needing its own copy of the DSL's rules.
|
|
160
|
+
*/
|
|
161
|
+
function asQuery(spec) {
|
|
162
|
+
const { range, ...rest } = spec.query;
|
|
163
|
+
return {
|
|
164
|
+
...rest,
|
|
165
|
+
range: range === "inherit" ? { since: 0, until: 1 } : range,
|
|
166
|
+
// The two keys the spec grammar drops, restored at their DSL defaults so the
|
|
167
|
+
// document `validateQuery` sees is a complete one.
|
|
168
|
+
format: "full",
|
|
169
|
+
explain: false,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Check a structurally-valid panel spec against the registry.
|
|
174
|
+
*
|
|
175
|
+
* Runs the DSL's own validation first — a spec whose query cannot be answered
|
|
176
|
+
* is not a panel, whatever chart it asks for — and stops there if the metric
|
|
177
|
+
* did not resolve, because every remaining check is about that metric. Chart
|
|
178
|
+
* and encoding objections are then collected together, so an agent that got
|
|
179
|
+
* both wrong learns both in one round trip.
|
|
180
|
+
*/
|
|
181
|
+
export function validatePanelSpec(spec) {
|
|
182
|
+
const query = asQuery(spec);
|
|
183
|
+
const { issues: queryIssues, metric, tier } = validateQuery(query);
|
|
184
|
+
const issues = queryIssues.map((issue) => ({
|
|
185
|
+
...issue,
|
|
186
|
+
path: `query.${issue.path}`,
|
|
187
|
+
}));
|
|
188
|
+
if (!metric || tier == null)
|
|
189
|
+
return { issues };
|
|
190
|
+
// --- chart vs grain -----------------------------------------------------
|
|
191
|
+
if (!chartSuitsMetric(spec.chart, metric)) {
|
|
192
|
+
const rule = RULE_BY_CHART.get(spec.chart);
|
|
193
|
+
const alternatives = chartsForMetric(metric);
|
|
194
|
+
issues.push({
|
|
195
|
+
code: "chart_grain_mismatch",
|
|
196
|
+
path: "chart",
|
|
197
|
+
message: `"${metric.id}" cannot be drawn as a ${spec.chart}: that chart needs ${rule?.requires ?? "something this metric does not have"}, ` +
|
|
198
|
+
`and this metric's rows are one per ${metric.grain}. Draw it as ${list([...alternatives])}.`,
|
|
199
|
+
accepted: [...alternatives],
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
// --- encoding vs the result's columns -----------------------------------
|
|
203
|
+
const columns = resultColumns(metric, query);
|
|
204
|
+
const columnSet = new Set(columns);
|
|
205
|
+
for (const [channel, column] of Object.entries(spec.encoding ?? {})) {
|
|
206
|
+
if (column == null || columnSet.has(column))
|
|
207
|
+
continue;
|
|
208
|
+
issues.push({
|
|
209
|
+
code: "unknown_encoding_column",
|
|
210
|
+
path: `encoding.${channel}`,
|
|
211
|
+
message: `"${metric.id}" returns no column "${column}"${tier === "generic" ? " when grouped this way" : ""}. Its result columns are ${list(columns)}.`,
|
|
212
|
+
accepted: columns,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return { issues, metric, tier };
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* The chart to pre-fill when an agent pins an answer it just computed.
|
|
219
|
+
*
|
|
220
|
+
* Pure, registry-only and deliberately unambitious: it reads the grain and
|
|
221
|
+
* picks the drawing that grain *is*. A voxelised metric is a world heatmap, a
|
|
222
|
+
* binned one is a 2D heatmap, a bucketed one is a line, a single record is a
|
|
223
|
+
* stat, a ranked list is bars — and anything left over is a table, which can
|
|
224
|
+
* always be drawn. The result always satisfies {@link chartSuitsMetric}, so the
|
|
225
|
+
* assistant's "Pin as panel" never proposes a spec the collector would refuse.
|
|
226
|
+
*
|
|
227
|
+
* `query` is taken so a *regrouped* metric is suggested on the shape it will
|
|
228
|
+
* actually return: `top_meshes` grouped by `source` is still a ranked list, but
|
|
229
|
+
* a generic-tier query that drops the metric's own label column should not be
|
|
230
|
+
* offered a bar it cannot name.
|
|
231
|
+
*/
|
|
232
|
+
export function suggestChart(metric, query) {
|
|
233
|
+
const resolved = typeof metric === "string" ? getMetric(metric) : metric;
|
|
234
|
+
if (resolved == null)
|
|
235
|
+
return "table";
|
|
236
|
+
const columns = new Set(resultColumns(resolved, query));
|
|
237
|
+
const preference = [
|
|
238
|
+
"world3d",
|
|
239
|
+
"heatmap2d",
|
|
240
|
+
"stat",
|
|
241
|
+
"line",
|
|
242
|
+
"bar",
|
|
243
|
+
"table",
|
|
244
|
+
];
|
|
245
|
+
for (const chart of preference) {
|
|
246
|
+
if (!chartSuitsMetric(chart, resolved))
|
|
247
|
+
continue;
|
|
248
|
+
// A generic-tier regrouping can project away the very column the chart
|
|
249
|
+
// would have been drawn from, so the suggestion is checked against the
|
|
250
|
+
// columns the query really returns rather than against the metric's own.
|
|
251
|
+
if (chart === "bar") {
|
|
252
|
+
const label = labelColumn(resolved);
|
|
253
|
+
const measure = measureColumn(resolved);
|
|
254
|
+
if (label == null || measure == null)
|
|
255
|
+
continue;
|
|
256
|
+
if (!columns.has(label) || !columns.has(measure))
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (chart === "line") {
|
|
260
|
+
const axis = axisColumn(resolved);
|
|
261
|
+
if (axis == null || !columns.has(axis))
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
return chart;
|
|
265
|
+
}
|
|
266
|
+
return "table";
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* The default encoding for a chart over a metric: the metric's own axis or
|
|
270
|
+
* label on `x`, its headline measure on `y`.
|
|
271
|
+
*
|
|
272
|
+
* Shared by the assistant's pre-fill and by the renderer's fallback when a spec
|
|
273
|
+
* carries no `encoding` at all, so "what does this panel draw when nobody said"
|
|
274
|
+
* has exactly one answer.
|
|
275
|
+
*/
|
|
276
|
+
export function defaultEncoding(metric, chart) {
|
|
277
|
+
const measure = measureColumn(metric);
|
|
278
|
+
const x = chart === "line" || chart === "area"
|
|
279
|
+
? (axisColumn(metric) ?? labelColumn(metric))
|
|
280
|
+
: labelColumn(metric);
|
|
281
|
+
return {
|
|
282
|
+
...(x != null ? { x } : {}),
|
|
283
|
+
...(measure != null ? { y: measure } : {}),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=panelSpec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panelSpec.js","sourceRoot":"","sources":["../src/panelSpec.ts"],"names":[],"mappings":"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"}
|