@formant/formant-cli 0.4.2 → 0.4.4

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,46 @@
1
+ /**
2
+ * Shared utilities for querying per-stream per-device data presence
3
+ * via the analytics SQL backend.
4
+ *
5
+ * Uses a UNION ALL across all telemetry tables to discover what data
6
+ * exists, grouped by (device_id, stream_name, stream_type).
7
+ */
8
+ export interface StreamPresenceRow {
9
+ data_points: number;
10
+ device_id: string;
11
+ first_seen: string;
12
+ last_seen: string;
13
+ stream_name: string;
14
+ stream_type: string;
15
+ }
16
+ /**
17
+ * Build a SQL query that returns per-stream per-device data presence.
18
+ *
19
+ * Returns columns: device_id, stream_name, stream_type, data_points, first_seen, last_seen
20
+ */
21
+ export declare function buildPresenceSQL(options: {
22
+ days?: number;
23
+ deviceIds?: string[];
24
+ limit?: number;
25
+ streamNames?: string[];
26
+ streamTypes?: string[];
27
+ }): string;
28
+ /**
29
+ * Build a SQL query that returns the last time any data was seen per device.
30
+ *
31
+ * Returns columns: device_id, last_seen, total_points, stream_count
32
+ */
33
+ export declare function buildLastSeenSQL(options: {
34
+ days?: number;
35
+ deviceIds?: string[];
36
+ }): string;
37
+ /**
38
+ * Normalize a timestamp string from analytics SQL (e.g. "2026-02-19 23:37:04.747")
39
+ * to ISO 8601 format ("2026-02-19T23:37:04.747Z").
40
+ */
41
+ export declare function toIsoDateTime(sqlTimestamp: string): string;
42
+ /**
43
+ * Freshness label based on how recently data was seen.
44
+ */
45
+ export type FreshnessLevel = 'active' | 'dormant' | 'recent' | 'stale';
46
+ export declare function getFreshness(lastSeenIso: string): FreshnessLevel;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Shared utilities for querying per-stream per-device data presence
3
+ * via the analytics SQL backend.
4
+ *
5
+ * Uses a UNION ALL across all telemetry tables to discover what data
6
+ * exists, grouped by (device_id, stream_name, stream_type).
7
+ */
8
+ /**
9
+ * The telemetry tables that hold stream data.
10
+ * Each has: organization_id, device_id, name, tags, time, and type-specific value columns.
11
+ */
12
+ const TELEMETRY_TABLES = [
13
+ { streamType: 'numeric', table: 'query_numeric' },
14
+ { streamType: 'text', table: 'query_text' },
15
+ { streamType: 'json', table: 'query_json' },
16
+ { streamType: 'location', table: 'query_location' },
17
+ { streamType: 'battery', table: 'query_battery' },
18
+ { streamType: 'health', table: 'query_health' },
19
+ { streamType: 'bitset', table: 'query_bitset' },
20
+ { streamType: 'numeric_set', table: 'query_numeric_set' },
21
+ ];
22
+ /**
23
+ * Build a SQL query that returns per-stream per-device data presence.
24
+ *
25
+ * Returns columns: device_id, stream_name, stream_type, data_points, first_seen, last_seen
26
+ */
27
+ export function buildPresenceSQL(options) {
28
+ const { days = 7, deviceIds, limit = 500, streamNames, streamTypes } = options;
29
+ // Filter to requested stream types or use all
30
+ const tables = streamTypes
31
+ ? TELEMETRY_TABLES.filter((t) => streamTypes.includes(t.streamType))
32
+ : TELEMETRY_TABLES;
33
+ if (tables.length === 0) {
34
+ throw new Error(`No matching stream types. Valid types: ${TELEMETRY_TABLES.map((t) => t.streamType).join(', ')}`);
35
+ }
36
+ const deviceFilter = deviceIds?.length
37
+ ? `AND device_id IN (${deviceIds.map((id) => `'${id}'`).join(', ')})`
38
+ : '';
39
+ const nameFilter = streamNames?.length
40
+ ? `AND name IN (${streamNames.map((n) => `'${n}'`).join(', ')})`
41
+ : '';
42
+ const subqueries = tables.map(({ streamType, table }) => `SELECT device_id, name AS stream_name, '${streamType}' AS stream_type, ` +
43
+ `count(*) AS data_points, min(time) AS first_seen, max(time) AS last_seen ` +
44
+ `FROM ${table} ` +
45
+ `WHERE time > now() - INTERVAL ${days} DAY ${deviceFilter} ${nameFilter} ` +
46
+ `GROUP BY device_id, name`);
47
+ return (`SELECT device_id, stream_name, stream_type, data_points, first_seen, last_seen FROM (\n` +
48
+ subqueries.join('\nUNION ALL\n') +
49
+ `\n) ORDER BY last_seen DESC LIMIT ${limit}`);
50
+ }
51
+ /**
52
+ * Build a SQL query that returns the last time any data was seen per device.
53
+ *
54
+ * Returns columns: device_id, last_seen, total_points, stream_count
55
+ */
56
+ export function buildLastSeenSQL(options) {
57
+ const { days = 30, deviceIds } = options;
58
+ const deviceFilter = deviceIds?.length
59
+ ? `AND device_id IN (${deviceIds.map((id) => `'${id}'`).join(', ')})`
60
+ : '';
61
+ const subqueries = TELEMETRY_TABLES.map(({ table }) => `SELECT device_id, max(time) AS last_seen, count(*) AS data_points, count(DISTINCT name) AS stream_count ` +
62
+ `FROM ${table} ` +
63
+ `WHERE time > now() - INTERVAL ${days} DAY ${deviceFilter} ` +
64
+ `GROUP BY device_id`);
65
+ return (`SELECT device_id, max(last_seen) AS last_seen, sum(data_points) AS total_points, sum(stream_count) AS stream_count FROM (\n` +
66
+ subqueries.join('\nUNION ALL\n') +
67
+ `\n) GROUP BY device_id ORDER BY last_seen DESC`);
68
+ }
69
+ /**
70
+ * Normalize a timestamp string from analytics SQL (e.g. "2026-02-19 23:37:04.747")
71
+ * to ISO 8601 format ("2026-02-19T23:37:04.747Z").
72
+ */
73
+ export function toIsoDateTime(sqlTimestamp) {
74
+ if (!sqlTimestamp)
75
+ return sqlTimestamp;
76
+ // Already ISO
77
+ if (sqlTimestamp.includes('T'))
78
+ return sqlTimestamp;
79
+ // Replace first space with T, append Z if no timezone
80
+ const iso = sqlTimestamp.replace(' ', 'T');
81
+ return iso.endsWith('Z') ? iso : iso + 'Z';
82
+ }
83
+ export function getFreshness(lastSeenIso) {
84
+ const lastSeen = new Date(lastSeenIso).getTime();
85
+ const now = Date.now();
86
+ const hoursAgo = (now - lastSeen) / (1000 * 60 * 60);
87
+ if (hoursAgo < 1)
88
+ return 'active';
89
+ if (hoursAgo < 24)
90
+ return 'recent';
91
+ if (hoursAgo < 7 * 24)
92
+ return 'stale';
93
+ return 'dormant';
94
+ }
95
+ //# sourceMappingURL=presence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presence.js","sourceRoot":"","sources":["../../src/lib/presence.ts"],"names":[],"mappings":"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"}