@into-cps-association/logger-ms 0.1.1

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 (79) hide show
  1. package/LICENSE.md +3 -0
  2. package/README.md +198 -0
  3. package/dist/src/app.controller.d.ts +12 -0
  4. package/dist/src/app.controller.js +53 -0
  5. package/dist/src/app.controller.js.map +1 -0
  6. package/dist/src/app.module.d.ts +2 -0
  7. package/dist/src/app.module.js +44 -0
  8. package/dist/src/app.module.js.map +1 -0
  9. package/dist/src/config/certificates.d.ts +5 -0
  10. package/dist/src/config/certificates.js +47 -0
  11. package/dist/src/config/certificates.js.map +1 -0
  12. package/dist/src/config/cli.d.ts +1 -0
  13. package/dist/src/config/cli.js +45 -0
  14. package/dist/src/config/cli.js.map +1 -0
  15. package/dist/src/config/config.interface.d.ts +17 -0
  16. package/dist/src/config/config.interface.js +2 -0
  17. package/dist/src/config/config.interface.js.map +1 -0
  18. package/dist/src/config/config.service.d.ts +21 -0
  19. package/dist/src/config/config.service.js +275 -0
  20. package/dist/src/config/config.service.js.map +1 -0
  21. package/dist/src/config/cors.d.ts +7 -0
  22. package/dist/src/config/cors.js +29 -0
  23. package/dist/src/config/cors.js.map +1 -0
  24. package/dist/src/config/util.d.ts +1 -0
  25. package/dist/src/config/util.js +5 -0
  26. package/dist/src/config/util.js.map +1 -0
  27. package/dist/src/dto/log-event.dto.d.ts +37 -0
  28. package/dist/src/dto/log-event.dto.js +125 -0
  29. package/dist/src/dto/log-event.dto.js.map +1 -0
  30. package/dist/src/log-event-validation.pipe.d.ts +4 -0
  31. package/dist/src/log-event-validation.pipe.js +23 -0
  32. package/dist/src/log-event-validation.pipe.js.map +1 -0
  33. package/dist/src/logger-auth.guard.d.ts +7 -0
  34. package/dist/src/logger-auth.guard.js +46 -0
  35. package/dist/src/logger-auth.guard.js.map +1 -0
  36. package/dist/src/logs/logs.module.d.ts +2 -0
  37. package/dist/src/logs/logs.module.js +19 -0
  38. package/dist/src/logs/logs.module.js.map +1 -0
  39. package/dist/src/logs/logs.service.d.ts +29 -0
  40. package/dist/src/logs/logs.service.js +201 -0
  41. package/dist/src/logs/logs.service.js.map +1 -0
  42. package/dist/src/main.d.ts +12 -0
  43. package/dist/src/main.js +59 -0
  44. package/dist/src/main.js.map +1 -0
  45. package/dist/src/socket-address-throttler.guard.d.ts +12 -0
  46. package/dist/src/socket-address-throttler.guard.js +10 -0
  47. package/dist/src/socket-address-throttler.guard.js.map +1 -0
  48. package/dist/src/validation.pipe.d.ts +8 -0
  49. package/dist/src/validation.pipe.js +20 -0
  50. package/dist/src/validation.pipe.js.map +1 -0
  51. package/dist/test/e2e/app.e2e.spec.d.ts +1 -0
  52. package/dist/test/e2e/app.e2e.spec.js +276 -0
  53. package/dist/test/e2e/app.e2e.spec.js.map +1 -0
  54. package/dist/test/unit/certificates.spec.d.ts +1 -0
  55. package/dist/test/unit/certificates.spec.js +46 -0
  56. package/dist/test/unit/certificates.spec.js.map +1 -0
  57. package/dist/test/unit/cli.spec.d.ts +1 -0
  58. package/dist/test/unit/cli.spec.js +100 -0
  59. package/dist/test/unit/cli.spec.js.map +1 -0
  60. package/dist/test/unit/config.service.spec.d.ts +1 -0
  61. package/dist/test/unit/config.service.spec.js +189 -0
  62. package/dist/test/unit/config.service.spec.js.map +1 -0
  63. package/dist/test/unit/cors.spec.d.ts +1 -0
  64. package/dist/test/unit/cors.spec.js +41 -0
  65. package/dist/test/unit/cors.spec.js.map +1 -0
  66. package/dist/test/unit/logger-auth.guard.spec.d.ts +1 -0
  67. package/dist/test/unit/logger-auth.guard.spec.js +40 -0
  68. package/dist/test/unit/logger-auth.guard.spec.js.map +1 -0
  69. package/dist/test/unit/logs.service.spec.d.ts +1 -0
  70. package/dist/test/unit/logs.service.spec.js +246 -0
  71. package/dist/test/unit/logs.service.spec.js.map +1 -0
  72. package/dist/test/unit/socket-address-throttler.guard.spec.d.ts +1 -0
  73. package/dist/test/unit/socket-address-throttler.guard.spec.js +18 -0
  74. package/dist/test/unit/socket-address-throttler.guard.spec.js.map +1 -0
  75. package/dist/test/unit/validation.pipe.spec.d.ts +1 -0
  76. package/dist/test/unit/validation.pipe.spec.js +132 -0
  77. package/dist/test/unit/validation.pipe.spec.js.map +1 -0
  78. package/dist/tsconfig.tsbuildinfo +1 -0
  79. package/package.json +80 -0
