@alisio/plugin-telemetry 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.
Files changed (53) hide show
  1. package/.agents/skills/telemetry/SKILL.md +52 -0
  2. package/LICENSE +21 -0
  3. package/README.md +188 -0
  4. package/cover.svg +54 -0
  5. package/dist/commands.d.ts +19 -0
  6. package/dist/commands.d.ts.map +1 -0
  7. package/dist/commands.js +298 -0
  8. package/dist/commands.js.map +1 -0
  9. package/dist/config.d.ts +145 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +524 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/database.d.ts +16 -0
  14. package/dist/database.d.ts.map +1 -0
  15. package/dist/database.js +67 -0
  16. package/dist/database.js.map +1 -0
  17. package/dist/events.d.ts +135 -0
  18. package/dist/events.d.ts.map +1 -0
  19. package/dist/events.js +255 -0
  20. package/dist/events.js.map +1 -0
  21. package/dist/format.d.ts +36 -0
  22. package/dist/format.d.ts.map +1 -0
  23. package/dist/format.js +49 -0
  24. package/dist/format.js.map +1 -0
  25. package/dist/index.d.ts +38 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +78 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/otlp.d.ts +69 -0
  30. package/dist/otlp.d.ts.map +1 -0
  31. package/dist/otlp.js +616 -0
  32. package/dist/otlp.js.map +1 -0
  33. package/dist/redact.d.ts +36 -0
  34. package/dist/redact.d.ts.map +1 -0
  35. package/dist/redact.js +163 -0
  36. package/dist/redact.js.map +1 -0
  37. package/dist/runtime.d.ts +80 -0
  38. package/dist/runtime.d.ts.map +1 -0
  39. package/dist/runtime.js +290 -0
  40. package/dist/runtime.js.map +1 -0
  41. package/dist/store.d.ts +188 -0
  42. package/dist/store.d.ts.map +1 -0
  43. package/dist/store.js +539 -0
  44. package/dist/store.js.map +1 -0
  45. package/dist/tools.d.ts +21 -0
  46. package/dist/tools.d.ts.map +1 -0
  47. package/dist/tools.js +292 -0
  48. package/dist/tools.js.map +1 -0
  49. package/dist/version.d.ts +3 -0
  50. package/dist/version.d.ts.map +1 -0
  51. package/dist/version.js +3 -0
  52. package/dist/version.js.map +1 -0
  53. package/package.json +54 -0
