@shetty4l/core 0.1.26 → 0.1.29

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shetty4l/core",
3
- "version": "0.1.26",
3
+ "version": "0.1.29",
4
4
  "description": "Shared infrastructure primitives for Bun/TypeScript services",
5
5
  "repository": {
6
6
  "type": "git",
@@ -17,7 +17,8 @@
17
17
  "./cli": "./src/cli.ts",
18
18
  "./daemon": "./src/daemon.ts",
19
19
  "./db": "./src/db.ts",
20
- "./http": "./src/http.ts"
20
+ "./http": "./src/http.ts",
21
+ "./log": "./src/log.ts"
21
22
  },
22
23
  "files": [
23
24
  "src/",
package/src/cli.ts CHANGED
@@ -81,7 +81,9 @@ export function createLogsCommand(opts: LogsCommandOpts): CommandHandler {
81
81
  return 0;
82
82
  }
83
83
 
84
- const text = await file.text();
84
+ const raw = await file.text();
85
+ // Strip null bytes that can appear from historical Bun.file() corruption
86
+ const text = raw.replaceAll("\0", "");
85
87
  const allLines = text.split("\n").filter((l) => l.length > 0);
86
88
 
87
89
  if (allLines.length === 0) {
package/src/daemon.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  mkdirSync,
14
14
  openSync,
15
15
  readFileSync,
16
+ renameSync,
16
17
  unlinkSync,
17
18
  } from "fs";
18
19
  import { join } from "path";
@@ -160,10 +161,20 @@ export function createDaemonManager(opts: DaemonManagerOpts): DaemonManager {
160
161
  mkdirSync(configDir, { recursive: true });
161
162
  }
162
163
 
163
- // Open log file in append mode so previous content is preserved
164
- // and ongoing console.error output from the child is captured.
164
+ // Rotate previous log file so it doesn't grow unbounded.
165
+ // Keep one generation: service.log -> service.log.old
166
+ if (existsSync(logFile)) {
167
+ try {
168
+ renameSync(logFile, `${logFile}.old`);
169
+ } catch {
170
+ // Best-effort — if rotation fails, append to existing file
171
+ }
172
+ }
173
+
174
+ // Open log file in append mode so ongoing console.error output
175
+ // from the child is captured.
165
176
  // Bun.file() opens with O_WRONLY|O_CREAT (no append, no truncate)
166
- // which writes from offset 0 and corrupts logs.
177
+ // which writes from offset 0 and corrupts logs — always use openSync("a").
167
178
  const logFd = openSync(logFile, "a");
168
179
 
169
180
  const proc = Bun.spawn(["bun", "run", cliPath, serveCommand], {
package/src/http.ts CHANGED
@@ -81,6 +81,17 @@ export interface ServerOpts {
81
81
  req: Request,
82
82
  url: URL,
83
83
  ) => Response | Promise<Response> | null | Promise<Response | null>;
84
+ /**
85
+ * Optional custom health endpoint handler.
86
+ * When provided, called instead of the default healthResponse().
87
+ * Return a full Response to control both body and HTTP status
88
+ * (e.g. 503 for degraded state). Use healthResponse() inside
89
+ * the handler for the standard healthy case.
90
+ */
91
+ onHealth?: (
92
+ version: string,
93
+ startTime: number,
94
+ ) => Response | Promise<Response>;
84
95
  }
85
96
 
86
97
  export interface HttpServer {
@@ -100,7 +111,7 @@ export interface HttpServer {
100
111
  * 4. If onRequest returns null -> 404
101
112
  */
102
113
  export function createServer(opts: ServerOpts): HttpServer {
103
- const { port, host = "127.0.0.1", version, onRequest, name } = opts;
114
+ const { port, host = "127.0.0.1", version, onRequest, onHealth, name } = opts;
104
115
  const startTime = Date.now();
105
116
  const prefix = name ? `${name}: ` : "";
106
117
 
@@ -115,7 +126,9 @@ export function createServer(opts: ServerOpts): HttpServer {
115
126
  }
116
127
 
117
128
  if (url.pathname === "/health" && req.method === "GET") {
118
- return healthResponse(version, startTime);
129
+ return onHealth
130
+ ? onHealth(version, startTime)
131
+ : healthResponse(version, startTime);
119
132
  }
120
133
 
121
134
  try {
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Shared infrastructure primitives for Bun/TypeScript services.
5
5
  *
6
6
  * Import from the root for convenience, or from sub-paths for specificity:
7
- * import { config, http } from "@shetty4l/core"
7
+ * import { config, http, log } from "@shetty4l/core"
8
8
  * import { parsePort } from "@shetty4l/core/config"
9
9
  */
10
10
 
@@ -14,6 +14,7 @@ export * as config from "./config";
14
14
  export * as daemon from "./daemon";
15
15
  export * as db from "./db";
16
16
  export * as http from "./http";
17
+ export * as log from "./log";
17
18
  export type { Err, Ok, Port, Result } from "./result";
18
19
  export { err, ok } from "./result";
19
20
  export type { ShutdownOpts } from "./signals";
package/src/log.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Lightweight structured logger for all services.
3
+ *
4
+ * Each service creates a named logger via `createLogger("serviceName")`.
5
+ * Output format: `[ISO timestamp] name: message`
6
+ * All output goes to stderr via console.error so stdout stays clean for
7
+ * structured CLI output (--json).
8
+ */
9
+
10
+ export type Logger = (msg: string) => void;
11
+
12
+ /**
13
+ * Create a prefixed logger that writes to stderr.
14
+ *
15
+ * @param name - Service or module name (e.g. "cortex", "synapse")
16
+ * @returns A function that logs `[timestamp] name: msg` to stderr
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const log = createLogger("cortex");
21
+ * log("processing loop started");
22
+ * // => [2026-02-20T11:36:00.000Z] cortex: processing loop started
23
+ * ```
24
+ */
25
+ export function createLogger(name: string): Logger {
26
+ return (msg: string) => {
27
+ console.error(`[${new Date().toISOString()}] ${name}: ${msg}`);
28
+ };
29
+ }