@sera4/essentia 3.0.13 → 3.1.0-rc.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 (91) hide show
  1. package/README.md +93 -308
  2. package/dist/ts/cache/index.d.ts +33 -0
  3. package/dist/ts/cache/index.js +175 -0
  4. package/dist/ts/cache/index.js.map +1 -0
  5. package/dist/ts/configurations/server-config.d.ts +4 -0
  6. package/dist/ts/configurations/server-config.js +2 -0
  7. package/dist/ts/configurations/server-config.js.map +1 -0
  8. package/dist/ts/constants/index.d.ts +7 -0
  9. package/dist/ts/constants/index.js +8 -0
  10. package/dist/ts/constants/index.js.map +1 -0
  11. package/dist/ts/cycle/index.d.ts +53 -0
  12. package/dist/ts/cycle/index.js +171 -0
  13. package/dist/ts/cycle/index.js.map +1 -0
  14. package/dist/ts/dns/dns-cache.d.ts +50 -0
  15. package/dist/ts/dns/dns-cache.js +144 -0
  16. package/dist/ts/dns/dns-cache.js.map +1 -0
  17. package/dist/ts/dns/index.d.ts +4 -0
  18. package/dist/ts/dns/index.js +4 -0
  19. package/dist/ts/dns/index.js.map +1 -0
  20. package/dist/ts/formatter/index.d.ts +45 -0
  21. package/dist/ts/formatter/index.js +82 -0
  22. package/dist/ts/formatter/index.js.map +1 -0
  23. package/dist/ts/hal/index.d.ts +26 -0
  24. package/dist/ts/hal/index.js +70 -0
  25. package/dist/ts/hal/index.js.map +1 -0
  26. package/dist/ts/health/index.d.ts +52 -0
  27. package/dist/ts/health/index.js +170 -0
  28. package/dist/ts/health/index.js.map +1 -0
  29. package/dist/ts/helpers/index.d.ts +1 -0
  30. package/dist/ts/helpers/index.js +2 -0
  31. package/dist/ts/helpers/index.js.map +1 -0
  32. package/dist/ts/helpers/test-server-wrapper.d.ts +56 -0
  33. package/dist/ts/helpers/test-server-wrapper.js +153 -0
  34. package/dist/ts/helpers/test-server-wrapper.js.map +1 -0
  35. package/{index.js → dist/ts/index.d.ts} +14 -11
  36. package/dist/ts/index.js +25 -0
  37. package/dist/ts/index.js.map +1 -0
  38. package/dist/ts/last-commit/index.d.ts +12 -0
  39. package/dist/ts/last-commit/index.js +82 -0
  40. package/dist/ts/last-commit/index.js.map +1 -0
  41. package/dist/ts/logger/index.d.ts +4 -0
  42. package/dist/ts/logger/index.js +5 -0
  43. package/dist/ts/logger/index.js.map +1 -0
  44. package/dist/ts/logger/s4-logger.d.ts +41 -0
  45. package/dist/ts/logger/s4-logger.js +134 -0
  46. package/dist/ts/logger/s4-logger.js.map +1 -0
  47. package/dist/ts/paginator/index.d.ts +2 -0
  48. package/dist/ts/paginator/index.js +3 -0
  49. package/dist/ts/paginator/index.js.map +1 -0
  50. package/dist/ts/paginator/s4-pagination.d.ts +28 -0
  51. package/dist/ts/paginator/s4-pagination.js +49 -0
  52. package/dist/ts/paginator/s4-pagination.js.map +1 -0
  53. package/dist/ts/paginator/sql-pagination.d.ts +52 -0
  54. package/dist/ts/paginator/sql-pagination.js +176 -0
  55. package/dist/ts/paginator/sql-pagination.js.map +1 -0
  56. package/dist/ts/paper-trail/helpers.d.ts +14 -0
  57. package/dist/ts/paper-trail/helpers.js +72 -0
  58. package/dist/ts/paper-trail/helpers.js.map +1 -0
  59. package/dist/ts/paper-trail/index.d.ts +54 -0
  60. package/dist/ts/paper-trail/index.js +235 -0
  61. package/dist/ts/paper-trail/index.js.map +1 -0
  62. package/dist/ts/prompts/index.d.ts +21 -0
  63. package/dist/ts/prompts/index.js +68 -0
  64. package/dist/ts/prompts/index.js.map +1 -0
  65. package/dist/ts/queue/index.d.ts +232 -0
  66. package/dist/ts/queue/index.js +446 -0
  67. package/dist/ts/queue/index.js.map +1 -0
  68. package/dist/ts/queue/publisher.d.ts +41 -0
  69. package/dist/ts/queue/publisher.js +87 -0
  70. package/dist/ts/queue/publisher.js.map +1 -0
  71. package/dist/ts/queue/queue-logger.d.ts +10 -0
  72. package/dist/ts/queue/queue-logger.js +35 -0
  73. package/dist/ts/queue/queue-logger.js.map +1 -0
  74. package/dist/ts/queue/subscriber.d.ts +55 -0
  75. package/dist/ts/queue/subscriber.js +104 -0
  76. package/dist/ts/queue/subscriber.js.map +1 -0
  77. package/dist/ts/safe-proxy/index.d.ts +24 -0
  78. package/dist/ts/safe-proxy/index.js +50 -0
  79. package/dist/ts/safe-proxy/index.js.map +1 -0
  80. package/dist/ts/serializer/index.d.ts +52 -0
  81. package/dist/ts/serializer/index.js +83 -0
  82. package/dist/ts/serializer/index.js.map +1 -0
  83. package/dist/ts/task-scheduler/index.d.ts +130 -0
  84. package/dist/ts/task-scheduler/index.js +261 -0
  85. package/dist/ts/task-scheduler/index.js.map +1 -0
  86. package/dist/ts/utils/index.d.ts +49 -0
  87. package/dist/ts/utils/index.js +162 -0
  88. package/dist/ts/utils/index.js.map +1 -0
  89. package/last-commit.ts +12 -0
  90. package/package.json +28 -11
  91. package/package.tar.gz +0 -0
