@rljson/server 0.0.8 → 0.0.9

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.
@@ -0,0 +1,63 @@
1
+ import { ServerLogger } from './logger.ts';
2
+ /**
3
+ * Options for creating a FileLogger.
4
+ */
5
+ export interface FileLoggerOptions {
6
+ /**
7
+ * Absolute path to the log file.
8
+ * Parent directories are created automatically if they don't exist.
9
+ */
10
+ filePath: string;
11
+ /**
12
+ * When `true`, log entries are also written to console
13
+ * (info/traffic → console.log, warn → console.warn, error → console.error).
14
+ * Defaults to `false`.
15
+ */
16
+ echo?: boolean;
17
+ }
18
+ /**
19
+ * Appends log entries to a file. Optionally echoes to console.
20
+ *
21
+ * Each line is a self-contained JSON object for easy parsing:
22
+ * ```
23
+ * {"ts":"2026-02-25T12:00:00.000Z","level":"info","source":"Server","message":"initialized","data":{"port":3000}}
24
+ * ```
25
+ *
26
+ * Parent directories are created on construction if they don't exist.
27
+ * Uses synchronous writes (`appendFileSync`) to guarantee ordering
28
+ * and avoid lost entries on crash.
29
+ */
30
+ export declare class FileLogger implements ServerLogger {
31
+ private readonly _filePath;
32
+ private readonly _echo;
33
+ constructor(options: FileLoggerOptions);
34
+ /** The file path this logger writes to. */
35
+ get filePath(): string;
36
+ /** Whether console echo is enabled. */
37
+ get echo(): boolean;
38
+ info(source: string, message: string, data?: Record<string, unknown>): void;
39
+ warn(source: string, message: string, data?: Record<string, unknown>): void;
40
+ error(source: string, message: string, error?: unknown, data?: Record<string, unknown>): void;
41
+ traffic(direction: 'in' | 'out', source: string, event: string, data?: Record<string, unknown>): void;
42
+ /**
43
+ * Build a standard log entry object.
44
+ * @param level - Log level string
45
+ * @param source - Component identifier
46
+ * @param message - Human-readable message
47
+ * @param data - Optional structured context
48
+ */
49
+ private _entry;
50
+ /**
51
+ * Append a JSON line to the log file.
52
+ * @param entry - The log entry object to serialize
53
+ */
54
+ private _write;
55
+ /**
56
+ * Format a human-readable console line.
57
+ * @param level - Display level label (e.g. 'INFO')
58
+ * @param source - Component identifier
59
+ * @param message - Human-readable message
60
+ * @param data - Optional structured context
61
+ */
62
+ private _format;
63
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  export { Client } from './client.ts';
2
2
  export type { ClientOptions } from './client.ts';
3
+ export { FileLogger } from './file-logger.ts';
4
+ export type { FileLoggerOptions } from './file-logger.ts';
3
5
  export { BufferedLogger, ConsoleLogger, FilteredLogger, NoopLogger, noopLogger, } from './logger.ts';
4
6
  export type { LogEntry, ServerLogger } from './logger.ts';
5
7
  export { Server } from './server.ts';
package/dist/server.js CHANGED
@@ -2,6 +2,8 @@ import { hshBuffer } from "@rljson/hash";
2
2
  import { Readable } from "node:stream";
3
3
  import { Db, Connector } from "@rljson/db";
4
4
  import { IoPeerBridge, IoMulti, IoPeer, IoServer, IoMem, SocketMock } from "@rljson/io";
5
+ import { existsSync, mkdirSync, appendFileSync } from "node:fs";
6
+ import { dirname } from "node:path";
5
7
  import { syncEvents, Route } from "@rljson/rljson";
6
8
  import { syncEvents as syncEvents2 } from "@rljson/rljson";
7
9
  class BsMem {
@@ -1399,6 +1401,116 @@ class Client extends BaseNode {
1399
1401
  );
1400
1402
  }
1401
1403
  }
