@kici-dev/shared 0.1.12 → 0.1.14

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,48 +1,3 @@
1
1
  import "./chunk-gOLHoazu.js";
2
- import { readFile } from "node:fs/promises";
3
- import { existsSync } from "node:fs";
4
- import { fileURLToPath } from "node:url";
5
- import { transformSync } from "oxc-transform";
6
- //#region src/ts-loader-hook.ts
7
- function resolve(specifier, context, nextResolve) {
8
- if (specifier.endsWith(".js") && (specifier.startsWith("./") || specifier.startsWith("../"))) try {
9
- if (context.parentURL) {
10
- if (!existsSync(fileURLToPath(new URL(specifier, context.parentURL)))) {
11
- const tsSpecifier = specifier.slice(0, -3) + ".ts";
12
- if (existsSync(fileURLToPath(new URL(tsSpecifier, context.parentURL)))) return nextResolve(tsSpecifier, context);
13
- }
14
- }
15
- } catch {}
16
- return nextResolve(specifier, context);
17
- }
18
- async function load(url, context, nextLoad) {
19
- if (!url.startsWith("file:")) return nextLoad(url, context);
20
- const bareUrl = url.split("?")[0].split("#")[0];
21
- const isTs = bareUrl.endsWith(".ts");
22
- const isTsx = bareUrl.endsWith(".tsx");
23
- if (!isTs && !isTsx) return nextLoad(url, context);
24
- const filePath = fileURLToPath(bareUrl);
25
- const result = transformSync(filePath, await readFile(filePath, "utf8"), {
26
- lang: isTsx ? "tsx" : "ts",
27
- sourcemap: true,
28
- typescript: { allowNamespaces: true }
29
- });
30
- if (result.errors.length) {
31
- const msg = result.errors.map((e) => e.message).join("\n");
32
- throw new Error(`oxc-transform failed for ${filePath}:\n${msg}`);
33
- }
34
- let code = result.code;
35
- if (result.map) {
36
- const b64 = Buffer.from(JSON.stringify(result.map)).toString("base64");
37
- code += `\n//# sourceMappingURL=data:application/json;base64,${b64}\n`;
38
- }
39
- return {
40
- format: "module",
41
- source: code,
42
- shortCircuit: true
43
- };
44
- }
45
- //#endregion
46
- export { load, resolve };
47
-
48
- //# sourceMappingURL=ts-loader-hook.js.map
2
+ export * from "@kici-dev/core/ts-loader-hook";
3
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kici-dev/shared",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
5
5
  "keywords": [
6
6
  "kici",
@@ -95,7 +95,8 @@
95
95
  "winston-daily-rotate-file": "^5.0.0",
96
96
  "yaml": "^2.8.3",
97
97
  "zod": "^4.3.6",
98
- "zx": "^8.8.5"
98
+ "zx": "^8.8.5",
99
+ "@kici-dev/core": "0.1.14"
99
100
  },
100
101
  "devDependencies": {
101
102
  "@opentelemetry/sdk-trace-base": "^2.7.0",
package/sbom.spdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "@kici-dev/shared@0.1.12",
6
- "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fshared/0.1.12/1172a492-36f2-4dec-92a9-62941a834899",
5
+ "name": "@kici-dev/shared@0.1.14",
6
+ "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fshared/0.1.14/a35018ec-f363-4930-96e3-4e308475eca8",
7
7
  "creationInfo": {
8
- "created": "2026-05-27T16:57:23Z",
8
+ "created": "2026-05-30T03:05:47Z",
9
9
  "creators": [
10
10
  "Tool: kici-sbom-generator"
11
11
  ]
@@ -944,10 +944,30 @@
944
944
  "description": "javascript standard data structure library which benchmark against C++ STL",
945
945
  "homepage": "https://js-sdsl.org"
946
946
  },
947
+ {
948
+ "SPDXID": "SPDXRef-Package--kici-dev-core-0.1.14",
949
+ "name": "@kici-dev/core",
950
+ "versionInfo": "0.1.14",
951
+ "downloadLocation": "NOASSERTION",
952
+ "filesAnalyzed": false,
953
+ "licenseConcluded": "NOASSERTION",
954
+ "licenseDeclared": "Apache-2.0",
955
+ "copyrightText": "NOASSERTION",
956
+ "supplier": "NOASSERTION",
957
+ "externalRefs": [
958
+ {
959
+ "referenceCategory": "PACKAGE-MANAGER",
960
+ "referenceType": "purl",
961
+ "referenceLocator": "pkg:npm/%40kici-dev/core@0.1.14"
962
+ }
963
+ ],
964
+ "description": "Light shared utilities for the KiCI stack (logging, errors, formatting, crypto, zx init, the TypeScript ESM loader hook). No server-side dependencies.",
965
+ "homepage": "https://kici.dev"
966
+ },
947
967
  {
948
968
  "SPDXID": "SPDXRef-RootPackage",
949
969
  "name": "@kici-dev/shared",
950
- "versionInfo": "0.1.12",
970
+ "versionInfo": "0.1.14",
951
971
  "downloadLocation": "NOASSERTION",
952
972
  "filesAnalyzed": false,
953
973
  "licenseConcluded": "NOASSERTION",
@@ -958,7 +978,7 @@
958
978
  {
959
979
  "referenceCategory": "PACKAGE-MANAGER",
960
980
  "referenceType": "purl",
961
- "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.12"
981
+ "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.14"
962
982
  }
963
983
  ],
964
984
  "description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
@@ -6421,11 +6441,46 @@
6421
6441
  "relatedSpdxElement": "SPDXRef-Package-yargs-17.7.2",
6422
6442
  "relationshipType": "DEPENDS_ON"
6423
6443
  },