package/README.md CHANGED
@@ -1,354 +1,139 @@
1
- # ESSENTIA
1
+ # ESSENTIA 3.1
2
2
 
3
3
  [![License](https://img.shields.io/badge/License-Proprietary-red.svg)](LICENSE)
4
- [![Docker](https://img.shields.io/badge/Docker-Ready-blue.svg)](https://hub.docker.com/)
5
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.3+-blue.svg)](https://www.typescriptlang.org/)
6
- [![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)
7
-
8
- A comprehensive TypeScript library providing essential utilities for TWS services. Built with modern TypeScript practices and full type safety.
9
-
10
- ## Project Structure
11
-
12
- All modules are written in TypeScript and located in the `/ts` directory:
13
-
14
- - `/ts/logger` - S4Logger implementation with Winston integration
15
- - `/ts/utils` - Utility functions (UUID validation, array conversion, etc.)
16
- - `/ts/dns` - DNS caching functionality with configurable TTL
17
- - `/ts/health` - Health check utilities for service monitoring
18
- - `/ts/cycle` - Cycle deployment watcher for version tracking
19
- - `/ts/constants` - Shared constants and configuration
20
- - `/ts/helpers` - Helper functions and utilities
21
- - `/ts/paginator` - Pagination utilities for SQL and data arrays
22
- - `/ts/cache` - Redis cache helper with connection management
23
- - `/ts/prompts` - CLI prompt utilities with argument parsing
24
- - `/ts/safe-proxy` - Safe object property access with error handling
25
- - `/ts/queue` - AMQP message queue management
26
- - `/ts/last-commit` - Git commit information retrieval
27
- - `/ts/hal` - HAL decorator for API responses
28
- - `/ts/formatter` - Data formatting and error response utilities
29
- - `/ts/serializer` - Sequelize model serialization utilities
30
- - `/ts/paper-trail` - Data versioning and change tracking
31
-
32
- ## Quick Start
33
-
34
- Install the package:
4
+ [![TypeScript](https://img.shields.io/badge/TypeScript-6.x-blue.svg)](https://www.typescriptlang.org/)
5
+ [![Node.js](https://img.shields.io/badge/Node.js-22+-green.svg)](https://nodejs.org/)
35
6
 
36
- ```bash
37
- npm install @sera4/essentia
38
- ```
39
-
40
- ### Basic Usage
7
+ Shared TypeScript library for TWS/sera4 microservices. ESM, strict mode, full type declarations.
41
8
 
42
- ```typescript
43
- import {
44
- sqlPaginator,
45
- paginator,
46
- DnsCache,
47
- S4Logger,
48
- utils,
49
- constants
50
- } from '@sera4/essentia';
51
-
52
- // Pagination
53
- const result = sqlPaginator('SELECT * FROM users', { page: 1, limit: 10 });
54
- const paginated = paginator(data, { page: 1, limit: 20 });
55
-
56
- // DNS caching
57
- const dnsCache = new DnsCache();
58
- const ip = await dnsCache.resolveTarget('https://example.com');
59
-
60
- // Logging
61
- const logger = new S4Logger();
62
- logger.configure({ level: 'debug', service: 'my-service' });
63
- logger.info('Application started');
64
-
65
- // Utilities
66
- const isValidUuid = utils.isValidUuidV4('123e4567-e89b-12d3-a456-426614174000');
67
- ```
68
-
69
- ### Advanced Usage
70
-
71
- ```typescript
72
- import {
73
- sqlPaginator,
74
- paginator,
75
- DnsCache,
76
- S4Logger,
77
- HealthCheck,
78
- CycleDeploymentWatcher,
79
- halDecorator,
80
- formatter,
81
- queue,
82
- paperTrail,
83
- serializer,
84
- lastCommit,
85
- utils,
86
- constants,
87
- helpers,
88
- prompts,
89
- safeProxy
90
- } from '@sera4/essentia';
91
-
92
- // Pagination examples
93
- const sqlResult = sqlPaginator('SELECT * FROM users WHERE active = ?', {
94
- page: 1,
95
- limit: 10,
96
- orderBy: 'created_at',
97
- orderDirection: 'DESC'
98
- });
99
-
100
- const paginatedData = paginator(userList, {
101
- page: 1,
102
- limit: 20,
103
- total: 100
104
- });
105
-
106
- // DNS caching with configuration
107
- const dnsCache = DnsCache.getInstance({
108
- cacheTtlMs: 5000,
109
- purgeIntervalMs: 120000,
110
- debug: true
111
- });
112
- const ip = await dnsCache.resolveTarget('https://example.com');
113
-
114
- // Logging with advanced configuration
115
- const logger = new S4Logger();
116
- logger.configure({
117
- level: 'debug',
118
- service: 'my-service',
119
- format: 'json'
120
- });
121
- logger.info('Application started');
122
-
123
- // Health checks
124
- const healthCheck = new HealthCheck();
125
- healthCheck.addCheck('database', async () => {
126
- // Your database health check logic
127
- return { status: 'healthy' };
128
- });
129
-
130
- // Cycle deployment monitoring
131
- const watcher = CycleDeploymentWatcher.getInstance();
132
- const currentVersion = watcher.getCurrentVersion('gateway');
133
-
134
- // HAL decorator for API responses
135
- const response = halDecorator(data, {
136
- self: '/api/users',
137
- next: '/api/users?page=2'
138
- });
139
-
140
- // Queue management
141
- await queue.openConnection({
142
- connectionUrl: 'amqp://localhost',
143
- logEnabled: true
144
- });
145
- await queue.registerPublisher({
146
- exchange: { name: 'my-exchange', type: 'topic' }
147
- });
148
- await queue.publishMessage('my-exchange', 'my-routing-key', { data: 'message' });
149
-
150
- // Paper trail for data versioning
151
- const trail = paperTrail(originalData, {
152
- userId: 'user123',
153
- action: 'update'
154
- });
155
-
156
- // Data serialization
157
- const serialized = serializer(data, {
158
- format: 'json',
159
- pretty: true
160
- });
161
-
162
- // Last commit information
163
- const commitInfo = await lastCommit.getLastCommit();
164
- console.log(`Deployed version: ${commitInfo.hash}`);
165
-
166
- // Utility functions
167
- const safeData = safeProxy(data);
168
- const helper = helpers.someHelperFunction();
169
- const parser = prompts.setupCLIParser('My CLI Tool');
170
- ```
9
+ **Requires Node.js ≥ 22.**
171
10
 
172
- ## Available Modules
11
+ ---
173
12
 
174
- All modules are written in TypeScript and provide full type safety:
13
+ ## What's new in 3.1
175
14
 
176
- ### Core Modules
177
- - **Logging**: `S4Logger` - Winston-based logging utility with multiple log levels and formatting options
178
- - **DNS Cache**: `DnsCache` - Singleton class for caching DNS lookups with configurable TTL
179
- - **Health Checks**: `HealthCheck` - Utilities for implementing health check endpoints
180
- - **Cycle Deployment Watcher**: `CycleDeploymentWatcher` - Monitor and react to changes in Cycle deployment tags
181
- - **Utils**: `utils` - General utility functions (UUID validation, array conversion, route type detection, JSONB helpers)
15
+ **Breaking changes**
182
16
 
183
- ### Data Management
184
- - **Pagination**: `sqlPaginator`, `paginator` - Utilities for handling pagination in SQL queries and data arrays
185
- - **Cache**: `cache` - Redis cache helper with connection management and key generation
186
- - **Serializer**: `serializer` - Sequelize model serialization utilities with custom decorators
187
- - **Paper Trail**: `paperTrail` - Track changes to data models with automatic versioning and diff generation
17
+ - **Node.js ≥ 22 required** (was ≥ 18 in 3.x)
18
+ - **TypeScript 6** (up from 5.3) stricter inference rules may surface new type errors in consuming projects
19
+ - All test files are now `.ts` only and use the `*.test.ts` convention; the `.js` test glob has been removed from the test runner
188
20
 
189
- ### API & Communication
190
- - **HAL Decorator**: `halDecorator` - Adds HAL (Hypertext Application Language) support to API responses
191
- - **Formatter**: `formatter` - Data formatting utilities and error response formatting
192
- - **Queue**: `queue` - AMQP message queue management with publishers and subscribers
193
- - **Safe Proxy**: `safeProxy` - Safe object property access with error handling
21
+ **New**
194
22
 
195
- ### Utilities
196
- - **Constants**: `constants` - Shared constants and configuration values
197
- - **Helpers**: `helpers` - Helper functions and utilities
198
- - **Prompts**: `prompts` - CLI prompt utilities with argument parsing
199
- - **Last Commit**: `lastCommit` - Retrieve and display git commit information
23
+ - **Biome** replaces ad-hoc linting — single tool for lint, format, and import sorting (`npm run check`)
24
+ - **Husky pre-commit hook** — Biome auto-fixes staged files before every commit
25
+ - `tsconfig.test.json` separate typecheck pass covering both `ts/` and `test/`
26
+ - `.nvmrc` pinned to Node 22
200
27
 
201
- ### Cycle Deployment Watcher
28
+ **Improvements**
202
29
 
203
- The Cycle Deployment Watcher provides functionality to monitor and react to changes in Cycle deployment tags. It's particularly useful for tracking deployment tags in a Cycle environment.
30
+ - Strict-mode cleanup across all modules `noImplicitAny`, unused imports/variables enforced as errors
31
+ - All source files use `node:` protocol for built-in imports (`node:fs`, `node:path`, etc.)
32
+ - All file names normalised to kebab-case (e.g. `dns-cache.ts`, `cycle-deployment-watcher.test.ts`)
33
+ - New test suites added for `cache`, `hal`, `last-commit`, `paper-trail`, `safe-proxy`, `serializer`, `utils`, `s4-formatter`, `s4-pagination` — 190 tests total
204
34
 
205
- #### Methods
35
+ ---
206
36
 
207
- - `getInstance()`: Returns the singleton instance of the watcher
208
- - `getCurrentVersion(service: string)`: Returns the current version for a service
209
- - `getLegacyVersion(service: string)`: Returns the legacy version for a service
210
- - `getTagsForVersion(version: string)`: Returns all tags that match a specific version
211
- - `addListener(listener: (tags: Record<string, string>) => void)`: Adds a listener for tag changes
212
- - `destroy()`: Cleans up resources and removes all listeners
37
+ ## Setup
213
38
 
214
- #### Environment Variables
39
+ ```bash
40
+ npm install
41
+ npm run build
42
+ npm test
43
+ ```
215
44
 
216
- - `CYCLE_DEPLOYMENT_VERSION`: Optional environment variable to specify the current deployment version
45
+ ---
217
46
 
218
- ## TypeScript Support
47
+ ## Scripts
219
48
 
220
- This package is built entirely in TypeScript and provides:
49
+ | Script | What it does |
50
+ | ----------------------- | ---------------------------------------------- |
51
+ | `npm run build` | Compile TypeScript → `dist/ts/` |
52
+ | `npm test` | Run all tests (Mocha + Chai, JUnit XML output) |
53
+ | `npm run test:coverage` | Tests with c8 coverage HTML report |
54
+ | `npm run typecheck` | Type-check without emitting |
55
+ | `npm run lint` | Biome lint across `ts/` and `test/` |
56
+ | `npm run lint:fix` | Biome lint with auto-fix |
57
+ | `npm run format` | Biome format write pass |
58
+ | `npm run format:check` | Biome format check (CI-safe) |
59
+ | `npm run check` | Biome lint + format + import sort |
60
+ | `npm run check:fix` | `check` with auto-fix |
221
61
 
222
- - **Full Type Safety**: All modules include comprehensive TypeScript interfaces and type definitions
223
- - **IntelliSense Support**: Complete autocomplete and IntelliSense in modern IDEs
224
- - **Compile-time Error Checking**: Catch errors at compile time rather than runtime
225
- - **Modern ES Modules**: Uses ES modules with proper import/export syntax
226
- - **Declaration Files**: Generated `.d.ts` files for all modules
62
+ ---
227
63
 
228
- ### Type Definitions
64
+ ## Pre-commit hook
229
65
 
230
- All modules export their TypeScript interfaces, allowing you to use them in your own code:
66
+ Husky runs Biome on staged files:
231
67
 
232
- ```typescript
233
- import {
234
- LoggerOptions,
235
- DnsCacheConfig,
236
- HealthCheckOptions,
237
- PaginationOptions
238
- } from '@sera4/essentia';
239
-
240
- // Use the types in your own interfaces
241
- interface MyServiceConfig {
242
- logger: LoggerOptions;
243
- dns: DnsCacheConfig;
244
- health: HealthCheckOptions;
245
- }
68
+ ```
69
+ npx biome check --write --staged --no-errors-on-unmatched
246
70
  ```
247
71
 
248
- ## Contributing
72
+ The hook is wired via `npm run prepare` (runs automatically after `npm install`).
249
73
 
250
- When contributing new features or fixes, please:
74
+ ---
251
75
 
252
- 1. Use TypeScript for all new code
253
- 2. Follow the existing TypeScript patterns and conventions
254
- 3. Include appropriate type definitions and interfaces
255
- 4. Add unit tests for new functionality
256
- 5. Update this documentation as needed
257
- 6. Ensure all code passes the TypeScript compiler with strict mode enabled
76
+ ## Modules
258
77
 
259
- ## Running Tests
78
+ All source lives under `ts/`. Each module exports from its `index.ts`.
260
79
 
261
- The project uses Mocha and Chai for testing. To run the tests:
80
+ | Module | Export | Description |
81
+ | ------------------- | ------------------------------------ | --------------------------------------------------------------------------- |
82
+ | `ts/logger` | `s4logger`, `S4Logger` | Winston logger with trace/debug/info/warn/error levels |
83
+ | `ts/utils` | `utils` | UUID validation, integer array parsing, route type detection, JSONB helpers |
84
+ | `ts/dns` | `DnsCache` | Singleton DNS lookup cache with configurable TTL |
85
+ | `ts/health` | `HealthCheck` | Health check endpoint utilities |
86
+ | `ts/cycle` | `CycleDeploymentWatcher` | Watches Cycle environment file for deployment tag changes |
87
+ | `ts/constants` | `TWS_ROUTE_TYPES` | Shared route type constants |
88
+ | `ts/helpers` | `helpers`, `TestServerWrapper` | Misc helpers, test HTTP server wrapper |
89
+ | `ts/paginator` | `sqlPaginator`, `paginator` | SQL and array pagination |
90
+ | `ts/cache` | `cache`, `Cache`, `CacheConfigError` | Redis cache wrapper (fakeredis supported for tests) |
91
+ | `ts/prompts` | `setupCLIParser`, `cliSleep`, etc. | CLI argument parsing and prompt utilities |
92
+ | `ts/safe-proxy` | `safeProxy` | Axios wrapper that forwards auth headers between services |
93
+ | `ts/queue` | `queue` | AMQP publisher/subscriber with fanout support |
94
+ | `ts/last-commit` | `lastCommit` | Read/write git branch + commit hash to a JSON file |
95
+ | `ts/hal` | `halDecorator` | Decorates Sequelize models with HAL-style `_links` / `_resource` |
96
+ | `ts/formatter` | `S4Formatter` | Error response formatting |
97
+ | `ts/serializer` | `serializer` | Sequelize model serialization |
98
+ | `ts/paper-trail` | `paperTrail` | Sequelize hook-based audit trail (diff + revision storage) |
262
99
 
263
- 1. Install dependencies:
264
- ```bash
265
- npm install
266
- ```
100
+ ---
267
101
 
268
- 2. Run all tests:
269
- ```bash
270
- npm test
271
- ```
102
+ ## Usage
272
103
 
273
- 3. Run tests for a specific module:
274
- ```bash
275
- npm test -- --grep "DnsCache"
276
- ```
277
-
278
- 4. Run tests with coverage:
279
- ```bash
280
- npm run test:coverage
281
- ```
282
-
283
- 5. Run tests in watch mode (useful during development):
284
- ```bash
285
- npm run test:watch
286
- ```
104
+ ```typescript
105
+ import { s4logger, utils, DnsCache, queue, safeProxy } from "@sera4/essentia";
287
106
 
288
- ### Test Environment
107
+ s4logger.configure({ level: "info", service: "my-service", format: "json" });
108
+ s4logger.info("Starting");
289
109
 
290
- The test environment is configured to:
291
- - Use ES modules
292
- - Support TypeScript
293
- - Mock external dependencies
294
- - Run tests in parallel
110
+ const isValid = utils.isValidUuidV4("26d61a82-3587-4875-98a8-e950e1bf2350");
295
111
 
296
- ### Writing Tests
112
+ const dns = DnsCache.getInstance();
113
+ const ip = await dns.resolveTarget("https://example.com");
297
114
 
298
- When writing new tests:
299
- 1. Place test files in the `test` directory, mirroring the source structure
300
- 2. Use `.test.ts` extension for TypeScript test files
301
- 3. Follow the existing test patterns and conventions
302
- 4. Use sinon for mocking and stubbing
303
- 5. Include both positive and negative test cases
304
- 6. Test edge cases and error conditions
115
+ await queue.openConnection({ connectionUrl: "amqp://localhost" });
116
+ await queue.publishMessage("my-exchange", "routing.key", { payload: true });
305
117
 
306
- Example test structure:
307
- ```typescript
308
- import { expect } from 'chai';
309
- import sinon from 'sinon';
310
- import { MyModule } from '../../ts/my-module';
311
-
312
- describe('MyModule', () => {
313
- let myModule: MyModule;
314
- let mockDependency: sinon.SinonStub;
315
-
316
- beforeEach(() => {
317
- myModule = new MyModule();
318
- mockDependency = sinon.stub();
319
- });
320
-
321
- afterEach(() => {
322
- sinon.restore();
323
- });
324
-
325
- describe('someMethod', () => {
326
- it('should do something', async () => {
327
- mockDependency.resolves('expected result');
328
-
329
- const result = await myModule.someMethod();
330
-
331
- expect(result).to.equal('expected result');
332
- expect(mockDependency.calledOnce).to.be.true;
333
- });
334
- });
335
- });
118
+ await safeProxy.post(res.locals, "http://other-service/endpoint", { data: {} });
336
119
  ```
337
120
 
338
- ## Building
121
+ ---
122
+
123
+ ## Testing
339
124
 
340
- To build the project:
125
+ Tests run manually — no CI pipeline yet.
341
126
 
342
127
  ```bash
343
- npm run build
128
+ npm test # all tests
129
+ npm run test:coverage # HTML coverage report in coverage/
130
+ npm test -- --grep "DnsCache" # run a specific suite
344
131
  ```
345
132
 
346
- This will:
347
- - Compile all TypeScript files to JavaScript
348
- - Generate declaration files (`.d.ts`)
349
- - Create source maps for debugging
350
- - Output everything to the `dist/` directory
133
+ Test files live in `test/`, mirroring the `ts/` structure. Files use the `.test.ts` naming convention.
134
+
135
+ ---
351
136
 
352
137
  ## License
353
138
 
354
- This project is proprietary software. All rights reserved.
139
+ Proprietary. All rights reserved.
@@ -0,0 +1,33 @@
1
+ interface CacheConfig {
2
+ password?: string;
3
+ database?: number;
4
+ host?: string;
5
+ port?: number;
6
+ fake?: boolean;
7
+ [key: string]: any;
8
+ }
9
+ declare class CacheConfigError extends Error {
10
+ constructor(message: string);
11
+ }
12
+ declare class Cache {
13
+ private redisClient;
14
+ private servicePrefix;
15
+ constructor(config: CacheConfig, servicePrefix: string);
16
+ ping(): Promise<string>;
17
+ properKey(key: string, path?: string): string;
18
+ writeHash(_path: string, key: string, value: any): Promise<number>;
19
+ writeHashBlocking(_path: string, key: string, value: any): void;
20
+ writeMultiHash(path: string, j: Record<string, any>): Promise<string>;
21
+ readHashKey(obj: string, key: string, autoConvert?: boolean): Promise<any>;
22
+ readHash(path: string): Promise<Record<string, any> | null>;
23
+ deleteHashKey(hash: string, key: string): Promise<void>;
24
+ get(key: string): Promise<string | null>;
25
+ getAsync(key: string): Promise<string | null>;
26
+ writeKey(key: string, value: any, expiry?: number): Promise<string>;
27
+ deleteKey(key: string): Promise<number>;
28
+ expire(path: string, expiry: number): Promise<number>;
29
+ exists(path: string): Promise<number>;
30
+ deleteAllKeys(): Promise<string>;
31
+ }
32
+ export default function (config: CacheConfig, servicePrefix: string): Cache;
33
+ export { Cache, CacheConfigError };
@@ -0,0 +1,175 @@
1
+ import { createRequire } from "node:module";
2
+ import { promisify } from "node:util";
3
+ import { S4Logger } from "../logger/s4-logger.js";
4
+ const require = createRequire(import.meta.url);
5
+ const logger = new S4Logger();
6
+ const isEmpty = (obj) => {
7
+ return [Object, Array].includes(obj?.constructor) && !Object.entries(obj || {}).length;
8
+ };
9
+ class CacheConfigError extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = "CacheConfigError";
13
+ }
14
+ }
15
+ /* Redis cache helper
16
+ * Example use: Place the following code in your project to setup redis use
17
+ *
18
+ * import { cache } from "@sera4/essentia";
19
+ * const cacheHelper = cache({ password: .., database: .., host: .., port: .. }, "service:"));
20
+ *
21
+ */
22
+ const convertRedisKeyValueToJson = (v) => {
23
+ return v && v.length > 0 && v[0] !== null ? JSON.parse(v) : null;
24
+ };
25
+ const convertRedisHashToJson = (v) => {
26
+ if (v) {
27
+ const result = {};
28
+ for (const k in v) {
29
+ if (Object.hasOwn(v, k)) {
30
+ result[k] = JSON.parse(v[k]);
31
+ }
32
+ }
33
+ return result;
34
+ }
35
+ else {
36
+ return null;
37
+ }
38
+ };
39
+ function convertJsonToRedisValue(j) {
40
+ const result = {};
41
+ for (const key in j) {
42
+ if (Object.hasOwn(j, key)) {
43
+ result[key] = JSON.stringify(j[key]);
44
+ }
45
+ }
46
+ return result;
47
+ }
48
+ class Cache {
49
+ redisClient;
50
+ servicePrefix;
51
+ constructor(config, servicePrefix) {
52
+ if (config === undefined || isEmpty(config)) {
53
+ throw new CacheConfigError("Invalid cache configuration");
54
+ }
55
+ if (servicePrefix == null) {
56
+ throw new CacheConfigError("Invalid service prefix");
57
+ }
58
+ if (config.fake) {
59
+ // used in testing
60
+ this.redisClient = require("fakeredis").createClient("fake backend");
61
+ }
62
+ else {
63
+ this.redisClient = require("redis").createClient(config);
64
+ }
65
+ this.redisClient.on("error", (err) => {
66
+ logger.error("Cache/Redis error: ", err);
67
+ });
68
+ this.servicePrefix = servicePrefix;
69
+ }
70
+ ping() {
71
+ return this.redisClient.ping();
72
+ }
73
+ properKey(key, path) {
74
+ let p = this.servicePrefix + key;
75
+ if (path) {
76
+ p += path;
77
+ }
78
+ return p;
79
+ }
80
+ writeHash(_path, key, value) {
81
+ return this.redisClient.hsetAsync(this.properKey(key), key, value);
82
+ }
83
+ writeHashBlocking(_path, key, value) {
84
+ this.redisClient.hset(this.properKey(key), key, value);
85
+ }
86
+ // write multiple hash keys and stringify every value
87
+ writeMultiHash(path, j) {
88
+ return this.redisClient.hmsetAsync(this.properKey(path), convertJsonToRedisValue(j));
89
+ }
90
+ readHashKey(obj, key, autoConvert = true) {
91
+ return new Promise((resolve, reject) => {
92
+ this.redisClient.hget(this.properKey(key, obj), key, (e, r) => {
93
+ if (e) {
94
+ logger.error("Redis hmget error:", e);
95
+ reject(e);
96
+ }
97
+ else {
98
+ resolve(autoConvert ? convertRedisKeyValueToJson(r) : r);
99
+ }
100
+ });
101
+ });
102
+ }
103
+ readHash(path) {
104
+ return new Promise((resolve, reject) => {
105
+ this.redisClient.hgetall(this.properKey(path), (e, r) => {
106
+ if (e) {
107
+ console.log("Redis hget error:", e);
108
+ reject(e);
109
+ }
110
+ else {
111
+ resolve(convertRedisHashToJson(r));
112
+ }
113
+ });
114
+ });
115
+ }
116
+ deleteHashKey(hash, key) {
117
+ return new Promise((resolve, reject) => {
118
+ this.redisClient.hdel(this.properKey(key, hash), key, (err) => {
119
+ if (err) {
120
+ logger.error("Redis hdel error:", err);
121
+ reject(err);
122
+ }
123
+ else {
124
+ resolve();
125
+ }
126
+ });
127
+ });
128
+ }
129
+ get(key) {
130
+ return this.redisClient.getAsync(this.properKey(key));
131
+ }
132
+ getAsync(key) {
133
+ return promisify(this.redisClient.get.bind(this.redisClient))(this.properKey(key));
134
+ }
135
+ /* a single key write with optional expiry */
136
+ // returns bluebird promise
137
+ writeKey(key, value, expiry) {
138
+ const fullKey = this.servicePrefix + key;
139
+ if (expiry) {
140
+ return this.redisClient.setAsync(fullKey, value, "EX", expiry);
141
+ }
142
+ else {
143
+ return this.redisClient.setAsync(fullKey, value);
144
+ }
145
+ }
146
+ deleteKey(key) {
147
+ return this.redisClient.delAsync(this.properKey(key));
148
+ }
149
+ expire(path, expiry) {
150
+ return this.redisClient.expire(path, expiry);
151
+ }
152
+ exists(path) {
153
+ return this.redisClient.exists(path);
154
+ }
155
+ deleteAllKeys() {
156
+ return new Promise((resolve, reject) => {
157
+ if (process.env.NODE_ENV === "production") {
158
+ throw new Error("Clearing system cache is not permitted in production");
159
+ }
160
+ this.redisClient.flushdb((err, res) => {
161
+ if (err) {
162
+ reject(err);
163
+ }
164
+ else {
165
+ resolve(res);
166
+ }
167
+ });
168
+ });
169
+ }
170
+ }
171
+ export default function (config, servicePrefix) {
172
+ return new Cache(config, servicePrefix);
173
+ }
174
+ export { Cache, CacheConfigError };
175
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../ts/cache/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export interface ServerConfig {
2
+ s4_identity_endpoint: string;
3
+ debug_dns?: boolean;
4
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=server-config.js.map