package/LICENSE.md ADDED
@@ -0,0 +1,3 @@
1
+ # License
2
+
3
+ Please refer to the repository root license file: `../../LICENSE.md`.
package/README.md ADDED
@@ -0,0 +1,198 @@
1
+ # :notebook: Logger microservice
2
+
3
+ The logger microservice ingests workflow log events produced by the DTaaS
4
+ client and stores them as JSON Lines (`.jsonl`), which is easy to process with
5
+ `jq`.
6
+
7
+ ## :arrow_down: Install
8
+
9
+ ### Default NPM Registry
10
+
11
+ The default registry for npm packages is [npmjs](https://registry.npmjs.org).
12
+ Install the package with the following command
13
+
14
+ ```bash
15
+ npm install -g @into-cps-association/logger-ms
16
+ ```
17
+
18
+ ### Github NPM Registry
19
+
20
+ The package is also available in Github
21
+ [packages registry](https://github.com/orgs/INTO-CPS-Association/packages).
22
+
23
+ Set the registry and install the package with the following commands
24
+
25
+ ```bash
26
+ npm config set @into-cps-association:registry https://npm.pkg.github.com
27
+ npm install -g @into-cps-association/logger-ms
28
+ ```
29
+
30
+ The _npm install_ command asks for username and password. The username is
31
+ your Github username and the password is your Github
32
+ [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens).
33
+ In order for the npm to download the package, your personal access token
34
+ needs to have _read:packages_ scope.
35
+
36
+ ## API
37
+
38
+ - `GET /logger/health` returns service status.
39
+ - `POST /logger` ingests one event and appends it to a JSONL file.
40
+
41
+ ## Configuration
42
+
43
+ The service loads configuration in this order:
44
+
45
+ 1. CLI `--config <file>` or `-c <file>`
46
+ 2. `LOGGER_CONFIG_PATH` environment variable
47
+ 3. `logger.yaml` in the current working directory (if present)
48
+ 4. Built-in defaults
49
+
50
+ Environment variables always override YAML values.
51
+
52
+ ### YAML fields
53
+
54
+ - `hostname` (default: `127.0.0.1`; set `0.0.0.0` for Docker/reverse-proxy
55
+ deployments)
56
+ - `port` (default: `4003`)
57
+ - `cors-allow-origin` (default: disabled; set to a single origin or YAML list
58
+ of origins for browser clients)
59
+ - `cors-allow-credentials` (default: `false`; enable only with explicit
60
+ allowed origins, never `*`)
61
+ - `auth-token` (default: empty string) — a static bearer token for non-browser
62
+ producers. When set, `POST /logger` requires an
63
+ `Authorization: Bearer <auth-token>` header matching this value; requests
64
+ without it are rejected with `401 Unauthorized`. Leave empty to accept
65
+ unauthenticated requests (the default). **Note:** the bundled DTaaS client
66
+ posts events via `navigator.sendBeacon`, which cannot set custom headers, so
67
+ enabling this setting will block ingestion from that client. Browser ingest
68
+ security is delegated to the reverse proxy.
69
+ - `tls` (default: `false`)
70
+ - `certs` (default: `./certs`)
71
+ - `log-file-path` (default: `./logs/workflow-logs.jsonl`)
72
+ - `max-payload-bytes` (default: `65536`)
73
+ - `log-max-bytes` (default: `52428800`)
74
+ - `log-retention-files` (default: `5` rotated files)
75
+ - `throttle-ttl` (default: `60000` milliseconds)
76
+ - `throttle-limit` (default: `120` requests per throttle window)
77
+
78
+ A sample configuration is given below. Copy it into a file named
79
+ `logger.yaml`, and update the values for your setup:
80
+
81
+ ```yaml
82
+ hostname: 127.0.0.1
83
+ port: 4003
84
+ # Restrictive same origin.
85
+ cors-allow-origin: http://localhost
86
+ # One external domain.
87
+ # cors-allow-origin: https://client.example.org
88
+ # Three external domains.
89
+ # cors-allow-origin:
90
+ # - https://client-a.example.org
91
+ # - https://client-b.example.org
92
+ # - https://client-c.example.org
93
+ cors-allow-credentials: false
94
+ auth-token: ''
95
+ tls: false
96
+ certs: ./certs
97
+ log-file-path: ./logs/workflow-logs.jsonl
98
+ max-payload-bytes: 65536
99
+ log-max-bytes: 52428800
100
+ log-retention-files: 5
101
+ # Limits are per TCP peer; behind a reverse proxy this is a shared budget.
102
+ throttle-ttl: 60000
103
+ throttle-limit: 120
104
+ ```
105
+
106
+ The same sample can also be downloaded:
107
+
108
+ ```bash
109
+ curl -o logger.yaml \
110
+ https://raw.githubusercontent.com/INTO-CPS-Association/DTaaS/feature/distributed-demo/servers/logger/config/logger.yaml.sample
111
+ ```
112
+
113
+ ### Environment variables
114
+
115
+ - `LOGGER_CONFIG_PATH`
116
+ - `LOGGER_HOSTNAME` (default: `127.0.0.1`; use `0.0.0.0` in containers)
117
+ - `LOGGER_PORT` (default: `4003`)
118
+ - `LOGGER_CORS_ALLOW_ORIGIN` (default: disabled)
119
+ - `LOGGER_CORS_ALLOW_CREDENTIALS` (default: `false`)
120
+ - `LOGGER_AUTH_TOKEN`
121
+ - `LOGGER_TLS`
122
+ - `LOGGER_CERTS_DIR`
123
+ - `LOGGER_LOG_FILE_PATH` (default: `logs/workflow-logs.jsonl`)
124
+ - `LOGGER_MAX_PAYLOAD_BYTES` (default: `65536`)
125
+ - `LOGGER_LOG_MAX_BYTES` (default: `52428800`)
126
+ - `LOGGER_LOG_RETENTION_FILES` (default: `5`)
127
+ - `LOGGER_THROTTLE_TTL` (default: `60000` milliseconds)
128
+ - `LOGGER_THROTTLE_LIMIT` (default: `120`)
129
+
130
+ External authentication and edge rate limiting are provided by the reverse
131
+ proxy in the deployment compose files. The service also applies an internal
132
+ request throttle for callers that bypass the proxy.
133
+
134
+ The logger identifies callers by their TCP peer address and deliberately does
135
+ not trust forwarded client-address headers. Behind Traefik, requests therefore
136
+ share the proxy container's throttle budget. Set `throttle-limit` (or
137
+ `LOGGER_THROTTLE_LIMIT`) high enough for the combined request volume of all
138
+ expected users during `throttle-ttl`.
139
+
140
+ The service sends `Access-Control-Allow-Credentials: true` only when
141
+ `cors-allow-credentials` is enabled. Credentials cannot be enabled with a
142
+ wildcard CORS origin.
143
+
144
+ ## TLS support
145
+
146
+ Set `tls: true` (or `LOGGER_TLS=true`) to enable HTTPS.
147
+
148
+ Certificates are read from the configured cert directory:
149
+
150
+ - `<certs>/fullchain.pem`
151
+ - `<certs>/privkey.pem`
152
+
153
+ If either file is missing and TLS is enabled, the service auto-generates a
154
+ self-signed certificate using OpenSSL with RSA-4096 + SHA-256 and stores the
155
+ files in the certs directory.
156
+
157
+ ## Log storage format
158
+
159
+ Each request is appended as one JSON object per line (`.jsonl`). This format is
160
+ append-efficient and can be queried directly:
161
+
162
+ ```bash
163
+ jq -c '.event' logs/workflow-logs.jsonl
164
+ ```
165
+
166
+ The active log rotates at `log-max-bytes` and keeps the configured number of
167
+ rotated files. The defaults are 50 MiB and 5 rotated files, so capacity should
168
+ allow for the active file plus those retained rotated files.
169
+
170
+ Log writes are best-effort analytics storage. Graceful shutdown closes the
171
+ write stream, but recent events may be lost on hard container termination
172
+ because writes are not fsynced per request.
173
+
174
+ ## :rocket: Use
175
+
176
+ Start the logger with the `logger.yaml` file in the working directory,
177
+ or with the built-in defaults if there is no such file:
178
+
179
+ ```bash
180
+ logger-ms
181
+ ```
182
+
183
+ To use a configuration file at another location, run
184
+
185
+ ```bash
186
+ logger-ms -c FILE-PATH
187
+ logger-ms --config FILE-PATH
188
+ ```
189
+
190
+ The logger listens on <http://127.0.0.1:4003/logger> by default.
191
+ You can press `Ctrl+C` to halt the application.
192
+
193
+ ## Use in Docker Environment
194
+
195
+ The logger is also available as the `intocps/logger-ms` docker image.
196
+ Please see the
197
+ [docker instructions](https://github.com/INTO-CPS-Association/DTaaS/blob/feature/distributed-demo/servers/logger/DOCKER.md)
198
+ for running it.
@@ -0,0 +1,12 @@
1
+ import LogsService from './logs/logs.service.js';
2
+ import { LogEventDto } from './dto/log-event.dto.js';
3
+ type HealthResponse = {
4
+ status: 'ok';
5
+ };
6
+ export default class AppController {
7
+ private readonly logsService;
8
+ constructor(logsService: LogsService);
9
+ health(): HealthResponse;
10
+ ingestEvent(logEventDto: LogEventDto): Promise<void>;
11
+ }
12
+ export {};
@@ -0,0 +1,53 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { Body, Controller, Get, HttpStatus, Post, UseGuards, UsePipes, HttpCode, } from '@nestjs/common';
14
+ import { SkipThrottle } from '@nestjs/throttler';
15
+ import LogsService from './logs/logs.service.js';
16
+ import LogEventValidationPipe from './log-event-validation.pipe.js';
17
+ import LoggerAuthGuard from './logger-auth.guard.js';
18
+ let AppController = class AppController {
19
+ logsService;
20
+ constructor(logsService) {
21
+ this.logsService = logsService;
22
+ }
23
+ health() {
24
+ return { status: 'ok' };
25
+ }
26
+ async ingestEvent(logEventDto) {
27
+ await this.logsService.appendEvent(logEventDto);
28
+ }
29
+ };
30
+ __decorate([
31
+ Get('health'),
32
+ HttpCode(HttpStatus.OK),
33
+ SkipThrottle(),
34
+ __metadata("design:type", Function),
35
+ __metadata("design:paramtypes", []),
36
+ __metadata("design:returntype", Object)
37
+ ], AppController.prototype, "health", null);
38
+ __decorate([
39
+ Post(),
40
+ HttpCode(HttpStatus.NO_CONTENT),
41
+ UseGuards(LoggerAuthGuard),
42
+ UsePipes(LogEventValidationPipe),
43
+ __param(0, Body()),
44
+ __metadata("design:type", Function),
45
+ __metadata("design:paramtypes", [Object]),
46
+ __metadata("design:returntype", Promise)
47
+ ], AppController.prototype, "ingestEvent", null);
48
+ AppController = __decorate([
49
+ Controller('logger'),
50
+ __metadata("design:paramtypes", [LogsService])
51
+ ], AppController);
52
+ export default AppController;
53
+ //# sourceMappingURL=app.controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.controller.js","sourceRoot":"","sources":["../../src/app.controller.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EACL,IAAI,EACJ,UAAU,EACV,GAAG,EACH,UAAU,EACV,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,QAAQ,GACT,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,WAAW,MAAM,wBAAwB,CAAC;AAEjD,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,eAAe,MAAM,wBAAwB,CAAC;AAOtC,IAAM,aAAa,GAAnB,MAAM,aAAa;IAEH;IAA7B,YAA6B,WAAwB;QAAxB,gBAAW,GAAX,WAAW,CAAa;IAAG,CAAC;IAKzD,MAAM;QACJ,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC1B,CAAC;IAMK,AAAN,KAAK,CAAC,WAAW,CAAS,WAAwB;QAChD,MAAM,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF,CAAA;AAXC;IAHC,GAAG,CAAC,QAAQ,CAAC;IACb,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;IACvB,YAAY,EAAE;;;;2CAGd;AAMK;IAJL,IAAI,EAAE;IACN,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;IAC/B,SAAS,CAAC,eAAe,CAAC;IAC1B,QAAQ,CAAC,sBAAsB,CAAC;IACd,WAAA,IAAI,EAAE,CAAA;;;;gDAExB;AAjBkB,aAAa;IADjC,UAAU,CAAC,QAAQ,CAAC;qCAGuB,WAAW;GAFlC,aAAa,CAkBjC;eAlBoB,aAAa"}
@@ -0,0 +1,2 @@
1
+ export default class AppModule {
2
+ }
@@ -0,0 +1,44 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { Module } from '@nestjs/common';
8
+ import { APP_GUARD } from '@nestjs/core';
9
+ import { ThrottlerModule } from '@nestjs/throttler';
10
+ import AppController from './app.controller.js';
11
+ import LogEventValidationPipe from './log-event-validation.pipe.js';
12
+ import LoggerAuthGuard from './logger-auth.guard.js';
13
+ import Config from './config/config.service.js';
14
+ import LogsModule from './logs/logs.module.js';
15
+ import SocketAddressThrottlerGuard from './socket-address-throttler.guard.js';
16
+ let AppModule = class AppModule {
17
+ };
18
+ AppModule = __decorate([
19
+ Module({
20
+ imports: [
21
+ LogsModule,
22
+ ThrottlerModule.forRootAsync({
23
+ imports: [LogsModule],
24
+ inject: [Config],
25
+ useFactory: (config) => ({
26
+ throttlers: [
27
+ {
28
+ ttl: config.getThrottleTtl(),
29
+ limit: config.getThrottleLimit(),
30
+ },
31
+ ],
32
+ }),
33
+ }),
34
+ ],
35
+ controllers: [AppController],
36
+ providers: [
37
+ LogEventValidationPipe,
38
+ LoggerAuthGuard,
39
+ { provide: APP_GUARD, useClass: SocketAddressThrottlerGuard },
40
+ ],
41
+ })
42
+ ], AppModule);
43
+ export default AppModule;
44
+ //# sourceMappingURL=app.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.module.js","sourceRoot":"","sources":["../../src/app.module.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,aAAa,MAAM,qBAAqB,CAAC;AAChD,OAAO,sBAAsB,MAAM,gCAAgC,CAAC;AACpE,OAAO,eAAe,MAAM,wBAAwB,CAAC;AACrD,OAAO,MAAM,MAAM,4BAA4B,CAAC;AAChD,OAAO,UAAU,MAAM,uBAAuB,CAAC;AAC/C,OAAO,2BAA2B,MAAM,qCAAqC,CAAC;AAyB/D,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,SAAS;IAvB7B,MAAM,CAAC;QACN,OAAO,EAAE;YACP,UAAU;YACV,eAAe,CAAC,YAAY,CAAC;gBAC3B,OAAO,EAAE,CAAC,UAAU,CAAC;gBACrB,MAAM,EAAE,CAAC,MAAM,CAAC;gBAChB,UAAU,EAAE,CAAC,MAAc,EAAE,EAAE,CAAC,CAAC;oBAC/B,UAAU,EAAE;wBACV;4BACE,GAAG,EAAE,MAAM,CAAC,cAAc,EAAE;4BAC5B,KAAK,EAAE,MAAM,CAAC,gBAAgB,EAAE;yBACjC;qBACF;iBACF,CAAC;aACH,CAAC;SACH;QACD,WAAW,EAAE,CAAC,aAAa,CAAC;QAC5B,SAAS,EAAE;YACT,sBAAsB;YACtB,eAAe;YACf,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,2BAA2B,EAAE;SAC9D;KACF,CAAC;GACmB,SAAS,CAAG;eAAZ,SAAS"}
@@ -0,0 +1,5 @@
1
+ export type CertificatePaths = {
2
+ certFile: string;
3
+ keyFile: string;
4
+ };
5
+ export declare function ensureCertificates(certsDirectory: string): Promise<CertificatePaths>;
@@ -0,0 +1,47 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { chmod, mkdir } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { execFile } from 'node:child_process';
5
+ import { promisify } from 'node:util';
6
+ const execFileAsync = promisify(execFile);
7
+ const CERT_FILE = 'fullchain.pem';
8
+ const KEY_FILE = 'privkey.pem';
9
+ const DEFAULT_KEY_BITS = '4096';
10
+ const DEFAULT_DAYS = '825';
11
+ function requiredCertificatePaths(certsDirectory) {
12
+ return {
13
+ certFile: path.join(certsDirectory, CERT_FILE),
14
+ keyFile: path.join(certsDirectory, KEY_FILE),
15
+ };
16
+ }
17
+ function hasUsableCertificates(paths) {
18
+ return existsSync(paths.certFile) && existsSync(paths.keyFile);
19
+ }
20
+ export async function ensureCertificates(certsDirectory) {
21
+ await mkdir(certsDirectory, { recursive: true, mode: 0o700 });
22
+ const paths = requiredCertificatePaths(certsDirectory);
23
+ if (!hasUsableCertificates(paths)) {
24
+ await execFileAsync('openssl', [
25
+ 'req',
26
+ '-x509',
27
+ '-newkey',
28
+ `rsa:${DEFAULT_KEY_BITS}`,
29
+ '-sha256',
30
+ '-days',
31
+ DEFAULT_DAYS,
32
+ '-nodes',
33
+ '-keyout',
34
+ paths.keyFile,
35
+ '-out',
36
+ paths.certFile,
37
+ '-subj',
38
+ '/CN=localhost',
39
+ ]);
40
+ await Promise.all([
41
+ chmod(paths.keyFile, 0o600),
42
+ chmod(paths.certFile, 0o644),
43
+ ]);
44
+ }
45
+ return paths;
46
+ }
47
+ //# sourceMappingURL=certificates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificates.js","sourceRoot":"","sources":["../../../src/config/certificates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAO1C,MAAM,SAAS,GAAG,eAAe,CAAC;AAClC,MAAM,QAAQ,GAAG,aAAa,CAAC;AAC/B,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,MAAM,YAAY,GAAG,KAAK,CAAC;AAE3B,SAAS,wBAAwB,CAAC,cAAsB;IACtD,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,SAAS,CAAC;QAC9C,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC;KAC7C,CAAC;AACJ,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAuB;IACpD,OAAO,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,cAAsB;IAEtB,MAAM,KAAK,CAAC,cAAc,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,wBAAwB,CAAC,cAAc,CAAC,CAAC;IACvD,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,aAAa,CAAC,SAAS,EAAE;YAC7B,KAAK;YACL,OAAO;YACP,SAAS;YACT,OAAO,gBAAgB,EAAE;YACzB,SAAS;YACT,OAAO;YACP,YAAY;YACZ,QAAQ;YACR,SAAS;YACT,KAAK,CAAC,OAAO;YACb,MAAM;YACN,KAAK,CAAC,QAAQ;YACd,OAAO;YACP,eAAe;SAChB,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,GAAG,CAAC;YAChB,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC;YAC3B,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC;SAC7B,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1 @@
1
+ export default function resolveConfigPath(argv: ReadonlyArray<string>): string | undefined;
@@ -0,0 +1,45 @@
1
+ import { existsSync } from 'node:fs';
2
+ import resolveFile from './util.js';
3
+ const CONFIG_FLAG = '--config';
4
+ const CONFIG_SHORT_FLAG = '-c';
5
+ const DEFAULT_CONFIG_FILE = 'logger.yaml';
6
+ function parseConfigFromArgs(argv) {
7
+ let configPath;
8
+ for (let i = 2; i < argv.length; i += 1) {
9
+ const arg = argv[i];
10
+ if (arg === CONFIG_SHORT_FLAG || arg === CONFIG_FLAG) {
11
+ const value = argv[i + 1];
12
+ if (value === undefined || value.startsWith('-')) {
13
+ throw new Error(`${arg} requires a file path`);
14
+ }
15
+ configPath = value;
16
+ i += 1;
17
+ continue;
18
+ }
19
+ if (arg.startsWith(`${CONFIG_FLAG}=`)) {
20
+ const value = arg.slice(`${CONFIG_FLAG}=`.length);
21
+ if (value.trim() === '') {
22
+ throw new Error(`${CONFIG_FLAG} requires a file path`);
23
+ }
24
+ configPath = value;
25
+ }
26
+ }
27
+ return configPath;
28
+ }
29
+ export default function resolveConfigPath(argv) {
30
+ const fromCli = parseConfigFromArgs(argv);
31
+ const fromEnvRaw = process.env.LOGGER_CONFIG_PATH;
32
+ const fromEnv = fromEnvRaw !== undefined && fromEnvRaw.trim() !== ''
33
+ ? fromEnvRaw.trim()
34
+ : undefined;
35
+ const selected = fromCli ?? fromEnv ?? DEFAULT_CONFIG_FILE;
36
+ const resolvedPath = resolveFile(selected);
37
+ if (existsSync(resolvedPath)) {
38
+ return resolvedPath;
39
+ }
40
+ if (fromCli !== undefined || fromEnv !== undefined) {
41
+ throw new Error(`Logger config file does not exist: ${resolvedPath}`);
42
+ }
43
+ return undefined;
44
+ }
45
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/config/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,WAAW,MAAM,WAAW,CAAC;AAEpC,MAAM,WAAW,GAAG,UAAU,CAAC;AAC/B,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,mBAAmB,GAAG,aAAa,CAAC;AAE1C,SAAS,mBAAmB,CAAC,IAA2B;IACtD,IAAI,UAA8B,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,iBAAiB,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACrD,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjD,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,uBAAuB,CAAC,CAAC;YACjD,CAAC;YACD,UAAU,GAAG,KAAK,CAAC;YACnB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,WAAW,GAAG,CAAC,MAAM,CAAC,CAAC;YAClD,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,GAAG,WAAW,uBAAuB,CAAC,CAAC;YACzD,CAAC;YACD,UAAU,GAAG,KAAK,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,CACvC,IAA2B;IAE3B,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAClD,MAAM,OAAO,GACX,UAAU,KAAK,SAAS,IAAI,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE;QAClD,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE;QACnB,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,QAAQ,GAAG,OAAO,IAAI,OAAO,IAAI,mBAAmB,CAAC;IAC3D,MAAM,YAAY,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAE3C,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,OAAO,YAAY,CAAC;IACtB,CAAC;IACD,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACnD,MAAM,IAAI,KAAK,CAAC,sCAAsC,YAAY,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,17 @@
1
+ export type CorsAllowOrigin = string | string[];
2
+ export interface IConfig {
3
+ loadConfig(configPath?: string): void;
4
+ getHostname(): string;
5
+ getPort(): number;
6
+ getCorsAllowOrigin(): CorsAllowOrigin;
7
+ getCorsAllowCredentials(): boolean;
8
+ getAuthToken(): string;
9
+ getTls(): boolean;
10
+ getCertsDirectory(): string;
11
+ getLogFilePath(): string;
12
+ getMaxPayloadBytes(): number;
13
+ getLogMaxBytes(): number;
14
+ getLogRetentionFiles(): number;
15
+ getThrottleTtl(): number;
16
+ getThrottleLimit(): number;
17
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=config.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.interface.js","sourceRoot":"","sources":["../../../src/config/config.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { type CorsAllowOrigin, IConfig } from './config.interface.js';
2
+ export default class Config implements IConfig {
3
+ private configValues;
4
+ constructor();
5
+ loadConfig(configPath?: string): void;
6
+ getHostname(): string;
7
+ getPort(): number;
8
+ getCorsAllowOrigin(): CorsAllowOrigin;
9
+ getCorsAllowCredentials(): boolean;
10
+ getAuthToken(): string;
11
+ getTls(): boolean;
12
+ getCertsDirectory(): string;
13
+ getLogFilePath(): string;
14
+ getMaxPayloadBytes(): number;
15
+ getLogMaxBytes(): number;
16
+ getLogRetentionFiles(): number;
17
+ getThrottleTtl(): number;
18
+ getThrottleLimit(): number;
19
+ private loadYamlConfig;
20
+ private applyEnvOverrides;
21
+ }