@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.
- package/README.md +85 -29
- package/dist/commands/device/list.d.ts +7 -1
- package/dist/commands/device/list.js +64 -10
- package/dist/commands/device/list.js.map +1 -1
- package/dist/commands/device/streams.d.ts +1 -0
- package/dist/commands/device/streams.js +78 -23
- package/dist/commands/device/streams.js.map +1 -1
- package/dist/commands/query/index.d.ts +1 -1
- package/dist/commands/query/index.js +20 -6
- package/dist/commands/query/index.js.map +1 -1
- package/dist/lib/presence.d.ts +46 -0
- package/dist/lib/presence.js +95 -0
- package/dist/lib/presence.js.map +1 -0
- package/oclif.manifest.json +1099 -1132
- package/package.json +1 -1
- package/dist/commands/device/last-seen.d.ts +0 -10
- package/dist/commands/device/last-seen.js +0 -25
- package/dist/commands/device/last-seen.js.map +0 -1
|
@@ -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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"}
|