@uptimizr/db-postgres 0.0.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.
@@ -0,0 +1,62 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { apiKeyPrefix, generateApiKey, hashApiKey, } from "@uptimizr/db";
3
+ export { hashApiKey, apiKeyPrefix, generateApiKey };
4
+ /**
5
+ * Project + API-key metadata for the single-tenant Postgres store (ADR 0020).
6
+ *
7
+ * Mirrors the DuckDB metadata helpers, but on a real relational engine: there
8
+ * is still no `org_id` (single-tenant). API keys are stored as SHA-256 hashes
9
+ * (never plaintext). Timestamp columns are read as epoch-ms and surfaced as
10
+ * `Date`, matching the other engines so the store contract is identical.
11
+ */
12
+ /** `timestamp` → epoch milliseconds (NULL-preserving). */
13
+ const EPOCH_MS = (col) => `(EXTRACT(EPOCH FROM ${col}) * 1000)::bigint`;
14
+ function toProject(row) {
15
+ return { id: row.id, name: row.name, orgId: null, createdAt: new Date(row.created_at_ms) };
16
+ }
17
+ /** Create a project and return it. */
18
+ export async function createProject(client, name) {
19
+ const rows = await client.query(`INSERT INTO projects (id, name) VALUES ($1, $2)
20
+ RETURNING id, name, ${EPOCH_MS("created_at")} AS created_at_ms`, [randomUUID(), name]);
21
+ return toProject(rows[0]);
22
+ }
23
+ /** Fetch a project by id, or `null` if it does not exist. */
24
+ export async function getProject(client, id) {
25
+ const rows = await client.query(`SELECT id, name, ${EPOCH_MS("created_at")} AS created_at_ms FROM projects WHERE id = $1`, [id]);
26
+ const row = rows[0];
27
+ return row ? toProject(row) : null;
28
+ }
29
+ /**
30
+ * Issue a new API key for a project. Returns both the record and the plaintext
31
+ * key — the plaintext is shown to the caller exactly once and never stored.
32
+ */
33
+ export async function createApiKey(client, projectId, capability = "query") {
34
+ const key = generateApiKey();
35
+ const rows = await client.query(`INSERT INTO api_keys (id, project_id, key_hash, key_prefix, capability)
36
+ VALUES ($1, $2, $3, $4, $5)
37
+ RETURNING id, project_id, key_prefix, ${EPOCH_MS("created_at")} AS created_at_ms,
38
+ ${EPOCH_MS("revoked_at")} AS revoked_at_ms, capability`, [randomUUID(), projectId, hashApiKey(key), apiKeyPrefix(key), capability]);
39
+ const row = rows[0];
40
+ return {
41
+ key,
42
+ record: {
43
+ id: row.id,
44
+ projectId: row.project_id,
45
+ keyPrefix: row.key_prefix,
46
+ createdAt: new Date(row.created_at_ms),
47
+ revokedAt: row.revoked_at_ms == null ? null : new Date(row.revoked_at_ms),
48
+ capability: row.capability,
49
+ },
50
+ };
51
+ }
52
+ /**
53
+ * Resolve a plaintext API key to its (non-revoked) project id and capability, or
54
+ * `null` when the key is unknown or revoked. The collector uses this to
55
+ * authenticate and scope read requests at the boundary.
56
+ */
57
+ export async function resolveApiKey(client, plaintext) {
58
+ const rows = await client.query(`SELECT project_id, capability FROM api_keys WHERE key_hash = $1 AND revoked_at IS NULL`, [hashApiKey(plaintext)]);
59
+ const row = rows[0];
60
+ return row ? { projectId: row.project_id, capability: row.capability } : null;
61
+ }
62
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../src/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type QuerySpec } from "@uptimizr/db";
2
+ import type { PostgresClient } from "./client.js";
3
+ /**
4
+ * Execute a dialect-agnostic {@link QuerySpec} (rendered with `postgresDialect`)
5
+ * against the Postgres store and return typed rows. The dialect emits named
6
+ * `$name::type` placeholders; they are rewritten here to `pg`'s positional
7
+ * `$1…$n` form (the shared `toPositionalParams` helper the SQL Server port
8
+ * reuses with `@p1…`). The client's type parsers return plain-JS values
9
+ * (64-bit integers and numerics as numbers, arrays as arrays), so rows match the
10
+ * shapes produced by the DuckDB `runDuckdbQuery`.
11
+ */
12
+ export declare function runPostgresQuery<T>(client: PostgresClient, spec: QuerySpec): Promise<T[]>;
13
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAG/F"}
@@ -0,0 +1,15 @@
1
+ import { toPositionalParams } from "@uptimizr/db";
2
+ /**
3
+ * Execute a dialect-agnostic {@link QuerySpec} (rendered with `postgresDialect`)
4
+ * against the Postgres store and return typed rows. The dialect emits named
5
+ * `$name::type` placeholders; they are rewritten here to `pg`'s positional
6
+ * `$1…$n` form (the shared `toPositionalParams` helper the SQL Server port
7
+ * reuses with `@p1…`). The client's type parsers return plain-JS values
8
+ * (64-bit integers and numerics as numbers, arrays as arrays), so rows match the
9
+ * shapes produced by the DuckDB `runDuckdbQuery`.
10
+ */
11
+ export async function runPostgresQuery(client, spec) {
12
+ const { sql, values } = toPositionalParams(spec.query, spec.query_params, (i) => `$${i}`);
13
+ return client.query(sql, values);
14
+ }
15
+ //# sourceMappingURL=queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAkB,MAAM,cAAc,CAAC;AAGlE;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAI,MAAsB,EAAE,IAAe;IAC/E,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC1F,OAAO,MAAM,CAAC,KAAK,CAAI,GAAG,EAAE,MAAM,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { SceneRepresentation, SceneRepresentationKind, SceneRepresentationSummary } from "@uptimizr/db";
2
+ import type { SceneProxy } from "@uptimizr/schema";
3
+ import type { PostgresClient } from "./client.js";
4
+ export type { SceneRepresentation, SceneRepresentationKind, SceneRepresentationSummary };
5
+ /**
6
+ * Insert or replace the scene proxy for `(projectId, proxy.sceneId)`. Stores the
7
+ * full proxy as JSON text and promotes bounds/hash/version/captured-at to columns
8
+ * for cheap listing. An optional `label` is merged in (kept if not provided).
9
+ */
10
+ export declare function upsertSceneProxy(client: PostgresClient, projectId: string, proxy: SceneProxy, label?: string): Promise<SceneRepresentation>;
11
+ /** Fetch one scene representation (including the proxy blob), or `null`. */
12
+ export declare function getSceneRepresentation(client: PostgresClient, projectId: string, sceneId: string): Promise<SceneRepresentation | null>;
13
+ /** List a project's scene representations (without proxy blobs), newest first. */
14
+ export declare function listSceneRepresentations(client: PostgresClient, projectId: string): Promise<SceneRepresentationSummary[]>;
15
+ //# sourceMappingURL=sceneRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sceneRegistry.d.ts","sourceRoot":"","sources":["../src/sceneRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACvB,0BAA0B,EAC3B,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAQ,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,YAAY,EAAE,mBAAmB,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,CAAC;AA8DzF;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,EACjB,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,mBAAmB,CAAC,CAkC9B;AAED,4EAA4E;AAC5E,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAQrC;AAED,kFAAkF;AAClF,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAoBvC"}
@@ -0,0 +1,97 @@
1
+ import { toPostgresTimestamp } from "@uptimizr/db";
2
+ function toKind(value) {
3
+ return value === "proxy" || value === "asset" ? value : "none";
4
+ }
5
+ function toUpAxis(value) {
6
+ return value === "z" ? "z" : "y";
7
+ }
8
+ function parseJson(value) {
9
+ if (value == null)
10
+ return null;
11
+ return JSON.parse(value);
12
+ }
13
+ function rowToRepresentation(row) {
14
+ return {
15
+ projectId: row.project_id,
16
+ sceneId: row.scene_id,
17
+ label: row.label,
18
+ kind: toKind(row.kind),
19
+ upAxis: toUpAxis(row.up_axis),
20
+ unitScale: Number(row.unit_scale),
21
+ bounds: parseJson(row.bounds),
22
+ proxy: parseJson(row.proxy),
23
+ assetUrl: row.asset_url,
24
+ contentHash: row.content_hash,
25
+ proxyVersion: row.proxy_version === null ? null : Number(row.proxy_version),
26
+ capturedAt: row.captured_at_ms === null ? null : new Date(row.captured_at_ms),
27
+ updatedAt: new Date(row.updated_at_ms),
28
+ };
29
+ }
30
+ const SELECT_COLS = `project_id, scene_id, label, kind, up_axis, unit_scale, bounds, proxy,
31
+ asset_url, content_hash, proxy_version,
32
+ (EXTRACT(EPOCH FROM captured_at) * 1000)::bigint AS captured_at_ms,
33
+ (EXTRACT(EPOCH FROM updated_at) * 1000)::bigint AS updated_at_ms`;
34
+ /**
35
+ * Insert or replace the scene proxy for `(projectId, proxy.sceneId)`. Stores the
36
+ * full proxy as JSON text and promotes bounds/hash/version/captured-at to columns
37
+ * for cheap listing. An optional `label` is merged in (kept if not provided).
38
+ */
39
+ export async function upsertSceneProxy(client, projectId, proxy, label) {
40
+ const rows = await client.query(`INSERT INTO scene_representations
41
+ (project_id, scene_id, label, kind, up_axis, unit_scale, bounds, proxy,
42
+ asset_url, content_hash, proxy_version, captured_at, updated_at)
43
+ VALUES ($1, $2, $3, 'proxy', $4, $5, $6, $7,
44
+ NULL, $8, $9, $10::timestamp, (now() AT TIME ZONE 'utc'))
45
+ ON CONFLICT (project_id, scene_id) DO UPDATE SET
46
+ label = COALESCE(EXCLUDED.label, scene_representations.label),
47
+ kind = 'proxy',
48
+ up_axis = EXCLUDED.up_axis,
49
+ unit_scale = EXCLUDED.unit_scale,
50
+ bounds = EXCLUDED.bounds,
51
+ proxy = EXCLUDED.proxy,
52
+ asset_url = NULL,
53
+ content_hash = EXCLUDED.content_hash,
54
+ proxy_version = EXCLUDED.proxy_version,
55
+ captured_at = EXCLUDED.captured_at,
56
+ updated_at = (now() AT TIME ZONE 'utc')
57
+ RETURNING ${SELECT_COLS}`, [
58
+ projectId,
59
+ proxy.sceneId,
60
+ label ?? null,
61
+ proxy.upAxis,
62
+ proxy.unitScale,
63
+ JSON.stringify(proxy.bounds),
64
+ JSON.stringify(proxy),
65
+ proxy.contentHash,
66
+ proxy.version,
67
+ toPostgresTimestamp(proxy.capturedAt),
68
+ ]);
69
+ return rowToRepresentation(rows[0]);
70
+ }
71
+ /** Fetch one scene representation (including the proxy blob), or `null`. */
72
+ export async function getSceneRepresentation(client, projectId, sceneId) {
73
+ const rows = await client.query(`SELECT ${SELECT_COLS} FROM scene_representations
74
+ WHERE project_id = $1 AND scene_id = $2`, [projectId, sceneId]);
75
+ const row = rows[0];
76
+ return row ? rowToRepresentation(row) : null;
77
+ }
78
+ /** List a project's scene representations (without proxy blobs), newest first. */
79
+ export async function listSceneRepresentations(client, projectId) {
80
+ const rows = await client.query(`SELECT scene_id, label, kind, up_axis, unit_scale, bounds, asset_url,
81
+ content_hash, proxy_version,
82
+ (EXTRACT(EPOCH FROM captured_at) * 1000)::bigint AS captured_at_ms,
83
+ (EXTRACT(EPOCH FROM updated_at) * 1000)::bigint AS updated_at_ms
84
+ FROM scene_representations
85
+ WHERE project_id = $1
86
+ ORDER BY updated_at DESC`, [projectId]);
87
+ return rows.map((row) => ({
88
+ sceneId: row.scene_id,
89
+ label: row.label,
90
+ kind: toKind(row.kind),
91
+ bounds: parseJson(row.bounds),
92
+ contentHash: row.content_hash,
93
+ capturedAt: row.captured_at_ms === null ? null : new Date(row.captured_at_ms),
94
+ updatedAt: new Date(row.updated_at_ms),
95
+ }));
96
+ }
97
+ //# sourceMappingURL=sceneRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sceneRegistry.js","sourceRoot":"","sources":["../src/sceneRegistry.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@uptimizr/db-postgres",
3
+ "version": "0.0.0",
4
+ "description": "Optional single-tenant PostgreSQL store for Uptimizr — composes the @uptimizr/db dialect-agnostic query layer and CollectorStore contract for self-hosters who already run Postgres and want a multi-writer relational backend.",
5
+ "keywords": [
6
+ "uptimizr",
7
+ "analytics",
8
+ "postgres",
9
+ "postgresql",
10
+ "storage",
11
+ "query",
12
+ "events"
13
+ ],
14
+ "license": "Apache-2.0",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/RaananW/Uptimizr.git",
18
+ "directory": "oss/packages/db-postgres"
19
+ },
20
+ "bugs": {
21
+ "url": "https://github.com/RaananW/Uptimizr/issues"
22
+ },
23
+ "homepage": "https://uptimizr.com/docs/deploy/collector/",
24
+ "author": "Raanan Weber (https://github.com/RaananW)",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "type": "module",
29
+ "sideEffects": false,
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "README.md",
39
+ "LICENSE"
40
+ ],
41
+ "dependencies": {
42
+ "pg": "^8.23.0",
43
+ "@uptimizr/schema": "0.6.1",
44
+ "@uptimizr/db": "0.8.2"
45
+ },
46
+ "devDependencies": {
47
+ "@types/node": "^26.4.0",
48
+ "@types/pg": "^8.23.1",
49
+ "tsx": "^4.23.13",
50
+ "vitest": "^4.1.11"
51
+ },
52
+ "scripts": {
53
+ "build": "tsc -p tsconfig.json",
54
+ "dev": "tsc -p tsconfig.json --watch",
55
+ "typecheck": "tsc -p tsconfig.json --noEmit",
56
+ "test": "vitest run",
57
+ "lint": "eslint .",
58
+ "clean": "rm -rf dist"
59
+ }
60
+ }