package/dist/config.js ADDED
@@ -0,0 +1,524 @@
1
+ /**
2
+ * Configuration, path resolution and safe persistence.
3
+ *
4
+ * PRECEDENCE (highest first): explicit non-secret command/tool argument, then
5
+ * environment, then the config file, then built-in safe defaults. The config
6
+ * file lives at `<configHome>/telemetry/config.json`; the database lives at
7
+ * `ALISIO_TELEMETRY_DB` or `<stateHome>/telemetry/telemetry.sqlite`.
8
+ *
9
+ * CREDENTIALS ARE NEVER PERSISTED. The OTLP token is read from an environment
10
+ * variable at export time only. The config file may reference *which* variable
11
+ * holds it (`otlp.tokenEnv`) but never its value. Secret-shaped keys anywhere in
12
+ * the file are rejected with an actionable message rather than silently kept.
13
+ *
14
+ * FAIL CLOSED. An invalid file or environment produces a structured error, not a
15
+ * throw that could crash the host. The plugin disables telemetry and surfaces the
16
+ * message; the agent run continues.
17
+ */
18
+ import { chmodSync, closeSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, writeSync, } from "node:fs";
19
+ import { homedir } from "node:os";
20
+ import { dirname, join } from "node:path";
21
+ export const ENV_KEYS = {
22
+ db: "ALISIO_TELEMETRY_DB",
23
+ configHome: "ALISIO_CONFIG_HOME",
24
+ stateHome: "ALISIO_STATE_HOME",
25
+ xdgConfigHome: "XDG_CONFIG_HOME",
26
+ xdgStateHome: "XDG_STATE_HOME",
27
+ home: "HOME",
28
+ retentionDays: "ALISIO_TELEMETRY_RETENTION_DAYS",
29
+ otlpEnabled: "ALISIO_TELEMETRY_OTLP_ENABLED",
30
+ otlpEndpoint: "ALISIO_TELEMETRY_OTLP_ENDPOINT",
31
+ otlpTokenEnv: "ALISIO_TELEMETRY_OTLP_TOKEN_ENV",
32
+ otlpInstanceId: "ALISIO_TELEMETRY_OTLP_INSTANCE_ID",
33
+ serviceName: "ALISIO_TELEMETRY_SERVICE_NAME",
34
+ environment: "ALISIO_TELEMETRY_ENVIRONMENT",
35
+ samplingRatio: "ALISIO_TELEMETRY_SAMPLING_RATIO",
36
+ capturePrompts: "ALISIO_TELEMETRY_CAPTURE_PROMPTS",
37
+ captureCompletions: "ALISIO_TELEMETRY_CAPTURE_COMPLETIONS",
38
+ captureToolArguments: "ALISIO_TELEMETRY_CAPTURE_TOOL_ARGUMENTS",
39
+ captureToolResults: "ALISIO_TELEMETRY_CAPTURE_TOOL_RESULTS",
40
+ redactionMode: "ALISIO_TELEMETRY_REDACTION_MODE",
41
+ otlpSignals: "ALISIO_TELEMETRY_OTLP_SIGNALS",
42
+ otlpGzip: "ALISIO_TELEMETRY_OTLP_GZIP",
43
+ batchSize: "ALISIO_TELEMETRY_BATCH_SIZE",
44
+ flushIntervalMs: "ALISIO_TELEMETRY_FLUSH_INTERVAL_MS",
45
+ maxQueue: "ALISIO_TELEMETRY_MAX_QUEUE",
46
+ };
47
+ /**
48
+ * The credential itself is intentionally NOT listed above: it is read directly
49
+ * from this name at export time and never flows through configuration.
50
+ */
51
+ export const OTLP_TOKEN_ENV = "ALISIO_TELEMETRY_OTLP_TOKEN";
52
+ export class ConfigError extends Error {
53
+ constructor(message) {
54
+ super(message);
55
+ this.name = "ConfigError";
56
+ }
57
+ }
58
+ function fail(message) {
59
+ throw new ConfigError(message);
60
+ }
61
+ export function createDefaultConfig() {
62
+ return {
63
+ version: 1,
64
+ retentionDays: 30,
65
+ capture: { prompts: false, completions: false, toolArguments: false, toolResults: false },
66
+ redaction: { mode: "strict" },
67
+ otlp: {
68
+ enabled: false,
69
+ endpoint: null,
70
+ headers: {},
71
+ tokenEnv: OTLP_TOKEN_ENV,
72
+ instanceId: "",
73
+ serviceName: "alisio",
74
+ environment: "",
75
+ samplingRatio: 1,
76
+ signals: { traces: true, logs: true, metrics: false },
77
+ gzip: false,
78
+ maxAttempts: 5,
79
+ timeoutMs: 10_000,
80
+ batchSize: 200,
81
+ },
82
+ batch: { batchSize: 50, flushIntervalMs: 5_000, maxQueue: 10_000 },
83
+ };
84
+ }
85
+ /** Resolve config/state homes with the documented precedence. */
86
+ export function resolveTelemetryPaths(env = process.env, overrides = {}) {
87
+ const home = env[ENV_KEYS.home]?.trim() || homedir();
88
+ const xdgConfig = env[ENV_KEYS.xdgConfigHome]?.trim();
89
+ const xdgState = env[ENV_KEYS.xdgStateHome]?.trim();
90
+ const configHome = env[ENV_KEYS.configHome]?.trim() ||
91
+ (xdgConfig ? join(xdgConfig, "alisio") : join(home, ".config", "alisio"));
92
+ const stateHome = env[ENV_KEYS.stateHome]?.trim() ||
93
+ (xdgState ? join(xdgState, "alisio") : join(home, ".local", "state", "alisio"));
94
+ const database = overrides.database?.trim() ||
95
+ env[ENV_KEYS.db]?.trim() ||
96
+ join(stateHome, "telemetry", "telemetry.sqlite");
97
+ const configFile = overrides.configFile?.trim() || join(configHome, "telemetry", "config.json");
98
+ return { configFile, database };
99
+ }
100
+ // ---------------------------------------------------------------------------
101
+ // Primitive parsers
102
+ // ---------------------------------------------------------------------------
103
+ function isPlainObject(value) {
104
+ return typeof value === "object" && value !== null && !Array.isArray(value);
105
+ }
106
+ const SECRET_KEY = /(?:secret|password|passwd|credential|authorization|bearer|cookie|private[_-]?key|api[_-]?key|apikey)/i;
107
+ const TOKEN_KEY = /(?:^|[_-])token(?:$|[_-])/i;
108
+ /** A key that must never appear in the persisted configuration. */
109
+ function isSecretKey(key) {
110
+ if (key === "tokenEnv")
111
+ return false;
112
+ return SECRET_KEY.test(key) || key.toLowerCase() === "token" || TOKEN_KEY.test(key);
113
+ }
114
+ /** Reject unknown and secret-shaped keys, with an actionable message. */
115
+ function assertKeys(object, allowed, where) {
116
+ for (const key of Object.keys(object)) {
117
+ if (allowed.includes(key))
118
+ continue;
119
+ if (isSecretKey(key))
120
+ fail(`${where}: field "${key}" is not allowed. Credentials are never persisted; set the token environment variable instead and reference its name with "otlp.tokenEnv".`);
121
+ fail(`${where}: unknown field "${key}" (allowed: ${allowed.join(", ")})`);
122
+ }
123
+ }
124
+ function readBoolean(value, where) {
125
+ if (typeof value === "boolean")
126
+ return value;
127
+ if (typeof value === "string") {
128
+ const normalized = value.trim().toLowerCase();
129
+ if (["1", "true", "yes", "on"].includes(normalized))
130
+ return true;
131
+ if (["0", "false", "no", "off"].includes(normalized))
132
+ return false;
133
+ }
134
+ fail(`${where}: expected a boolean, got ${JSON.stringify(value)}`);
135
+ }
136
+ function readInteger(value, where, min, max) {
137
+ const numeric = typeof value === "number"
138
+ ? value
139
+ : typeof value === "string" && value.trim() !== ""
140
+ ? Number(value)
141
+ : Number.NaN;
142
+ if (!Number.isInteger(numeric))
143
+ fail(`${where}: expected an integer, got ${JSON.stringify(value)}`);
144
+ if (numeric < min || numeric > max)
145
+ fail(`${where}: expected an integer between ${min} and ${max}, got ${numeric}`);
146
+ return numeric;
147
+ }
148
+ function readRatio(value, where) {
149
+ const numeric = typeof value === "number"
150
+ ? value
151
+ : typeof value === "string" && value.trim() !== ""
152
+ ? Number(value)
153
+ : Number.NaN;
154
+ if (!Number.isFinite(numeric) || numeric < 0 || numeric > 1)
155
+ fail(`${where}: expected a number between 0 and 1, got ${JSON.stringify(value)}`);
156
+ return numeric;
157
+ }
158
+ function readBoundedString(value, where, max, allowEmpty = false) {
159
+ if (typeof value !== "string")
160
+ fail(`${where}: expected a string, got ${JSON.stringify(value)}`);
161
+ const trimmed = value.trim();
162
+ if (!allowEmpty && trimmed === "")
163
+ fail(`${where}: must not be empty`);
164
+ if (trimmed.length > max)
165
+ fail(`${where}: must be at most ${max} characters`);
166
+ return trimmed;
167
+ }
168
+ /** Validate and normalize an OTLP base endpoint. Credentials in the URL are refused. */
169
+ export function parseEndpoint(value, where = "otlp.endpoint") {
170
+ let url;
171
+ try {
172
+ url = new URL(value.trim());
173
+ }
174
+ catch {
175
+ fail(`${where}: not a valid absolute URL`);
176
+ }
177
+ if (url.protocol !== "https:" && url.protocol !== "http:")
178
+ fail(`${where}: must use http or https`);
179
+ if (url.username !== "" || url.password !== "")
180
+ fail(`${where}: must not embed credentials`);
181
+ if (url.search !== "")
182
+ fail(`${where}: must not include a query string`);
183
+ if (url.hash !== "")
184
+ fail(`${where}: must not include a fragment`);
185
+ const base = `${url.origin}${url.pathname}`.replace(/\/+$/, "");
186
+ return base;
187
+ }
188
+ function readHeaders(value, where) {
189
+ if (!isPlainObject(value))
190
+ fail(`${where}: expected an object of string headers`);
191
+ const headers = {};
192
+ for (const [key, raw] of Object.entries(value)) {
193
+ if (isSecretKey(key))
194
+ fail(`${where}: header "${key}" looks like a credential and is refused. Only non-secret headers are persisted; authorization is injected at export time from the token environment variable.`);
195
+ if (typeof raw !== "string")
196
+ fail(`${where}.${key}: header value must be a string`);
197
+ if (raw.length > 1000)
198
+ fail(`${where}.${key}: header value is too long`);
199
+ headers[key] = raw;
200
+ }
201
+ return headers;
202
+ }
203
+ function readSignals(value, where) {
204
+ if (isPlainObject(value))
205
+ assertKeys(value, ["traces", "logs", "metrics"], where);
206
+ else
207
+ fail(`${where}: expected an object of booleans`);
208
+ const object = value;
209
+ return {
210
+ traces: object.traces === undefined ? true : readBoolean(object.traces, `${where}.traces`),
211
+ logs: object.logs === undefined ? true : readBoolean(object.logs, `${where}.logs`),
212
+ metrics: object.metrics === undefined ? false : readBoolean(object.metrics, `${where}.metrics`),
213
+ };
214
+ }
215
+ // ---------------------------------------------------------------------------
216
+ // Config-file validation and merging
217
+ // ---------------------------------------------------------------------------
218
+ /** Parse a raw config object into a partial config, rejecting unknown/secret keys. */
219
+ export function parsePartialConfig(raw, where = "config") {
220
+ if (!isPlainObject(raw))
221
+ fail(`${where}: expected a JSON object`);
222
+ assertKeys(raw, ["version", "retentionDays", "capture", "redaction", "otlp", "batch"], where);
223
+ const partial = {};
224
+ if (raw.version !== undefined && raw.version !== 1)
225
+ fail(`${where}.version: unsupported version ${JSON.stringify(raw.version)}`);
226
+ if (raw.retentionDays !== undefined)
227
+ partial.retentionDays = readInteger(raw.retentionDays, `${where}.retentionDays`, 1, 3650);
228
+ if (raw.capture !== undefined) {
229
+ if (!isPlainObject(raw.capture))
230
+ fail(`${where}.capture: expected an object`);
231
+ assertKeys(raw.capture, ["prompts", "completions", "toolArguments", "toolResults"], `${where}.capture`);
232
+ const capture = {};
233
+ for (const key of ["prompts", "completions", "toolArguments", "toolResults"]) {
234
+ if (raw.capture[key] !== undefined)
235
+ capture[key] = readBoolean(raw.capture[key], `${where}.capture.${key}`);
236
+ }
237
+ partial.capture = capture;
238
+ }
239
+ if (raw.redaction !== undefined) {
240
+ if (!isPlainObject(raw.redaction))
241
+ fail(`${where}.redaction: expected an object`);
242
+ assertKeys(raw.redaction, ["mode"], `${where}.redaction`);
243
+ if (raw.redaction.mode !== undefined) {
244
+ const mode = raw.redaction.mode;
245
+ if (mode !== "strict" && mode !== "standard")
246
+ fail(`${where}.redaction.mode: expected "strict" or "standard", got ${JSON.stringify(mode)}`);
247
+ partial.redaction = { mode };
248
+ }
249
+ }
250
+ if (raw.otlp !== undefined) {
251
+ if (!isPlainObject(raw.otlp))
252
+ fail(`${where}.otlp: expected an object`);
253
+ assertKeys(raw.otlp, [
254
+ "enabled",
255
+ "endpoint",
256
+ "headers",
257
+ "tokenEnv",
258
+ "instanceId",
259
+ "serviceName",
260
+ "environment",
261
+ "samplingRatio",
262
+ "signals",
263
+ "gzip",
264
+ "maxAttempts",
265
+ "timeoutMs",
266
+ "batchSize",
267
+ ], `${where}.otlp`);
268
+ const otlp = {};
269
+ if (raw.otlp.enabled !== undefined)
270
+ otlp.enabled = readBoolean(raw.otlp.enabled, `${where}.otlp.enabled`);
271
+ if (raw.otlp.endpoint !== undefined) {
272
+ if (raw.otlp.endpoint === null || raw.otlp.endpoint === "")
273
+ otlp.endpoint = null;
274
+ else
275
+ otlp.endpoint = parseEndpoint(readBoundedString(raw.otlp.endpoint, `${where}.otlp.endpoint`, 2048), `${where}.otlp.endpoint`);
276
+ }
277
+ if (raw.otlp.headers !== undefined)
278
+ otlp.headers = readHeaders(raw.otlp.headers, `${where}.otlp.headers`);
279
+ if (raw.otlp.tokenEnv !== undefined) {
280
+ const name = readBoundedString(raw.otlp.tokenEnv, `${where}.otlp.tokenEnv`, 200);
281
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
282
+ fail(`${where}.otlp.tokenEnv: must be a valid environment variable name`);
283
+ otlp.tokenEnv = name;
284
+ }
285
+ if (raw.otlp.instanceId !== undefined)
286
+ otlp.instanceId = readBoundedString(raw.otlp.instanceId, `${where}.otlp.instanceId`, 200, true);
287
+ if (raw.otlp.serviceName !== undefined)
288
+ otlp.serviceName = readBoundedString(raw.otlp.serviceName, `${where}.otlp.serviceName`, 200);
289
+ if (raw.otlp.environment !== undefined)
290
+ otlp.environment = readBoundedString(raw.otlp.environment, `${where}.otlp.environment`, 100, true);
291
+ if (raw.otlp.samplingRatio !== undefined)
292
+ otlp.samplingRatio = readRatio(raw.otlp.samplingRatio, `${where}.otlp.samplingRatio`);
293
+ if (raw.otlp.signals !== undefined)
294
+ otlp.signals = readSignals(raw.otlp.signals, `${where}.otlp.signals`);
295
+ if (raw.otlp.gzip !== undefined)
296
+ otlp.gzip = readBoolean(raw.otlp.gzip, `${where}.otlp.gzip`);
297
+ if (raw.otlp.maxAttempts !== undefined)
298
+ otlp.maxAttempts = readInteger(raw.otlp.maxAttempts, `${where}.otlp.maxAttempts`, 1, 10);
299
+ if (raw.otlp.timeoutMs !== undefined)
300
+ otlp.timeoutMs = readInteger(raw.otlp.timeoutMs, `${where}.otlp.timeoutMs`, 1_000, 120_000);
301
+ if (raw.otlp.batchSize !== undefined)
302
+ otlp.batchSize = readInteger(raw.otlp.batchSize, `${where}.otlp.batchSize`, 1, 10_000);
303
+ partial.otlp = otlp;
304
+ }
305
+ if (raw.batch !== undefined) {
306
+ if (!isPlainObject(raw.batch))
307
+ fail(`${where}.batch: expected an object`);
308
+ assertKeys(raw.batch, ["batchSize", "flushIntervalMs", "maxQueue"], `${where}.batch`);
309
+ const batch = {};
310
+ if (raw.batch.batchSize !== undefined)
311
+ batch.batchSize = readInteger(raw.batch.batchSize, `${where}.batch.batchSize`, 1, 10_000);
312
+ if (raw.batch.flushIntervalMs !== undefined)
313
+ batch.flushIntervalMs = readInteger(raw.batch.flushIntervalMs, `${where}.batch.flushIntervalMs`, 250, 600_000);
314
+ if (raw.batch.maxQueue !== undefined)
315
+ batch.maxQueue = readInteger(raw.batch.maxQueue, `${where}.batch.maxQueue`, 100, 1_000_000);
316
+ partial.batch = batch;
317
+ }
318
+ return partial;
319
+ }
320
+ function merge(base, patch) {
321
+ return {
322
+ version: 1,
323
+ retentionDays: patch.retentionDays ?? base.retentionDays,
324
+ capture: { ...base.capture, ...(patch.capture ?? {}) },
325
+ redaction: { ...base.redaction, ...(patch.redaction ?? {}) },
326
+ otlp: {
327
+ ...base.otlp,
328
+ ...(patch.otlp ?? {}),
329
+ signals: { ...base.otlp.signals, ...(patch.otlp?.signals ?? {}) },
330
+ },
331
+ batch: { ...base.batch, ...(patch.batch ?? {}) },
332
+ };
333
+ }
334
+ /** Environment overrides parsed into the same partial shape as the config file. */
335
+ export function environmentOverrides(env) {
336
+ const raw = {};
337
+ const put = (key, value) => {
338
+ const [head, tail] = key.split(".");
339
+ if (tail === undefined) {
340
+ raw[head] = value;
341
+ return;
342
+ }
343
+ const nested = raw[head] ?? {};
344
+ nested[tail] = value;
345
+ raw[head] = nested;
346
+ };
347
+ if (env[ENV_KEYS.retentionDays]?.trim())
348
+ put("retentionDays", env[ENV_KEYS.retentionDays]);
349
+ if (env[ENV_KEYS.otlpEnabled] !== undefined)
350
+ put("otlp.enabled", env[ENV_KEYS.otlpEnabled]);
351
+ const endpointEnv = env[ENV_KEYS.otlpEndpoint];
352
+ if (endpointEnv !== undefined && endpointEnv.trim() !== "")
353
+ put("otlp.endpoint", endpointEnv);
354
+ if (env[ENV_KEYS.otlpTokenEnv]?.trim())
355
+ put("otlp.tokenEnv", env[ENV_KEYS.otlpTokenEnv]);
356
+ if (env[ENV_KEYS.otlpInstanceId] !== undefined)
357
+ put("otlp.instanceId", env[ENV_KEYS.otlpInstanceId]);
358
+ if (env[ENV_KEYS.serviceName]?.trim())
359
+ put("otlp.serviceName", env[ENV_KEYS.serviceName]);
360
+ if (env[ENV_KEYS.environment] !== undefined)
361
+ put("otlp.environment", env[ENV_KEYS.environment]);
362
+ if (env[ENV_KEYS.samplingRatio]?.trim())
363
+ put("otlp.samplingRatio", env[ENV_KEYS.samplingRatio]);
364
+ if (env[ENV_KEYS.otlpGzip] !== undefined)
365
+ put("otlp.gzip", env[ENV_KEYS.otlpGzip]);
366
+ if (env[ENV_KEYS.batchSize]?.trim())
367
+ put("otlp.batchSize", env[ENV_KEYS.batchSize]);
368
+ if (env[ENV_KEYS.capturePrompts] !== undefined)
369
+ put("capture.prompts", env[ENV_KEYS.capturePrompts]);
370
+ if (env[ENV_KEYS.captureCompletions] !== undefined)
371
+ put("capture.completions", env[ENV_KEYS.captureCompletions]);
372
+ if (env[ENV_KEYS.captureToolArguments] !== undefined)
373
+ put("capture.toolArguments", env[ENV_KEYS.captureToolArguments]);
374
+ if (env[ENV_KEYS.captureToolResults] !== undefined)
375
+ put("capture.toolResults", env[ENV_KEYS.captureToolResults]);
376
+ if (env[ENV_KEYS.redactionMode]?.trim())
377
+ put("redaction.mode", env[ENV_KEYS.redactionMode]);
378
+ const signalsEnv = env[ENV_KEYS.otlpSignals];
379
+ if (signalsEnv?.trim()) {
380
+ const enabled = new Set(signalsEnv.split(",").map((signal) => signal.trim().toLowerCase()));
381
+ put("otlp.signals", {
382
+ traces: enabled.has("traces"),
383
+ logs: enabled.has("logs"),
384
+ metrics: enabled.has("metrics"),
385
+ });
386
+ }
387
+ if (env[ENV_KEYS.flushIntervalMs]?.trim())
388
+ put("batch.flushIntervalMs", env[ENV_KEYS.flushIntervalMs]);
389
+ if (env[ENV_KEYS.maxQueue]?.trim())
390
+ put("batch.maxQueue", env[ENV_KEYS.maxQueue]);
391
+ return parsePartialConfig(raw, "environment");
392
+ }
393
+ function readConfigFile(path) {
394
+ try {
395
+ const text = readFileSync(path, "utf8");
396
+ return { raw: JSON.parse(text), missing: false };
397
+ }
398
+ catch (error) {
399
+ const code = error.code;
400
+ if (code === "ENOENT")
401
+ return { raw: null, missing: true };
402
+ if (error instanceof SyntaxError)
403
+ fail(`config file ${path} is not valid JSON: ${error.message}`);
404
+ fail(`cannot read config file ${path}`);
405
+ }
406
+ }
407
+ /**
408
+ * Load, merge and validate the effective configuration. Returns a structured
409
+ * result; it never throws, so an invalid configuration can never crash a host.
410
+ */
411
+ export function loadTelemetryConfig(options = {}) {
412
+ const env = options.env ?? process.env;
413
+ const paths = options.paths ?? resolveTelemetryPaths(env);
414
+ try {
415
+ let fromFile = {};
416
+ if (!options.skipFile) {
417
+ const { raw, missing } = options.file !== undefined
418
+ ? { raw: options.file, missing: false }
419
+ : readConfigFile(paths.configFile);
420
+ if (!missing && raw !== null && raw !== undefined)
421
+ fromFile = parsePartialConfig(raw, "config file");
422
+ }
423
+ const fromEnv = environmentOverrides(env);
424
+ const merged = merge(merge(merge(createDefaultConfig(), fromFile), fromEnv), options.overrides ?? {});
425
+ // Re-parse the fully merged object so every value is re-validated in
426
+ // context (a partial that was valid alone must stay valid combined).
427
+ const validated = parsePartialConfig(merged, "configuration");
428
+ const config = merge(createDefaultConfig(), validated);
429
+ return { ok: true, config, paths };
430
+ }
431
+ catch (error) {
432
+ const message = error instanceof ConfigError
433
+ ? error.message
434
+ : error instanceof Error
435
+ ? error.message
436
+ : String(error);
437
+ return { ok: false, error: message, paths };
438
+ }
439
+ }
440
+ // ---------------------------------------------------------------------------
441
+ // Persistence
442
+ // ---------------------------------------------------------------------------
443
+ /** Serialize a config for storage. The shape contains no credential by construction. */
444
+ export function serializeConfig(config) {
445
+ return `${JSON.stringify(config, null, 2)}\n`;
446
+ }
447
+ /**
448
+ * Apply validated overrides on top of a base configuration and return the
449
+ * effective result. Used by the setup command; throws `ConfigError` on invalid
450
+ * input so the caller can report an actionable message.
451
+ */
452
+ export function updateConfig(base, overrides) {
453
+ const merged = merge(base, overrides);
454
+ const validated = parsePartialConfig(merged, "configuration");
455
+ return merge(createDefaultConfig(), validated);
456
+ }
457
+ /**
458
+ * Atomically write the config file with 0600 file mode and 0700 parent. Write
459
+ * to a sibling temp file, fsync, rename over the target.
460
+ */
461
+ export function writeConfigFile(path, config) {
462
+ const directory = dirname(path);
463
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
464
+ try {
465
+ chmodSync(directory, 0o700);
466
+ }
467
+ catch {
468
+ // Hardening only.
469
+ }
470
+ const temp = `${path}.${process.pid}.tmp`;
471
+ const text = serializeConfig(config);
472
+ const descriptor = openSync(temp, "w", 0o600);
473
+ try {
474
+ writeSync(descriptor, text, 0, "utf8");
475
+ fsyncSync(descriptor);
476
+ }
477
+ finally {
478
+ closeSync(descriptor);
479
+ }
480
+ try {
481
+ chmodSync(temp, 0o600);
482
+ }
483
+ catch {
484
+ // Hardening only.
485
+ }
486
+ renameSync(temp, path);
487
+ try {
488
+ chmodSync(path, 0o600);
489
+ }
490
+ catch {
491
+ // Hardening only.
492
+ }
493
+ }
494
+ /**
495
+ * A display projection of the configuration. It contains no credential (there
496
+ * is none) and reports whether the token environment variable is present
497
+ * without ever reading or echoing its value.
498
+ */
499
+ export function describeConfig(config, env = process.env) {
500
+ return {
501
+ version: config.version,
502
+ retentionDays: config.retentionDays,
503
+ capture: { ...config.capture },
504
+ redaction: { ...config.redaction },
505
+ otlp: {
506
+ enabled: config.otlp.enabled,
507
+ endpoint: config.otlp.endpoint,
508
+ headers: Object.keys(config.otlp.headers),
509
+ tokenEnv: config.otlp.tokenEnv,
510
+ tokenConfigured: Boolean(env[config.otlp.tokenEnv]?.trim()),
511
+ instanceId: config.otlp.instanceId,
512
+ serviceName: config.otlp.serviceName,
513
+ environment: config.otlp.environment,
514
+ samplingRatio: config.otlp.samplingRatio,
515
+ signals: { ...config.otlp.signals },
516
+ gzip: config.otlp.gzip,
517
+ maxAttempts: config.otlp.maxAttempts,
518
+ timeoutMs: config.otlp.timeoutMs,
519
+ batchSize: config.otlp.batchSize,
520
+ },
521
+ batch: { ...config.batch },
522
+ };
523
+ }
524
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { SqlDatabase } from "@alisio/sdk";
2
+ export type { SqlDatabase, SqlRow, SqlStatement, SqlValue } from "@alisio/sdk";
3
+ export interface ConfigureDatabaseOptions {
4
+ /** Milliseconds a locked database waits before failing. Defaults to 5000. */
5
+ busyTimeoutMs?: number;
6
+ /** Skip the WAL/busy_timeout/foreign_keys pragmas (used only by focused tests). */
7
+ minimal?: boolean;
8
+ }
9
+ /** File mode bits of `path`, or null when it does not exist. Exposed for tests. */
10
+ export declare function fileMode(path: string): number | null;
11
+ /**
12
+ * Harden an already-open host port with the telemetry pragmas and file
13
+ * permissions. The port is returned unchanged so callers can chain it.
14
+ */
15
+ export declare function configureDatabase(database: SqlDatabase, path: string, options?: ConfigureDatabaseOptions): SqlDatabase;
16
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE/E,MAAM,WAAW,wBAAwB;IACvC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAID,mFAAmF;AACnF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMpD;AAuBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,wBAA6B,GACrC,WAAW,CAiBb"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * The host-provided SQLite storage port.
3
+ *
4
+ * The database is opened by the host through `api.storage.sqlite(path)`, so the
5
+ * plugin never depends on a runtime SQLite driver. The host port applies its
6
+ * file permissions only when it creates the file and sets no pragmas, so this
7
+ * module hardens the port immediately after it is opened: it enables WAL, a
8
+ * `busy_timeout`, foreign keys and NORMAL synchronous mode, and defensively
9
+ * tightens the database file to 0600 and its parent directory to 0700.
10
+ * `PRAGMA optimize` runs periodically from the store.
11
+ *
12
+ * The types are re-exported from `@alisio/sdk` so the rest of the plugin stays
13
+ * driver-agnostic. Tests must run without a host; they inject an equivalent
14
+ * `SqlDatabase` from `test/sqlite-driver.ts`, which is never shipped.
15
+ */
16
+ import { chmodSync, mkdirSync, statSync } from "node:fs";
17
+ import { dirname } from "node:path";
18
+ const DEFAULT_BUSY_TIMEOUT_MS = 5_000;
19
+ /** File mode bits of `path`, or null when it does not exist. Exposed for tests. */
20
+ export function fileMode(path) {
21
+ try {
22
+ return statSync(path).mode & 0o777;
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ /** Create (if needed) and tighten the parent directory to 0700. */
29
+ function ensureParent(path) {
30
+ const parent = dirname(path);
31
+ mkdirSync(parent, { recursive: true, mode: 0o700 });
32
+ // `mkdirSync`'s mode is masked by the process umask, so tighten explicitly.
33
+ try {
34
+ chmodSync(parent, 0o700);
35
+ }
36
+ catch {
37
+ // A read-only or foreign filesystem is not a reason to fail telemetry.
38
+ }
39
+ }
40
+ /** Best-effort 0600 on the database file; permissions are hardening, not a gate. */
41
+ function tightenFile(path) {
42
+ try {
43
+ chmodSync(path, 0o600);
44
+ }
45
+ catch {
46
+ // Ignore: some filesystems reject chmod.
47
+ }
48
+ }
49
+ /**
50
+ * Harden an already-open host port with the telemetry pragmas and file
51
+ * permissions. The port is returned unchanged so callers can chain it.
52
+ */
53
+ export function configureDatabase(database, path, options = {}) {
54
+ const inMemory = path === ":memory:" || path === "";
55
+ if (!inMemory) {
56
+ ensureParent(path);
57
+ tightenFile(path);
58
+ }
59
+ if (!options.minimal) {
60
+ database.exec("PRAGMA journal_mode = WAL");
61
+ database.exec(`PRAGMA busy_timeout = ${Math.max(0, options.busyTimeoutMs ?? DEFAULT_BUSY_TIMEOUT_MS)}`);
62
+ database.exec("PRAGMA foreign_keys = ON");
63
+ database.exec("PRAGMA synchronous = NORMAL");
64
+ }
65
+ return database;
66
+ }
67
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYpC,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAEtC,mFAAmF;AACnF,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,mEAAmE;AACnE,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACpD,4EAA4E;IAC5E,IAAI,CAAC;QACH,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,CAAC;QACH,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,yCAAyC;IAC3C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAqB,EACrB,IAAY,EACZ,OAAO,GAA6B,EAAE;IAEtC,MAAM,QAAQ,GAAG,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,EAAE,CAAC;IACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,WAAW,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC3C,QAAQ,CAAC,IAAI,CACX,yBAAyB,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,aAAa,IAAI,uBAAuB,CAAC,EAAE,CACzF,CAAC;QACF,QAAQ,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC1C,QAAQ,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}