@calltelemetry/cli 1.2.1 → 1.4.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.
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../src/lib/deployment.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,KAAK,CAAC;AAItD,wBAAgB,oBAAoB,IAAI,cAAc,CAwBrD;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAgB7D;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
1
+ {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../src/lib/deployment.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,MAAM,MAAM,cAAc,GAAG,gBAAgB,GAAG,KAAK,CAAC;AAmBtD,wBAAgB,oBAAoB,IAAI,cAAc,CA+BrD;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAgB7D;AAED,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
@@ -6,9 +6,33 @@ import { existsSync } from 'node:fs';
6
6
  import { isKubeConfigAvailable } from './k8s-client.js';
7
7
  import { getPrefs } from './prefs.js';
8
8
  import { getPaths } from './paths.js';
9
- import { debug } from './log.js';
9
+ import { readEnvKeys } from './env.js';
10
+ import { debug, warnLog } from './log.js';
10
11
  let cachedBackend = null;
12
+ /**
13
+ * DEPLOY_MODE from the appliance .env — the install-scoped contract that
14
+ * `ct update` merges and preserves alongside image version pins. Accepts
15
+ * `compose`/`docker-compose` and `k3s` (case-insensitive); anything else
16
+ * warns and falls through to the next precedence leg.
17
+ */
18
+ function deployModeFromEnv() {
19
+ const raw = readEnvKeys()['DEPLOY_MODE']?.trim().toLowerCase();
20
+ if (!raw)
21
+ return null;
22
+ if (raw === 'k3s')
23
+ return 'k3s';
24
+ if (raw === 'compose' || raw === 'docker-compose')
25
+ return 'docker-compose';
26
+ warnLog(`Invalid DEPLOY_MODE "${raw}" in .env — expected compose|k3s, ignoring`);
27
+ return null;
28
+ }
11
29
  export function detectDeploymentMode() {
30
+ // .env flag wins: install-scoped, durable across updates (REL-3246)
31
+ const envMode = deployModeFromEnv();
32
+ if (envMode) {
33
+ debug(`Deployment mode from .env DEPLOY_MODE: ${envMode}`);
34
+ return envMode;
35
+ }
12
36
  const prefs = getPrefs();
13
37
  // User override from preferences
14
38
  if (prefs.deploymentMode && prefs.deploymentMode !== 'docker-compose') {
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../src/lib/deployment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAKjC,IAAI,aAAa,GAA6B,IAAI,CAAC;AAEnD,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IAEzB,iCAAiC;IACjC,IAAI,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,cAAc,KAAK,gBAAgB,EAAE,CAAC;QACtE,KAAK,CAAC,+BAA+B,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC,cAAc,CAAC;IAC9B,CAAC;IAED,iDAAiD;IACjD,IAAI,UAAU,CAAC,kBAAkB,CAAC,IAAI,qBAAqB,EAAE,EAAE,CAAC;QAC9D,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,2BAA2B;IAC3B,MAAM,EAAE,WAAW,EAAE,GAAG,QAAQ,EAAE,CAAC;IACnC,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,KAAK,CAAC,8CAA8C,CAAC,CAAC;QACtD,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,2DAA2D,CAAC,CAAC;IACnE,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IAExC,MAAM,IAAI,GAAG,oBAAoB,EAAE,CAAC;IAEpC,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,aAAa,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAChE,aAAa,GAAG,IAAI,cAAc,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,SAAS,IAAI,UAAU,CAAC,CAAC;IAC/B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../src/lib/deployment.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAK1C,IAAI,aAAa,GAA6B,IAAI,CAAC;AAEnD;;;;;GAKG;AACH,SAAS,iBAAiB;IACxB,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC/D,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAChC,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,gBAAgB;QAAE,OAAO,gBAAgB,CAAC;IAC3E,OAAO,CAAC,wBAAwB,GAAG,4CAA4C,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,oBAAoB;IAClC,oEAAoE;IACpE,MAAM,OAAO,GAAG,iBAAiB,EAAE,CAAC;IACpC,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,0CAA0C,OAAO,EAAE,CAAC,CAAC;QAC3D,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IAEzB,iCAAiC;IACjC,IAAI,KAAK,CAAC,cAAc,IAAI,KAAK,CAAC,cAAc,KAAK,gBAAgB,EAAE,CAAC;QACtE,KAAK,CAAC,+BAA+B,KAAK,CAAC,cAAc,EAAE,CAAC,CAAC;QAC7D,OAAO,KAAK,CAAC,cAAc,CAAC;IAC9B,CAAC;IAED,iDAAiD;IACjD,IAAI,UAAU,CAAC,kBAAkB,CAAC,IAAI,qBAAqB,EAAE,EAAE,CAAC;QAC9D,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAC3C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,2BAA2B;IAC3B,MAAM,EAAE,WAAW,EAAE,GAAG,QAAQ,EAAE,CAAC;IACnC,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,KAAK,CAAC,8CAA8C,CAAC,CAAC;QACtD,OAAO,gBAAgB,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,2DAA2D,CAAC,CAAC;IACnE,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,IAAI,aAAa;QAAE,OAAO,aAAa,CAAC;IAExC,MAAM,IAAI,GAAG,oBAAoB,EAAE,CAAC;IAEpC,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnB,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;QACzB,aAAa,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC;IAC7D,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAChE,aAAa,GAAG,IAAI,cAAc,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,SAAS,IAAI,UAAU,CAAC,CAAC;IAC/B,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,aAAa,GAAG,IAAI,CAAC;AACvB,CAAC"}
@@ -1,4 +1,4 @@
1
- export type HelmfileEnvironment = 'ct-dev' | 'ct-prod' | 'ct-test';
1
+ export type HelmfileEnvironment = 'ct-dev' | 'ct-prod' | 'ct-test' | 'ct-appliance';
2
2
  export interface HelmfileOpts {
3
3
  helmfilePath: string;
4
4
  environment: HelmfileEnvironment;
@@ -1 +1 @@
1
- {"version":3,"file":"helmfile.d.ts","sourceRoot":"","sources":["../../src/lib/helmfile.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAEnE,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,mBAAmB,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAOvD;AAWD,wBAAgB,mBAAmB,IAAI,MAAM,CAY5C;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOpE;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOrE;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvE;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAMxE"}
1
+ {"version":3,"file":"helmfile.d.ts","sourceRoot":"","sources":["../../src/lib/helmfile.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,mBAAmB,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,cAAc,CAAC;AAEpF,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,mBAAmB,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAOvD;AAWD,wBAAgB,mBAAmB,IAAI,MAAM,CAY5C;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOpE;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOrE;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAMtE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAOvE;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAMxE"}
@@ -0,0 +1,78 @@
1
+ import { type Preferences } from '../prefs.js';
2
+ import type { DeploymentMode } from '../deployment.js';
3
+ import type { HelmfileEnvironment } from '../helmfile.js';
4
+ export declare const APPLIANCE_INFO_SCHEMA_VERSION = 1;
5
+ export declare const DEFAULT_APPLIANCE_HOSTNAME = "calltelemetry";
6
+ export declare const APPLIANCE_DEPLOYMENT_MODES: readonly DeploymentMode[];
7
+ export declare const APPLIANCE_HELMFILE_ENVIRONMENTS: readonly HelmfileEnvironment[];
8
+ /** Non-secret image pins carried in the appliance `.env`. */
9
+ export interface ApplianceVersions {
10
+ cli?: string;
11
+ web?: string;
12
+ vue?: string;
13
+ jtapi?: string;
14
+ ctMedia?: string;
15
+ syslog?: string;
16
+ traceroute?: string;
17
+ }
18
+ export interface ApplianceInfo {
19
+ schemaVersion: typeof APPLIANCE_INFO_SCHEMA_VERSION;
20
+ /** Stable installation identifier derived from the install dir + machine id. */
21
+ installationId: string;
22
+ installDir: string;
23
+ hostname: string;
24
+ deploymentMode: DeploymentMode;
25
+ k8sNamespace: string;
26
+ k8sEnvironment: HelmfileEnvironment;
27
+ versions: ApplianceVersions;
28
+ createdAt: string;
29
+ updatedAt: string;
30
+ }
31
+ export interface ApplianceInfoValidation {
32
+ valid: boolean;
33
+ errors: string[];
34
+ }
35
+ export declare class ApplianceInfoValidationError extends Error {
36
+ readonly errors: string[];
37
+ constructor(errors: string[]);
38
+ }
39
+ /**
40
+ * Derive a stable, non-license installation identifier. This is not the
41
+ * licensing `CT-APP-*` identifier; it exists only so job receipts from the
42
+ * same install can be correlated.
43
+ */
44
+ export declare function deriveInstallationId(installDir: string, machineId?: string): string;
45
+ /** Map `.env` pin keys onto the non-secret appliance version record. */
46
+ export declare function versionsFromEnv(env: Record<string, string>): ApplianceVersions;
47
+ export declare function validateApplianceInfo(info: unknown): ApplianceInfoValidation;
48
+ export declare function assertValidApplianceInfo(info: unknown): asserts info is ApplianceInfo;
49
+ /** Resolve the persisted inventory path under the appliance k8s payload. */
50
+ export declare function resolveApplianceInfoPath(installDir: string): string;
51
+ /**
52
+ * Persist a validated inventory snapshot. The file is mode 0600 because it
53
+ * carries host placement details, even though it carries no credentials.
54
+ */
55
+ export declare function saveApplianceInfo(info: ApplianceInfo, path?: string): Promise<void>;
56
+ /** Load and validate an inventory snapshot. Missing files return null. */
57
+ export declare function loadApplianceInfo(path: string): ApplianceInfo | null;
58
+ export interface CollectApplianceInfoOptions {
59
+ installDir?: string;
60
+ hostname?: string;
61
+ machineId?: string;
62
+ env?: Record<string, string>;
63
+ prefs?: Preferences;
64
+ cliVersion?: string;
65
+ now?: Date;
66
+ }
67
+ /**
68
+ * Build a fresh snapshot from the appliance `.env`, paths, and preferences.
69
+ * The caller is responsible for persisting it with `saveApplianceInfo`.
70
+ */
71
+ export declare function collectApplianceInfo(options?: CollectApplianceInfoOptions): ApplianceInfo;
72
+ /**
73
+ * Refresh an existing snapshot in place. Identity (`installationId`,
74
+ * `installDir`, `createdAt`) is preserved; placement, versions, and
75
+ * `updatedAt` are replaced.
76
+ */
77
+ export declare function refreshApplianceInfo(previous: ApplianceInfo, updates: Pick<ApplianceInfo, 'deploymentMode' | 'k8sNamespace' | 'k8sEnvironment' | 'versions' | 'hostname'>, now?: Date): ApplianceInfo;
78
+ //# sourceMappingURL=appliance-info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appliance-info.d.ts","sourceRoot":"","sources":["../../../src/lib/k8s/appliance-info.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Appliance inventory for the Kubernetes deployment path.
3
+ *
4
+ * This is the durable, validated record of *what this appliance is* — the
5
+ * installation identity, deployment mode, namespace/environment, and the
6
+ * image pins read from the appliance `.env`. It is deliberately separate
7
+ * from `~/.ct/preferences.json`: preferences are operator overrides, while
8
+ * this file is a generated snapshot that can be attached to a job receipt.
9
+ *
10
+ * The snapshot never contains credentials. Only non-secret image pins and
11
+ * placement settings are persisted; `.env` remains the source of truth for
12
+ * everything else.
13
+ */
14
+ import { createHash } from 'node:crypto';
15
+ import { existsSync, readFileSync } from 'node:fs';
16
+ import { dirname, join } from 'node:path';
17
+ import { mkdirSafe, writeFileSafe } from '../fs.js';
18
+ import { getPaths } from '../paths.js';
19
+ import { getPrefs } from '../prefs.js';
20
+ import { isValidHostname } from '../identity.js';
21
+ import { readEnvKeys } from '../env.js';
22
+ export const APPLIANCE_INFO_SCHEMA_VERSION = 1;
23
+ export const DEFAULT_APPLIANCE_HOSTNAME = 'calltelemetry';
24
+ export const APPLIANCE_DEPLOYMENT_MODES = [
25
+ 'docker-compose',
26
+ 'k3s',
27
+ ];
28
+ export const APPLIANCE_HELMFILE_ENVIRONMENTS = [
29
+ 'ct-dev',
30
+ 'ct-prod',
31
+ 'ct-test',
32
+ 'ct-appliance',
33
+ ];
34
+ export class ApplianceInfoValidationError extends Error {
35
+ errors;
36
+ constructor(errors) {
37
+ super(`Invalid appliance info: ${errors.join('; ')}`);
38
+ this.name = 'ApplianceInfoValidationError';
39
+ this.errors = errors;
40
+ }
41
+ }
42
+ const DNS_LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
43
+ const INSTALLATION_ID = /^[a-f0-9]{16,64}$/;
44
+ const VERSION_VALUE = /^\S+$/;
45
+ const MAX_VERSION_LENGTH = 128;
46
+ function isIsoTimestamp(value) {
47
+ if (typeof value !== 'string' || value.length === 0)
48
+ return false;
49
+ const parsed = Date.parse(value);
50
+ return Number.isFinite(parsed);
51
+ }
52
+ function isScalarVersion(value) {
53
+ return (typeof value === 'string' &&
54
+ value.length > 0 &&
55
+ value.length <= MAX_VERSION_LENGTH &&
56
+ VERSION_VALUE.test(value) &&
57
+ // eslint-disable-next-line no-control-regex
58
+ !/[\u0000-\u001f\u007f]/.test(value));
59
+ }
60
+ /**
61
+ * Derive a stable, non-license installation identifier. This is not the
62
+ * licensing `CT-APP-*` identifier; it exists only so job receipts from the
63
+ * same install can be correlated.
64
+ */
65
+ export function deriveInstallationId(installDir, machineId = '') {
66
+ return createHash('sha256')
67
+ .update(`${installDir}\u0000${machineId}`)
68
+ .digest('hex')
69
+ .slice(0, 16);
70
+ }
71
+ /** Map `.env` pin keys onto the non-secret appliance version record. */
72
+ export function versionsFromEnv(env) {
73
+ const versions = {};
74
+ const mapping = [
75
+ ['cli', 'CT_CLI_VERSION'],
76
+ ['web', 'WEB_VERSION'],
77
+ ['vue', 'VUE_VERSION'],
78
+ ['jtapi', 'JTAPI_VERSION'],
79
+ ['ctMedia', 'CT_MEDIA_VERSION'],
80
+ ['syslog', 'CT_SYSLOG_INGEST_VERSION'],
81
+ ['traceroute', 'TRACEROUTE_VERSION'],
82
+ ];
83
+ for (const [field, key] of mapping) {
84
+ const value = env[key]?.trim();
85
+ if (value)
86
+ versions[field] = value;
87
+ }
88
+ return versions;
89
+ }
90
+ export function validateApplianceInfo(info) {
91
+ const errors = [];
92
+ if (typeof info !== 'object' || info === null || Array.isArray(info)) {
93
+ return { valid: false, errors: ['appliance info must be an object'] };
94
+ }
95
+ const value = info;
96
+ if (value.schemaVersion !== APPLIANCE_INFO_SCHEMA_VERSION) {
97
+ errors.push(`schemaVersion must be ${APPLIANCE_INFO_SCHEMA_VERSION}`);
98
+ }
99
+ if (typeof value.installationId !== 'string' || !INSTALLATION_ID.test(value.installationId)) {
100
+ errors.push('installationId must be a 16-64 character lowercase hex string');
101
+ }
102
+ if (typeof value.installDir !== 'string' || value.installDir.trim().length === 0) {
103
+ errors.push('installDir must be a non-empty string');
104
+ }
105
+ if (typeof value.hostname !== 'string' ||
106
+ !isValidHostname(value.hostname)) {
107
+ errors.push('hostname must be a valid RFC 1123 hostname');
108
+ }
109
+ if (typeof value.deploymentMode !== 'string' ||
110
+ !APPLIANCE_DEPLOYMENT_MODES.includes(value.deploymentMode)) {
111
+ errors.push(`deploymentMode must be one of ${APPLIANCE_DEPLOYMENT_MODES.join(', ')}`);
112
+ }
113
+ if (typeof value.k8sNamespace !== 'string' ||
114
+ !DNS_LABEL.test(value.k8sNamespace)) {
115
+ errors.push('k8sNamespace must be a valid DNS-1123 label');
116
+ }
117
+ if (typeof value.k8sEnvironment !== 'string' ||
118
+ !APPLIANCE_HELMFILE_ENVIRONMENTS.includes(value.k8sEnvironment)) {
119
+ errors.push(`k8sEnvironment must be one of ${APPLIANCE_HELMFILE_ENVIRONMENTS.join(', ')}`);
120
+ }
121
+ if (typeof value.versions !== 'object' || value.versions === null || Array.isArray(value.versions)) {
122
+ errors.push('versions must be an object');
123
+ }
124
+ else {
125
+ for (const [field, pin] of Object.entries(value.versions)) {
126
+ if (!['cli', 'web', 'vue', 'jtapi', 'ctMedia', 'syslog', 'traceroute'].includes(field)) {
127
+ errors.push(`versions.${field} is not a recognized component`);
128
+ continue;
129
+ }
130
+ if (pin !== undefined && !isScalarVersion(pin)) {
131
+ errors.push(`versions.${field} must be a non-empty single-token version string`);
132
+ }
133
+ }
134
+ }
135
+ if (!isIsoTimestamp(value.createdAt)) {
136
+ errors.push('createdAt must be an ISO timestamp');
137
+ }
138
+ if (!isIsoTimestamp(value.updatedAt)) {
139
+ errors.push('updatedAt must be an ISO timestamp');
140
+ }
141
+ else if (isIsoTimestamp(value.createdAt) && Date.parse(value.updatedAt) < Date.parse(value.createdAt)) {
142
+ errors.push('updatedAt must not be earlier than createdAt');
143
+ }
144
+ return { valid: errors.length === 0, errors };
145
+ }
146
+ export function assertValidApplianceInfo(info) {
147
+ const result = validateApplianceInfo(info);
148
+ if (!result.valid)
149
+ throw new ApplianceInfoValidationError(result.errors);
150
+ }
151
+ /** Resolve the persisted inventory path under the appliance k8s payload. */
152
+ export function resolveApplianceInfoPath(installDir) {
153
+ return join(installDir, 'k8s', 'appliance-info.json');
154
+ }
155
+ /**
156
+ * Persist a validated inventory snapshot. The file is mode 0600 because it
157
+ * carries host placement details, even though it carries no credentials.
158
+ */
159
+ export async function saveApplianceInfo(info, path = resolveApplianceInfoPath(info.installDir)) {
160
+ assertValidApplianceInfo(info);
161
+ await mkdirSafe(dirname(path));
162
+ await writeFileSafe(path, JSON.stringify(info, null, 2) + '\n', { mode: 0o600 });
163
+ }
164
+ /** Load and validate an inventory snapshot. Missing files return null. */
165
+ export function loadApplianceInfo(path) {
166
+ if (!existsSync(path))
167
+ return null;
168
+ let parsed;
169
+ try {
170
+ parsed = JSON.parse(readFileSync(path, 'utf-8'));
171
+ }
172
+ catch (err) {
173
+ throw new ApplianceInfoValidationError([`could not parse ${path}: ${err.message}`]);
174
+ }
175
+ assertValidApplianceInfo(parsed);
176
+ return parsed;
177
+ }
178
+ /**
179
+ * Build a fresh snapshot from the appliance `.env`, paths, and preferences.
180
+ * The caller is responsible for persisting it with `saveApplianceInfo`.
181
+ */
182
+ export function collectApplianceInfo(options = {}) {
183
+ const installDir = options.installDir ?? getPaths().installDir;
184
+ const env = options.env ?? readEnvKeys();
185
+ const prefs = options.prefs ?? getPrefs();
186
+ const now = options.now ?? new Date();
187
+ const timestamp = now.toISOString();
188
+ if (!prefs.deploymentMode || !APPLIANCE_DEPLOYMENT_MODES.includes(prefs.deploymentMode)) {
189
+ throw new ApplianceInfoValidationError(['preferences.deploymentMode is invalid']);
190
+ }
191
+ if (!prefs.k8sEnvironment || !APPLIANCE_HELMFILE_ENVIRONMENTS.includes(prefs.k8sEnvironment)) {
192
+ throw new ApplianceInfoValidationError(['preferences.k8sEnvironment is invalid']);
193
+ }
194
+ const versions = versionsFromEnv(env);
195
+ if (options.cliVersion)
196
+ versions.cli = options.cliVersion;
197
+ const info = {
198
+ schemaVersion: APPLIANCE_INFO_SCHEMA_VERSION,
199
+ installationId: deriveInstallationId(installDir, options.machineId),
200
+ installDir,
201
+ hostname: options.hostname ?? DEFAULT_APPLIANCE_HOSTNAME,
202
+ deploymentMode: prefs.deploymentMode,
203
+ k8sNamespace: prefs.k8sNamespace,
204
+ k8sEnvironment: prefs.k8sEnvironment,
205
+ versions,
206
+ createdAt: timestamp,
207
+ updatedAt: timestamp,
208
+ };
209
+ assertValidApplianceInfo(info);
210
+ return info;
211
+ }
212
+ /**
213
+ * Refresh an existing snapshot in place. Identity (`installationId`,
214
+ * `installDir`, `createdAt`) is preserved; placement, versions, and
215
+ * `updatedAt` are replaced.
216
+ */
217
+ export function refreshApplianceInfo(previous, updates, now = new Date()) {
218
+ const next = {
219
+ ...previous,
220
+ ...updates,
221
+ updatedAt: now.toISOString(),
222
+ };
223
+ assertValidApplianceInfo(next);
224
+ return next;
225
+ }
226
+ //# sourceMappingURL=appliance-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appliance-info.js","sourceRoot":"","sources":["../../../src/lib/k8s/appliance-info.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAoB,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAIxC,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAC/C,MAAM,CAAC,MAAM,0BAA0B,GAAG,eAAe,CAAC;AAE1D,MAAM,CAAC,MAAM,0BAA0B,GAA8B;IACnE,gBAAgB;IAChB,KAAK;CACN,CAAC;AAEF,MAAM,CAAC,MAAM,+BAA+B,GAAmC;IAC7E,QAAQ;IACR,SAAS;IACT,SAAS;IACT,cAAc;CACf,CAAC;AAgCF,MAAM,OAAO,4BAA6B,SAAQ,KAAK;IAC5C,MAAM,CAAW;IAE1B,YAAY,MAAgB;QAC1B,KAAK,CAAC,2BAA2B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;QAC3C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,MAAM,SAAS,GAAG,sCAAsC,CAAC;AACzD,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAC5C,MAAM,aAAa,GAAG,OAAO,CAAC;AAC9B,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAE/B,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,MAAM,IAAI,kBAAkB;QAClC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;QACzB,4CAA4C;QAC5C,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CACrC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAkB,EAAE,SAAS,GAAG,EAAE;IACrE,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,GAAG,UAAU,SAAS,SAAS,EAAE,CAAC;SACzC,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,GAA2B;IACzD,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,OAAO,GAA6C;QACxD,CAAC,KAAK,EAAE,gBAAgB,CAAC;QACzB,CAAC,KAAK,EAAE,aAAa,CAAC;QACtB,CAAC,KAAK,EAAE,aAAa,CAAC;QACtB,CAAC,OAAO,EAAE,eAAe,CAAC;QAC1B,CAAC,SAAS,EAAE,kBAAkB,CAAC;QAC/B,CAAC,QAAQ,EAAE,0BAA0B,CAAC;QACtC,CAAC,YAAY,EAAE,oBAAoB,CAAC;KACrC,CAAC;IACF,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;QACnC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC;QAC/B,IAAI,KAAK;YAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;IACrC,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,kCAAkC,CAAC,EAAE,CAAC;IACxE,CAAC;IACD,MAAM,KAAK,GAAG,IAA8B,CAAC;IAE7C,IAAI,KAAK,CAAC,aAAa,KAAK,6BAA6B,EAAE,CAAC;QAC1D,MAAM,CAAC,IAAI,CAAC,yBAAyB,6BAA6B,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QAC5F,MAAM,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;IAC/E,CAAC;IACD,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjF,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IACvD,CAAC;IACD,IACE,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ;QAClC,CAAC,eAAe,CAAC,KAAK,CAAC,QAAQ,CAAC,EAChC,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;IAC5D,CAAC;IACD,IACE,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ;QACxC,CAAC,0BAA0B,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAgC,CAAC,EAC5E,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,iCAAiC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,IACE,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ;QACtC,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EACnC,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;IAC7D,CAAC;IACD,IACE,OAAO,KAAK,CAAC,cAAc,KAAK,QAAQ;QACxC,CAAC,+BAA+B,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAqC,CAAC,EACtF,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,iCAAiC,+BAA+B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnG,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IAC5C,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1D,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvF,MAAM,CAAC,IAAI,CAAC,YAAY,KAAK,gCAAgC,CAAC,CAAC;gBAC/D,SAAS;YACX,CAAC;YACD,IAAI,GAAG,KAAK,SAAS,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC/C,MAAM,CAAC,IAAI,CAAC,YAAY,KAAK,kDAAkD,CAAC,CAAC;YACnF,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IACpD,CAAC;IACD,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACrC,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;IACpD,CAAC;SAAM,IAAI,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACxG,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAa;IACpD,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,MAAM,IAAI,4BAA4B,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC3E,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,wBAAwB,CAAC,UAAkB;IACzD,OAAO,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,qBAAqB,CAAC,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAmB,EACnB,IAAI,GAAG,wBAAwB,CAAC,IAAI,CAAC,UAAU,CAAC;IAEhD,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B,MAAM,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,IAAI,4BAA4B,CAAC,CAAC,mBAAmB,IAAI,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACtF,CAAC;IACD,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACjC,OAAO,MAAM,CAAC;AAChB,CAAC;AAYD;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAuC,EAAE;IAC5E,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,QAAQ,EAAE,CAAC,UAAU,CAAC;IAC/D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,WAAW,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,QAAQ,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;IACtC,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAEpC,IAAI,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,0BAA0B,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QACxF,MAAM,IAAI,4BAA4B,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,cAAc,IAAI,CAAC,+BAA+B,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;QAC7F,MAAM,IAAI,4BAA4B,CAAC,CAAC,uCAAuC,CAAC,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,OAAO,CAAC,UAAU;QAAE,QAAQ,CAAC,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC;IAE1D,MAAM,IAAI,GAAkB;QAC1B,aAAa,EAAE,6BAA6B;QAC5C,cAAc,EAAE,oBAAoB,CAAC,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC;QACnE,UAAU;QACV,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,0BAA0B;QACxD,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,QAAQ;QACR,SAAS,EAAE,SAAS;QACpB,SAAS,EAAE,SAAS;KACrB,CAAC;IACF,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAuB,EACvB,OAA4G,EAC5G,GAAG,GAAG,IAAI,IAAI,EAAE;IAEhB,MAAM,IAAI,GAAkB;QAC1B,GAAG,QAAQ;QACX,GAAG,OAAO;QACV,SAAS,EAAE,GAAG,CAAC,WAAW,EAAE;KAC7B,CAAC;IACF,wBAAwB,CAAC,IAAI,CAAC,CAAC;IAC/B,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,63 @@
1
+ export declare const JOB_LOG_SCHEMA_VERSION = 1;
2
+ export declare const DEFAULT_JOB_LOG_MAX_BYTES: number;
3
+ export type ApplianceJobLogLevel = 'info' | 'warn' | 'error';
4
+ export declare const APPLIANCE_JOB_LOG_LEVELS: readonly ApplianceJobLogLevel[];
5
+ export type ApplianceJobLogDetail = string | number | boolean;
6
+ export interface ApplianceJobLogEvent {
7
+ schemaVersion: typeof JOB_LOG_SCHEMA_VERSION;
8
+ jobId: string;
9
+ seq: number;
10
+ at: string;
11
+ level: ApplianceJobLogLevel;
12
+ phase: string;
13
+ message: string;
14
+ details?: Record<string, ApplianceJobLogDetail>;
15
+ }
16
+ export interface JobLogValidation {
17
+ valid: boolean;
18
+ errors: string[];
19
+ }
20
+ export interface JobLogReadResult {
21
+ events: ApplianceJobLogEvent[];
22
+ invalid: Array<{
23
+ line: number;
24
+ error: string;
25
+ }>;
26
+ }
27
+ export declare class JobLogValidationError extends Error {
28
+ readonly errors: string[];
29
+ constructor(errors: string[]);
30
+ }
31
+ /** Redact a single string value without changing non-secret text. */
32
+ export declare function redactJobLogValue(value: string): string;
33
+ /** Redact secret-looking keys and URL userinfo from a detail map. */
34
+ export declare function redactJobLogDetails(details: Record<string, unknown> | undefined): Record<string, ApplianceJobLogDetail> | undefined;
35
+ export declare function validateJobLogEvent(event: unknown): JobLogValidation;
36
+ export declare function assertValidJobLogEvent(event: unknown): asserts event is ApplianceJobLogEvent;
37
+ /** Build a fully populated, redacted event. */
38
+ export declare function createJobLogEvent(input: {
39
+ jobId: string;
40
+ seq: number;
41
+ phase: string;
42
+ message: string;
43
+ level?: ApplianceJobLogLevel;
44
+ details?: Record<string, unknown>;
45
+ now?: Date;
46
+ }): ApplianceJobLogEvent;
47
+ export declare function resolveJobLogPath(installDir: string): string;
48
+ /**
49
+ * Append one event as a single JSONL record. The file is created/kept mode
50
+ * 0600. A permission failure falls back to passwordless `sudo tee -a`, the
51
+ * same contract as `writeFileSafe`.
52
+ */
53
+ export declare function appendJobLogEvent(logPath: string, event: ApplianceJobLogEvent): Promise<void>;
54
+ /** Parse the log, reporting (but not throwing on) corrupt lines. */
55
+ export declare function readJobLog(logPath: string): JobLogReadResult;
56
+ /** Return the most recent valid events, preserving file order. */
57
+ export declare function tailJobLog(logPath: string, limit?: number): ApplianceJobLogEvent[];
58
+ /**
59
+ * Rotate an oversized log to `<path>.1`, keeping one previous generation.
60
+ * Returns true when a rotation happened.
61
+ */
62
+ export declare function rotateJobLogIfNeeded(logPath: string, maxBytes?: number): boolean;
63
+ //# sourceMappingURL=appliance-job-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"appliance-job-logger.d.ts","sourceRoot":"","sources":["../../../src/lib/k8s/appliance-job-logger.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,sBAAsB,IAAI,CAAC;AACxC,eAAO,MAAM,yBAAyB,QAAkB,CAAC;AAEzD,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAC7D,eAAO,MAAM,wBAAwB,EAAE,SAAS,oBAAoB,EAA8B,CAAC;AAEnG,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,OAAO,sBAAsB,CAAC;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,oBAAoB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjD;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;gBAEd,MAAM,EAAE,MAAM,EAAE;CAK7B;AA2BD,qEAAqE;AACrE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAC3C,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,GAAG,SAAS,CAenD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,gBAAgB,CA0DpE;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,oBAAoB,CAG5F;AAED,+CAA+C;AAC/C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ,GAAG,oBAAoB,CAcvB;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAsB5D;AAED,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,oBAAoB,EAAE,CAM9E;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,SAA4B,GACnC,OAAO,CAKT"}