1404
+ class FileLogger {
1405
+ _filePath;
1406
+ _echo;
1407
+ constructor(options) {
1408
+ this._filePath = options.filePath;
1409
+ this._echo = options.echo ?? false;
1410
+ const dir = dirname(this._filePath);
1411
+ if (!existsSync(dir)) {
1412
+ mkdirSync(dir, { recursive: true });
1413
+ }
1414
+ }
1415
+ /** The file path this logger writes to. */
1416
+ get filePath() {
1417
+ return this._filePath;
1418
+ }
1419
+ /** Whether console echo is enabled. */
1420
+ get echo() {
1421
+ return this._echo;
1422
+ }
1423
+ info(source, message, data) {
1424
+ const entry = this._entry("info", source, message, data);
1425
+ this._write(entry);
1426
+ if (this._echo) {
1427
+ console.log(this._format("INFO", source, message, data));
1428
+ }
1429
+ }
1430
+ warn(source, message, data) {
1431
+ const entry = this._entry("warn", source, message, data);
1432
+ this._write(entry);
1433
+ if (this._echo) {
1434
+ console.warn(this._format("WARN", source, message, data));
1435
+ }
1436
+ }
1437
+ error(source, message, error, data) {
1438
+ const entry = {
1439
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1440
+ level: "error",
1441
+ source,
1442
+ message
1443
+ };
1444
+ if (error !== void 0) {
1445
+ entry["error"] = error instanceof Error ? { name: error.name, message: error.message, stack: error.stack } : String(error);
1446
+ }
1447
+ if (data !== void 0) {
1448
+ entry["data"] = data;
1449
+ }
1450
+ this._write(entry);
1451
+ if (this._echo) {
1452
+ const errStr = error ? ` ${error}` : "";
1453
+ const dataStr = data ? " " + JSON.stringify(data) : "";
1454
+ console.error(`[ERROR] [${source}] ${message}${errStr}${dataStr}`);
1455
+ }
1456
+ }
1457
+ traffic(direction, source, event, data) {
1458
+ const entry = {
1459
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1460
+ level: "traffic",
1461
+ direction,
1462
+ source,
1463
+ event
1464
+ };
1465
+ if (data !== void 0) {
1466
+ entry["data"] = data;
1467
+ }
1468
+ this._write(entry);
1469
+ if (this._echo) {
1470
+ const arrow = direction === "in" ? "⬅" : "➡";
1471
+ const dataStr = data ? " " + JSON.stringify(data) : "";
1472
+ console.log(`[TRAFFIC] ${arrow} [${source}] ${event}${dataStr}`);
1473
+ }
1474
+ }
1475
+ // ...........................................................................
1476
+ /**
1477
+ * Build a standard log entry object.
1478
+ * @param level - Log level string
1479
+ * @param source - Component identifier
1480
+ * @param message - Human-readable message
1481
+ * @param data - Optional structured context
1482
+ */
1483
+ _entry(level, source, message, data) {
1484
+ const entry = {
1485
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1486
+ level,
1487
+ source,
1488
+ message
1489
+ };
1490
+ if (data !== void 0) {
1491
+ entry["data"] = data;
1492
+ }
1493
+ return entry;
1494
+ }
1495
+ /**
1496
+ * Append a JSON line to the log file.
1497
+ * @param entry - The log entry object to serialize
1498
+ */
1499
+ _write(entry) {
1500
+ appendFileSync(this._filePath, JSON.stringify(entry) + "\n", "utf-8");
1501
+ }
1502
+ /**
1503
+ * Format a human-readable console line.
1504
+ * @param level - Display level label (e.g. 'INFO')
1505
+ * @param source - Component identifier
1506
+ * @param message - Human-readable message
1507
+ * @param data - Optional structured context
1508
+ */
1509
+ _format(level, source, message, data) {
1510
+ const dataStr = data ? " " + JSON.stringify(data) : "";
1511
+ return `[${level}] [${source}] ${message}${dataStr}`;
1512
+ }
1513
+ }
1402
1514
  class Server extends BaseNode {
1403
1515
  constructor(_route, _localIo, _localBs, options) {
1404
1516
  super(_localIo);
@@ -2157,6 +2269,7 @@ export {
2157
2269
  BufferedLogger,
2158
2270
  Client,
2159
2271
  ConsoleLogger,
2272
+ FileLogger,
2160
2273
  FilteredLogger,
2161
2274
  NoopLogger,
2162
2275
  Server,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rljson/server",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "Rljson server description",
5
5
  "homepage": "https://github.com/rljson/server",
6
6
  "bugs": "https://github.com/rljson/server/issues",
@@ -20,21 +20,21 @@
20
20
  ],
21
21
  "type": "module",
22
22
  "devDependencies": {
23
- "@types/node": "^25.2.3",
24
- "@typescript-eslint/eslint-plugin": "^8.56.0",
25
- "@typescript-eslint/parser": "^8.56.0",
23
+ "@types/node": "^25.3.0",
24
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
25
+ "@typescript-eslint/parser": "^8.56.1",
26
26
  "@vitest/coverage-v8": "^4.0.18",
27
27
  "cross-env": "^10.1.0",
28
28
  "eslint": "~9.39.2",
29
- "eslint-plugin-jsdoc": "^62.5.5",
30
- "eslint-plugin-tsdoc": "^0.5.0",
29
+ "eslint-plugin-jsdoc": "^62.7.1",
30
+ "eslint-plugin-tsdoc": "^0.5.1",
31
31
  "globals": "^17.3.0",
32
32
  "jsdoc": "^4.0.5",
33
33
  "read-pkg": "^10.1.0",
34
34
  "socket.io": "^4.8.3",
35
35
  "socket.io-client": "^4.8.3",
36
36
  "typescript": "~5.9.3",
37
- "typescript-eslint": "^8.56.0",
37
+ "typescript-eslint": "^8.56.1",
38
38
  "vite": "^7.3.1",
39
39
  "vite-node": "^5.3.0",
40
40
  "vite-plugin-dts": "^4.5.4",
@@ -44,11 +44,11 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@rljson/bs": "^0.0.21",
47
- "@rljson/db": "^0.0.14",
47
+ "@rljson/db": "^0.0.15",
48
48
  "@rljson/hash": "^0.0.18",
49
49
  "@rljson/io": "^0.0.66",
50
50
  "@rljson/json": "^0.0.23",
51
- "@rljson/rljson": "^0.0.76"
51
+ "@rljson/rljson": "^0.0.78"
52
52
  },
53
53
  "scripts": {
54
54
  "build": "pnpm exec vite build && tsc && node scripts/copy-readme-to-dist.js",