@uptimizr/db 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +109 -0
- package/LICENSE +201 -0
- package/README.md +89 -0
- package/dist/cli/createProject.d.ts +3 -0
- package/dist/cli/createProject.d.ts.map +1 -0
- package/dist/cli/createProject.js +41 -0
- package/dist/cli/createProject.js.map +1 -0
- package/dist/cli/migrate.d.ts +3 -0
- package/dist/cli/migrate.d.ts.map +1 -0
- package/dist/cli/migrate.js +21 -0
- package/dist/cli/migrate.js.map +1 -0
- package/dist/cli/seed.d.ts +2 -0
- package/dist/cli/seed.d.ts.map +1 -0
- package/dist/cli/seed.js +175 -0
- package/dist/cli/seed.js.map +1 -0
- package/dist/duckdb/client.d.ts +42 -0
- package/dist/duckdb/client.d.ts.map +1 -0
- package/dist/duckdb/client.js +93 -0
- package/dist/duckdb/client.js.map +1 -0
- package/dist/duckdb/events.d.ts +44 -0
- package/dist/duckdb/events.d.ts.map +1 -0
- package/dist/duckdb/events.js +225 -0
- package/dist/duckdb/events.js.map +1 -0
- package/dist/duckdb/migrations.d.ts +20 -0
- package/dist/duckdb/migrations.d.ts.map +1 -0
- package/dist/duckdb/migrations.js +323 -0
- package/dist/duckdb/migrations.js.map +1 -0
- package/dist/duckdb/projects.d.ts +23 -0
- package/dist/duckdb/projects.d.ts.map +1 -0
- package/dist/duckdb/projects.js +55 -0
- package/dist/duckdb/projects.js.map +1 -0
- package/dist/duckdb/queries.d.ts +10 -0
- package/dist/duckdb/queries.d.ts.map +1 -0
- package/dist/duckdb/queries.js +10 -0
- package/dist/duckdb/queries.js.map +1 -0
- package/dist/duckdb/sceneRegistry.d.ts +15 -0
- package/dist/duckdb/sceneRegistry.d.ts.map +1 -0
- package/dist/duckdb/sceneRegistry.js +98 -0
- package/dist/duckdb/sceneRegistry.js.map +1 -0
- package/dist/env.d.ts +25 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +55 -0
- package/dist/env.js.map +1 -0
- package/dist/events.d.ts +107 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +153 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/metadata.d.ts +84 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +23 -0
- package/dist/metadata.js.map +1 -0
- package/dist/parity/cases.d.ts +31 -0
- package/dist/parity/cases.d.ts.map +1 -0
- package/dist/parity/cases.js +524 -0
- package/dist/parity/cases.js.map +1 -0
- package/dist/parity/compare.d.ts +47 -0
- package/dist/parity/compare.d.ts.map +1 -0
- package/dist/parity/compare.js +90 -0
- package/dist/parity/compare.js.map +1 -0
- package/dist/parity/fixtures.d.ts +45 -0
- package/dist/parity/fixtures.d.ts.map +1 -0
- package/dist/parity/fixtures.js +157 -0
- package/dist/parity/fixtures.js.map +1 -0
- package/dist/parity/index.d.ts +12 -0
- package/dist/parity/index.d.ts.map +1 -0
- package/dist/parity/index.js +12 -0
- package/dist/parity/index.js.map +1 -0
- package/dist/query/aggregations.d.ts +393 -0
- package/dist/query/aggregations.d.ts.map +1 -0
- package/dist/query/aggregations.js +1412 -0
- package/dist/query/aggregations.js.map +1 -0
- package/dist/query/dialect.d.ts +100 -0
- package/dist/query/dialect.d.ts.map +1 -0
- package/dist/query/dialect.js +88 -0
- package/dist/query/dialect.js.map +1 -0
- package/dist/query/duckdbDialect.d.ts +27 -0
- package/dist/query/duckdbDialect.d.ts.map +1 -0
- package/dist/query/duckdbDialect.js +83 -0
- package/dist/query/duckdbDialect.js.map +1 -0
- package/dist/query/index.d.ts +22 -0
- package/dist/query/index.d.ts.map +1 -0
- package/dist/query/index.js +30 -0
- package/dist/query/index.js.map +1 -0
- package/dist/query/types.d.ts +388 -0
- package/dist/query/types.d.ts.map +1 -0
- package/dist/query/types.js +11 -0
- package/dist/query/types.js.map +1 -0
- package/llms.txt +21 -0
- package/package.json +71 -0
package/dist/env.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection settings for the OSS DuckDB store, read from the environment
|
|
3
|
+
* (ADR 0020).
|
|
4
|
+
*
|
|
5
|
+
* Names mirror `.env.example`. Everything has a local-dev default so the package
|
|
6
|
+
* is usable out of the box (a single persisted `.duckdb` file).
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
10
|
+
function bool(value, fallback) {
|
|
11
|
+
if (value == null)
|
|
12
|
+
return fallback;
|
|
13
|
+
return value === "1" || value.toLowerCase() === "true";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Walk up from `start` until a directory containing `pnpm-workspace.yaml` is
|
|
17
|
+
* found, i.e. the monorepo root. Returns `undefined` if none exists.
|
|
18
|
+
*/
|
|
19
|
+
function findRepoRoot(start) {
|
|
20
|
+
let dir = start;
|
|
21
|
+
for (;;) {
|
|
22
|
+
if (existsSync(join(dir, "pnpm-workspace.yaml")))
|
|
23
|
+
return dir;
|
|
24
|
+
const parent = dirname(dir);
|
|
25
|
+
if (parent === dir)
|
|
26
|
+
return undefined;
|
|
27
|
+
dir = parent;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The default DuckDB file location when `DUCKDB_PATH` is unset.
|
|
32
|
+
*
|
|
33
|
+
* Resolved against the **repo root** (not the process cwd) so every tool — the
|
|
34
|
+
* collector server, the migrate/seed/new-project CLIs — converges on one
|
|
35
|
+
* canonical store no matter which package directory it runs from. Falls back to
|
|
36
|
+
* the cwd-relative path only when the repo root can't be located (e.g. when the
|
|
37
|
+
* package is consumed outside the monorepo).
|
|
38
|
+
*/
|
|
39
|
+
function defaultDuckdbPath() {
|
|
40
|
+
const root = findRepoRoot(process.cwd());
|
|
41
|
+
return root ? join(root, "data", "uptimizr.duckdb") : "./data/uptimizr.duckdb";
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build {@link DbSettings} from an env-like record (defaults to `process.env`).
|
|
45
|
+
* Passing an explicit record keeps this pure and testable.
|
|
46
|
+
*/
|
|
47
|
+
export function readDbSettings(env = process.env) {
|
|
48
|
+
return {
|
|
49
|
+
duckdb: {
|
|
50
|
+
path: env.DUCKDB_PATH ?? defaultDuckdbPath(),
|
|
51
|
+
},
|
|
52
|
+
enableRawSessionRetention: bool(env.ENABLE_RAW_SESSION_RETENTION, false),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=env.js.map
|
package/dist/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAgB1C,SAAS,IAAI,CAAC,KAAyB,EAAE,QAAiB;IACxD,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,QAAQ,CAAC;IACnC,OAAO,KAAK,KAAK,GAAG,IAAI,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;AACzD,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,KAAa;IACjC,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,SAAS,CAAC;QACR,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,SAAS,CAAC;QACrC,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,iBAAiB;IACxB,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,wBAAwB,CAAC;AACjF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAW,OAAO,CAAC,GAAG;IACnD,OAAO;QACL,MAAM,EAAE;YACN,IAAI,EAAE,GAAG,CAAC,WAAW,IAAI,iBAAiB,EAAE;SAC7C;QACD,yBAAyB,EAAE,IAAI,CAAC,GAAG,CAAC,4BAA4B,EAAE,KAAK,CAAC;KACzE,CAAC;AACJ,CAAC"}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-neutral event-row mapping (ADR 0020).
|
|
3
|
+
*
|
|
4
|
+
* `toEventRow` flattens a validated event into the wide column set both storage
|
|
5
|
+
* engines share — DuckDB (OSS) and the single-tenant ClickHouse adapter (scale
|
|
6
|
+
* tier). Keeping it here, free of any engine client, lets both stores
|
|
7
|
+
* reuse one mapping and lets OSS carry zero ClickHouse references.
|
|
8
|
+
*/
|
|
9
|
+
import { type AnyEvent, type Device, type NodeTransformEvent, type SceneMeta, type SessionUser } from "@uptimizr/schema";
|
|
10
|
+
/** Flat row matching the wide `events` table columns (engine-independent). */
|
|
11
|
+
export interface EventRow {
|
|
12
|
+
project_id: string;
|
|
13
|
+
session_id: string;
|
|
14
|
+
visitor_id: string;
|
|
15
|
+
event_type: string;
|
|
16
|
+
ts: string;
|
|
17
|
+
sdk_version: string;
|
|
18
|
+
url: string;
|
|
19
|
+
scene_id: string;
|
|
20
|
+
source: string;
|
|
21
|
+
handedness: string;
|
|
22
|
+
source_id: string;
|
|
23
|
+
ray_origin: number[];
|
|
24
|
+
ray_direction: number[];
|
|
25
|
+
position: number[];
|
|
26
|
+
direction: number[];
|
|
27
|
+
hit_point: number[];
|
|
28
|
+
screen: number[];
|
|
29
|
+
mesh: string;
|
|
30
|
+
fps: number;
|
|
31
|
+
visible_ms: number;
|
|
32
|
+
centered_ms: number;
|
|
33
|
+
screen_fraction: number;
|
|
34
|
+
texture_bytes: number;
|
|
35
|
+
geometry_bytes: number;
|
|
36
|
+
triangles: number;
|
|
37
|
+
vertices: number;
|
|
38
|
+
js_heap_bytes: number;
|
|
39
|
+
cap_from: string;
|
|
40
|
+
cap_to: string;
|
|
41
|
+
frame_time_ms: number;
|
|
42
|
+
frame_time_p95_ms: number;
|
|
43
|
+
long_frames: number;
|
|
44
|
+
dpr: number;
|
|
45
|
+
render_scale: number;
|
|
46
|
+
name: string;
|
|
47
|
+
payload: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Format an epoch-millisecond timestamp as a naive-UTC `YYYY-MM-DD HH:MM:SS.mmm`
|
|
51
|
+
* literal. This is the timestamp form both engines accept (ClickHouse
|
|
52
|
+
* `DateTime64(3)` and DuckDB `TIMESTAMP`), avoiding seconds/millis ambiguity.
|
|
53
|
+
*/
|
|
54
|
+
export declare function formatUtcTimestamp(epochMs: number): string;
|
|
55
|
+
/**
|
|
56
|
+
* Map a validated event into a flat row. Hot, queryable fields are promoted into
|
|
57
|
+
* dedicated columns for aggregation; the full event is preserved in `payload`
|
|
58
|
+
* (JSON) so reads remain replay-complete regardless of extraction.
|
|
59
|
+
*/
|
|
60
|
+
export declare function toEventRow(event: AnyEvent): EventRow;
|
|
61
|
+
/** Per-session descriptor extracted from the session's `session_start` event. */
|
|
62
|
+
export interface SessionMeta {
|
|
63
|
+
sessionId: string;
|
|
64
|
+
/** Session start time as a naive-UTC `YYYY-MM-DD HH:MM:SS.mmm` string, if known. */
|
|
65
|
+
startedAt: string | undefined;
|
|
66
|
+
device: Device | undefined;
|
|
67
|
+
scene: SceneMeta | undefined;
|
|
68
|
+
user: SessionUser | undefined;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Flat row matching the dedicated `node_samples` table (ADR 0027 §9). The
|
|
72
|
+
* `node_transform` event is split out of the wide `events` table: it is the
|
|
73
|
+
* highest-cardinality signal in the system, so it gets its own transform-shaped
|
|
74
|
+
* storage instead of padding `events` with quaternion/bone columns that are null
|
|
75
|
+
* for every other type. `bone_id` is `''` for the Tier-1 node/root tier; `scale`
|
|
76
|
+
* is `[]` when the sample omitted it (unchanged from identity / last sample).
|
|
77
|
+
* `child_path` (ADR 0033) is `''` for the declared root and for bone rows; it is
|
|
78
|
+
* the descendant's path relative to `node_id` for a Tier-1 subtree child.
|
|
79
|
+
*/
|
|
80
|
+
export interface NodeSampleRow {
|
|
81
|
+
project_id: string;
|
|
82
|
+
session_id: string;
|
|
83
|
+
ts: string;
|
|
84
|
+
sdk_version: string;
|
|
85
|
+
scene_id: string;
|
|
86
|
+
node_id: string;
|
|
87
|
+
bone_id: string;
|
|
88
|
+
child_path: string;
|
|
89
|
+
position: number[];
|
|
90
|
+
rotation: number[];
|
|
91
|
+
scale: number[];
|
|
92
|
+
}
|
|
93
|
+
/** Map a validated `node_transform` event into a flat {@link NodeSampleRow}. */
|
|
94
|
+
export declare function toNodeSampleRow(event: NodeTransformEvent): NodeSampleRow;
|
|
95
|
+
/**
|
|
96
|
+
* Reconstruct a replay-complete `node_transform` event from a stored
|
|
97
|
+
* {@link NodeSampleRow}. The dedicated table keeps only the transform-shaped
|
|
98
|
+
* columns, so this rehydrates the schema event for the replay merge (ADR 0027
|
|
99
|
+
* §8). `tsEpochMs` is the row's `ts` already converted back to epoch ms by the
|
|
100
|
+
* caller (engine-specific timestamp decoding stays in the store).
|
|
101
|
+
*/
|
|
102
|
+
export declare function nodeSampleRowToEvent(row: Pick<NodeSampleRow, "project_id" | "session_id" | "sdk_version" | "scene_id" | "node_id" | "bone_id" | "child_path"> & {
|
|
103
|
+
position: number[];
|
|
104
|
+
rotation: number[];
|
|
105
|
+
scale: number[];
|
|
106
|
+
}, tsEpochMs: number): NodeTransformEvent;
|
|
107
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/dist/events.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-neutral event-row mapping (ADR 0020).
|
|
3
|
+
*
|
|
4
|
+
* `toEventRow` flattens a validated event into the wide column set both storage
|
|
5
|
+
* engines share — DuckDB (OSS) and the single-tenant ClickHouse adapter (scale
|
|
6
|
+
* tier). Keeping it here, free of any engine client, lets both stores
|
|
7
|
+
* reuse one mapping and lets OSS carry zero ClickHouse references.
|
|
8
|
+
*/
|
|
9
|
+
import { DEFAULT_SCENE_ID, } from "@uptimizr/schema";
|
|
10
|
+
/**
|
|
11
|
+
* Format an epoch-millisecond timestamp as a naive-UTC `YYYY-MM-DD HH:MM:SS.mmm`
|
|
12
|
+
* literal. This is the timestamp form both engines accept (ClickHouse
|
|
13
|
+
* `DateTime64(3)` and DuckDB `TIMESTAMP`), avoiding seconds/millis ambiguity.
|
|
14
|
+
*/
|
|
15
|
+
export function formatUtcTimestamp(epochMs) {
|
|
16
|
+
const d = new Date(epochMs);
|
|
17
|
+
const p = (n, w = 2) => String(n).padStart(w, "0");
|
|
18
|
+
return (`${d.getUTCFullYear()}-${p(d.getUTCMonth() + 1)}-${p(d.getUTCDate())} ` +
|
|
19
|
+
`${p(d.getUTCHours())}:${p(d.getUTCMinutes())}:${p(d.getUTCSeconds())}.${p(d.getUTCMilliseconds(), 3)}`);
|
|
20
|
+
}
|
|
21
|
+
function vec(value) {
|
|
22
|
+
return Array.isArray(value) && value.every((n) => typeof n === "number")
|
|
23
|
+
? value
|
|
24
|
+
: [];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Map a validated event into a flat row. Hot, queryable fields are promoted into
|
|
28
|
+
* dedicated columns for aggregation; the full event is preserved in `payload`
|
|
29
|
+
* (JSON) so reads remain replay-complete regardless of extraction.
|
|
30
|
+
*/
|
|
31
|
+
export function toEventRow(event) {
|
|
32
|
+
// The discriminated union widens awkwardly across payload variants; read
|
|
33
|
+
// optional fields through a permissive view without losing the validated input.
|
|
34
|
+
const e = event;
|
|
35
|
+
const hitPoint = vec(e.hitPoint).length ? vec(e.hitPoint) : vec(e.point);
|
|
36
|
+
const mesh = typeof e.mesh === "string" ? e.mesh : typeof e.hitMesh === "string" ? e.hitMesh : "";
|
|
37
|
+
// `name` carries the custom-event name / asset name, and is reused as the coarse
|
|
38
|
+
// `phase` label for compile_stall (#42) and the `kind` label for
|
|
39
|
+
// capability_change (#49) so those rollups can group without a dedicated column.
|
|
40
|
+
const name = typeof e.name === "string"
|
|
41
|
+
? e.name
|
|
42
|
+
: typeof e.phase === "string"
|
|
43
|
+
? e.phase
|
|
44
|
+
: typeof e.kind === "string"
|
|
45
|
+
? e.kind
|
|
46
|
+
: "";
|
|
47
|
+
const ray = (e.ray ?? {});
|
|
48
|
+
return {
|
|
49
|
+
project_id: event.projectId,
|
|
50
|
+
session_id: event.sessionId,
|
|
51
|
+
visitor_id: event.visitorId ?? "",
|
|
52
|
+
event_type: event.type,
|
|
53
|
+
ts: formatUtcTimestamp(event.ts),
|
|
54
|
+
sdk_version: event.sdkVersion,
|
|
55
|
+
url: event.url ?? "",
|
|
56
|
+
scene_id: typeof e.sceneId === "string" && e.sceneId.length > 0 ? e.sceneId : DEFAULT_SCENE_ID,
|
|
57
|
+
source: typeof e.source === "string" && e.source.length > 0 ? e.source : "mouse",
|
|
58
|
+
handedness: typeof e.handedness === "string" ? e.handedness : "",
|
|
59
|
+
source_id: typeof e.sourceId === "string" ? e.sourceId : "",
|
|
60
|
+
ray_origin: vec(ray.origin),
|
|
61
|
+
ray_direction: vec(ray.direction),
|
|
62
|
+
position: vec(e.position),
|
|
63
|
+
direction: vec(e.direction),
|
|
64
|
+
hit_point: hitPoint,
|
|
65
|
+
screen: vec(e.screen),
|
|
66
|
+
mesh,
|
|
67
|
+
fps: typeof e.fps === "number" ? e.fps : 0,
|
|
68
|
+
// mesh_visibility dwell metrics (#37): promoted for the object-attention
|
|
69
|
+
// aggregation; 0 on every other event type (the full event stays in payload).
|
|
70
|
+
// hover_dwell (#48) reuses this column for its `dwellMs` duration, and
|
|
71
|
+
// compile_stall (#42) reuses it for its `durationMs` — all are millisecond
|
|
72
|
+
// durations, so no extra column/migration is needed.
|
|
73
|
+
visible_ms: typeof e.visibleMs === "number"
|
|
74
|
+
? e.visibleMs
|
|
75
|
+
: typeof e.dwellMs === "number"
|
|
76
|
+
? e.dwellMs
|
|
77
|
+
: typeof e.durationMs === "number"
|
|
78
|
+
? e.durationMs
|
|
79
|
+
: 0,
|
|
80
|
+
centered_ms: typeof e.centeredMs === "number" ? e.centeredMs : 0,
|
|
81
|
+
screen_fraction: typeof e.maxScreenFraction === "number" ? e.maxScreenFraction : 0,
|
|
82
|
+
// resource_sample (#44) GPU / memory footprint metrics; 0 on other event
|
|
83
|
+
// types (the full event stays in payload). Every field is optional on the
|
|
84
|
+
// event, so undefined maps to 0 (NULL-equivalent for SUM/AVG/MAX).
|
|
85
|
+
texture_bytes: typeof e.textureBytes === "number" ? e.textureBytes : 0,
|
|
86
|
+
geometry_bytes: typeof e.geometryBytes === "number" ? e.geometryBytes : 0,
|
|
87
|
+
triangles: typeof e.triangles === "number" ? e.triangles : 0,
|
|
88
|
+
vertices: typeof e.vertices === "number" ? e.vertices : 0,
|
|
89
|
+
js_heap_bytes: typeof e.jsHeapBytes === "number" ? e.jsHeapBytes : 0,
|
|
90
|
+
// capability_change (#49) transition tokens; '' on other event types (the
|
|
91
|
+
// full event, including `reason`, stays in payload). `kind` lives in `name`.
|
|
92
|
+
cap_from: typeof e.from === "string" ? e.from : "",
|
|
93
|
+
cap_to: typeof e.to === "string" ? e.to : "",
|
|
94
|
+
// frame_perf (#80) percentile/jank/resolution detail; 0 on other event types
|
|
95
|
+
// (the full event stays in payload). All are optional on the event, so an
|
|
96
|
+
// absent field maps to 0 — perf queries filter `event_type = 'frame_perf'`
|
|
97
|
+
// and use `nullIf(...)` where 0 is not a meaningful sample (dpr/renderScale).
|
|
98
|
+
frame_time_ms: typeof e.frameTimeMs === "number" ? e.frameTimeMs : 0,
|
|
99
|
+
frame_time_p95_ms: typeof e.frameTimeP95Ms === "number" ? e.frameTimeP95Ms : 0,
|
|
100
|
+
long_frames: typeof e.longFrames === "number" ? e.longFrames : 0,
|
|
101
|
+
dpr: typeof e.dpr === "number" ? e.dpr : 0,
|
|
102
|
+
render_scale: typeof e.renderScale === "number" ? e.renderScale : 0,
|
|
103
|
+
name,
|
|
104
|
+
payload: JSON.stringify(event),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Map a validated `node_transform` event into a flat {@link NodeSampleRow}. */
|
|
108
|
+
export function toNodeSampleRow(event) {
|
|
109
|
+
return {
|
|
110
|
+
project_id: event.projectId,
|
|
111
|
+
session_id: event.sessionId,
|
|
112
|
+
ts: formatUtcTimestamp(event.ts),
|
|
113
|
+
sdk_version: event.sdkVersion,
|
|
114
|
+
scene_id: typeof event.sceneId === "string" && event.sceneId.length > 0
|
|
115
|
+
? event.sceneId
|
|
116
|
+
: DEFAULT_SCENE_ID,
|
|
117
|
+
node_id: event.nodeId,
|
|
118
|
+
bone_id: event.boneId ?? "",
|
|
119
|
+
child_path: event.childPath ?? "",
|
|
120
|
+
position: [...event.position],
|
|
121
|
+
rotation: [...event.rotation],
|
|
122
|
+
scale: event.scale ? [...event.scale] : [],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Reconstruct a replay-complete `node_transform` event from a stored
|
|
127
|
+
* {@link NodeSampleRow}. The dedicated table keeps only the transform-shaped
|
|
128
|
+
* columns, so this rehydrates the schema event for the replay merge (ADR 0027
|
|
129
|
+
* §8). `tsEpochMs` is the row's `ts` already converted back to epoch ms by the
|
|
130
|
+
* caller (engine-specific timestamp decoding stays in the store).
|
|
131
|
+
*/
|
|
132
|
+
export function nodeSampleRowToEvent(row, tsEpochMs) {
|
|
133
|
+
const event = {
|
|
134
|
+
type: "node_transform",
|
|
135
|
+
projectId: row.project_id,
|
|
136
|
+
sessionId: row.session_id,
|
|
137
|
+
ts: tsEpochMs,
|
|
138
|
+
sdkVersion: row.sdk_version,
|
|
139
|
+
nodeId: row.node_id,
|
|
140
|
+
position: row.position,
|
|
141
|
+
rotation: row.rotation,
|
|
142
|
+
};
|
|
143
|
+
if (row.scene_id && row.scene_id !== DEFAULT_SCENE_ID)
|
|
144
|
+
event.sceneId = row.scene_id;
|
|
145
|
+
if (row.bone_id)
|
|
146
|
+
event.boneId = row.bone_id;
|
|
147
|
+
if (row.child_path)
|
|
148
|
+
event.childPath = row.child_path;
|
|
149
|
+
if (row.scale.length === 3)
|
|
150
|
+
event.scale = row.scale;
|
|
151
|
+
return event;
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@uptimizr/db` — the OSS storage contracts and the single-file DuckDB store
|
|
3
|
+
* (ADR 0020).
|
|
4
|
+
*
|
|
5
|
+
* Ships the dialect-agnostic query layer, engine-neutral event-row mapping and
|
|
6
|
+
* metadata types, and a fully-functional DuckDB store (events + metadata in one
|
|
7
|
+
* file). It carries no ClickHouse/Postgres dependency — an optional,
|
|
8
|
+
* separately-licensed scale store composes these contracts.
|
|
9
|
+
*
|
|
10
|
+
* Server/Node only — no DOM imports. Aggregations are query-time in v1.
|
|
11
|
+
*/
|
|
12
|
+
export { readDbSettings } from "./env.js";
|
|
13
|
+
export type { DbSettings, DuckdbSettings } from "./env.js";
|
|
14
|
+
export { toEventRow, formatUtcTimestamp } from "./events.js";
|
|
15
|
+
export type { EventRow, SessionMeta } from "./events.js";
|
|
16
|
+
export { toNodeSampleRow, nodeSampleRowToEvent } from "./events.js";
|
|
17
|
+
export type { NodeSampleRow } from "./events.js";
|
|
18
|
+
export { hashApiKey, apiKeyPrefix, generateApiKey } from "./metadata.js";
|
|
19
|
+
export type { Project, ApiKeyRecord, ApiKeyCapability, ResolvedApiKey, SceneRepresentation, SceneRepresentationKind, SceneRepresentationSummary, } from "./metadata.js";
|
|
20
|
+
export type { Dialect, ParamType } from "./query/dialect.js";
|
|
21
|
+
export { duckdbDialect, toDuckdbTimestamp } from "./query/duckdbDialect.js";
|
|
22
|
+
export { buildListSessions, buildPointerHeatmap, buildWorldHeatmap, buildGazeHeatmap, buildCameraDirectionHeatmap, buildCameraPositionHeatmap, buildSessionTrajectory, buildClickGazeRay, buildFlowHeatmap, buildTopMeshes, buildMeshDwell, buildDeadClicks, buildRageClicks, buildHoverDwell, buildCompileStalls, buildResourceSummary, buildCapabilityChanges, buildCameraGestures, buildPerfSummary, buildPerfDistribution, buildFpsHistogram, buildFrameTimePercentiles, buildJankRate, buildPerfByDevice, buildPerfByScene, buildResourcePercentiles, buildStabilityCounts, buildPerfDaily, buildEventsDaily, buildDistinctScenes, buildTimeseries, buildEventTypeCounts, buildSceneCoverage, buildCameraDistance, buildNavigationStats, buildXrRotationRate, buildXrSourceUsage, buildXrAbandonment, buildInteractionsBySource, } from "./query/aggregations.js";
|
|
23
|
+
export type { QuerySpec, RangeOptions, SceneOptions, SourceOptions, SessionOptions, CameraModeOptions, TimeseriesOptions, SessionSummaryRow, HeatmapBinRow, WorldHeatmapBinRow, PositionBinRow, TrajectoryPointRow, DirectionBinRow, ClickGazeRayRow, FlowLinkRow, MeshCountRow, MeshDwellRow, DeadClickRow, RageClickRow, HoverDwellRow, CompileStallRow, ResourceSummaryRow, CapabilityChangeRow, CameraGestureRow, PerfSummaryRow, PerfDistributionRow, FpsHistogramRow, FrameTimePercentileRow, JankRateRow, PerfByDeviceRow, PerfBySceneRow, ResourcePercentileRow, StabilityCountRow, PerfDailyRow, EventsDailyRow, SceneRow, TimeseriesBucketRow, EventTypeCountRow, CoverageVoxelRow, CameraDistanceBucketRow, NavigationStatsRow, XrRotationRateRow, XrSourceUsageRow, XrAbandonmentRow, InteractionSourceRow, } from "./query/types.js";
|
|
24
|
+
export { createDuckdbClient, convertValue } from "./duckdb/client.js";
|
|
25
|
+
export type { DuckdbClient, DuckdbRow } from "./duckdb/client.js";
|
|
26
|
+
export { DUCKDB_MIGRATIONS, migrateDuckdb } from "./duckdb/migrations.js";
|
|
27
|
+
export { runDuckdbQuery } from "./duckdb/queries.js";
|
|
28
|
+
export { insertEvents as duckdbInsertEvents, getSessionEvents as duckdbGetSessionEvents, streamSessionEvents as duckdbStreamSessionEvents, getSessionMeta as duckdbGetSessionMeta, } from "./duckdb/events.js";
|
|
29
|
+
export { createProject as duckdbCreateProject, getProject as duckdbGetProject, createApiKey as duckdbCreateApiKey, resolveApiKey as duckdbResolveApiKey, } from "./duckdb/projects.js";
|
|
30
|
+
export { upsertSceneProxy as duckdbUpsertSceneProxy, getSceneRepresentation as duckdbGetSceneRepresentation, listSceneRepresentations as duckdbListSceneRepresentations, } from "./duckdb/sceneRegistry.js";
|
|
31
|
+
export { PARITY_PROJECT_ID, PARITY_T0, PARITY_RANGE, PARITY_DAY_RANGE, PARITY_DAY, PARITY_EVENTS, } from "./parity/fixtures.js";
|
|
32
|
+
export { PARITY_ABS_TOLERANCE, PARITY_REL_TOLERANCE, diffParity } from "./parity/compare.js";
|
|
33
|
+
export type { ParityRow, ParityCompareOptions } from "./parity/compare.js";
|
|
34
|
+
export { PARITY_CASES } from "./parity/cases.js";
|
|
35
|
+
export type { ParityCase } from "./parity/cases.js";
|
|
36
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@uptimizr/db` — the OSS storage contracts and the single-file DuckDB store
|
|
3
|
+
* (ADR 0020).
|
|
4
|
+
*
|
|
5
|
+
* Ships the dialect-agnostic query layer, engine-neutral event-row mapping and
|
|
6
|
+
* metadata types, and a fully-functional DuckDB store (events + metadata in one
|
|
7
|
+
* file). It carries no ClickHouse/Postgres dependency — an optional,
|
|
8
|
+
* separately-licensed scale store composes these contracts.
|
|
9
|
+
*
|
|
10
|
+
* Server/Node only — no DOM imports. Aggregations are query-time in v1.
|
|
11
|
+
*/
|
|
12
|
+
export { readDbSettings } from "./env.js";
|
|
13
|
+
// --- Engine-neutral event-row mapping (ADR 0020) ---
|
|
14
|
+
export { toEventRow, formatUtcTimestamp } from "./events.js";
|
|
15
|
+
// --- Scene-actor transform mapping (node_transform → node_samples, ADR 0027) ---
|
|
16
|
+
export { toNodeSampleRow, nodeSampleRowToEvent } from "./events.js";
|
|
17
|
+
// --- Engine-neutral metadata helpers and types (ADR 0020) ---
|
|
18
|
+
export { hashApiKey, apiKeyPrefix, generateApiKey } from "./metadata.js";
|
|
19
|
+
export { duckdbDialect, toDuckdbTimestamp } from "./query/duckdbDialect.js";
|
|
20
|
+
export { buildListSessions, buildPointerHeatmap, buildWorldHeatmap, buildGazeHeatmap, buildCameraDirectionHeatmap, buildCameraPositionHeatmap, buildSessionTrajectory, buildClickGazeRay, buildFlowHeatmap, buildTopMeshes, buildMeshDwell, buildDeadClicks, buildRageClicks, buildHoverDwell, buildCompileStalls, buildResourceSummary, buildCapabilityChanges, buildCameraGestures, buildPerfSummary, buildPerfDistribution, buildFpsHistogram, buildFrameTimePercentiles, buildJankRate, buildPerfByDevice, buildPerfByScene, buildResourcePercentiles, buildStabilityCounts, buildPerfDaily, buildEventsDaily, buildDistinctScenes, buildTimeseries, buildEventTypeCounts, buildSceneCoverage, buildCameraDistance, buildNavigationStats, buildXrRotationRate, buildXrSourceUsage, buildXrAbandonment, buildInteractionsBySource, } from "./query/aggregations.js";
|
|
21
|
+
// --- DuckDB (OSS single-file store, ADR 0020) ---
|
|
22
|
+
export { createDuckdbClient, convertValue } from "./duckdb/client.js";
|
|
23
|
+
export { DUCKDB_MIGRATIONS, migrateDuckdb } from "./duckdb/migrations.js";
|
|
24
|
+
export { runDuckdbQuery } from "./duckdb/queries.js";
|
|
25
|
+
export { insertEvents as duckdbInsertEvents, getSessionEvents as duckdbGetSessionEvents, streamSessionEvents as duckdbStreamSessionEvents, getSessionMeta as duckdbGetSessionMeta, } from "./duckdb/events.js";
|
|
26
|
+
export { createProject as duckdbCreateProject, getProject as duckdbGetProject, createApiKey as duckdbCreateApiKey, resolveApiKey as duckdbResolveApiKey, } from "./duckdb/projects.js";
|
|
27
|
+
export { upsertSceneProxy as duckdbUpsertSceneProxy, getSceneRepresentation as duckdbGetSceneRepresentation, listSceneRepresentations as duckdbListSceneRepresentations, } from "./duckdb/sceneRegistry.js";
|
|
28
|
+
// --- Cross-engine parity harness (ADR 0020) ---
|
|
29
|
+
// Shared fixtures, golden expectations, and a tolerance-aware comparator. OSS
|
|
30
|
+
// runs DuckDB-vs-golden; the scale tier reuses these to run DuckDB-vs-ClickHouse.
|
|
31
|
+
export { PARITY_PROJECT_ID, PARITY_T0, PARITY_RANGE, PARITY_DAY_RANGE, PARITY_DAY, PARITY_EVENTS, } from "./parity/fixtures.js";
|
|
32
|
+
export { PARITY_ABS_TOLERANCE, PARITY_REL_TOLERANCE, diffParity } from "./parity/compare.js";
|
|
33
|
+
export { PARITY_CASES } from "./parity/cases.js";
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1C,sDAAsD;AACtD,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAG7D,kFAAkF;AAClF,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGpE,+DAA+D;AAC/D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAgBzE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,2BAA2B,EAC3B,0BAA0B,EAC1B,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,eAAe,EACf,eAAe,EACf,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,yBAAyB,EACzB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AAiDjC,mDAAmD;AACnD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EACL,YAAY,IAAI,kBAAkB,EAClC,gBAAgB,IAAI,sBAAsB,EAC1C,mBAAmB,IAAI,yBAAyB,EAChD,cAAc,IAAI,oBAAoB,GACvC,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,aAAa,IAAI,mBAAmB,EACpC,UAAU,IAAI,gBAAgB,EAC9B,YAAY,IAAI,kBAAkB,EAClC,aAAa,IAAI,mBAAmB,GACrC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,gBAAgB,IAAI,sBAAsB,EAC1C,sBAAsB,IAAI,4BAA4B,EACtD,wBAAwB,IAAI,8BAA8B,GAC3D,MAAM,2BAA2B,CAAC;AAEnC,iDAAiD;AACjD,8EAA8E;AAC9E,kFAAkF;AAClF,OAAO,EACL,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,aAAa,GACd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAE7F,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-neutral metadata helpers and types (ADR 0020).
|
|
3
|
+
*
|
|
4
|
+
* API-key hashing/generation are pure crypto and the project / API-key / scene
|
|
5
|
+
* representation shapes are storage-independent. Both the OSS DuckDB store and
|
|
6
|
+
* the scale-tier Postgres metadata clients reuse these, so the type contracts live
|
|
7
|
+
* once and OSS carries no Postgres dependency.
|
|
8
|
+
*/
|
|
9
|
+
import type { Aabb, SceneProxy } from "@uptimizr/schema";
|
|
10
|
+
/** SHA-256 hash of an API key. Only the hash is ever stored (never plaintext). */
|
|
11
|
+
export declare function hashApiKey(plaintext: string): string;
|
|
12
|
+
/** Display prefix used to identify a key without revealing it. */
|
|
13
|
+
export declare function apiKeyPrefix(plaintext: string): string;
|
|
14
|
+
/** Generate a new opaque API key (`utk_` + 32 random bytes, base64url). */
|
|
15
|
+
export declare function generateApiKey(): string;
|
|
16
|
+
export interface Project {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
/** Owning organization (scale tier). `null` for single-tenant/OSS projects. */
|
|
20
|
+
orgId: string | null;
|
|
21
|
+
createdAt: Date;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* What a project API key is allowed to do. `query` keys may read the analytics
|
|
25
|
+
* API (the default — public ingestion is keyless, so issued keys are for
|
|
26
|
+
* reads); `ingest` keys are reserved for server-side write paths.
|
|
27
|
+
*/
|
|
28
|
+
export type ApiKeyCapability = "ingest" | "query";
|
|
29
|
+
export interface ApiKeyRecord {
|
|
30
|
+
id: string;
|
|
31
|
+
projectId: string;
|
|
32
|
+
keyPrefix: string;
|
|
33
|
+
createdAt: Date;
|
|
34
|
+
revokedAt: Date | null;
|
|
35
|
+
/** What this key is allowed to do. Defaults to `query`. */
|
|
36
|
+
capability: ApiKeyCapability;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The result of resolving a plaintext API key: the project it authenticates and
|
|
40
|
+
* the capability that scopes what it may do at the request boundary.
|
|
41
|
+
*/
|
|
42
|
+
export interface ResolvedApiKey {
|
|
43
|
+
projectId: string;
|
|
44
|
+
capability: ApiKeyCapability;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* One representation per `(projectId, sceneId)`. Gives world-space heatmaps a
|
|
48
|
+
* backdrop — an engine-agnostic {@link SceneProxy} captured from a live scene, a
|
|
49
|
+
* URL to an external display asset, or `"none"` (registered, label only).
|
|
50
|
+
*/
|
|
51
|
+
export type SceneRepresentationKind = "none" | "proxy" | "asset";
|
|
52
|
+
export interface SceneRepresentation {
|
|
53
|
+
projectId: string;
|
|
54
|
+
sceneId: string;
|
|
55
|
+
/** Human-friendly label for the scene (developer-supplied). */
|
|
56
|
+
label: string | null;
|
|
57
|
+
kind: SceneRepresentationKind;
|
|
58
|
+
upAxis: "y" | "z";
|
|
59
|
+
unitScale: number;
|
|
60
|
+
/** Overall world bounds `[minX,minY,minZ,maxX,maxY,maxZ]`, when known. */
|
|
61
|
+
bounds: Aabb | null;
|
|
62
|
+
/** Full proxy geometry when `kind === "proxy"`. */
|
|
63
|
+
proxy: SceneProxy | null;
|
|
64
|
+
/** External asset URL when `kind === "asset"`. */
|
|
65
|
+
assetUrl: string | null;
|
|
66
|
+
/** Content digest of the proxy/asset for cache validation. */
|
|
67
|
+
contentHash: string | null;
|
|
68
|
+
/** Proxy wire-format version, when a proxy is stored. */
|
|
69
|
+
proxyVersion: number | null;
|
|
70
|
+
/** When the geometry was captured (epoch-based; `null` for `"none"`). */
|
|
71
|
+
capturedAt: Date | null;
|
|
72
|
+
updatedAt: Date;
|
|
73
|
+
}
|
|
74
|
+
/** Lightweight registry listing row (omits the heavy `proxy` blob). */
|
|
75
|
+
export interface SceneRepresentationSummary {
|
|
76
|
+
sceneId: string;
|
|
77
|
+
label: string | null;
|
|
78
|
+
kind: SceneRepresentationKind;
|
|
79
|
+
bounds: Aabb | null;
|
|
80
|
+
contentHash: string | null;
|
|
81
|
+
capturedAt: Date | null;
|
|
82
|
+
updatedAt: Date;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAIzD,kFAAkF;AAClF,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,2EAA2E;AAC3E,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAID,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAElD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,2DAA2D;IAC3D,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAID;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEjE,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,EAAE,GAAG,GAAG,GAAG,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,MAAM,EAAE,IAAI,GAAG,IAAI,CAAC;IACpB,mDAAmD;IACnD,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACzB,kDAAkD;IAClD,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,yDAAyD;IACzD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,yEAAyE;IACzE,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,uEAAuE;AACvE,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,EAAE,IAAI,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;CACjB"}
|
package/dist/metadata.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-neutral metadata helpers and types (ADR 0020).
|
|
3
|
+
*
|
|
4
|
+
* API-key hashing/generation are pure crypto and the project / API-key / scene
|
|
5
|
+
* representation shapes are storage-independent. Both the OSS DuckDB store and
|
|
6
|
+
* the scale-tier Postgres metadata clients reuse these, so the type contracts live
|
|
7
|
+
* once and OSS carries no Postgres dependency.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
10
|
+
// --- API keys (pure crypto) ---
|
|
11
|
+
/** SHA-256 hash of an API key. Only the hash is ever stored (never plaintext). */
|
|
12
|
+
export function hashApiKey(plaintext) {
|
|
13
|
+
return createHash("sha256").update(plaintext).digest("hex");
|
|
14
|
+
}
|
|
15
|
+
/** Display prefix used to identify a key without revealing it. */
|
|
16
|
+
export function apiKeyPrefix(plaintext) {
|
|
17
|
+
return plaintext.slice(0, 12);
|
|
18
|
+
}
|
|
19
|
+
/** Generate a new opaque API key (`utk_` + 32 random bytes, base64url). */
|
|
20
|
+
export function generateApiKey() {
|
|
21
|
+
return `utk_${randomBytes(32).toString("base64url")}`;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../src/metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAGtD,iCAAiC;AAEjC,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9D,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-engine parity cases (Phase C, ADR 0020).
|
|
3
|
+
*
|
|
4
|
+
* Each case pairs one dialect-agnostic aggregation builder with the
|
|
5
|
+
* engine-independent golden output it must produce for {@link PARITY_EVENTS}.
|
|
6
|
+
* The golden is authored as truth (hand-verified from the fixtures) so that any
|
|
7
|
+
* engine — DuckDB in OSS, ClickHouse in the scale tier — can be checked against
|
|
8
|
+
* the same expectations. Two engines that both match the golden are, by
|
|
9
|
+
* transitivity, in parity with each other.
|
|
10
|
+
*
|
|
11
|
+
* Comparison uses the tolerance rules in {@link diffParity}: order-insensitive,
|
|
12
|
+
* float-tolerant on continuous columns, integer-exact on bin indices, and
|
|
13
|
+
* temporal projection columns excluded.
|
|
14
|
+
*/
|
|
15
|
+
import type { Dialect } from "../query/dialect.js";
|
|
16
|
+
import type { QuerySpec } from "../query/types.js";
|
|
17
|
+
import type { ParityRow } from "./compare.js";
|
|
18
|
+
export interface ParityCase {
|
|
19
|
+
/** Stable identifier (also the test name). */
|
|
20
|
+
readonly name: string;
|
|
21
|
+
/** Render the aggregation for a given engine dialect. */
|
|
22
|
+
build(dialect: Dialect): QuerySpec;
|
|
23
|
+
/** Columns that together order a row for multiset comparison. */
|
|
24
|
+
readonly sortKeys: readonly string[];
|
|
25
|
+
/** Engine-specific temporal columns excluded from comparison. */
|
|
26
|
+
readonly ignoreColumns?: readonly string[];
|
|
27
|
+
/** Engine-independent expected output. */
|
|
28
|
+
readonly golden: readonly ParityRow[];
|
|
29
|
+
}
|
|
30
|
+
export declare const PARITY_CASES: readonly ParityCase[];
|
|
31
|
+
//# sourceMappingURL=cases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cases.d.ts","sourceRoot":"","sources":["../../src/parity/cases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA2CH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAS9C,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,iEAAiE;IACjE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,0CAA0C;IAC1C,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;CACvC;AAID,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EA2f7C,CAAC"}
|