6444
+ {
6445
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6446
+ "relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.128.0",
6447
+ "relationshipType": "DEPENDS_ON"
6448
+ },
6449
+ {
6450
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6451
+ "relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
6452
+ "relationshipType": "DEPENDS_ON"
6453
+ },
6454
+ {
6455
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6456
+ "relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
6457
+ "relationshipType": "DEPENDS_ON"
6458
+ },
6459
+ {
6460
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6461
+ "relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
6462
+ "relationshipType": "DEPENDS_ON"
6463
+ },
6464
+ {
6465
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6466
+ "relatedSpdxElement": "SPDXRef-Package-zod-4.3.6",
6467
+ "relationshipType": "DEPENDS_ON"
6468
+ },
6469
+ {
6470
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.14",
6471
+ "relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
6472
+ "relationshipType": "DEPENDS_ON"
6473
+ },
6424
6474
  {
6425
6475
  "spdxElementId": "SPDXRef-RootPackage",
6426
6476
  "relatedSpdxElement": "SPDXRef-Package--aws-sdk-client-s3-3.1038.0",
6427
6477
  "relationshipType": "DEPENDS_ON"
6428
6478
  },
6479
+ {
6480
+ "spdxElementId": "SPDXRef-RootPackage",
6481
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.14",
6482
+ "relationshipType": "DEPENDS_ON"
6483
+ },
6429
6484
  {
6430
6485
  "spdxElementId": "SPDXRef-RootPackage",
6431
6486
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-api-1.9.1",
package/dist/crypto.d.ts DELETED
@@ -1,33 +0,0 @@
1
- /** Compute SHA-256 hex digest of a string or Buffer. */
2
- export declare function sha256(input: string | Buffer): string;
3
- /** Compute SHA-256 hex digest of a file's contents. */
4
- export declare function sha256File(filePath: string): Promise<string>;
5
- /**
6
- * Normalize line endings to LF so hashes computed on different platforms agree.
7
- *
8
- * Git for Windows ships with `core.autocrlf=true` in the system gitconfig, so a
9
- * `git clone` of a Linux-authored repo on a Windows host checks out text files
10
- * with CRLF in the working tree. The compiler hashed the LF source on Linux,
11
- * but the agent on Windows reads CRLF and computes a different hash — every
12
- * dispatch fails with a "lock file is out of date" error even though the
13
- * semantic content is identical.
14
- *
15
- * Applied at the boundaries where source / asset content enters the hash:
16
- * - raw workflow source (`.kici/workflows/*.ts`) at hash time, in both the
17
- * compiler (lockfile generation) and the agent (drift verification).
18
- * - file content portions of the asset digest (`hashFiles` resolution) on
19
- * both sides.
20
- *
21
- * Standalone `\r` is also collapsed to `\n` for safety against legacy
22
- * Mac-style endings, though TypeScript source files essentially never carry
23
- * those in practice.
24
- */
25
- export declare function normalizeLineEndings(input: string): string;
26
- /**
27
- * Derive an AES-256 key from an X25519 ECDH shared secret using HKDF.
28
- *
29
- * Used by the compiler (encrypt) and agent (decrypt) for tarball uploads.
30
- * Keys must be DER-encoded (PKCS8 for private, SPKI for public).
31
- */
32
- export declare function deriveSharedSecret(ourPrivateKey: Buffer, theirPublicKey: Buffer): Buffer;
33
- //# sourceMappingURL=crypto.d.ts.map
package/dist/crypto.js DELETED
@@ -1,67 +0,0 @@
1
- import "./chunk-gOLHoazu.js";
2
- import crypto, { createHash } from "node:crypto";
3
- import { readFile } from "node:fs/promises";
4
- //#region src/crypto.ts
5
- /** Compute SHA-256 hex digest of a string or Buffer. */
6
- function sha256(input) {
7
- return createHash("sha256").update(input).digest("hex");
8
- }
9
- /** Compute SHA-256 hex digest of a file's contents. */
10
- async function sha256File(filePath) {
11
- return sha256(await readFile(filePath));
12
- }
13
- /**
14
- * Normalize line endings to LF so hashes computed on different platforms agree.
15
- *
16
- * Git for Windows ships with `core.autocrlf=true` in the system gitconfig, so a
17
- * `git clone` of a Linux-authored repo on a Windows host checks out text files
18
- * with CRLF in the working tree. The compiler hashed the LF source on Linux,
19
- * but the agent on Windows reads CRLF and computes a different hash — every
20
- * dispatch fails with a "lock file is out of date" error even though the
21
- * semantic content is identical.
22
- *
23
- * Applied at the boundaries where source / asset content enters the hash:
24
- * - raw workflow source (`.kici/workflows/*.ts`) at hash time, in both the
25
- * compiler (lockfile generation) and the agent (drift verification).
26
- * - file content portions of the asset digest (`hashFiles` resolution) on
27
- * both sides.
28
- *
29
- * Standalone `\r` is also collapsed to `\n` for safety against legacy
30
- * Mac-style endings, though TypeScript source files essentially never carry
31
- * those in practice.
32
- */
33
- function normalizeLineEndings(input) {
34
- return input.replace(/\r\n?/g, "\n");
35
- }
36
- /** HKDF info string for ECDH-derived AES keys (upload encryption). */
37
- const HKDF_INFO = "kici-upload-encryption";
38
- /** Empty salt — ECDH output is already high entropy. */
39
- const HKDF_SALT = Buffer.alloc(0);
40
- /**
41
- * Derive an AES-256 key from an X25519 ECDH shared secret using HKDF.
42
- *
43
- * Used by the compiler (encrypt) and agent (decrypt) for tarball uploads.
44
- * Keys must be DER-encoded (PKCS8 for private, SPKI for public).
45
- */
46
- function deriveSharedSecret(ourPrivateKey, theirPublicKey) {
47
- const ourKeyObj = crypto.createPrivateKey({
48
- key: ourPrivateKey,
49
- format: "der",
50
- type: "pkcs8"
51
- });
52
- const theirKeyObj = crypto.createPublicKey({
53
- key: theirPublicKey,
54
- format: "der",
55
- type: "spki"
56
- });
57
- const sharedSecret = crypto.diffieHellman({
58
- publicKey: theirKeyObj,
59
- privateKey: ourKeyObj
60
- });
61
- const derivedKey = crypto.hkdfSync("sha256", sharedSecret, HKDF_SALT, HKDF_INFO, 32);
62
- return Buffer.from(derivedKey);
63
- }
64
- //#endregion
65
- export { deriveSharedSecret, normalizeLineEndings, sha256, sha256File };
66
-
67
- //# sourceMappingURL=crypto.js.map
package/dist/error.d.ts DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * Extract a human-readable error message from an unknown thrown value.
3
- */
4
- export declare function toErrorMessage(err: unknown): string;
5
- /**
6
- * Serialize an error into a structured object suitable for logging.
7
- *
8
- * Captures the message, error type name, common diagnostic fields
9
- * (`code`, `status`, response details), and the chained `cause`.
10
- * Falls back to a non-empty descriptor when `err.message` is empty —
11
- * an empty message field is a debugging dead end (we've hit it on
12
- * sync failures where the underlying library throws errors with no
13
- * message but populated `.code` / `.response.status`).
14
- */
15
- export declare function serializeError(err: unknown): Record<string, unknown>;
16
- //# sourceMappingURL=error.d.ts.map
package/dist/error.js DELETED
@@ -1,58 +0,0 @@
1
- import "./chunk-gOLHoazu.js";
2
- //#region src/error.ts
3
- /**
4
- * Extract a human-readable error message from an unknown thrown value.
5
- */
6
- function toErrorMessage(err) {
7
- return err instanceof Error ? err.message : String(err);
8
- }
9
- /**
10
- * Serialize an error into a structured object suitable for logging.
11
- *
12
- * Captures the message, error type name, common diagnostic fields
13
- * (`code`, `status`, response details), and the chained `cause`.
14
- * Falls back to a non-empty descriptor when `err.message` is empty —
15
- * an empty message field is a debugging dead end (we've hit it on
16
- * sync failures where the underlying library throws errors with no
17
- * message but populated `.code` / `.response.status`).
18
- */
19
- function serializeError(err) {
20
- if (err === null || err === void 0) return { message: String(err) };
21
- if (typeof err !== "object") return { message: String(err) };
22
- const e = err;
23
- const out = {};
24
- const rawMessage = err instanceof Error ? err.message : e.message;
25
- out.message = rawMessage && rawMessage.length > 0 ? rawMessage : `<${describeShape(err)}>`;
26
- if (err instanceof Error && err.name && err.name !== "Error") out.name = err.name;
27
- if (typeof e.code === "string" || typeof e.code === "number") out.code = e.code;
28
- const response = e.response;
29
- if (response && typeof response === "object") {
30
- if (typeof response.status === "number") out.status = response.status;
31
- if (response.statusText) out.statusText = response.statusText;
32
- if (response.data !== void 0) out.responseData = trimResponseData(response.data);
33
- }
34
- if (e.cause !== void 0) out.cause = serializeError(e.cause);
35
- return out;
36
- }
37
- /**
38
- * Describe an error's shape when its `.message` is empty so logs
39
- * still convey something useful (vs. a bare `error: ""`).
40
- */
41
- function describeShape(err) {
42
- const ctor = err.constructor?.name;
43
- if (ctor && ctor !== "Object") return `${ctor} with empty message`;
44
- const keys = Object.keys(err).slice(0, 5).join(",");
45
- return keys ? `object{${keys}}` : "empty error";
46
- }
47
- /**
48
- * Cap response payload size to keep logs readable.
49
- */
50
- function trimResponseData(data) {
51
- const s = typeof data === "string" ? data : JSON.stringify(data);
52
- if (s.length <= 500) return data;
53
- return s.slice(0, 500) + `…(+${s.length - 500} chars)`;
54
- }
55
- //#endregion
56
- export { serializeError, toErrorMessage };
57
-
58
- //# sourceMappingURL=error.js.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=error.test.d.ts.map
@@ -1,5 +0,0 @@
1
- /**
2
- * Format bytes to a human-readable string.
3
- */
4
- export declare function formatBytes(bytes: number): string;
5
- //# sourceMappingURL=format-bytes.d.ts.map
@@ -1,15 +0,0 @@
1
- import "./chunk-gOLHoazu.js";
2
- //#region src/format-bytes.ts
3
- /**
4
- * Format bytes to a human-readable string.
5
- */
6
- function formatBytes(bytes) {
7
- if (bytes < 1024) return `${bytes} B`;
8
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
9
- if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
10
- return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
11
- }
12
- //#endregion
13
- export { formatBytes };
14
-
15
- //# sourceMappingURL=format-bytes.js.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=format-bytes.test.d.ts.map
@@ -1,11 +0,0 @@
1
- /**
2
- * Format seconds into human-readable uptime.
3
- * Examples: "45s", "3m 12s", "2h 15m", "1d 3h 12m"
4
- */
5
- export declare function formatUptime(seconds: number): string;
6
- /**
7
- * Format a duration in milliseconds to a human-readable string.
8
- * Examples: "0s", "0.3s", "12.3s", "1m 23s", "1h 2m 3s"
9
- */
10
- export declare function formatDuration(ms: number): string;
11
- //# sourceMappingURL=format-duration.d.ts.map
@@ -1,32 +0,0 @@
1
- import "./chunk-gOLHoazu.js";
2
- //#region src/format-duration.ts
3
- /**
4
- * Format seconds into human-readable uptime.
5
- * Examples: "45s", "3m 12s", "2h 15m", "1d 3h 12m"
6
- */
7
- function formatUptime(seconds) {
8
- if (seconds < 60) return `${seconds}s`;
9
- if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
10
- const hours = Math.floor(seconds / 3600);
11
- const mins = Math.floor(seconds % 3600 / 60);
12
- if (hours < 24) return `${hours}h ${mins}m`;
13
- return `${Math.floor(hours / 24)}d ${hours % 24}h ${mins}m`;
14
- }
15
- /**
16
- * Format a duration in milliseconds to a human-readable string.
17
- * Examples: "0s", "0.3s", "12.3s", "1m 23s", "1h 2m 3s"
18
- */
19
- function formatDuration(ms) {
20
- if (ms < 0) return "0s";
21
- const totalSeconds = ms / 1e3;
22
- if (totalSeconds < 60) return `${totalSeconds.toFixed(1)}s`;
23
- const hours = Math.floor(totalSeconds / 3600);
24
- const minutes = Math.floor(totalSeconds % 3600 / 60);
25
- const seconds = Math.floor(totalSeconds % 60);
26
- if (hours > 0) return `${hours}h ${minutes}m ${seconds}s`;
27
- return `${minutes}m ${seconds}s`;
28
- }
29
- //#endregion
30
- export { formatDuration, formatUptime };
31
-
32
- //# sourceMappingURL=format-duration.js.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=format-duration.test.d.ts.map
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=idempotency.test.d.ts.map
package/dist/logger.d.ts DELETED
@@ -1,60 +0,0 @@
1
- import winston from 'winston';
2
- /** Set the service name for all loggers in this process. Call once at startup. */
3
- export declare function setServiceName(name: 'platform' | 'orchestrator' | 'agent'): void;
4
- /** Get the current service name (for testing/inspection). */
5
- export declare function getServiceName(): string | undefined;
6
- /**
7
- * Build the rotated log filename. When a stable instance ID is available in the
8
- * environment, append it so multiple processes (e.g. several orchestrators or
9
- * agents) can safely share one KICI_LOG_DIR without racing on the same file.
10
- *
11
- * Precedence matches the tier that owns each variable:
12
- * orchestrator (KICI_CLUSTER_INSTANCE_ID) > agent (KICI_AGENT_ID) > platform
13
- * (KICI_PLATFORM_INSTANCE_ID). Sanitize defensively to filesystem-safe characters.
14
- */
15
- export declare function buildLogFilename(serviceName: string | undefined): string;
16
- /** Log level type */
17
- export type LogLevel = 'error' | 'warn' | 'info' | 'debug';
18
- /** Minimal logger interface for dependency injection (avoids coupling to winston). */
19
- export interface Logger {
20
- info(message: string, meta?: Record<string, unknown>): void;
21
- warn(message: string, meta?: Record<string, unknown>): void;
22
- error(message: string, meta?: Record<string, unknown>): void;
23
- }
24
- /** Logger creation options */
25
- interface LoggerOptions {
26
- /**
27
- * Use JSON format (default: auto-detected from KICI_LOG_FORMAT env var, with
28
- * a TTY fallback). Passing an explicit boolean wins over the env var.
29
- */
30
- json?: boolean;
31
- /** Log level (default: 'info') */
32
- level?: LogLevel;
33
- /** Optional prefix for all messages */
34
- prefix?: string;
35
- }
36
- /**
37
- * Create a winston logger instance.
38
- *
39
- * @param options - Logger configuration options
40
- * @returns Configured winston logger
41
- */
42
- export declare function createLogger(options?: LoggerOptions): winston.Logger;
43
- /**
44
- * Default singleton logger instance for simple use cases. If KICI_LOG_DIR is
45
- * set but setServiceName() hasn't been called yet (CLI tools, scripts),
46
- * the file transport stays deferred and is attached only once a service
47
- * name is known — protecting against writing to `kici-<instanceId>-*.log`.
48
- */
49
- export declare const logger: winston.Logger;
50
- /**
51
- * Wrap an async startup function so that any thrown error is logged
52
- * through the structured (JSON-aware) logger before the process exits.
53
- *
54
- * Without this guard, a top-level `await` rejection in an ESM entry
55
- * point is printed by Node.js's default handler (multi-line, not JSON),
56
- * which breaks log aggregators like ELK.
57
- */
58
- export declare function guardStartup(log: winston.Logger, fn: () => Promise<void>): Promise<void>;
59
- export {};
60
- //# sourceMappingURL=logger.d.ts.map