@hkdigital/lib-sveltekit 0.1.70 → 0.1.72
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/dist/classes/cache/IndexedDbCache.d.ts +212 -0
- package/dist/classes/cache/IndexedDbCache.js +673 -0
- package/dist/classes/cache/MemoryResponseCache.d.ts +101 -14
- package/dist/classes/cache/MemoryResponseCache.js +97 -12
- package/dist/classes/cache/index.d.ts +1 -1
- package/dist/classes/cache/index.js +2 -1
- package/dist/classes/events/EventEmitter.d.ts +142 -0
- package/dist/classes/events/EventEmitter.js +275 -0
- package/dist/classes/events/index.d.ts +1 -0
- package/dist/classes/events/index.js +2 -0
- package/dist/classes/logging/Logger.d.ts +74 -0
- package/dist/classes/logging/Logger.js +158 -0
- package/dist/classes/logging/constants.d.ts +14 -0
- package/dist/classes/logging/constants.js +18 -0
- package/dist/classes/logging/index.d.ts +2 -0
- package/dist/classes/logging/index.js +4 -0
- package/dist/classes/services/ServiceBase.d.ts +153 -0
- package/dist/classes/services/ServiceBase.js +409 -0
- package/dist/classes/services/ServiceManager.d.ts +350 -0
- package/dist/classes/services/ServiceManager.js +1114 -0
- package/dist/classes/services/constants.d.ts +11 -0
- package/dist/classes/services/constants.js +12 -0
- package/dist/classes/services/index.d.ts +3 -0
- package/dist/classes/services/index.js +5 -0
- package/dist/util/env/index.d.ts +1 -0
- package/dist/util/env/index.js +9 -0
- package/dist/util/http/caching.js +24 -12
- package/dist/util/http/http-request.js +12 -7
- package/package.json +2 -1
- package/dist/classes/cache/PersistentResponseCache.d.ts +0 -46
- /package/dist/classes/cache/{PersistentResponseCache.js → PersistentResponseCache.js__} +0 -0
@@ -0,0 +1,409 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Base service class with lifecycle management and logging.
|
3
|
+
*
|
4
|
+
* ServiceBase provides a standardized lifecycle (initialize, start, stop,
|
5
|
+
* destroy) with state transitions, error handling, and integrated logging.
|
6
|
+
* Services should extend this class and override the protected _init, _start,
|
7
|
+
* _stop, and _destroy methods to implement their specific functionality.
|
8
|
+
*
|
9
|
+
* @example
|
10
|
+
* // Creating a service
|
11
|
+
* import { ServiceBase } from './ServiceBase.js';
|
12
|
+
*
|
13
|
+
* class DatabaseService extends ServiceBase {
|
14
|
+
* constructor() {
|
15
|
+
* super('database');
|
16
|
+
* this.connection = null;
|
17
|
+
* }
|
18
|
+
*
|
19
|
+
* async _init(config) {
|
20
|
+
* this.config = config;
|
21
|
+
* this.logger.debug('Database configured', { config });
|
22
|
+
* }
|
23
|
+
*
|
24
|
+
* async _start() {
|
25
|
+
* this.connection = await createConnection(this.config);
|
26
|
+
* this.logger.info('Database connected', { id: this.connection.id });
|
27
|
+
* }
|
28
|
+
*
|
29
|
+
* async _stop() {
|
30
|
+
* await this.connection.close();
|
31
|
+
* this.connection = null;
|
32
|
+
* this.logger.info('Database disconnected');
|
33
|
+
* }
|
34
|
+
* }
|
35
|
+
*
|
36
|
+
* // Using a service
|
37
|
+
* const db = new DatabaseService();
|
38
|
+
*
|
39
|
+
* await db.initialize({ host: 'localhost', port: 27017 });
|
40
|
+
* await db.start();
|
41
|
+
*
|
42
|
+
* // Listen for state changes
|
43
|
+
* db.on('stateChanged', ({ oldState, newState }) => {
|
44
|
+
* console.log(`Database service: ${oldState} -> ${newState}`);
|
45
|
+
* });
|
46
|
+
*
|
47
|
+
* // Later...
|
48
|
+
* await db.stop();
|
49
|
+
* await db.destroy();
|
50
|
+
*/
|
51
|
+
|
52
|
+
import { EventEmitter } from '../events';
|
53
|
+
import { Logger, INFO } from '../logging';
|
54
|
+
|
55
|
+
import {
|
56
|
+
CREATED,
|
57
|
+
INITIALIZING,
|
58
|
+
INITIALIZED,
|
59
|
+
STARTING,
|
60
|
+
RUNNING,
|
61
|
+
STOPPING,
|
62
|
+
STOPPED,
|
63
|
+
DESTROYING,
|
64
|
+
DESTROYED,
|
65
|
+
ERROR,
|
66
|
+
RECOVERING
|
67
|
+
} from './constants';
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Base class for all services
|
71
|
+
*/
|
72
|
+
export default class ServiceBase {
|
73
|
+
/**
|
74
|
+
* Create a new service
|
75
|
+
*
|
76
|
+
* @param {string} name - Service name
|
77
|
+
* @param {Object} [options] - Service options
|
78
|
+
* @param {string} [options.logLevel=INFO] - Initial log level
|
79
|
+
*/
|
80
|
+
constructor(name, options = {}) {
|
81
|
+
/**
|
82
|
+
* Service name
|
83
|
+
* @type {string}
|
84
|
+
*/
|
85
|
+
this.name = name;
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Event emitter for service events
|
89
|
+
* @type {EventEmitter}
|
90
|
+
*/
|
91
|
+
this.events = new EventEmitter();
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Current service state
|
95
|
+
* @type {string}
|
96
|
+
*/
|
97
|
+
this.state = CREATED;
|
98
|
+
|
99
|
+
/**
|
100
|
+
* Last error that occurred
|
101
|
+
* @type {Error|null}
|
102
|
+
*/
|
103
|
+
this.error = null;
|
104
|
+
|
105
|
+
/**
|
106
|
+
* Last stable state before error
|
107
|
+
* @type {string|null}
|
108
|
+
* @private
|
109
|
+
*/
|
110
|
+
this._preErrorState = null;
|
111
|
+
|
112
|
+
/**
|
113
|
+
* Service logger
|
114
|
+
* @type {Logger}
|
115
|
+
*/
|
116
|
+
this.logger = new Logger(name, options.logLevel || INFO);
|
117
|
+
|
118
|
+
// Set the initial state through _setState to ensure
|
119
|
+
// the event is emitted consistently
|
120
|
+
this._setState(CREATED);
|
121
|
+
}
|
122
|
+
|
123
|
+
/**
|
124
|
+
* Set the service log level
|
125
|
+
*
|
126
|
+
* @param {string} level - New log level
|
127
|
+
* @returns {boolean} True if level was set, false if invalid
|
128
|
+
*/
|
129
|
+
setLogLevel(level) {
|
130
|
+
return this.logger.setLevel(level);
|
131
|
+
}
|
132
|
+
|
133
|
+
/**
|
134
|
+
* Initialize the service
|
135
|
+
*
|
136
|
+
* @param {Object} [config] - Service configuration
|
137
|
+
* @returns {Promise<boolean>} True if initialized successfully
|
138
|
+
*/
|
139
|
+
async initialize(config = {}) {
|
140
|
+
try {
|
141
|
+
this._setState(INITIALIZING);
|
142
|
+
this.logger.debug('Initializing service', { config });
|
143
|
+
|
144
|
+
await this._init(config);
|
145
|
+
|
146
|
+
this._setState(INITIALIZED);
|
147
|
+
this.logger.info('Service initialized');
|
148
|
+
return true;
|
149
|
+
} catch (error) {
|
150
|
+
this._setError('initialization', error);
|
151
|
+
return false;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
/**
|
156
|
+
* Start the service
|
157
|
+
*
|
158
|
+
* @returns {Promise<boolean>} True if started successfully
|
159
|
+
*/
|
160
|
+
async start() {
|
161
|
+
// Check if service can be started
|
162
|
+
if (this.state !== INITIALIZED && this.state !== STOPPED) {
|
163
|
+
this._setError(
|
164
|
+
'startup',
|
165
|
+
new Error(`Cannot start service in state: ${this.state}`)
|
166
|
+
);
|
167
|
+
return false;
|
168
|
+
}
|
169
|
+
|
170
|
+
try {
|
171
|
+
this._setState(STARTING);
|
172
|
+
this.logger.debug('Starting service');
|
173
|
+
|
174
|
+
await this._start();
|
175
|
+
|
176
|
+
this._setState(RUNNING);
|
177
|
+
this.logger.info('Service started');
|
178
|
+
return true;
|
179
|
+
} catch (error) {
|
180
|
+
this._setError('startup', error);
|
181
|
+
return false;
|
182
|
+
}
|
183
|
+
}
|
184
|
+
|
185
|
+
/**
|
186
|
+
* Stop the service
|
187
|
+
*
|
188
|
+
* @returns {Promise<boolean>} True if stopped successfully
|
189
|
+
*/
|
190
|
+
async stop() {
|
191
|
+
// Check if service can be stopped
|
192
|
+
if (this.state !== RUNNING) {
|
193
|
+
this._setError(
|
194
|
+
'stopping',
|
195
|
+
new Error(`Cannot stop service in state: ${this.state}`)
|
196
|
+
);
|
197
|
+
return false;
|
198
|
+
}
|
199
|
+
|
200
|
+
try {
|
201
|
+
this._setState(STOPPING);
|
202
|
+
this.logger.debug('Stopping service');
|
203
|
+
|
204
|
+
await this._stop();
|
205
|
+
|
206
|
+
this._setState(STOPPED);
|
207
|
+
this.logger.info('Service stopped');
|
208
|
+
return true;
|
209
|
+
} catch (error) {
|
210
|
+
this._setError('stopping', error);
|
211
|
+
return false;
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
/**
|
216
|
+
* Recover the service
|
217
|
+
*
|
218
|
+
* @returns {Promise<boolean>} True if stopped successfully
|
219
|
+
*/
|
220
|
+
async recover() {
|
221
|
+
if (this.state !== ERROR) {
|
222
|
+
this.logger.warn(`Can only recover from ERROR state, current state: ${this.state}`);
|
223
|
+
return false;
|
224
|
+
}
|
225
|
+
|
226
|
+
try {
|
227
|
+
this._setState(RECOVERING);
|
228
|
+
this.logger.info('Attempting service recovery');
|
229
|
+
|
230
|
+
const targetState = this._preErrorState;
|
231
|
+
|
232
|
+
// Allow service-specific recovery logic
|
233
|
+
await this._recover();
|
234
|
+
|
235
|
+
// this._setState(targetState);
|
236
|
+
if( this.state !== ERROR )
|
237
|
+
{
|
238
|
+
// Clear
|
239
|
+
this._preErrorState = null;
|
240
|
+
}
|
241
|
+
|
242
|
+
// Clear error
|
243
|
+
this.error = null;
|
244
|
+
|
245
|
+
|
246
|
+
// If recovery successful, return to initialized state
|
247
|
+
this._setState(INITIALIZED);
|
248
|
+
this.logger.info('Service recovery successful');
|
249
|
+
|
250
|
+
|
251
|
+
return true;
|
252
|
+
} catch (error) {
|
253
|
+
this._setError('recovery', error);
|
254
|
+
return false;
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
/**
|
259
|
+
* Destroy the service
|
260
|
+
*
|
261
|
+
* @returns {Promise<boolean>} True if destroyed successfully
|
262
|
+
*/
|
263
|
+
async destroy() {
|
264
|
+
try {
|
265
|
+
this._setState(DESTROYING);
|
266
|
+
this.logger.debug('Destroying service');
|
267
|
+
|
268
|
+
await this._destroy();
|
269
|
+
|
270
|
+
this._setState(DESTROYED);
|
271
|
+
this.logger.info('Service destroyed');
|
272
|
+
|
273
|
+
// Clean up event listeners
|
274
|
+
this.events.removeAllListeners();
|
275
|
+
this.logger.removeAllListeners();
|
276
|
+
|
277
|
+
return true;
|
278
|
+
} catch (error) {
|
279
|
+
this._setError('destruction', error);
|
280
|
+
return false;
|
281
|
+
}
|
282
|
+
}
|
283
|
+
|
284
|
+
/**
|
285
|
+
* Add an event listener
|
286
|
+
*
|
287
|
+
* @param {string} eventName - Event name
|
288
|
+
* @param {Function} handler - Event handler
|
289
|
+
* @returns {Function} Unsubscribe function
|
290
|
+
*/
|
291
|
+
on(eventName, handler) {
|
292
|
+
return this.events.on(eventName, handler);
|
293
|
+
}
|
294
|
+
|
295
|
+
/**
|
296
|
+
* Emit an event
|
297
|
+
*
|
298
|
+
* @param {string} eventName - Event name
|
299
|
+
* @param {*} data - Event data
|
300
|
+
* @returns {boolean} True if event had listeners
|
301
|
+
*/
|
302
|
+
emit(eventName, data) {
|
303
|
+
return this.events.emit(eventName, data);
|
304
|
+
}
|
305
|
+
|
306
|
+
// Protected methods to be overridden by subclasses
|
307
|
+
|
308
|
+
/**
|
309
|
+
* Initialize the service (to be overridden)
|
310
|
+
*
|
311
|
+
* @protected
|
312
|
+
* @param {Object} config - Service configuration
|
313
|
+
* @returns {Promise<void>}
|
314
|
+
*/
|
315
|
+
async _init(config) {
|
316
|
+
// Default implementation does nothing
|
317
|
+
}
|
318
|
+
|
319
|
+
/**
|
320
|
+
* Start the service (to be overridden)
|
321
|
+
*
|
322
|
+
* @protected
|
323
|
+
* @returns {Promise<void>}
|
324
|
+
*/
|
325
|
+
async _start() {
|
326
|
+
// Default implementation does nothing
|
327
|
+
}
|
328
|
+
|
329
|
+
/**
|
330
|
+
* Stop the service (to be overridden)
|
331
|
+
*
|
332
|
+
* @protected
|
333
|
+
* @returns {Promise<void>}
|
334
|
+
*/
|
335
|
+
async _stop() {
|
336
|
+
// Default implementation does nothing
|
337
|
+
}
|
338
|
+
|
339
|
+
/**
|
340
|
+
* Destroy the service (to be overridden)
|
341
|
+
*
|
342
|
+
* @protected
|
343
|
+
* @returns {Promise<void>}
|
344
|
+
*/
|
345
|
+
async _destroy() {
|
346
|
+
// Default implementation does nothing
|
347
|
+
}
|
348
|
+
|
349
|
+
/**
|
350
|
+
* Recover the service from an error (to be overridden)
|
351
|
+
*
|
352
|
+
* @protected
|
353
|
+
* @returns {Promise<void>}
|
354
|
+
*/
|
355
|
+
async _recover() {
|
356
|
+
// @note the user implementation is responsible for setting the target state
|
357
|
+
this._setState( this._preErrorState );
|
358
|
+
}
|
359
|
+
|
360
|
+
// Private helper methods
|
361
|
+
|
362
|
+
/**
|
363
|
+
* Set the service state
|
364
|
+
*
|
365
|
+
* @private
|
366
|
+
* @param {string} state - New state
|
367
|
+
*/
|
368
|
+
_setState(state) {
|
369
|
+
const oldState = this.state;
|
370
|
+
this.state = state;
|
371
|
+
|
372
|
+
this.logger.debug(`State changed from ${oldState} to ${state}`);
|
373
|
+
|
374
|
+
this.events.emit('stateChanged', {
|
375
|
+
service: this.name,
|
376
|
+
oldState,
|
377
|
+
newState: state
|
378
|
+
});
|
379
|
+
}
|
380
|
+
|
381
|
+
/**
|
382
|
+
* Set an error state
|
383
|
+
*
|
384
|
+
* @private
|
385
|
+
* @param {string} operation - Operation that failed
|
386
|
+
* @param {Error} error - Error that occurred
|
387
|
+
*/
|
388
|
+
_setError(operation, error) {
|
389
|
+
|
390
|
+
if (this.state !== ERROR) {
|
391
|
+
// Store current state before transitioning to ERROR
|
392
|
+
this._preErrorState = this.state;
|
393
|
+
}
|
394
|
+
|
395
|
+
this.error = error;
|
396
|
+
this._setState(ERROR);
|
397
|
+
|
398
|
+
this.logger.error(`${operation} error`, {
|
399
|
+
error: error.message,
|
400
|
+
stack: error.stack
|
401
|
+
});
|
402
|
+
|
403
|
+
this.events.emit('error', {
|
404
|
+
service: this.name,
|
405
|
+
operation,
|
406
|
+
error
|
407
|
+
});
|
408
|
+
}
|
409
|
+
}
|