@plyaz/core 1.2.1 → 1.3.0

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 (37) hide show
  1. package/README.md +248 -183
  2. package/dist/domain/example/FrontendExampleDomainService.d.ts.map +1 -1
  3. package/dist/domain/featureFlags/providers/database.d.ts +6 -1
  4. package/dist/domain/featureFlags/providers/database.d.ts.map +1 -1
  5. package/dist/entry-backend.d.ts +3 -1
  6. package/dist/entry-backend.d.ts.map +1 -1
  7. package/dist/entry-backend.js +3145 -3325
  8. package/dist/entry-backend.js.map +1 -1
  9. package/dist/entry-backend.mjs +2732 -2899
  10. package/dist/entry-backend.mjs.map +1 -1
  11. package/dist/entry-frontend.js +1594 -1406
  12. package/dist/entry-frontend.js.map +1 -1
  13. package/dist/entry-frontend.mjs +1568 -1379
  14. package/dist/entry-frontend.mjs.map +1 -1
  15. package/dist/index.js +3130 -3318
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +3133 -3308
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/init/CoreInitializer.d.ts +9 -8
  20. package/dist/init/CoreInitializer.d.ts.map +1 -1
  21. package/dist/init/ServiceRegistry.d.ts.map +1 -1
  22. package/dist/init/nestjs/index.js +1511 -1336
  23. package/dist/init/nestjs/index.js.map +1 -1
  24. package/dist/init/nestjs/index.mjs +1527 -1352
  25. package/dist/init/nestjs/index.mjs.map +1 -1
  26. package/dist/models/example/ExampleRepository.d.ts +45 -3
  27. package/dist/models/example/ExampleRepository.d.ts.map +1 -1
  28. package/dist/models/featureFlags/FeatureFlagRepository.d.ts +72 -471
  29. package/dist/models/featureFlags/FeatureFlagRepository.d.ts.map +1 -1
  30. package/dist/services/DbService.d.ts +2 -0
  31. package/dist/services/DbService.d.ts.map +1 -1
  32. package/dist/services/NotificationService.d.ts +2 -0
  33. package/dist/services/NotificationService.d.ts.map +1 -1
  34. package/dist/services/StorageService.d.ts +2 -0
  35. package/dist/services/StorageService.d.ts.map +1 -1
  36. package/dist/utils/common/id.d.ts.map +1 -1
  37. package/package.json +3 -3
@@ -1,19 +1,19 @@
1
1
  'use strict';
2
2
 
3
- var logger$1 = require('@plyaz/logger');
3
+ var config = require('@plyaz/config');
4
+ var types = require('@plyaz/types');
5
+ var events = require('events');
4
6
  var db = require('@plyaz/db');
5
7
  var errors = require('@plyaz/errors');
6
8
  var errors$1 = require('@plyaz/types/errors');
7
9
  var core = require('@plyaz/types/core');
8
- var events = require('events');
9
- var config = require('@plyaz/config');
10
- var types = require('@plyaz/types');
10
+ var storage = require('@plyaz/storage');
11
+ var notifications = require('@plyaz/notifications');
12
+ var logger$1 = require('@plyaz/logger');
11
13
  var api = require('@plyaz/api');
12
14
  var common = require('@nestjs/common');
13
15
  var rxjs = require('rxjs');
14
16
  var features = require('@plyaz/types/features');
15
- var storage = require('@plyaz/storage');
16
- var notifications = require('@plyaz/notifications');
17
17
  var store = require('@plyaz/store');
18
18
  var observability = require('@plyaz/types/observability');
19
19
  var examples = require('@plyaz/types/examples');
@@ -50,7 +50,15 @@ var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
50
50
  // @plyaz package - Built with tsup
51
51
  var __defProp = Object.defineProperty;
52
52
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
53
+ var __getOwnPropNames = Object.getOwnPropertyNames;
53
54
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
55
+ var __esm = (fn, res) => function __init() {
56
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
57
+ };
58
+ var __export = (target, all) => {
59
+ for (var name in all)
60
+ __defProp(target, name, { get: all[name], enumerable: true });
61
+ };
54
62
  var __decorateClass = (decorators, target, key, kind) => {
55
63
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
56
64
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
@@ -67,29 +75,26 @@ function hashString(str) {
67
75
  }
68
76
  return hash >>> 0;
69
77
  }
70
- __name(hashString, "hashString");
71
78
  function isInRollout(identifier, percentage) {
72
79
  if (percentage >= config.MATH_CONSTANTS.PERCENTAGE_MAX) return true;
73
80
  if (percentage <= 0) return false;
74
81
  const hash = hashString(identifier);
75
82
  return hash % config.MATH_CONSTANTS.PERCENTAGE_MAX < percentage;
76
83
  }
77
- __name(isInRollout, "isInRollout");
78
84
  function createRolloutIdentifier(featureKey, userId) {
79
85
  const trimmedUserId = userId?.trim();
80
86
  const effectiveUserId = trimmedUserId && trimmedUserId.length > 0 ? trimmedUserId : "anonymous";
81
87
  return `${featureKey}:${effectiveUserId}`;
82
88
  }
83
- __name(createRolloutIdentifier, "createRolloutIdentifier");
89
+ var init_hash = __esm({
90
+ "src/utils/common/hash.ts"() {
91
+ __name(hashString, "hashString");
92
+ __name(isInRollout, "isInRollout");
93
+ __name(createRolloutIdentifier, "createRolloutIdentifier");
94
+ }
95
+ });
84
96
 
85
97
  // src/utils/common/id.ts
86
- var RANDOM_ID_RADIX = 36;
87
- var RANDOM_ID_SLICE_START = 2;
88
- var SHORT_ID_LENGTH = 8;
89
- var HEX_RADIX = 16;
90
- var HEX_SLICE_START = 2;
91
- var HEX_SLICE_END = 18;
92
- var SPAN_ID_LENGTH = 16;
93
98
  function generateId() {
94
99
  const cryptoApi = globalThis.crypto;
95
100
  if (cryptoApi?.randomUUID) {
@@ -97,7 +102,6 @@ function generateId() {
97
102
  }
98
103
  return `${Date.now()}-${Math.random().toString(RANDOM_ID_RADIX).slice(RANDOM_ID_SLICE_START)}`;
99
104
  }
100
- __name(generateId, "generateId");
101
105
  function generateShortId() {
102
106
  const cryptoApi = globalThis.crypto;
103
107
  if (cryptoApi?.randomUUID) {
@@ -105,11 +109,9 @@ function generateShortId() {
105
109
  }
106
110
  return Math.random().toString(RANDOM_ID_RADIX).slice(RANDOM_ID_SLICE_START, RANDOM_ID_SLICE_START + SHORT_ID_LENGTH);
107
111
  }
108
- __name(generateShortId, "generateShortId");
109
112
  function generateCorrelationId() {
110
113
  return `${Date.now()}-${generateShortId()}`;
111
114
  }
112
- __name(generateCorrelationId, "generateCorrelationId");
113
115
  function generateTraceId() {
114
116
  const cryptoApi = globalThis.crypto;
115
117
  if (cryptoApi?.randomUUID) {
@@ -117,7 +119,6 @@ function generateTraceId() {
117
119
  }
118
120
  return Math.random().toString(HEX_RADIX).substring(HEX_SLICE_START, HEX_SLICE_END) + Math.random().toString(HEX_RADIX).substring(HEX_SLICE_START, HEX_SLICE_END);
119
121
  }
120
- __name(generateTraceId, "generateTraceId");
121
122
  function generateSpanId() {
122
123
  const cryptoApi = globalThis.crypto;
123
124
  if (cryptoApi?.randomUUID) {
@@ -125,20 +126,34 @@ function generateSpanId() {
125
126
  }
126
127
  return Math.random().toString(HEX_RADIX).substring(HEX_SLICE_START, HEX_SLICE_END);
127
128
  }
128
- __name(generateSpanId, "generateSpanId");
129
+ var RANDOM_ID_RADIX, RANDOM_ID_SLICE_START, SHORT_ID_LENGTH, HEX_RADIX, HEX_SLICE_START, HEX_SLICE_END, SPAN_ID_LENGTH;
130
+ var init_id = __esm({
131
+ "src/utils/common/id.ts"() {
132
+ RANDOM_ID_RADIX = 36;
133
+ RANDOM_ID_SLICE_START = 2;
134
+ SHORT_ID_LENGTH = 8;
135
+ HEX_RADIX = 16;
136
+ HEX_SLICE_START = 2;
137
+ HEX_SLICE_END = 18;
138
+ SPAN_ID_LENGTH = 16;
139
+ __name(generateId, "generateId");
140
+ __name(generateShortId, "generateShortId");
141
+ __name(generateCorrelationId, "generateCorrelationId");
142
+ __name(generateTraceId, "generateTraceId");
143
+ __name(generateSpanId, "generateSpanId");
144
+ }
145
+ });
129
146
  function isStringFalsy(value) {
130
147
  if (value === "") return true;
131
148
  const lower = value.toLowerCase().trim();
132
149
  return ["false", "no", "0", "off", "disabled"].includes(lower);
133
150
  }
134
- __name(isStringFalsy, "isStringFalsy");
135
151
  function isObjectTruthy(value) {
136
152
  if (Array.isArray(value)) return value.length > 0;
137
153
  if (value instanceof Map || value instanceof Set) return value.size > 0;
138
154
  if (value.constructor === Object) return Object.keys(value).length > 0;
139
155
  return true;
140
156
  }
141
- __name(isObjectTruthy, "isObjectTruthy");
142
157
  function isTruthy(value) {
143
158
  if (value === null || value === void 0) return false;
144
159
  switch (typeof value) {
@@ -157,747 +172,1215 @@ function isTruthy(value) {
157
172
  return false;
158
173
  }
159
174
  }
160
- __name(isTruthy, "isTruthy");
161
-
162
- // src/events/CoreEventManager.ts
163
- var MAX_EVENT_LISTENERS = 100;
164
- var CoreEventManagerClass = class {
165
- constructor() {
166
- this.emitter = new events.EventEmitter();
167
- this.subscriptions = /* @__PURE__ */ new Map();
168
- this.emitter.setMaxListeners(MAX_EVENT_LISTENERS);
169
- }
170
- static {
171
- __name(this, "CoreEventManagerClass");
172
- }
173
- emit(eventType, data) {
174
- const [scope] = eventType.split(":");
175
- const event = {
176
- type: eventType,
177
- scope: scope ?? "system",
178
- timestamp: Date.now(),
179
- correlationId: this.getCorrelationId(),
180
- data
181
- };
182
- this.emitter.emit(eventType, event);
183
- this.emitter.emit("*", event);
184
- return true;
185
- }
186
- on(eventType, handler) {
187
- this.emitter.on(eventType, handler);
188
- if (!this.subscriptions.has(eventType)) {
189
- this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
190
- }
191
- this.subscriptions.get(eventType).add(handler);
192
- return () => {
193
- this.emitter.off(eventType, handler);
194
- this.subscriptions.get(eventType)?.delete(handler);
195
- };
196
- }
197
- once(eventType, handler) {
198
- const wrappedHandler = /* @__PURE__ */ __name((event) => {
199
- handler(event);
200
- this.emitter.off(eventType, wrappedHandler);
201
- this.subscriptions.get(eventType)?.delete(wrappedHandler);
202
- }, "wrappedHandler");
203
- this.emitter.on(eventType, wrappedHandler);
204
- if (!this.subscriptions.has(eventType)) {
205
- this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
206
- }
207
- this.subscriptions.get(eventType).add(wrappedHandler);
208
- return () => {
209
- this.emitter.off(eventType, wrappedHandler);
210
- this.subscriptions.get(eventType)?.delete(wrappedHandler);
211
- };
175
+ var init_values = __esm({
176
+ "src/utils/common/values.ts"() {
177
+ __name(isStringFalsy, "isStringFalsy");
178
+ __name(isObjectTruthy, "isObjectTruthy");
179
+ __name(isTruthy, "isTruthy");
212
180
  }
213
- /**
214
- * Subscribe to all events in a scope
215
- *
216
- * @param scope - Event scope to listen to (e.g., CoreEventScope.AUTH)
217
- * @param handler - Event handler
218
- * @returns Unsubscribe function
219
- *
220
- * @example
221
- * ```typescript
222
- * CoreEventManager.onScope(CoreEventScope.AUTH, (event) => {
223
- * // Handles auth:login, auth:logout, auth:tokenRefresh, etc.
224
- * console.log(`Auth event: ${event.type}`, event.data);
225
- * });
226
- * ```
227
- */
228
- onScope(scope, handler) {
229
- const wrappedHandler = /* @__PURE__ */ __name((event) => {
230
- if (event.scope === scope) {
231
- handler(event);
232
- }
233
- }, "wrappedHandler");
234
- return this.on("*", wrappedHandler);
235
- }
236
- /**
237
- * Remove a specific handler from an event
238
- *
239
- * @param eventType - Event type
240
- * @param handler - Handler to remove
241
- */
242
- off(eventType, handler) {
243
- this.emitter.off(eventType, handler);
244
- this.subscriptions.get(eventType)?.delete(handler);
245
- }
246
- /**
247
- * Dispose all subscriptions
248
- */
249
- dispose() {
250
- this.subscriptions.forEach((handlers, eventType) => {
251
- handlers.forEach((handler) => this.emitter.off(eventType, handler));
252
- });
253
- this.subscriptions.clear();
254
- this.emitter.removeAllListeners();
255
- }
256
- /**
257
- * Generate correlation ID for event tracing
258
- */
259
- getCorrelationId() {
260
- return generateCorrelationId();
261
- }
262
- };
263
- var CoreEventManager = new CoreEventManagerClass();
181
+ });
264
182
 
265
- // src/services/DbService.ts
266
- var DEFAULT_ENCRYPTION_FIELDS = {
267
- // User PII
268
- users: ["password_hash", "phone_number", "date_of_birth"],
269
- // KYC sensitive data
270
- "backoffice.kyc_submissions": ["tax_id", "address_line1", "address_line2"],
271
- // Connected accounts OAuth tokens
272
- connected_accounts: ["access_token_encrypted", "refresh_token_encrypted", "wallet_address"],
273
- // Payment payout accounts
274
- user_payout_accounts: ["provider_account_id", "account_holder_name"],
275
- // Sessions
276
- sessions: ["token"]
277
- };
278
- var DEFAULT_CACHE_TTL_SECONDS = 300;
279
- var DEFAULT_AUDIT_RETENTION_DAYS = 180;
280
- var DEFAULT_POOL_SIZE = 10;
281
- var DEFAULT_CONFIG = {
282
- adapter: "sql",
283
- cache: {
284
- enabled: true,
285
- provider: "memory",
286
- ttl: DEFAULT_CACHE_TTL_SECONDS
287
- },
288
- softDelete: {
289
- enabled: true,
290
- field: "deleted_at",
291
- excludeTables: [
292
- "audit_logs",
293
- "audit.audit_logs",
294
- "audit.feature_flag_evaluations",
295
- "feature_flag_evaluations",
296
- "notification_events",
297
- "payments_activity",
298
- "campaign_analytics",
299
- "admin_actions",
300
- "backoffice.admin_actions"
301
- ]
302
- },
303
- audit: {
304
- enabled: true,
305
- // Enabled by default for compliance
306
- retentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
307
- excludeFields: ["password_hash", "api_key_hash", "token_hash"],
308
- excludeTables: ["audit_logs", "audit.audit_logs"],
309
- // Don't audit the audit table itself
310
- schema: "audit",
311
- // Use dedicated audit schema
312
- usePartitionedTables: true
313
- // Use daily partitioned tables (audit_log_yyyy_mm_dd)
314
- }
315
- // NOTE: Encryption requires key from environment or DbService.initialize()
316
- // Enable via: DbService.initialize({ encryption: { enabled: true, key: process.env.ENCRYPTION_KEY!, fields: DEFAULT_ENCRYPTION_FIELDS } })
317
- };
318
- var TABLE_REGISTRY = {
319
- // Migration 008: Feature Flags (custom ID column 'key')
320
- feature_flags: { idColumn: "key" },
321
- // Test Feature Flags (custom ID column 'key')
322
- test_feature_flags: { idColumn: "key" },
323
- // Migration 010: Universal Analytics (custom ID column 'user_id')
324
- user_analytics_summary: { idColumn: "user_id" }
325
- };
326
- var DbService = class _DbService {
327
- constructor() {
328
- this.databaseService = null;
329
- this.namedAdapters = /* @__PURE__ */ new Map();
330
- this.config = null;
331
- this.initialized = false;
332
- }
333
- static {
334
- __name(this, "DbService");
335
- }
336
- static {
337
- this.instance = null;
338
- }
339
- /**
340
- * Emits a database error event via CoreEventManager.
341
- * Called when database operations fail to integrate with global error handling.
342
- *
343
- * @param error - The error that occurred
344
- * @param operation - The operation that failed (e.g., 'transaction', 'query', 'healthCheck')
345
- * @param table - Optional table name involved in the operation
346
- * @param query - Optional query string that failed
347
- * @param recoverable - Whether the error is recoverable (default: false)
348
- */
349
- emitDatabaseError(error, operation, options) {
350
- const payload = {
351
- error,
352
- operation,
353
- table: options?.table,
354
- query: options?.query,
355
- recoverable: options?.recoverable ?? false
356
- };
357
- CoreEventManager.emit(core.CORE_EVENTS.DATABASE.ERROR, payload);
183
+ // src/utils/common/object.ts
184
+ var init_object = __esm({
185
+ "src/utils/common/object.ts"() {
358
186
  }
359
- /**
360
- * Gets the singleton instance of DbService
361
- *
362
- * @returns {DbService} The singleton instance
363
- */
364
- static getInstance() {
365
- _DbService.instance ??= new _DbService();
366
- return _DbService.instance;
187
+ });
188
+ var init_validation = __esm({
189
+ "src/utils/common/validation.ts"() {
367
190
  }
368
- /**
369
- * Checks if the database service has been initialized
370
- *
371
- * @returns {boolean} True if initialized
372
- */
373
- static isInitialized() {
374
- return _DbService.instance?.initialized ?? false;
191
+ });
192
+
193
+ // src/utils/common/index.ts
194
+ var init_common = __esm({
195
+ "src/utils/common/index.ts"() {
196
+ init_hash();
197
+ init_id();
198
+ init_values();
199
+ init_object();
200
+ init_validation();
375
201
  }
376
- /**
377
- * Resets the database service by closing connections and clearing the singleton instance
378
- *
379
- * @description Properly closes the database connection and clears the singleton.
380
- * Useful for testing or when you need to reinitialize with different configuration.
381
- *
382
- * @example
383
- * ```typescript
384
- * await DbService.reset();
385
- * await DbService.initialize({ adapter: 'sql', ... });
386
- * ```
387
- */
388
- static async reset() {
389
- if (_DbService.instance) {
390
- try {
391
- await _DbService.instance.databaseService?.close?.();
392
- } catch {
202
+ });
203
+ var MAX_EVENT_LISTENERS, CoreEventManagerClass; exports.CoreEventManager = void 0;
204
+ var init_CoreEventManager = __esm({
205
+ "src/events/CoreEventManager.ts"() {
206
+ init_common();
207
+ MAX_EVENT_LISTENERS = 100;
208
+ CoreEventManagerClass = class {
209
+ constructor() {
210
+ this.emitter = new events.EventEmitter();
211
+ this.subscriptions = /* @__PURE__ */ new Map();
212
+ this.emitter.setMaxListeners(MAX_EVENT_LISTENERS);
213
+ }
214
+ static {
215
+ __name(this, "CoreEventManagerClass");
216
+ }
217
+ emit(eventType, data) {
218
+ const [scope] = eventType.split(":");
219
+ const event = {
220
+ type: eventType,
221
+ scope: scope ?? "system",
222
+ timestamp: Date.now(),
223
+ correlationId: this.getCorrelationId(),
224
+ data
225
+ };
226
+ this.emitter.emit(eventType, event);
227
+ this.emitter.emit("*", event);
228
+ return true;
229
+ }
230
+ on(eventType, handler) {
231
+ this.emitter.on(eventType, handler);
232
+ if (!this.subscriptions.has(eventType)) {
233
+ this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
234
+ }
235
+ this.subscriptions.get(eventType).add(handler);
236
+ return () => {
237
+ this.emitter.off(eventType, handler);
238
+ this.subscriptions.get(eventType)?.delete(handler);
239
+ };
240
+ }
241
+ once(eventType, handler) {
242
+ const wrappedHandler = /* @__PURE__ */ __name((event) => {
243
+ handler(event);
244
+ this.emitter.off(eventType, wrappedHandler);
245
+ this.subscriptions.get(eventType)?.delete(wrappedHandler);
246
+ }, "wrappedHandler");
247
+ this.emitter.on(eventType, wrappedHandler);
248
+ if (!this.subscriptions.has(eventType)) {
249
+ this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
250
+ }
251
+ this.subscriptions.get(eventType).add(wrappedHandler);
252
+ return () => {
253
+ this.emitter.off(eventType, wrappedHandler);
254
+ this.subscriptions.get(eventType)?.delete(wrappedHandler);
255
+ };
256
+ }
257
+ /**
258
+ * Subscribe to all events in a scope
259
+ *
260
+ * @param scope - Event scope to listen to (e.g., CoreEventScope.AUTH)
261
+ * @param handler - Event handler
262
+ * @returns Unsubscribe function
263
+ *
264
+ * @example
265
+ * ```typescript
266
+ * CoreEventManager.onScope(CoreEventScope.AUTH, (event) => {
267
+ * // Handles auth:login, auth:logout, auth:tokenRefresh, etc.
268
+ * console.log(`Auth event: ${event.type}`, event.data);
269
+ * });
270
+ * ```
271
+ */
272
+ onScope(scope, handler) {
273
+ const wrappedHandler = /* @__PURE__ */ __name((event) => {
274
+ if (event.scope === scope) {
275
+ handler(event);
276
+ }
277
+ }, "wrappedHandler");
278
+ return this.on("*", wrappedHandler);
279
+ }
280
+ /**
281
+ * Remove a specific handler from an event
282
+ *
283
+ * @param eventType - Event type
284
+ * @param handler - Handler to remove
285
+ */
286
+ off(eventType, handler) {
287
+ this.emitter.off(eventType, handler);
288
+ this.subscriptions.get(eventType)?.delete(handler);
289
+ }
290
+ /**
291
+ * Dispose all subscriptions
292
+ */
293
+ dispose() {
294
+ this.subscriptions.forEach((handlers, eventType) => {
295
+ handlers.forEach((handler) => this.emitter.off(eventType, handler));
296
+ });
297
+ this.subscriptions.clear();
298
+ this.emitter.removeAllListeners();
299
+ }
300
+ /**
301
+ * Generate correlation ID for event tracing
302
+ */
303
+ getCorrelationId() {
304
+ return generateCorrelationId();
393
305
  }
394
- _DbService.instance = null;
395
- }
396
- }
397
- /**
398
- * Initializes the database connection
399
- *
400
- * @description Sets up the database connection using the provided configuration
401
- * or environment variables. This method is idempotent - calling it multiple
402
- * times won't create additional connections.
403
- *
404
- * **Environment Variables:**
405
- * - `DATABASE_URL` - PostgreSQL connection string (for sql/drizzle adapters)
406
- * - `ENCRYPTION_KEY` - 32-byte encryption key for field encryption (optional)
407
- * - `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `SUPABASE_ANON_PUBLIC_KEY` - For supabase adapter
408
- *
409
- * **Encryption:** If `ENCRYPTION_KEY` env is set, encryption is auto-enabled
410
- * using `DEFAULT_ENCRYPTION_FIELDS`. Override via config.encryption.
411
- *
412
- * @param {DbServiceConfig} [config] - Optional configuration
413
- * @returns {Promise<DbService>} The initialized DbService instance
414
- * @throws {DatabasePackageError} When configuration is invalid or connection fails
415
- *
416
- * @example
417
- * ```typescript
418
- * // Minimal - uses DATABASE_URL env, auto-enables encryption if ENCRYPTION_KEY set
419
- * await DbService.initialize();
420
- *
421
- * // With explicit encryption
422
- * await DbService.initialize({
423
- * adapter: 'sql',
424
- * encryption: {
425
- * enabled: true,
426
- * key: 'your-32-byte-encryption-key-here!!',
427
- * fields: DEFAULT_ENCRYPTION_FIELDS,
428
- * },
429
- * });
430
- *
431
- * // Or via Core.initialize() with env:
432
- * await Core.initialize({
433
- * env: { ENCRYPTION_KEY: '...' },
434
- * db: { adapter: 'sql' },
435
- * });
436
- * ```
437
- */
438
- /** Build encryption config from user config */
439
- static buildEncryptionConfig(config) {
440
- const encryption = config?.encryption;
441
- if (!encryption?.key) return void 0;
442
- return {
443
- enabled: encryption.enabled ?? true,
444
- key: encryption.key,
445
- fields: encryption.fields ?? DEFAULT_ENCRYPTION_FIELDS,
446
- algorithm: encryption.algorithm ?? "aes-256-gcm"
447
- };
448
- }
449
- /** Merge user config with defaults */
450
- static mergeConfig(config) {
451
- return {
452
- ...DEFAULT_CONFIG,
453
- ...config,
454
- softDelete: { ...DEFAULT_CONFIG.softDelete, ...config?.softDelete },
455
- cache: { ...DEFAULT_CONFIG.cache, ...config?.cache },
456
- audit: { ...DEFAULT_CONFIG.audit, ...config?.audit },
457
- encryption: _DbService.buildEncryptionConfig(config)
458
- };
459
- }
460
- /** Initialize named adapters */
461
- async initializeNamedAdapters(mergedConfig) {
462
- if (!mergedConfig.adapters) return;
463
- for (const [name, adapterConfig] of Object.entries(mergedConfig.adapters)) {
464
- const namedDbConfig = this.buildDatabaseConfig({
465
- ...mergedConfig,
466
- adapter: adapterConfig.adapter,
467
- drizzle: adapterConfig.drizzle,
468
- supabase: adapterConfig.supabase,
469
- sql: adapterConfig.sql
470
- });
471
- const namedService = await db.createDatabaseService(namedDbConfig);
472
- this.namedAdapters.set(name, namedService);
473
- }
474
- }
475
- static async initialize(config) {
476
- const instance = _DbService.getInstance();
477
- if (instance.initialized) {
478
- return instance;
479
- }
480
- const mergedConfig = _DbService.mergeConfig(config);
481
- instance.config = mergedConfig;
482
- const dbConfig = instance.buildDatabaseConfig(mergedConfig);
483
- instance.databaseService = await db.createDatabaseService(dbConfig);
484
- await instance.initializeNamedAdapters(mergedConfig);
485
- instance.initialized = true;
486
- return instance;
487
- }
488
- /**
489
- * Builds the DatabaseServiceConfig based on the adapter type
490
- * @private
491
- */
492
- /** Builds adapter-specific config based on adapter type */
493
- buildAdapterConfig(adapter, config) {
494
- const builders = {
495
- drizzle: /* @__PURE__ */ __name(() => this.buildDrizzleConfig(config), "drizzle"),
496
- supabase: /* @__PURE__ */ __name(() => this.buildSupabaseConfig(config), "supabase"),
497
- sql: /* @__PURE__ */ __name(() => this.buildSqlConfig(config), "sql")
498
- };
499
- const builder = builders[adapter];
500
- if (!builder) {
501
- throw new errors.DatabasePackageError(
502
- `Unsupported adapter type: ${adapter}`,
503
- errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
504
- );
505
- }
506
- return builder();
507
- }
508
- /** Builds soft delete extension config */
509
- buildSoftDeleteExtension(config) {
510
- if (!config.softDelete?.enabled) return void 0;
511
- return {
512
- enabled: true,
513
- field: config.softDelete.field ?? "deleted_at",
514
- excludeTables: config.softDelete.excludeTables
515
- };
516
- }
517
- /** Builds cache extension config */
518
- buildCacheExtension(config) {
519
- if (!config.cache?.enabled) return void 0;
520
- return {
521
- enabled: true,
522
- ttl: config.cache.ttl ?? DEFAULT_CACHE_TTL_SECONDS,
523
- provider: config.cache.provider ?? "memory",
524
- invalidation: config.cache.invalidation ?? "write"
525
- };
526
- }
527
- /** Builds audit extension config */
528
- buildAuditExtension(config) {
529
- if (!config.audit?.enabled) return void 0;
530
- return {
531
- enabled: true,
532
- retentionDays: config.audit.retentionDays ?? DEFAULT_AUDIT_RETENTION_DAYS,
533
- excludeFields: config.audit.excludeFields,
534
- excludeTables: config.audit.excludeTables,
535
- schema: config.audit.schema ?? "audit",
536
- usePartitionedTables: config.audit.usePartitionedTables ?? true
537
- };
538
- }
539
- /** Builds encryption extension config */
540
- buildEncryptionExtension(config) {
541
- if (!config.encryption?.enabled || !config.encryption.key) return void 0;
542
- return {
543
- enabled: true,
544
- key: config.encryption.key,
545
- fields: config.encryption.fields ?? {},
546
- algorithm: config.encryption.algorithm
547
306
  };
307
+ exports.CoreEventManager = new CoreEventManagerClass();
548
308
  }
549
- buildDatabaseConfig(config) {
550
- const adapter = config.adapter ?? "drizzle";
551
- const dbConfig = {
552
- adapter,
553
- config: this.buildAdapterConfig(adapter, config)
554
- };
555
- const softDelete = this.buildSoftDeleteExtension(config);
556
- const cache = this.buildCacheExtension(config);
557
- const audit = this.buildAuditExtension(config);
558
- const encryption = this.buildEncryptionExtension(config);
559
- if (softDelete) dbConfig.softDelete = softDelete;
560
- if (cache) dbConfig.cache = cache;
561
- if (audit) dbConfig.audit = audit;
562
- if (encryption) dbConfig.encryption = encryption;
563
- return dbConfig;
564
- }
565
- /**
566
- * Builds Drizzle adapter configuration
567
- * @private
568
- */
569
- buildDrizzleConfig(config) {
570
- const connectionString = config.drizzle?.connectionString;
571
- if (!connectionString) {
572
- throw new errors.DatabasePackageError(
573
- "Drizzle adapter requires a PostgreSQL connection string. Provide `drizzle.connectionString` in config or use Core.initialize() with DATABASE_URL in env. For Supabase, find this in Dashboard > Database > Connection string (URI).",
574
- errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
575
- );
576
- }
577
- const tableIdColumns = this.buildTableIdColumns();
578
- return {
579
- connectionString,
580
- poolSize: config.drizzle?.poolSize ?? DEFAULT_POOL_SIZE,
581
- ssl: config.drizzle?.ssl,
582
- schema: config.drizzle?.schema,
583
- // Pass through schema configuration
584
- tableIdColumns
309
+ });
310
+
311
+ // src/services/DbService.ts
312
+ var DbService_exports = {};
313
+ __export(DbService_exports, {
314
+ DEFAULT_ENCRYPTION_FIELDS: () => DEFAULT_ENCRYPTION_FIELDS,
315
+ DbService: () => DbService,
316
+ TABLE_REGISTRY: () => TABLE_REGISTRY
317
+ });
318
+ var DEFAULT_ENCRYPTION_FIELDS, DEFAULT_CACHE_TTL_SECONDS, DEFAULT_AUDIT_RETENTION_DAYS, DEFAULT_POOL_SIZE, DEFAULT_CONFIG, TABLE_REGISTRY, DbService;
319
+ var init_DbService = __esm({
320
+ "src/services/DbService.ts"() {
321
+ init_CoreEventManager();
322
+ DEFAULT_ENCRYPTION_FIELDS = {
323
+ // User PII
324
+ users: ["password_hash", "phone_number", "date_of_birth"],
325
+ // KYC sensitive data
326
+ "backoffice.kyc_submissions": ["tax_id", "address_line1", "address_line2"],
327
+ // Connected accounts OAuth tokens
328
+ connected_accounts: ["access_token_encrypted", "refresh_token_encrypted", "wallet_address"],
329
+ // Payment payout accounts
330
+ user_payout_accounts: ["provider_account_id", "account_holder_name"],
331
+ // Sessions
332
+ sessions: ["token"]
585
333
  };
586
- }
587
- /**
588
- * Builds Supabase adapter configuration
589
- * @private
590
- */
591
- // eslint-disable-next-line complexity
592
- buildSupabaseConfig(config) {
593
- const supabaseUrl = config.supabase?.supabaseUrl;
594
- const supabaseServiceKey = config.supabase?.supabaseServiceKey;
595
- const supabaseAnonKey = config.supabase?.supabaseAnonKey;
596
- if (!supabaseUrl || !supabaseServiceKey) {
597
- throw new errors.DatabasePackageError(
598
- "Supabase adapter requires supabaseUrl and supabaseServiceKey. Provide in config or use Core.initialize() with SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY in env.",
599
- errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
600
- );
601
- }
602
- if (!supabaseAnonKey) {
603
- throw new errors.DatabasePackageError(
604
- "Supabase adapter requires supabaseAnonKey. Provide in config or use Core.initialize() with SUPABASE_ANON_PUBLIC_KEY in env.",
605
- errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
606
- );
607
- }
608
- const tableIdColumns = this.buildTableIdColumns();
609
- return {
610
- supabaseUrl,
611
- supabaseServiceKey,
612
- supabaseAnonKey,
613
- schema: config.supabase?.schema ?? "public",
614
- tableIdColumns
334
+ DEFAULT_CACHE_TTL_SECONDS = 300;
335
+ DEFAULT_AUDIT_RETENTION_DAYS = 180;
336
+ DEFAULT_POOL_SIZE = 10;
337
+ DEFAULT_CONFIG = {
338
+ adapter: "sql",
339
+ cache: {
340
+ enabled: true,
341
+ provider: "memory",
342
+ ttl: DEFAULT_CACHE_TTL_SECONDS
343
+ },
344
+ softDelete: {
345
+ enabled: true,
346
+ field: "deleted_at",
347
+ excludeTables: [
348
+ "audit_logs",
349
+ "audit.audit_logs",
350
+ "audit.feature_flag_evaluations",
351
+ "feature_flag_evaluations",
352
+ "notification_events",
353
+ "payments_activity",
354
+ "campaign_analytics",
355
+ "admin_actions",
356
+ "backoffice.admin_actions"
357
+ ]
358
+ },
359
+ audit: {
360
+ enabled: true,
361
+ // Enabled by default for compliance
362
+ retentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
363
+ excludeFields: ["password_hash", "api_key_hash", "token_hash"],
364
+ excludeTables: ["audit_logs", "audit.audit_logs"],
365
+ // Don't audit the audit table itself
366
+ schema: "audit",
367
+ // Use dedicated audit schema
368
+ usePartitionedTables: true
369
+ // Use daily partitioned tables (audit_log_yyyy_mm_dd)
370
+ }
371
+ // NOTE: Encryption requires key from environment or DbService.initialize()
372
+ // Enable via: DbService.initialize({ encryption: { enabled: true, key: process.env.ENCRYPTION_KEY!, fields: DEFAULT_ENCRYPTION_FIELDS } })
615
373
  };
616
- }
617
- /**
618
- * Builds SQL adapter configuration
619
- * @private
620
- */
621
- buildSqlConfig(config) {
622
- const connectionString = config.sql?.connectionString;
623
- if (!connectionString) {
624
- throw new errors.DatabasePackageError(
625
- "SQL adapter requires a connection string. Provide `sql.connectionString` in config or use Core.initialize() with DATABASE_URL in env.",
626
- errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
627
- );
628
- }
629
- const tableIdColumns = this.buildTableIdColumns();
630
- return {
631
- connectionString,
632
- dialect: config.sql?.dialect ?? "postgresql",
633
- schema: config.sql?.schema,
634
- // Pass through schema configuration
635
- tableIdColumns
374
+ TABLE_REGISTRY = {
375
+ // Migration 008: Feature Flags (custom ID column 'key')
376
+ feature_flags: { idColumn: "key" },
377
+ // Test Feature Flags (custom ID column 'key')
378
+ test_feature_flags: { idColumn: "key" },
379
+ // Migration 010: Universal Analytics (custom ID column 'user_id')
380
+ user_analytics_summary: { idColumn: "user_id" }
636
381
  };
637
- }
638
- /**
639
- * Builds table ID column mappings from TABLE_REGISTRY
640
- * @private
641
- * @returns Record of table names to ID column names
642
- */
643
- // eslint-disable-next-line complexity
644
- buildTableIdColumns() {
645
- const tableIdColumns = {};
646
- const baseNameConflicts = /* @__PURE__ */ new Set();
647
- const baseNameMappings = /* @__PURE__ */ new Map();
648
- for (const tableName of Object.keys(TABLE_REGISTRY)) {
649
- if (tableName.includes(".")) {
650
- const baseName = tableName.split(".").pop();
651
- if (baseNameMappings.has(baseName) || TABLE_REGISTRY[baseName]) {
652
- baseNameConflicts.add(baseName);
653
- } else {
654
- baseNameMappings.set(baseName, tableName);
382
+ DbService = class _DbService {
383
+ constructor() {
384
+ this.databaseService = null;
385
+ this.namedAdapters = /* @__PURE__ */ new Map();
386
+ this.config = null;
387
+ this.initialized = false;
388
+ }
389
+ static {
390
+ __name(this, "DbService");
391
+ }
392
+ static {
393
+ this.instance = null;
394
+ }
395
+ /**
396
+ * Emits a database error event via CoreEventManager.
397
+ * Called when database operations fail to integrate with global error handling.
398
+ *
399
+ * @param error - The error that occurred
400
+ * @param operation - The operation that failed (e.g., 'transaction', 'query', 'healthCheck')
401
+ * @param table - Optional table name involved in the operation
402
+ * @param query - Optional query string that failed
403
+ * @param recoverable - Whether the error is recoverable (default: false)
404
+ */
405
+ emitDatabaseError(error, operation, options) {
406
+ const payload = {
407
+ error,
408
+ operation,
409
+ table: options?.table,
410
+ query: options?.query,
411
+ recoverable: options?.recoverable ?? false
412
+ };
413
+ exports.CoreEventManager.emit(core.CORE_EVENTS.DATABASE.ERROR, payload);
414
+ }
415
+ /**
416
+ * Gets the singleton instance of DbService
417
+ *
418
+ * @returns {DbService} The singleton instance
419
+ */
420
+ static getInstance() {
421
+ _DbService.instance ??= new _DbService();
422
+ return _DbService.instance;
423
+ }
424
+ /**
425
+ * Checks if the database service has been initialized
426
+ *
427
+ * @returns {boolean} True if initialized
428
+ */
429
+ static isInitialized() {
430
+ return _DbService.instance?.initialized ?? false;
431
+ }
432
+ /**
433
+ * Resets the database service by closing connections and clearing the singleton instance
434
+ *
435
+ * @description Properly closes the database connection and clears the singleton.
436
+ * Useful for testing or when you need to reinitialize with different configuration.
437
+ *
438
+ * @example
439
+ * ```typescript
440
+ * await DbService.reset();
441
+ * await DbService.initialize({ adapter: 'sql', ... });
442
+ * ```
443
+ */
444
+ static async reset() {
445
+ if (_DbService.instance) {
446
+ try {
447
+ await _DbService.instance.databaseService?.close?.();
448
+ } catch {
449
+ }
450
+ _DbService.instance = null;
655
451
  }
656
452
  }
657
- }
658
- for (const [tableName, config] of Object.entries(TABLE_REGISTRY)) {
659
- const idColumn = config.idColumn ?? "id";
660
- if (idColumn === "id") continue;
661
- tableIdColumns[tableName] = idColumn;
662
- if (!tableName.includes(".")) continue;
663
- const baseName = tableName.split(".").pop();
664
- if (!baseNameConflicts.has(baseName)) {
665
- tableIdColumns[baseName] = idColumn;
453
+ /**
454
+ * Initializes the database connection
455
+ *
456
+ * @description Sets up the database connection using the provided configuration
457
+ * or environment variables. This method is idempotent - calling it multiple
458
+ * times won't create additional connections.
459
+ *
460
+ * **Environment Variables:**
461
+ * - `DATABASE_URL` - PostgreSQL connection string (for sql/drizzle adapters)
462
+ * - `ENCRYPTION_KEY` - 32-byte encryption key for field encryption (optional)
463
+ * - `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `SUPABASE_ANON_PUBLIC_KEY` - For supabase adapter
464
+ *
465
+ * **Encryption:** If `ENCRYPTION_KEY` env is set, encryption is auto-enabled
466
+ * using `DEFAULT_ENCRYPTION_FIELDS`. Override via config.encryption.
467
+ *
468
+ * @param {DbServiceConfig} [config] - Optional configuration
469
+ * @returns {Promise<DbService>} The initialized DbService instance
470
+ * @throws {DatabasePackageError} When configuration is invalid or connection fails
471
+ *
472
+ * @example
473
+ * ```typescript
474
+ * // Minimal - uses DATABASE_URL env, auto-enables encryption if ENCRYPTION_KEY set
475
+ * await DbService.initialize();
476
+ *
477
+ * // With explicit encryption
478
+ * await DbService.initialize({
479
+ * adapter: 'sql',
480
+ * encryption: {
481
+ * enabled: true,
482
+ * key: 'your-32-byte-encryption-key-here!!',
483
+ * fields: DEFAULT_ENCRYPTION_FIELDS,
484
+ * },
485
+ * });
486
+ *
487
+ * // Or via Core.initialize() with env:
488
+ * await Core.initialize({
489
+ * env: { ENCRYPTION_KEY: '...' },
490
+ * db: { adapter: 'sql' },
491
+ * });
492
+ * ```
493
+ */
494
+ /** Build encryption config from user config */
495
+ static buildEncryptionConfig(config) {
496
+ const encryption = config?.encryption;
497
+ if (!encryption?.key) return void 0;
498
+ return {
499
+ enabled: encryption.enabled ?? true,
500
+ key: encryption.key,
501
+ fields: encryption.fields ?? DEFAULT_ENCRYPTION_FIELDS,
502
+ algorithm: encryption.algorithm ?? "aes-256-gcm"
503
+ };
666
504
  }
667
- }
668
- return tableIdColumns;
669
- }
670
- /**
671
- * Gets the initialized database service instance
672
- *
673
- * @param {string} [adapterName] - Optional named adapter to use instead of default
674
- * @returns {DatabaseServiceInterface} The database service instance
675
- * @throws {DatabasePackageError} When database is not initialized or named adapter not found
676
- */
677
- getDatabase(adapterName) {
678
- if (adapterName) {
679
- const namedAdapter = this.namedAdapters.get(adapterName);
680
- if (!namedAdapter) {
681
- throw new errors.DatabasePackageError(
682
- `Named adapter '${adapterName}' not found. Available adapters: ${Array.from(this.namedAdapters.keys()).join(", ")}`,
683
- errors$1.DATABASE_ERROR_CODES.INIT_FAILED
684
- );
505
+ /** Merge user config with defaults */
506
+ static mergeConfig(config) {
507
+ return {
508
+ ...DEFAULT_CONFIG,
509
+ ...config,
510
+ softDelete: { ...DEFAULT_CONFIG.softDelete, ...config?.softDelete },
511
+ cache: { ...DEFAULT_CONFIG.cache, ...config?.cache },
512
+ audit: { ...DEFAULT_CONFIG.audit, ...config?.audit },
513
+ encryption: _DbService.buildEncryptionConfig(config)
514
+ };
685
515
  }
686
- return namedAdapter;
687
- }
688
- if (!this.databaseService) {
689
- throw new errors.DatabasePackageError(
690
- "Database not initialized. Call DbService.initialize() first.",
691
- errors$1.DATABASE_ERROR_CODES.INIT_FAILED
692
- );
693
- }
694
- return this.databaseService;
695
- }
696
- /**
697
- * Gets a named adapter by name
698
- *
699
- * @param {string} name - The name of the adapter
700
- * @returns {DatabaseServiceInterface} The named adapter instance
701
- * @throws {DatabasePackageError} When adapter not found
702
- */
703
- getAdapter(name) {
704
- return this.getDatabase(name);
705
- }
706
- /**
707
- * Lists all available named adapters
708
- *
709
- * @returns {string[]} Array of adapter names
710
- */
711
- getAvailableAdapters() {
712
- return ["default", ...Array.from(this.namedAdapters.keys())];
713
- }
714
- /**
715
- * Executes a database transaction with automatic rollback on failure
716
- *
717
- * @template T The return type of the transaction callback
718
- * @param {Function} callback - Function that receives transaction object
719
- * @returns {Promise<T>} The result of the transaction callback
720
- * @throws {DatabasePackageError} When transaction fails
721
- */
722
- async transaction(callback) {
723
- const db = this.getDatabase();
724
- const result = await db.transaction(callback);
725
- if (!result.success) {
726
- const errorMessage = result.error?.message ?? "Transaction failed";
727
- const error = new errors.DatabasePackageError(errorMessage, errors$1.DATABASE_ERROR_CODES.TRANSACTION_FAILED);
728
- this.emitDatabaseError(error, "transaction", { recoverable: true });
729
- throw error;
730
- }
731
- if (result.value === void 0 || result.value === null) {
732
- const error = new errors.DatabasePackageError(
733
- "Transaction returned no value",
734
- errors$1.DATABASE_ERROR_CODES.INVALID_RESULT
735
- );
736
- this.emitDatabaseError(error, "transaction", { recoverable: false });
737
- throw error;
738
- }
739
- return result.value;
740
- }
741
- /**
742
- * Sets audit context for subsequent operations
743
- *
744
- * @param context - Audit context (userId, requestId, etc.)
745
- */
746
- async setAuditContext(context) {
747
- const db = this.getDatabase();
748
- await db.setAuditContext(context);
749
- }
750
- /**
751
- * Performs a health check on the database connection
752
- *
753
- * @returns Health check result
754
- */
755
- async healthCheck() {
756
- try {
757
- const db = this.getDatabase();
758
- const result = await db.healthCheck();
759
- if (result.success && result.value) {
516
+ /** Initialize named adapters */
517
+ async initializeNamedAdapters(mergedConfig) {
518
+ if (!mergedConfig.adapters) return;
519
+ for (const [name, adapterConfig] of Object.entries(mergedConfig.adapters)) {
520
+ const namedDbConfig = this.buildDatabaseConfig({
521
+ ...mergedConfig,
522
+ adapter: adapterConfig.adapter,
523
+ drizzle: adapterConfig.drizzle,
524
+ supabase: adapterConfig.supabase,
525
+ sql: adapterConfig.sql
526
+ });
527
+ const namedService = await db.createDatabaseService(namedDbConfig);
528
+ this.namedAdapters.set(name, namedService);
529
+ }
530
+ }
531
+ static async initialize(config) {
532
+ const instance = _DbService.getInstance();
533
+ if (instance.initialized) {
534
+ return instance;
535
+ }
536
+ const mergedConfig = _DbService.mergeConfig(config);
537
+ instance.config = mergedConfig;
538
+ const dbConfig = instance.buildDatabaseConfig(mergedConfig);
539
+ instance.databaseService = await db.createDatabaseService(dbConfig);
540
+ await instance.initializeNamedAdapters(mergedConfig);
541
+ instance.initialized = true;
542
+ return instance;
543
+ }
544
+ /**
545
+ * Builds the DatabaseServiceConfig based on the adapter type
546
+ * @private
547
+ */
548
+ /** Builds adapter-specific config based on adapter type */
549
+ buildAdapterConfig(adapter, config) {
550
+ const builders = {
551
+ drizzle: /* @__PURE__ */ __name(() => this.buildDrizzleConfig(config), "drizzle"),
552
+ supabase: /* @__PURE__ */ __name(() => this.buildSupabaseConfig(config), "supabase"),
553
+ sql: /* @__PURE__ */ __name(() => this.buildSqlConfig(config), "sql")
554
+ };
555
+ const builder = builders[adapter];
556
+ if (!builder) {
557
+ throw new errors.DatabasePackageError(
558
+ `Unsupported adapter type: ${adapter}`,
559
+ errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
560
+ );
561
+ }
562
+ return builder();
563
+ }
564
+ /** Builds soft delete extension config */
565
+ buildSoftDeleteExtension(config) {
566
+ if (!config.softDelete?.enabled) return void 0;
760
567
  return {
761
- isHealthy: result.value.isHealthy,
762
- responseTime: result.value.responseTime
568
+ enabled: true,
569
+ field: config.softDelete.field ?? "deleted_at",
570
+ excludeTables: config.softDelete.excludeTables
763
571
  };
764
572
  }
765
- const errorMessage = result.error?.message ?? "Health check failed";
766
- this.emitDatabaseError(
767
- new errors.DatabasePackageError(errorMessage, errors$1.DATABASE_ERROR_CODES.CONNECTION_ERROR),
768
- "healthCheck",
769
- { recoverable: true }
770
- );
771
- return {
772
- isHealthy: false,
773
- error: errorMessage
774
- };
775
- } catch (error) {
776
- this.emitDatabaseError(error, "healthCheck", { recoverable: true });
777
- return {
778
- isHealthy: false,
779
- error: error instanceof Error ? error.message : "Unknown error"
780
- };
781
- }
782
- }
783
- /**
784
- * Gets the table registry with all known tables and their ID columns
785
- *
786
- * @returns The complete table registry
787
- */
788
- static getTableRegistry() {
789
- return TABLE_REGISTRY;
790
- }
791
- /**
792
- * Gets ID column for a specific table
793
- *
794
- * @param tableName - Name of the table
795
- * @returns ID column name or 'id' as default
796
- */
797
- static getTableIdColumn(tableName) {
798
- return TABLE_REGISTRY[tableName]?.idColumn ?? "id";
799
- }
800
- /**
801
- * Reinitializes the database connection with new config
802
- *
803
- * @param {DbServiceConfig} [config] - New configuration
804
- * @returns {Promise<DbService>} The reinitialized DbService instance
805
- */
806
- static async reinitialize(config) {
807
- const instance = _DbService.getInstance();
808
- await instance.close();
809
- instance.initialized = false;
810
- return _DbService.initialize(config);
811
- }
812
- /**
813
- * Closes the database connection and cleans up resources
814
- */
815
- async close() {
816
- this.databaseService = null;
817
- this.initialized = false;
818
- this.config = null;
819
- }
820
- /**
821
- * Gets the current configuration
822
- *
823
- * @returns {DbServiceConfig | null} Current config or null if not initialized
824
- */
825
- getConfig() {
826
- return this.config;
827
- }
828
- /**
829
- * Gets the current adapter type
830
- *
831
- * @returns The adapter type or null if not initialized
832
- */
833
- getAdapterType() {
834
- return this.config?.adapter ?? null;
573
+ /** Builds cache extension config */
574
+ buildCacheExtension(config) {
575
+ if (!config.cache?.enabled) return void 0;
576
+ return {
577
+ enabled: true,
578
+ ttl: config.cache.ttl ?? DEFAULT_CACHE_TTL_SECONDS,
579
+ provider: config.cache.provider ?? "memory",
580
+ invalidation: config.cache.invalidation ?? "write"
581
+ };
582
+ }
583
+ /** Builds audit extension config */
584
+ buildAuditExtension(config) {
585
+ if (!config.audit?.enabled) return void 0;
586
+ return {
587
+ enabled: true,
588
+ retentionDays: config.audit.retentionDays ?? DEFAULT_AUDIT_RETENTION_DAYS,
589
+ excludeFields: config.audit.excludeFields,
590
+ excludeTables: config.audit.excludeTables,
591
+ schema: config.audit.schema ?? "audit",
592
+ usePartitionedTables: config.audit.usePartitionedTables ?? true
593
+ };
594
+ }
595
+ /** Builds encryption extension config */
596
+ buildEncryptionExtension(config) {
597
+ if (!config.encryption?.enabled || !config.encryption.key) return void 0;
598
+ return {
599
+ enabled: true,
600
+ key: config.encryption.key,
601
+ fields: config.encryption.fields ?? {},
602
+ algorithm: config.encryption.algorithm
603
+ };
604
+ }
605
+ buildDatabaseConfig(config) {
606
+ const adapter = config.adapter ?? "drizzle";
607
+ const dbConfig = {
608
+ adapter,
609
+ config: this.buildAdapterConfig(adapter, config)
610
+ };
611
+ const softDelete = this.buildSoftDeleteExtension(config);
612
+ const cache = this.buildCacheExtension(config);
613
+ const audit = this.buildAuditExtension(config);
614
+ const encryption = this.buildEncryptionExtension(config);
615
+ if (softDelete) dbConfig.softDelete = softDelete;
616
+ if (cache) dbConfig.cache = cache;
617
+ if (audit) dbConfig.audit = audit;
618
+ if (encryption) dbConfig.encryption = encryption;
619
+ return dbConfig;
620
+ }
621
+ /**
622
+ * Builds Drizzle adapter configuration
623
+ * @private
624
+ */
625
+ buildDrizzleConfig(config) {
626
+ const connectionString = config.drizzle?.connectionString;
627
+ if (!connectionString) {
628
+ throw new errors.DatabasePackageError(
629
+ "Drizzle adapter requires a PostgreSQL connection string. Provide `drizzle.connectionString` in config or use Core.initialize() with DATABASE_URL in env. For Supabase, find this in Dashboard > Database > Connection string (URI).",
630
+ errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
631
+ );
632
+ }
633
+ const tableIdColumns = this.buildTableIdColumns();
634
+ return {
635
+ connectionString,
636
+ poolSize: config.drizzle?.poolSize ?? DEFAULT_POOL_SIZE,
637
+ ssl: config.drizzle?.ssl,
638
+ schema: config.drizzle?.schema,
639
+ // Pass through schema configuration
640
+ tableIdColumns
641
+ };
642
+ }
643
+ /**
644
+ * Builds Supabase adapter configuration
645
+ * @private
646
+ */
647
+ // eslint-disable-next-line complexity
648
+ buildSupabaseConfig(config) {
649
+ const supabaseUrl = config.supabase?.supabaseUrl;
650
+ const supabaseServiceKey = config.supabase?.supabaseServiceKey;
651
+ const supabaseAnonKey = config.supabase?.supabaseAnonKey;
652
+ if (!supabaseUrl || !supabaseServiceKey) {
653
+ throw new errors.DatabasePackageError(
654
+ "Supabase adapter requires supabaseUrl and supabaseServiceKey. Provide in config or use Core.initialize() with SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY in env.",
655
+ errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
656
+ );
657
+ }
658
+ if (!supabaseAnonKey) {
659
+ throw new errors.DatabasePackageError(
660
+ "Supabase adapter requires supabaseAnonKey. Provide in config or use Core.initialize() with SUPABASE_ANON_PUBLIC_KEY in env.",
661
+ errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
662
+ );
663
+ }
664
+ const tableIdColumns = this.buildTableIdColumns();
665
+ return {
666
+ supabaseUrl,
667
+ supabaseServiceKey,
668
+ supabaseAnonKey,
669
+ schema: config.supabase?.schema ?? "public",
670
+ tableIdColumns
671
+ };
672
+ }
673
+ /**
674
+ * Builds SQL adapter configuration
675
+ * @private
676
+ */
677
+ buildSqlConfig(config) {
678
+ const connectionString = config.sql?.connectionString;
679
+ if (!connectionString) {
680
+ throw new errors.DatabasePackageError(
681
+ "SQL adapter requires a connection string. Provide `sql.connectionString` in config or use Core.initialize() with DATABASE_URL in env.",
682
+ errors$1.DATABASE_ERROR_CODES.CONFIG_REQUIRED
683
+ );
684
+ }
685
+ const tableIdColumns = this.buildTableIdColumns();
686
+ return {
687
+ connectionString,
688
+ dialect: config.sql?.dialect ?? "postgresql",
689
+ schema: config.sql?.schema,
690
+ // Pass through schema configuration
691
+ tableIdColumns
692
+ };
693
+ }
694
+ /**
695
+ * Builds table ID column mappings from TABLE_REGISTRY
696
+ * @private
697
+ * @returns Record of table names to ID column names
698
+ */
699
+ // eslint-disable-next-line complexity
700
+ buildTableIdColumns() {
701
+ const tableIdColumns = {};
702
+ const baseNameConflicts = /* @__PURE__ */ new Set();
703
+ const baseNameMappings = /* @__PURE__ */ new Map();
704
+ for (const tableName of Object.keys(TABLE_REGISTRY)) {
705
+ if (tableName.includes(".")) {
706
+ const baseName = tableName.split(".").pop();
707
+ if (baseNameMappings.has(baseName) || TABLE_REGISTRY[baseName]) {
708
+ baseNameConflicts.add(baseName);
709
+ } else {
710
+ baseNameMappings.set(baseName, tableName);
711
+ }
712
+ }
713
+ }
714
+ for (const [tableName, config] of Object.entries(TABLE_REGISTRY)) {
715
+ const idColumn = config.idColumn ?? "id";
716
+ if (idColumn === "id") continue;
717
+ tableIdColumns[tableName] = idColumn;
718
+ if (!tableName.includes(".")) continue;
719
+ const baseName = tableName.split(".").pop();
720
+ if (!baseNameConflicts.has(baseName)) {
721
+ tableIdColumns[baseName] = idColumn;
722
+ }
723
+ }
724
+ return tableIdColumns;
725
+ }
726
+ /**
727
+ * Gets the initialized database service instance
728
+ *
729
+ * @param {string} [adapterName] - Optional named adapter to use instead of default
730
+ * @returns {DatabaseServiceInterface} The database service instance
731
+ * @throws {DatabasePackageError} When database is not initialized or named adapter not found
732
+ */
733
+ getDatabase(adapterName) {
734
+ if (adapterName) {
735
+ const namedAdapter = this.namedAdapters.get(adapterName);
736
+ if (!namedAdapter) {
737
+ throw new errors.DatabasePackageError(
738
+ `Named adapter '${adapterName}' not found. Available adapters: ${Array.from(this.namedAdapters.keys()).join(", ")}`,
739
+ errors$1.DATABASE_ERROR_CODES.INIT_FAILED
740
+ );
741
+ }
742
+ return namedAdapter;
743
+ }
744
+ if (!this.databaseService) {
745
+ throw new errors.DatabasePackageError(
746
+ "Database not initialized. Call DbService.initialize() first.",
747
+ errors$1.DATABASE_ERROR_CODES.INIT_FAILED
748
+ );
749
+ }
750
+ return this.databaseService;
751
+ }
752
+ /**
753
+ * Gets a named adapter by name
754
+ *
755
+ * @param {string} name - The name of the adapter
756
+ * @returns {DatabaseServiceInterface} The named adapter instance
757
+ * @throws {DatabasePackageError} When adapter not found
758
+ */
759
+ getAdapter(name) {
760
+ return this.getDatabase(name);
761
+ }
762
+ /**
763
+ * Lists all available named adapters
764
+ *
765
+ * @returns {string[]} Array of adapter names
766
+ */
767
+ getAvailableAdapters() {
768
+ return ["default", ...Array.from(this.namedAdapters.keys())];
769
+ }
770
+ /**
771
+ * Executes a database transaction with automatic rollback on failure
772
+ *
773
+ * @template T The return type of the transaction callback
774
+ * @param {Function} callback - Function that receives transaction object
775
+ * @returns {Promise<T>} The result of the transaction callback
776
+ * @throws {DatabasePackageError} When transaction fails
777
+ */
778
+ async transaction(callback) {
779
+ const db = this.getDatabase();
780
+ const result = await db.transaction(callback);
781
+ if (!result.success) {
782
+ const errorMessage = result.error?.message ?? "Transaction failed";
783
+ const error = new errors.DatabasePackageError(errorMessage, errors$1.DATABASE_ERROR_CODES.TRANSACTION_FAILED);
784
+ this.emitDatabaseError(error, "transaction", { recoverable: true });
785
+ throw error;
786
+ }
787
+ if (result.value === void 0 || result.value === null) {
788
+ const error = new errors.DatabasePackageError(
789
+ "Transaction returned no value",
790
+ errors$1.DATABASE_ERROR_CODES.INVALID_RESULT
791
+ );
792
+ this.emitDatabaseError(error, "transaction", { recoverable: false });
793
+ throw error;
794
+ }
795
+ return result.value;
796
+ }
797
+ /**
798
+ * Sets audit context for subsequent operations
799
+ *
800
+ * @param context - Audit context (userId, requestId, etc.)
801
+ */
802
+ async setAuditContext(context) {
803
+ const db = this.getDatabase();
804
+ await db.setAuditContext(context);
805
+ }
806
+ /**
807
+ * Performs a health check on the database connection
808
+ *
809
+ * @returns Health check result
810
+ */
811
+ async healthCheck() {
812
+ try {
813
+ const db = this.getDatabase();
814
+ const result = await db.healthCheck();
815
+ if (result.success && result.value) {
816
+ return {
817
+ isHealthy: result.value.isHealthy,
818
+ responseTime: result.value.responseTime
819
+ };
820
+ }
821
+ const errorMessage = result.error?.message ?? "Health check failed";
822
+ this.emitDatabaseError(
823
+ new errors.DatabasePackageError(errorMessage, errors$1.DATABASE_ERROR_CODES.CONNECTION_ERROR),
824
+ "healthCheck",
825
+ { recoverable: true }
826
+ );
827
+ return {
828
+ isHealthy: false,
829
+ error: errorMessage
830
+ };
831
+ } catch (error) {
832
+ this.emitDatabaseError(error, "healthCheck", { recoverable: true });
833
+ return {
834
+ isHealthy: false,
835
+ error: error instanceof Error ? error.message : "Unknown error"
836
+ };
837
+ }
838
+ }
839
+ /**
840
+ * Gets the table registry with all known tables and their ID columns
841
+ *
842
+ * @returns The complete table registry
843
+ */
844
+ static getTableRegistry() {
845
+ return TABLE_REGISTRY;
846
+ }
847
+ /**
848
+ * Gets ID column for a specific table
849
+ *
850
+ * @param tableName - Name of the table
851
+ * @returns ID column name or 'id' as default
852
+ */
853
+ static getTableIdColumn(tableName) {
854
+ return TABLE_REGISTRY[tableName]?.idColumn ?? "id";
855
+ }
856
+ /**
857
+ * Reinitializes the database connection with new config
858
+ *
859
+ * @param {DbServiceConfig} [config] - New configuration
860
+ * @returns {Promise<DbService>} The reinitialized DbService instance
861
+ */
862
+ static async reinitialize(config) {
863
+ const instance = _DbService.getInstance();
864
+ await instance.close();
865
+ instance.initialized = false;
866
+ return _DbService.initialize(config);
867
+ }
868
+ /**
869
+ * Closes the database connection and cleans up resources
870
+ */
871
+ async close() {
872
+ this.databaseService = null;
873
+ this.initialized = false;
874
+ this.config = null;
875
+ }
876
+ /**
877
+ * Gets the current configuration
878
+ *
879
+ * @returns {DbServiceConfig | null} Current config or null if not initialized
880
+ */
881
+ getConfig() {
882
+ return this.config;
883
+ }
884
+ /**
885
+ * Gets the current adapter type
886
+ *
887
+ * @returns The adapter type or null if not initialized
888
+ */
889
+ getAdapterType() {
890
+ return this.config?.adapter ?? null;
891
+ }
892
+ /**
893
+ * Creates a dedicated database service instance (NOT the singleton)
894
+ *
895
+ * Use this when you need an isolated database connection with its own configuration
896
+ * that doesn't affect or get affected by the shared singleton instance.
897
+ *
898
+ * @param config - Database service configuration
899
+ * @returns Promise that resolves to a new dedicated DbService instance
900
+ *
901
+ * @example
902
+ * ```typescript
903
+ * // Create a dedicated instance for analytics database
904
+ * const analyticsDb = await DbService.createInstance({
905
+ * adapter: 'sql',
906
+ * sql: { connectionString: process.env.ANALYTICS_DB_URL },
907
+ * cache: { enabled: false }, // No caching for analytics
908
+ * });
909
+ *
910
+ * // This instance is independent from DbService.getInstance()
911
+ * const data = await analyticsDb.getDatabase().list('events');
912
+ *
913
+ * // Clean up when done
914
+ * await analyticsDb.close();
915
+ * ```
916
+ */
917
+ // eslint-disable-next-line complexity
918
+ static async createInstance(config) {
919
+ const dedicatedInstance = new _DbService();
920
+ const encryptionKey = config.encryption?.key;
921
+ const encryptionConfig = encryptionKey ? {
922
+ enabled: config.encryption?.enabled ?? true,
923
+ key: encryptionKey,
924
+ fields: config.encryption?.fields ?? DEFAULT_ENCRYPTION_FIELDS,
925
+ algorithm: config.encryption?.algorithm ?? "aes-256-gcm"
926
+ } : void 0;
927
+ const mergedConfig = {
928
+ ...DEFAULT_CONFIG,
929
+ ...config,
930
+ // Deep merge extensions
931
+ softDelete: { ...DEFAULT_CONFIG.softDelete, ...config.softDelete },
932
+ cache: { ...DEFAULT_CONFIG.cache, ...config.cache },
933
+ audit: { ...DEFAULT_CONFIG.audit, ...config.audit },
934
+ // Encryption only if key is available
935
+ encryption: encryptionConfig
936
+ };
937
+ dedicatedInstance.config = mergedConfig;
938
+ const dbConfig = dedicatedInstance.buildDatabaseConfig(mergedConfig);
939
+ dedicatedInstance.databaseService = await db.createDatabaseService(dbConfig);
940
+ if (mergedConfig.adapters) {
941
+ for (const [name, adapterConfig] of Object.entries(mergedConfig.adapters)) {
942
+ const namedDbConfig = dedicatedInstance.buildDatabaseConfig({
943
+ ...mergedConfig,
944
+ adapter: adapterConfig.adapter,
945
+ drizzle: adapterConfig.drizzle,
946
+ supabase: adapterConfig.supabase,
947
+ sql: adapterConfig.sql
948
+ });
949
+ const namedService = await db.createDatabaseService(namedDbConfig);
950
+ dedicatedInstance.namedAdapters.set(name, namedService);
951
+ }
952
+ }
953
+ dedicatedInstance.initialized = true;
954
+ return dedicatedInstance;
955
+ }
956
+ };
835
957
  }
836
- /**
837
- * Creates a dedicated database service instance (NOT the singleton)
838
- *
839
- * Use this when you need an isolated database connection with its own configuration
840
- * that doesn't affect or get affected by the shared singleton instance.
841
- *
842
- * @param config - Database service configuration
843
- * @returns Promise that resolves to a new dedicated DbService instance
844
- *
845
- * @example
846
- * ```typescript
847
- * // Create a dedicated instance for analytics database
848
- * const analyticsDb = await DbService.createInstance({
849
- * adapter: 'sql',
850
- * sql: { connectionString: process.env.ANALYTICS_DB_URL },
851
- * cache: { enabled: false }, // No caching for analytics
852
- * });
853
- *
854
- * // This instance is independent from DbService.getInstance()
855
- * const data = await analyticsDb.getDatabase().list('events');
856
- *
857
- * // Clean up when done
858
- * await analyticsDb.close();
859
- * ```
860
- */
861
- // eslint-disable-next-line complexity
862
- static async createInstance(config) {
863
- const dedicatedInstance = new _DbService();
864
- const encryptionKey = config.encryption?.key;
865
- const encryptionConfig = encryptionKey ? {
866
- enabled: config.encryption?.enabled ?? true,
867
- key: encryptionKey,
868
- fields: config.encryption?.fields ?? DEFAULT_ENCRYPTION_FIELDS,
869
- algorithm: config.encryption?.algorithm ?? "aes-256-gcm"
870
- } : void 0;
871
- const mergedConfig = {
872
- ...DEFAULT_CONFIG,
873
- ...config,
874
- // Deep merge extensions
875
- softDelete: { ...DEFAULT_CONFIG.softDelete, ...config.softDelete },
876
- cache: { ...DEFAULT_CONFIG.cache, ...config.cache },
877
- audit: { ...DEFAULT_CONFIG.audit, ...config.audit },
878
- // Encryption only if key is available
879
- encryption: encryptionConfig
958
+ });
959
+
960
+ // src/services/StorageService.ts
961
+ var StorageService_exports = {};
962
+ __export(StorageService_exports, {
963
+ StorageService: () => StorageService
964
+ });
965
+ var StorageService;
966
+ var init_StorageService = __esm({
967
+ "src/services/StorageService.ts"() {
968
+ init_CoreEventManager();
969
+ StorageService = class _StorageService {
970
+ constructor() {
971
+ this.storageService = null;
972
+ this.config = null;
973
+ this.initialized = false;
974
+ }
975
+ static {
976
+ __name(this, "StorageService");
977
+ }
978
+ static {
979
+ this.instance = null;
980
+ }
981
+ // ─────────────────────────────────────────────────────────────────
982
+ // Error Handling
983
+ // ─────────────────────────────────────────────────────────────────
984
+ /**
985
+ * Emits a storage error event via CoreEventManager.
986
+ * Called when storage operations fail to integrate with global error handling.
987
+ */
988
+ emitStorageError(error, operation, options) {
989
+ const payload = {
990
+ error,
991
+ operation,
992
+ fileId: options?.fileId,
993
+ filename: options?.filename,
994
+ recoverable: options?.recoverable ?? false
995
+ };
996
+ exports.CoreEventManager.emit(core.CORE_EVENTS.STORAGE.ERROR, payload);
997
+ }
998
+ // ─────────────────────────────────────────────────────────────────
999
+ // Singleton Management
1000
+ // ─────────────────────────────────────────────────────────────────
1001
+ /**
1002
+ * Gets the singleton instance of StorageService
1003
+ */
1004
+ static getInstance() {
1005
+ _StorageService.instance ??= new _StorageService();
1006
+ return _StorageService.instance;
1007
+ }
1008
+ /**
1009
+ * Checks if the storage service has been initialized
1010
+ */
1011
+ static isInitialized() {
1012
+ return _StorageService.instance?.initialized ?? false;
1013
+ }
1014
+ /**
1015
+ * Resets the storage service by clearing the singleton instance
1016
+ */
1017
+ static async reset() {
1018
+ if (_StorageService.instance) {
1019
+ _StorageService.instance.storageService = null;
1020
+ _StorageService.instance.config = null;
1021
+ _StorageService.instance.initialized = false;
1022
+ _StorageService.instance = null;
1023
+ }
1024
+ }
1025
+ /**
1026
+ * Initializes the storage service
1027
+ *
1028
+ * @param config - Storage service configuration
1029
+ * @returns The initialized StorageService instance
1030
+ */
1031
+ static async initialize(config) {
1032
+ const instance = _StorageService.getInstance();
1033
+ if (instance.initialized) {
1034
+ return instance;
1035
+ }
1036
+ instance.config = config;
1037
+ instance.storageService = new storage.StorageService(config);
1038
+ instance.initialized = true;
1039
+ return instance;
1040
+ }
1041
+ /**
1042
+ * Gets the raw underlying storage service instance without error handling wrapper.
1043
+ * Use this only if you need direct access to the underlying service.
1044
+ *
1045
+ * @returns The raw StorageService instance from @plyaz/storage
1046
+ * @throws {StoragePackageError} When storage is not initialized
1047
+ */
1048
+ getRawStorage() {
1049
+ if (!this.storageService) {
1050
+ throw new errors.StoragePackageError(
1051
+ "Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
1052
+ errors$1.STORAGE_ERROR_CODES.INITIALIZATION_FAILED
1053
+ );
1054
+ }
1055
+ return this.storageService;
1056
+ }
1057
+ // ─────────────────────────────────────────────────────────────────
1058
+ // Service Access
1059
+ // ─────────────────────────────────────────────────────────────────
1060
+ /**
1061
+ * Gets the storage service with automatic error handling.
1062
+ * All method calls are wrapped with try/catch and emit error events on failure.
1063
+ * Any method added to @plyaz/storage will be automatically available.
1064
+ *
1065
+ * @example
1066
+ * ```typescript
1067
+ * const storage = StorageService.getInstance().getStorage();
1068
+ * await storage.uploadFile({ file, filename: 'doc.pdf' });
1069
+ * await storage.deleteFile({ fileId: '123' });
1070
+ * ```
1071
+ *
1072
+ * @returns StorageServiceImpl with automatic error handling
1073
+ */
1074
+ getStorage() {
1075
+ const self = this;
1076
+ return new Proxy({}, {
1077
+ get(_, prop) {
1078
+ if (typeof prop === "symbol") {
1079
+ return void 0;
1080
+ }
1081
+ const storage = self.getRawStorage();
1082
+ const value = storage[prop];
1083
+ if (typeof value !== "function") {
1084
+ return value;
1085
+ }
1086
+ return (...args) => {
1087
+ try {
1088
+ const result = value.apply(storage, args);
1089
+ if (result instanceof Promise) {
1090
+ return result.catch((error) => {
1091
+ self.emitStorageError(error, prop, { recoverable: true });
1092
+ throw error;
1093
+ });
1094
+ }
1095
+ return result;
1096
+ } catch (error) {
1097
+ self.emitStorageError(error, prop, { recoverable: true });
1098
+ throw error;
1099
+ }
1100
+ };
1101
+ }
1102
+ });
1103
+ }
1104
+ // ─────────────────────────────────────────────────────────────────
1105
+ // Health Check (special handling for response transformation)
1106
+ // ─────────────────────────────────────────────────────────────────
1107
+ /**
1108
+ * Performs a health check on the storage service by checking all adapter health.
1109
+ * This method has special handling to transform the response format.
1110
+ */
1111
+ async healthCheck() {
1112
+ const startTime = Date.now();
1113
+ try {
1114
+ const storage = this.getRawStorage();
1115
+ if (typeof storage.checkAllAdaptersHealth === "function") {
1116
+ await storage.checkAllAdaptersHealth();
1117
+ }
1118
+ const summary = typeof storage.getHealthSummary === "function" ? storage.getHealthSummary() : null;
1119
+ const responseTime = Date.now() - startTime;
1120
+ return {
1121
+ // Check if all adapters are healthy (healthy count equals total count)
1122
+ isHealthy: summary ? summary.healthy === summary.total : true,
1123
+ responseTime,
1124
+ error: void 0
1125
+ };
1126
+ } catch (error) {
1127
+ this.emitStorageError(error, "healthCheck", { recoverable: true });
1128
+ return {
1129
+ isHealthy: false,
1130
+ responseTime: Date.now() - startTime,
1131
+ error: error instanceof Error ? error.message : "Unknown error"
1132
+ };
1133
+ }
1134
+ }
1135
+ // ─────────────────────────────────────────────────────────────────
1136
+ // Lifecycle
1137
+ // ─────────────────────────────────────────────────────────────────
1138
+ /**
1139
+ * Gets the current configuration
1140
+ */
1141
+ getConfig() {
1142
+ return this.config;
1143
+ }
1144
+ /**
1145
+ * Closes the storage service and cleans up resources
1146
+ */
1147
+ async close() {
1148
+ if (this.storageService) {
1149
+ await this.storageService.destroy();
1150
+ }
1151
+ this.storageService = null;
1152
+ this.initialized = false;
1153
+ this.config = null;
1154
+ }
1155
+ /**
1156
+ * Creates a dedicated storage service instance (NOT the singleton)
1157
+ *
1158
+ * Use this when you need an isolated storage connection with its own configuration.
1159
+ *
1160
+ * @param config - Storage service configuration
1161
+ * @returns Promise that resolves to a new dedicated StorageService instance
1162
+ */
1163
+ static async createInstance(config) {
1164
+ const dedicatedInstance = new _StorageService();
1165
+ dedicatedInstance.config = config;
1166
+ dedicatedInstance.storageService = new storage.StorageService(config);
1167
+ dedicatedInstance.initialized = true;
1168
+ return dedicatedInstance;
1169
+ }
880
1170
  };
881
- dedicatedInstance.config = mergedConfig;
882
- const dbConfig = dedicatedInstance.buildDatabaseConfig(mergedConfig);
883
- dedicatedInstance.databaseService = await db.createDatabaseService(dbConfig);
884
- if (mergedConfig.adapters) {
885
- for (const [name, adapterConfig] of Object.entries(mergedConfig.adapters)) {
886
- const namedDbConfig = dedicatedInstance.buildDatabaseConfig({
887
- ...mergedConfig,
888
- adapter: adapterConfig.adapter,
889
- drizzle: adapterConfig.drizzle,
890
- supabase: adapterConfig.supabase,
891
- sql: adapterConfig.sql
1171
+ }
1172
+ });
1173
+
1174
+ // src/services/NotificationService.ts
1175
+ var NotificationService_exports = {};
1176
+ __export(NotificationService_exports, {
1177
+ NotificationService: () => NotificationService
1178
+ });
1179
+ var NotificationService;
1180
+ var init_NotificationService = __esm({
1181
+ "src/services/NotificationService.ts"() {
1182
+ init_CoreEventManager();
1183
+ NotificationService = class _NotificationService {
1184
+ constructor() {
1185
+ this.notificationService = null;
1186
+ this.config = null;
1187
+ this.initialized = false;
1188
+ }
1189
+ static {
1190
+ __name(this, "NotificationService");
1191
+ }
1192
+ static {
1193
+ this.instance = null;
1194
+ }
1195
+ // ─────────────────────────────────────────────────────────────────
1196
+ // Error Handling
1197
+ // ─────────────────────────────────────────────────────────────────
1198
+ /**
1199
+ * Emits a notification error event via CoreEventManager.
1200
+ * Called when notification operations fail to integrate with global error handling.
1201
+ */
1202
+ emitNotificationError(error, operation, options) {
1203
+ const payload = {
1204
+ error,
1205
+ operation,
1206
+ recipientId: options?.recipientId,
1207
+ channel: options?.channel,
1208
+ recoverable: options?.recoverable ?? false
1209
+ };
1210
+ exports.CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.ERROR, payload);
1211
+ }
1212
+ // ─────────────────────────────────────────────────────────────────
1213
+ // Singleton Management
1214
+ // ─────────────────────────────────────────────────────────────────
1215
+ /**
1216
+ * Gets the singleton instance of NotificationService
1217
+ */
1218
+ static getInstance() {
1219
+ _NotificationService.instance ??= new _NotificationService();
1220
+ return _NotificationService.instance;
1221
+ }
1222
+ /**
1223
+ * Checks if the notification service has been initialized
1224
+ */
1225
+ static isInitialized() {
1226
+ return _NotificationService.instance?.initialized ?? false;
1227
+ }
1228
+ /**
1229
+ * Resets the notification service by clearing the singleton instance
1230
+ */
1231
+ static async reset() {
1232
+ if (_NotificationService.instance) {
1233
+ _NotificationService.instance.notificationService = null;
1234
+ _NotificationService.instance.config = null;
1235
+ _NotificationService.instance.initialized = false;
1236
+ _NotificationService.instance = null;
1237
+ }
1238
+ }
1239
+ /**
1240
+ * Initializes the notification service
1241
+ *
1242
+ * @param config - Notification service configuration
1243
+ * @returns The initialized NotificationService instance
1244
+ */
1245
+ static async initialize(config) {
1246
+ const instance = _NotificationService.getInstance();
1247
+ if (instance.initialized) {
1248
+ return instance;
1249
+ }
1250
+ instance.config = config;
1251
+ instance.notificationService = new notifications.NotificationService(config);
1252
+ instance.initialized = true;
1253
+ return instance;
1254
+ }
1255
+ /**
1256
+ * Gets the raw underlying notification service instance without error handling wrapper.
1257
+ * Use this only if you need direct access to the underlying service.
1258
+ *
1259
+ * @returns The raw NotificationService instance from @plyaz/notifications
1260
+ * @throws {NotificationsPackageError} When notifications is not initialized
1261
+ */
1262
+ getRawNotifications() {
1263
+ if (!this.notificationService) {
1264
+ throw new errors.NotificationPackageError(
1265
+ "Notifications not initialized. Call NotificationService.initialize() first or use Core.initialize() with notifications config.",
1266
+ errors$1.NOTIFICATION_ERROR_CODES.INITIALIZATION_FAILED
1267
+ );
1268
+ }
1269
+ return this.notificationService;
1270
+ }
1271
+ // ─────────────────────────────────────────────────────────────────
1272
+ // Service Access
1273
+ // ─────────────────────────────────────────────────────────────────
1274
+ /**
1275
+ * Gets the notification service with automatic error handling.
1276
+ * All method calls are wrapped with try/catch and emit error events on failure.
1277
+ * Any method added to @plyaz/notifications will be automatically available.
1278
+ *
1279
+ * @example
1280
+ * ```typescript
1281
+ * const notifications = NotificationService.getInstance().getNotifications();
1282
+ * await notifications.sendEmail({ to: 'user@example.com', templateId: 'welcome' });
1283
+ * await notifications.sendSMS({ to: '+1234567890', message: 'Hello!' });
1284
+ * ```
1285
+ *
1286
+ * @returns NotificationServiceImpl with automatic error handling
1287
+ */
1288
+ getNotifications() {
1289
+ const self = this;
1290
+ return new Proxy({}, {
1291
+ get(_, prop) {
1292
+ if (typeof prop === "symbol") {
1293
+ return void 0;
1294
+ }
1295
+ const notifications = self.getRawNotifications();
1296
+ const value = notifications[prop];
1297
+ if (typeof value !== "function") {
1298
+ return value;
1299
+ }
1300
+ return (...args) => {
1301
+ try {
1302
+ const result = value.apply(notifications, args);
1303
+ if (result instanceof Promise) {
1304
+ return result.catch((error) => {
1305
+ self.emitNotificationError(error, prop, { recoverable: true });
1306
+ throw error;
1307
+ });
1308
+ }
1309
+ return result;
1310
+ } catch (error) {
1311
+ self.emitNotificationError(error, prop, { recoverable: true });
1312
+ throw error;
1313
+ }
1314
+ };
1315
+ }
892
1316
  });
893
- const namedService = await db.createDatabaseService(namedDbConfig);
894
- dedicatedInstance.namedAdapters.set(name, namedService);
895
1317
  }
896
- }
897
- dedicatedInstance.initialized = true;
898
- return dedicatedInstance;
1318
+ // ─────────────────────────────────────────────────────────────────
1319
+ // Health Check (special handling for response transformation)
1320
+ // ─────────────────────────────────────────────────────────────────
1321
+ /**
1322
+ * Performs a health check on the notification service.
1323
+ * This method has special handling to transform the response format.
1324
+ */
1325
+ async healthCheck() {
1326
+ try {
1327
+ const notifications = this.getRawNotifications();
1328
+ const result = await notifications.healthCheck();
1329
+ return {
1330
+ isHealthy: result.healthy,
1331
+ providers: result.providers,
1332
+ // Use optional chaining since error may not exist on all health check results
1333
+ error: "error" in result ? result.error : void 0
1334
+ };
1335
+ } catch (error) {
1336
+ this.emitNotificationError(error, "healthCheck", { recoverable: true });
1337
+ return {
1338
+ isHealthy: false,
1339
+ error: error instanceof Error ? error.message : "Unknown error"
1340
+ };
1341
+ }
1342
+ }
1343
+ // ─────────────────────────────────────────────────────────────────
1344
+ // Lifecycle
1345
+ // ─────────────────────────────────────────────────────────────────
1346
+ /**
1347
+ * Gets the current configuration
1348
+ */
1349
+ getConfig() {
1350
+ return this.config;
1351
+ }
1352
+ /**
1353
+ * Closes the notification service and cleans up resources
1354
+ */
1355
+ async close() {
1356
+ this.notificationService = null;
1357
+ this.initialized = false;
1358
+ this.config = null;
1359
+ }
1360
+ /**
1361
+ * Creates a dedicated notification service instance (NOT the singleton)
1362
+ *
1363
+ * Use this when you need an isolated notification service with its own configuration.
1364
+ *
1365
+ * @param config - Notification service configuration
1366
+ * @returns Promise that resolves to a new dedicated NotificationService instance
1367
+ */
1368
+ static async createInstance(config) {
1369
+ const dedicatedInstance = new _NotificationService();
1370
+ dedicatedInstance.config = config;
1371
+ dedicatedInstance.notificationService = new notifications.NotificationService(config);
1372
+ dedicatedInstance.initialized = true;
1373
+ return dedicatedInstance;
1374
+ }
1375
+ };
899
1376
  }
900
- };
1377
+ });
1378
+
1379
+ // src/init/CoreInitializer.ts
1380
+ init_DbService();
1381
+
1382
+ // src/services/ApiClientService.ts
1383
+ init_CoreEventManager();
901
1384
  var MIN_RETRY_ATTEMPTS_PRODUCTION = 3;
902
1385
  function getConfigForEnvironment(env) {
903
1386
  switch (env) {
@@ -1112,7 +1595,7 @@ var ApiClientService = class _ApiClientService {
1112
1595
  requestId
1113
1596
  }
1114
1597
  };
1115
- CoreEventManager.emit(types.CORE_EVENTS.SYSTEM.ERROR, { errors: [serializedError] });
1598
+ exports.CoreEventManager.emit(types.CORE_EVENTS.SYSTEM.ERROR, { errors: [serializedError] });
1116
1599
  } else {
1117
1600
  const serializedErrors = errorDetails.map(
1118
1601
  (detail, index) => ({
@@ -1136,7 +1619,7 @@ var ApiClientService = class _ApiClientService {
1136
1619
  }
1137
1620
  })
1138
1621
  );
1139
- CoreEventManager.emit(types.CORE_EVENTS.SYSTEM.ERROR, { errors: serializedErrors });
1622
+ exports.CoreEventManager.emit(types.CORE_EVENTS.SYSTEM.ERROR, { errors: serializedErrors });
1140
1623
  }
1141
1624
  } catch (e) {
1142
1625
  console.error("[ApiClientService] Failed to emit error event:", e);
@@ -1289,7 +1772,7 @@ var ApiClientService = class _ApiClientService {
1289
1772
  error,
1290
1773
  duration: options.duration
1291
1774
  };
1292
- CoreEventManager.emit(types.CORE_EVENTS.API.REQUEST_ERROR, payload);
1775
+ exports.CoreEventManager.emit(types.CORE_EVENTS.API.REQUEST_ERROR, payload);
1293
1776
  if (options.rethrow && error instanceof Error) {
1294
1777
  throw error;
1295
1778
  }
@@ -1967,582 +2450,190 @@ var CacheManager = class {
1967
2450
  }
1968
2451
  }
1969
2452
  /**
1970
- * Disposes of the cache manager and cleans up resources.
1971
- *
1972
- * @returns Promise that resolves when cleanup is complete
1973
- */
1974
- async dispose() {
1975
- await this.strategy.dispose?.();
1976
- }
1977
- };
1978
- var CacheService = class _CacheService {
1979
- /** Private constructor to enforce singleton */
1980
- constructor() {
1981
- /** Cache manager instance */
1982
- this.cacheManager = null;
1983
- /** Configuration used to initialize cache */
1984
- this.config = null;
1985
- /** Logger instance */
1986
- this.logger = new logger$1.CoreLogger({ service: "CacheService" });
1987
- }
1988
- static {
1989
- __name(this, "CacheService");
1990
- }
1991
- static {
1992
- /** Singleton instance */
1993
- this.instance = null;
1994
- }
1995
- /**
1996
- * Initialize the cache service with configuration
1997
- *
1998
- * @param config - Cache configuration
1999
- * @throws {CorePackageError} If already initialized or config is invalid
2000
- *
2001
- * @example
2002
- * ```typescript
2003
- * await CacheService.initialize({
2004
- * strategy: 'redis',
2005
- * isEnabled: true,
2006
- * ttl: 300,
2007
- * prefix: 'app',
2008
- * redis: { url: process.env.REDIS_URL },
2009
- * });
2010
- * ```
2011
- */
2012
- static async initialize(config$1) {
2013
- if (this.instance?.cacheManager) {
2014
- throw new errors.CorePackageError(
2015
- "CacheService is already initialized. Call reset() first if you need to reinitialize.",
2016
- errors$1.ERROR_CODES.VALIDATION_ERROR
2017
- );
2018
- }
2019
- const service = this.instance ?? new _CacheService();
2020
- this.instance = service;
2021
- try {
2022
- service.logger.info("[CacheService] Initializing cache...", {
2023
- strategy: config$1.strategy,
2024
- isEnabled: config$1.isEnabled,
2025
- ttl: config$1.ttl
2026
- });
2027
- service.validateConfig(config$1);
2028
- const cacheConfig = {
2029
- ...config$1,
2030
- ttl: config$1.ttl ?? config.TIME_CONSTANTS.DEFAULT_CACHE_TTL
2031
- };
2032
- service.cacheManager = new CacheManager(cacheConfig);
2033
- service.config = config$1;
2034
- service.logger.info("[CacheService] Cache initialized successfully", {
2035
- strategy: config$1.strategy
2036
- });
2037
- } catch (error) {
2038
- service.logger.error("[CacheService] Failed to initialize cache", { error });
2039
- throw new errors.CorePackageError(
2040
- `Failed to initialize cache: ${error instanceof Error ? error.message : String(error)}`,
2041
- errors$1.ERROR_CODES.VALIDATION_ERROR,
2042
- { cause: error instanceof Error ? error : void 0 }
2043
- );
2044
- }
2045
- }
2046
- /**
2047
- * Get the singleton instance
2048
- *
2049
- * @throws {CorePackageError} If not initialized
2050
- * @returns CacheService singleton instance
2051
- *
2052
- * @example
2053
- * ```typescript
2054
- * const cacheService = CacheService.getInstance();
2055
- * const cache = cacheService.getCacheManager();
2056
- * ```
2057
- */
2058
- static getInstance() {
2059
- if (!this.instance) {
2060
- throw new errors.CorePackageError(
2061
- "CacheService not initialized. Call CacheService.initialize() first.",
2062
- errors$1.ERROR_CODES.CLIENT_INITIALIZATION_FAILED
2063
- );
2064
- }
2065
- return this.instance;
2066
- }
2067
- /**
2068
- * Get the cache manager instance
2069
- *
2070
- * @throws {CorePackageError} If cache not initialized
2071
- * @returns CacheManager instance
2072
- *
2073
- * @example
2074
- * ```typescript
2075
- * const cache = CacheService.getInstance().getCacheManager();
2076
- * await cache.set('user:123', userData);
2077
- * const user = await cache.get('user:123');
2078
- * ```
2079
- */
2080
- getCacheManager() {
2081
- if (!this.cacheManager) {
2082
- throw new errors.CorePackageError(
2083
- "Cache manager not initialized. Call CacheService.initialize() first.",
2084
- errors$1.ERROR_CODES.CLIENT_INITIALIZATION_FAILED
2085
- );
2086
- }
2087
- return this.cacheManager;
2088
- }
2089
- /**
2090
- * Get current cache configuration
2091
- *
2092
- * @returns Current cache configuration or null if not initialized
2093
- */
2094
- getConfig() {
2095
- return this.config;
2096
- }
2097
- /**
2098
- * Check if cache is initialized and enabled
2099
- *
2100
- * @returns True if cache is ready to use
2101
- */
2102
- isInitialized() {
2103
- return this.cacheManager !== null && (this.config?.isEnabled ?? false);
2104
- }
2105
- /**
2106
- * Reset the cache service (useful for testing)
2107
- *
2108
- * @internal
2109
- */
2110
- static reset() {
2111
- if (this.instance?.cacheManager) {
2112
- this.instance.logger.info("[CacheService] Resetting cache service");
2113
- this.instance.cacheManager.clear().catch((error) => {
2114
- this.instance?.logger.error("[CacheService] Error clearing cache during reset", { error });
2115
- });
2116
- }
2117
- this.instance = null;
2118
- }
2119
- /**
2120
- * Validate cache configuration
2121
- *
2122
- * @param config - Configuration to validate
2123
- * @throws {CorePackageError} If configuration is invalid
2124
- * @private
2125
- */
2126
- // eslint-disable-next-line complexity
2127
- validateConfig(config) {
2128
- if (!features.CACHE_STRATEGIES.includes(config.strategy)) {
2129
- throw new errors.CorePackageError(
2130
- `Invalid cache strategy: ${config.strategy}. Must be one of: ${features.CACHE_STRATEGIES.join(", ")}`,
2131
- errors$1.ERROR_CODES.VALIDATION_ERROR
2132
- );
2133
- }
2134
- if (config.ttl !== void 0 && (config.ttl < 0 || !Number.isFinite(config.ttl))) {
2135
- throw new errors.CorePackageError(
2136
- `Invalid TTL value: ${config.ttl}. Must be a positive number.`,
2137
- errors$1.ERROR_CODES.VALIDATION_ERROR
2138
- );
2139
- }
2140
- if (config.strategy === "redis") {
2141
- if (!config.redis?.url && !config.redis?.host) {
2142
- throw new errors.CorePackageError(
2143
- "Redis strategy requires either redis.url or redis.host configuration",
2144
- errors$1.ERROR_CODES.VALIDATION_ERROR
2145
- );
2146
- }
2147
- }
2148
- this.logger.debug("[CacheService] Configuration validated successfully");
2149
- }
2150
- };
2151
- var StorageService = class _StorageService {
2152
- constructor() {
2153
- this.storageService = null;
2154
- this.config = null;
2155
- this.initialized = false;
2156
- }
2157
- static {
2158
- __name(this, "StorageService");
2159
- }
2160
- static {
2161
- this.instance = null;
2162
- }
2163
- // ─────────────────────────────────────────────────────────────────
2164
- // Error Handling
2165
- // ─────────────────────────────────────────────────────────────────
2166
- /**
2167
- * Emits a storage error event via CoreEventManager.
2168
- * Called when storage operations fail to integrate with global error handling.
2169
- */
2170
- emitStorageError(error, operation, options) {
2171
- const payload = {
2172
- error,
2173
- operation,
2174
- fileId: options?.fileId,
2175
- filename: options?.filename,
2176
- recoverable: options?.recoverable ?? false
2177
- };
2178
- CoreEventManager.emit(core.CORE_EVENTS.STORAGE.ERROR, payload);
2179
- }
2180
- // ─────────────────────────────────────────────────────────────────
2181
- // Singleton Management
2182
- // ─────────────────────────────────────────────────────────────────
2183
- /**
2184
- * Gets the singleton instance of StorageService
2185
- */
2186
- static getInstance() {
2187
- _StorageService.instance ??= new _StorageService();
2188
- return _StorageService.instance;
2189
- }
2190
- /**
2191
- * Checks if the storage service has been initialized
2192
- */
2193
- static isInitialized() {
2194
- return _StorageService.instance?.initialized ?? false;
2195
- }
2196
- /**
2197
- * Resets the storage service by clearing the singleton instance
2198
- */
2199
- static async reset() {
2200
- if (_StorageService.instance) {
2201
- _StorageService.instance.storageService = null;
2202
- _StorageService.instance.config = null;
2203
- _StorageService.instance.initialized = false;
2204
- _StorageService.instance = null;
2205
- }
2206
- }
2207
- /**
2208
- * Initializes the storage service
2209
- *
2210
- * @param config - Storage service configuration
2211
- * @returns The initialized StorageService instance
2212
- */
2213
- static async initialize(config) {
2214
- const instance = _StorageService.getInstance();
2215
- if (instance.initialized) {
2216
- return instance;
2217
- }
2218
- instance.config = config;
2219
- instance.storageService = new storage.StorageService(config);
2220
- instance.initialized = true;
2221
- return instance;
2222
- }
2223
- /**
2224
- * Gets the raw underlying storage service instance without error handling wrapper.
2225
- * Use this only if you need direct access to the underlying service.
2226
- *
2227
- * @returns The raw StorageService instance from @plyaz/storage
2228
- * @throws {StoragePackageError} When storage is not initialized
2229
- */
2230
- getRawStorage() {
2231
- if (!this.storageService) {
2232
- throw new errors.StoragePackageError(
2233
- "Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
2234
- errors$1.STORAGE_ERROR_CODES.INITIALIZATION_FAILED
2235
- );
2236
- }
2237
- return this.storageService;
2238
- }
2239
- // ─────────────────────────────────────────────────────────────────
2240
- // Service Access
2241
- // ─────────────────────────────────────────────────────────────────
2242
- /**
2243
- * Gets the storage service with automatic error handling.
2244
- * All method calls are wrapped with try/catch and emit error events on failure.
2245
- * Any method added to @plyaz/storage will be automatically available.
2246
- *
2247
- * @example
2248
- * ```typescript
2249
- * const storage = StorageService.getInstance().getStorage();
2250
- * await storage.uploadFile({ file, filename: 'doc.pdf' });
2251
- * await storage.deleteFile({ fileId: '123' });
2252
- * ```
2253
- *
2254
- * @returns StorageServiceImpl with automatic error handling
2255
- */
2256
- getStorage() {
2257
- const self = this;
2258
- return new Proxy({}, {
2259
- get(_, prop) {
2260
- if (typeof prop === "symbol") {
2261
- return void 0;
2262
- }
2263
- const storage = self.getRawStorage();
2264
- const value = storage[prop];
2265
- if (typeof value !== "function") {
2266
- return value;
2267
- }
2268
- return (...args) => {
2269
- try {
2270
- const result = value.apply(storage, args);
2271
- if (result instanceof Promise) {
2272
- return result.catch((error) => {
2273
- self.emitStorageError(error, prop, { recoverable: true });
2274
- throw error;
2275
- });
2276
- }
2277
- return result;
2278
- } catch (error) {
2279
- self.emitStorageError(error, prop, { recoverable: true });
2280
- throw error;
2281
- }
2282
- };
2283
- }
2284
- });
2285
- }
2286
- // ─────────────────────────────────────────────────────────────────
2287
- // Health Check (special handling for response transformation)
2288
- // ─────────────────────────────────────────────────────────────────
2289
- /**
2290
- * Performs a health check on the storage service by checking all adapter health.
2291
- * This method has special handling to transform the response format.
2292
- */
2293
- async healthCheck() {
2294
- const startTime = Date.now();
2295
- try {
2296
- const storage = this.getRawStorage();
2297
- if (typeof storage.checkAllAdaptersHealth === "function") {
2298
- await storage.checkAllAdaptersHealth();
2299
- }
2300
- const summary = typeof storage.getHealthSummary === "function" ? storage.getHealthSummary() : null;
2301
- const responseTime = Date.now() - startTime;
2302
- return {
2303
- // Check if all adapters are healthy (healthy count equals total count)
2304
- isHealthy: summary ? summary.healthy === summary.total : true,
2305
- responseTime,
2306
- error: void 0
2307
- };
2308
- } catch (error) {
2309
- this.emitStorageError(error, "healthCheck", { recoverable: true });
2310
- return {
2311
- isHealthy: false,
2312
- responseTime: Date.now() - startTime,
2313
- error: error instanceof Error ? error.message : "Unknown error"
2314
- };
2315
- }
2316
- }
2317
- // ─────────────────────────────────────────────────────────────────
2318
- // Lifecycle
2319
- // ─────────────────────────────────────────────────────────────────
2320
- /**
2321
- * Gets the current configuration
2322
- */
2323
- getConfig() {
2324
- return this.config;
2325
- }
2326
- /**
2327
- * Closes the storage service and cleans up resources
2328
- */
2329
- async close() {
2330
- if (this.storageService) {
2331
- await this.storageService.destroy();
2332
- }
2333
- this.storageService = null;
2334
- this.initialized = false;
2335
- this.config = null;
2336
- }
2337
- /**
2338
- * Creates a dedicated storage service instance (NOT the singleton)
2339
- *
2340
- * Use this when you need an isolated storage connection with its own configuration.
2341
- *
2342
- * @param config - Storage service configuration
2343
- * @returns Promise that resolves to a new dedicated StorageService instance
2344
- */
2345
- static async createInstance(config) {
2346
- const dedicatedInstance = new _StorageService();
2347
- dedicatedInstance.config = config;
2348
- dedicatedInstance.storageService = new storage.StorageService(config);
2349
- dedicatedInstance.initialized = true;
2350
- return dedicatedInstance;
2351
- }
2352
- };
2353
- var NotificationService = class _NotificationService {
2354
- constructor() {
2355
- this.notificationService = null;
2356
- this.config = null;
2357
- this.initialized = false;
2358
- }
2359
- static {
2360
- __name(this, "NotificationService");
2361
- }
2362
- static {
2363
- this.instance = null;
2364
- }
2365
- // ─────────────────────────────────────────────────────────────────
2366
- // Error Handling
2367
- // ─────────────────────────────────────────────────────────────────
2368
- /**
2369
- * Emits a notification error event via CoreEventManager.
2370
- * Called when notification operations fail to integrate with global error handling.
2371
- */
2372
- emitNotificationError(error, operation, options) {
2373
- const payload = {
2374
- error,
2375
- operation,
2376
- recipientId: options?.recipientId,
2377
- channel: options?.channel,
2378
- recoverable: options?.recoverable ?? false
2379
- };
2380
- CoreEventManager.emit(core.CORE_EVENTS.NOTIFICATION.ERROR, payload);
2381
- }
2382
- // ─────────────────────────────────────────────────────────────────
2383
- // Singleton Management
2384
- // ─────────────────────────────────────────────────────────────────
2385
- /**
2386
- * Gets the singleton instance of NotificationService
2387
- */
2388
- static getInstance() {
2389
- _NotificationService.instance ??= new _NotificationService();
2390
- return _NotificationService.instance;
2391
- }
2392
- /**
2393
- * Checks if the notification service has been initialized
2394
- */
2395
- static isInitialized() {
2396
- return _NotificationService.instance?.initialized ?? false;
2397
- }
2398
- /**
2399
- * Resets the notification service by clearing the singleton instance
2400
- */
2401
- static async reset() {
2402
- if (_NotificationService.instance) {
2403
- _NotificationService.instance.notificationService = null;
2404
- _NotificationService.instance.config = null;
2405
- _NotificationService.instance.initialized = false;
2406
- _NotificationService.instance = null;
2407
- }
2408
- }
2409
- /**
2410
- * Initializes the notification service
2453
+ * Disposes of the cache manager and cleans up resources.
2411
2454
  *
2412
- * @param config - Notification service configuration
2413
- * @returns The initialized NotificationService instance
2455
+ * @returns Promise that resolves when cleanup is complete
2414
2456
  */
2415
- static async initialize(config) {
2416
- const instance = _NotificationService.getInstance();
2417
- if (instance.initialized) {
2418
- return instance;
2419
- }
2420
- instance.config = config;
2421
- instance.notificationService = new notifications.NotificationService(config);
2422
- instance.initialized = true;
2423
- return instance;
2457
+ async dispose() {
2458
+ await this.strategy.dispose?.();
2459
+ }
2460
+ };
2461
+ var CacheService = class _CacheService {
2462
+ /** Private constructor to enforce singleton */
2463
+ constructor() {
2464
+ /** Cache manager instance */
2465
+ this.cacheManager = null;
2466
+ /** Configuration used to initialize cache */
2467
+ this.config = null;
2468
+ /** Logger instance */
2469
+ this.logger = new logger$1.CoreLogger({ service: "CacheService" });
2470
+ }
2471
+ static {
2472
+ __name(this, "CacheService");
2473
+ }
2474
+ static {
2475
+ /** Singleton instance */
2476
+ this.instance = null;
2424
2477
  }
2425
2478
  /**
2426
- * Gets the raw underlying notification service instance without error handling wrapper.
2427
- * Use this only if you need direct access to the underlying service.
2479
+ * Initialize the cache service with configuration
2480
+ *
2481
+ * @param config - Cache configuration
2482
+ * @throws {CorePackageError} If already initialized or config is invalid
2428
2483
  *
2429
- * @returns The raw NotificationService instance from @plyaz/notifications
2430
- * @throws {NotificationsPackageError} When notifications is not initialized
2484
+ * @example
2485
+ * ```typescript
2486
+ * await CacheService.initialize({
2487
+ * strategy: 'redis',
2488
+ * isEnabled: true,
2489
+ * ttl: 300,
2490
+ * prefix: 'app',
2491
+ * redis: { url: process.env.REDIS_URL },
2492
+ * });
2493
+ * ```
2431
2494
  */
2432
- getRawNotifications() {
2433
- if (!this.notificationService) {
2434
- throw new errors.NotificationPackageError(
2435
- "Notifications not initialized. Call NotificationService.initialize() first or use Core.initialize() with notifications config.",
2436
- errors$1.NOTIFICATION_ERROR_CODES.INITIALIZATION_FAILED
2495
+ static async initialize(config$1) {
2496
+ if (this.instance?.cacheManager) {
2497
+ throw new errors.CorePackageError(
2498
+ "CacheService is already initialized. Call reset() first if you need to reinitialize.",
2499
+ errors$1.ERROR_CODES.VALIDATION_ERROR
2500
+ );
2501
+ }
2502
+ const service = this.instance ?? new _CacheService();
2503
+ this.instance = service;
2504
+ try {
2505
+ service.logger.info("[CacheService] Initializing cache...", {
2506
+ strategy: config$1.strategy,
2507
+ isEnabled: config$1.isEnabled,
2508
+ ttl: config$1.ttl
2509
+ });
2510
+ service.validateConfig(config$1);
2511
+ const cacheConfig = {
2512
+ ...config$1,
2513
+ ttl: config$1.ttl ?? config.TIME_CONSTANTS.DEFAULT_CACHE_TTL
2514
+ };
2515
+ service.cacheManager = new CacheManager(cacheConfig);
2516
+ service.config = config$1;
2517
+ service.logger.info("[CacheService] Cache initialized successfully", {
2518
+ strategy: config$1.strategy
2519
+ });
2520
+ } catch (error) {
2521
+ service.logger.error("[CacheService] Failed to initialize cache", { error });
2522
+ throw new errors.CorePackageError(
2523
+ `Failed to initialize cache: ${error instanceof Error ? error.message : String(error)}`,
2524
+ errors$1.ERROR_CODES.VALIDATION_ERROR,
2525
+ { cause: error instanceof Error ? error : void 0 }
2437
2526
  );
2438
2527
  }
2439
- return this.notificationService;
2440
2528
  }
2441
- // ─────────────────────────────────────────────────────────────────
2442
- // Service Access
2443
- // ─────────────────────────────────────────────────────────────────
2444
2529
  /**
2445
- * Gets the notification service with automatic error handling.
2446
- * All method calls are wrapped with try/catch and emit error events on failure.
2447
- * Any method added to @plyaz/notifications will be automatically available.
2530
+ * Get the singleton instance
2531
+ *
2532
+ * @throws {CorePackageError} If not initialized
2533
+ * @returns CacheService singleton instance
2448
2534
  *
2449
2535
  * @example
2450
2536
  * ```typescript
2451
- * const notifications = NotificationService.getInstance().getNotifications();
2452
- * await notifications.sendEmail({ to: 'user@example.com', templateId: 'welcome' });
2453
- * await notifications.sendSMS({ to: '+1234567890', message: 'Hello!' });
2537
+ * const cacheService = CacheService.getInstance();
2538
+ * const cache = cacheService.getCacheManager();
2454
2539
  * ```
2455
- *
2456
- * @returns NotificationServiceImpl with automatic error handling
2457
2540
  */
2458
- getNotifications() {
2459
- const self = this;
2460
- return new Proxy({}, {
2461
- get(_, prop) {
2462
- if (typeof prop === "symbol") {
2463
- return void 0;
2464
- }
2465
- const notifications = self.getRawNotifications();
2466
- const value = notifications[prop];
2467
- if (typeof value !== "function") {
2468
- return value;
2469
- }
2470
- return (...args) => {
2471
- try {
2472
- const result = value.apply(notifications, args);
2473
- if (result instanceof Promise) {
2474
- return result.catch((error) => {
2475
- self.emitNotificationError(error, prop, { recoverable: true });
2476
- throw error;
2477
- });
2478
- }
2479
- return result;
2480
- } catch (error) {
2481
- self.emitNotificationError(error, prop, { recoverable: true });
2482
- throw error;
2483
- }
2484
- };
2485
- }
2486
- });
2541
+ static getInstance() {
2542
+ if (!this.instance) {
2543
+ throw new errors.CorePackageError(
2544
+ "CacheService not initialized. Call CacheService.initialize() first.",
2545
+ errors$1.ERROR_CODES.CLIENT_INITIALIZATION_FAILED
2546
+ );
2547
+ }
2548
+ return this.instance;
2487
2549
  }
2488
- // ─────────────────────────────────────────────────────────────────
2489
- // Health Check (special handling for response transformation)
2490
- // ─────────────────────────────────────────────────────────────────
2491
2550
  /**
2492
- * Performs a health check on the notification service.
2493
- * This method has special handling to transform the response format.
2551
+ * Get the cache manager instance
2552
+ *
2553
+ * @throws {CorePackageError} If cache not initialized
2554
+ * @returns CacheManager instance
2555
+ *
2556
+ * @example
2557
+ * ```typescript
2558
+ * const cache = CacheService.getInstance().getCacheManager();
2559
+ * await cache.set('user:123', userData);
2560
+ * const user = await cache.get('user:123');
2561
+ * ```
2494
2562
  */
2495
- async healthCheck() {
2496
- try {
2497
- const notifications = this.getRawNotifications();
2498
- const result = await notifications.healthCheck();
2499
- return {
2500
- isHealthy: result.healthy,
2501
- providers: result.providers,
2502
- // Use optional chaining since error may not exist on all health check results
2503
- error: "error" in result ? result.error : void 0
2504
- };
2505
- } catch (error) {
2506
- this.emitNotificationError(error, "healthCheck", { recoverable: true });
2507
- return {
2508
- isHealthy: false,
2509
- error: error instanceof Error ? error.message : "Unknown error"
2510
- };
2563
+ getCacheManager() {
2564
+ if (!this.cacheManager) {
2565
+ throw new errors.CorePackageError(
2566
+ "Cache manager not initialized. Call CacheService.initialize() first.",
2567
+ errors$1.ERROR_CODES.CLIENT_INITIALIZATION_FAILED
2568
+ );
2511
2569
  }
2570
+ return this.cacheManager;
2512
2571
  }
2513
- // ─────────────────────────────────────────────────────────────────
2514
- // Lifecycle
2515
- // ─────────────────────────────────────────────────────────────────
2516
2572
  /**
2517
- * Gets the current configuration
2573
+ * Get current cache configuration
2574
+ *
2575
+ * @returns Current cache configuration or null if not initialized
2518
2576
  */
2519
2577
  getConfig() {
2520
2578
  return this.config;
2521
2579
  }
2522
2580
  /**
2523
- * Closes the notification service and cleans up resources
2581
+ * Check if cache is initialized and enabled
2582
+ *
2583
+ * @returns True if cache is ready to use
2524
2584
  */
2525
- async close() {
2526
- this.notificationService = null;
2527
- this.initialized = false;
2528
- this.config = null;
2585
+ isInitialized() {
2586
+ return this.cacheManager !== null && (this.config?.isEnabled ?? false);
2529
2587
  }
2530
2588
  /**
2531
- * Creates a dedicated notification service instance (NOT the singleton)
2589
+ * Reset the cache service (useful for testing)
2532
2590
  *
2533
- * Use this when you need an isolated notification service with its own configuration.
2591
+ * @internal
2592
+ */
2593
+ static reset() {
2594
+ if (this.instance?.cacheManager) {
2595
+ this.instance.logger.info("[CacheService] Resetting cache service");
2596
+ this.instance.cacheManager.clear().catch((error) => {
2597
+ this.instance?.logger.error("[CacheService] Error clearing cache during reset", { error });
2598
+ });
2599
+ }
2600
+ this.instance = null;
2601
+ }
2602
+ /**
2603
+ * Validate cache configuration
2534
2604
  *
2535
- * @param config - Notification service configuration
2536
- * @returns Promise that resolves to a new dedicated NotificationService instance
2605
+ * @param config - Configuration to validate
2606
+ * @throws {CorePackageError} If configuration is invalid
2607
+ * @private
2537
2608
  */
2538
- static async createInstance(config) {
2539
- const dedicatedInstance = new _NotificationService();
2540
- dedicatedInstance.config = config;
2541
- dedicatedInstance.notificationService = new notifications.NotificationService(config);
2542
- dedicatedInstance.initialized = true;
2543
- return dedicatedInstance;
2609
+ // eslint-disable-next-line complexity
2610
+ validateConfig(config) {
2611
+ if (!features.CACHE_STRATEGIES.includes(config.strategy)) {
2612
+ throw new errors.CorePackageError(
2613
+ `Invalid cache strategy: ${config.strategy}. Must be one of: ${features.CACHE_STRATEGIES.join(", ")}`,
2614
+ errors$1.ERROR_CODES.VALIDATION_ERROR
2615
+ );
2616
+ }
2617
+ if (config.ttl !== void 0 && (config.ttl < 0 || !Number.isFinite(config.ttl))) {
2618
+ throw new errors.CorePackageError(
2619
+ `Invalid TTL value: ${config.ttl}. Must be a positive number.`,
2620
+ errors$1.ERROR_CODES.VALIDATION_ERROR
2621
+ );
2622
+ }
2623
+ if (config.strategy === "redis") {
2624
+ if (!config.redis?.url && !config.redis?.host) {
2625
+ throw new errors.CorePackageError(
2626
+ "Redis strategy requires either redis.url or redis.host configuration",
2627
+ errors$1.ERROR_CODES.VALIDATION_ERROR
2628
+ );
2629
+ }
2630
+ }
2631
+ this.logger.debug("[CacheService] Configuration validated successfully");
2544
2632
  }
2545
2633
  };
2634
+
2635
+ // src/init/CoreInitializer.ts
2636
+ init_CoreEventManager();
2546
2637
  var BaseDomainService = class {
2547
2638
  // ─────────────────────────────────────────────────────────────────────────
2548
2639
  // Constructor
@@ -2941,6 +3032,9 @@ var BaseDomainService = class {
2941
3032
  );
2942
3033
  }
2943
3034
  };
3035
+
3036
+ // src/domain/base/BaseFrontendDomainService.ts
3037
+ init_CoreEventManager();
2944
3038
  var BaseFrontendDomainService = class extends BaseDomainService {
2945
3039
  // ─────────────────────────────────────────────────────────────────────────
2946
3040
  // Constructor
@@ -3749,7 +3843,7 @@ var BaseFrontendDomainService = class extends BaseDomainService {
3749
3843
  */
3750
3844
  emitEvent(event, payload) {
3751
3845
  const eventName = `${this.eventPrefix}:${event}`;
3752
- CoreEventManager.emit(eventName, payload);
3846
+ exports.CoreEventManager.emit(eventName, payload);
3753
3847
  this.logDebug(`Event emitted: ${eventName}`, payload);
3754
3848
  }
3755
3849
  // ─────────────────────────────────────────────────────────────────────────
@@ -3838,6 +3932,9 @@ var BaseFrontendDomainService = class extends BaseDomainService {
3838
3932
  );
3839
3933
  }
3840
3934
  };
3935
+
3936
+ // src/events/index.ts
3937
+ init_CoreEventManager();
3841
3938
  var BaseBackendDomainService = class extends BaseDomainService {
3842
3939
  static {
3843
3940
  __name(this, "BaseBackendDomainService");
@@ -4775,7 +4872,7 @@ var BaseBackendDomainService = class extends BaseDomainService {
4775
4872
  */
4776
4873
  emitEvent(event, payload) {
4777
4874
  if (this.emitEvents) {
4778
- CoreEventManager.emit(`${this.eventPrefix}:${event}`, payload);
4875
+ exports.CoreEventManager.emit(`${this.eventPrefix}:${event}`, payload);
4779
4876
  }
4780
4877
  }
4781
4878
  // ─────────────────────────────────────────────────────────────────────────
@@ -5235,6 +5332,10 @@ function keysToSnake(obj) {
5235
5332
  return result;
5236
5333
  }
5237
5334
  __name(keysToSnake, "keysToSnake");
5335
+
5336
+ // src/models/example/ExampleRepository.ts
5337
+ init_DbService();
5338
+ init_common();
5238
5339
  var EXAMPLE_TABLE = "examples";
5239
5340
  var DEFAULT_PAGINATION_LIMIT = 100;
5240
5341
  var DUMMY_DATA = [
@@ -5412,31 +5513,99 @@ var ExampleRepository = class _ExampleRepository extends db.BaseRepository {
5412
5513
  return super.delete(id, config);
5413
5514
  }
5414
5515
  // ─────────────────────────────────────────────────────────────────────────
5415
- // Domain-Specific Query Methods
5516
+ // Domain-Specific Query Methods (using QueryBuilder fluent API)
5416
5517
  // ─────────────────────────────────────────────────────────────────────────
5417
5518
  /**
5418
- * Find entities by status
5519
+ * Find entities by status using fluent QueryBuilder
5520
+ *
5521
+ * @example
5522
+ * ```typescript
5523
+ * const result = await repo.findByStatus('active');
5524
+ * ```
5419
5525
  */
5420
5526
  async findByStatus(status) {
5421
- return this.findMany({
5422
- filter: { field: "status", operator: "eq", value: status }
5423
- });
5527
+ if (this.useDummyData) {
5528
+ return this.findMany({
5529
+ filter: { field: "status", operator: "eq", value: status }
5530
+ });
5531
+ }
5532
+ return this.query().where("status", "eq", status).execute();
5424
5533
  }
5425
5534
  /**
5426
- * Find entities by owner
5535
+ * Find entities by owner using fluent QueryBuilder
5536
+ *
5537
+ * @example
5538
+ * ```typescript
5539
+ * const result = await repo.findByOwner('user-001');
5540
+ * ```
5427
5541
  */
5428
5542
  async findByOwner(ownerId) {
5429
- return this.findMany({
5430
- filter: { field: "owner_id", operator: "eq", value: ownerId }
5431
- });
5543
+ if (this.useDummyData) {
5544
+ return this.findMany({
5545
+ filter: { field: "owner_id", operator: "eq", value: ownerId }
5546
+ });
5547
+ }
5548
+ return this.query().where("owner_id", "eq", ownerId).execute();
5432
5549
  }
5433
5550
  /**
5434
- * Find visible entities only
5551
+ * Find visible entities only using fluent QueryBuilder
5552
+ *
5553
+ * @example
5554
+ * ```typescript
5555
+ * const result = await repo.findVisible();
5556
+ * ```
5435
5557
  */
5436
5558
  async findVisible() {
5437
- return this.findMany({
5438
- filter: { field: "is_visible", operator: "eq", value: true }
5439
- });
5559
+ if (this.useDummyData) {
5560
+ return this.findMany({
5561
+ filter: { field: "is_visible", operator: "eq", value: true }
5562
+ });
5563
+ }
5564
+ return this.query().where("is_visible", "eq", true).execute();
5565
+ }
5566
+ /**
5567
+ * Find active and visible entities using complex QueryBuilder
5568
+ *
5569
+ * @example
5570
+ * ```typescript
5571
+ * const items = await repo.findActiveAndVisible();
5572
+ * ```
5573
+ */
5574
+ async findActiveAndVisible() {
5575
+ if (this.useDummyData) {
5576
+ return this.dummyStore.filter((r) => r.status === "active" && r.is_visible && !r.deleted_at);
5577
+ }
5578
+ return this.query().where("status", "eq", "active").andWhere("is_visible", "eq", true).whereNull("deleted_at").orderByDesc("created_at").getMany();
5579
+ }
5580
+ /**
5581
+ * Find entities by owner with status filter using QueryBuilder
5582
+ *
5583
+ * @example
5584
+ * ```typescript
5585
+ * const items = await repo.findByOwnerWithStatus('user-001', 'active');
5586
+ * ```
5587
+ */
5588
+ async findByOwnerWithStatus(ownerId, status) {
5589
+ if (this.useDummyData) {
5590
+ return this.dummyStore.filter(
5591
+ (r) => r.owner_id === ownerId && r.status === status && !r.deleted_at
5592
+ );
5593
+ }
5594
+ return this.query().where("owner_id", "eq", ownerId).andWhere("status", "eq", status).orderByDesc("updated_at").getMany();
5595
+ }
5596
+ /**
5597
+ * Count entities by status using QueryBuilder
5598
+ *
5599
+ * @example
5600
+ * ```typescript
5601
+ * const count = await repo.countByStatus('active');
5602
+ * ```
5603
+ */
5604
+ async countByStatus(status) {
5605
+ if (this.useDummyData) {
5606
+ return this.dummyStore.filter((r) => r.status === status && !r.deleted_at).length;
5607
+ }
5608
+ return this.query().where("status", "eq", status).count();
5440
5609
  }
5441
5610
  /**
5442
5611
  * Check if entity exists by ID
@@ -5907,6 +6076,7 @@ var BackendExampleDomainService = class _BackendExampleDomainService extends Bas
5907
6076
  // ─────────────────────────────────────────────────────────────────────────
5908
6077
  };
5909
6078
  new BackendExampleDomainService();
6079
+ init_CoreEventManager();
5910
6080
  var DEFAULT_POLLING_INTERVAL_MS = 3e4;
5911
6081
  var FrontendExampleDomainService = class _FrontendExampleDomainService extends BaseFrontendDomainService {
5912
6082
  // ─────────────────────────────────────────────────────────────────────────
@@ -5956,6 +6126,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
5956
6126
  // store.setData(data);
5957
6127
  // // Can also call domain-specific methods or other stores
5958
6128
  // // store.selectItem(data.selectedId);
6129
+ // // store.selectItem(data.selectedId);
5959
6130
  // },
5960
6131
  // updateData: (store, data) => store.updateData(data),
5961
6132
  // setLoading: (store, isLoading) => store.setLoading(isLoading),
@@ -6035,7 +6206,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
6035
6206
  * Note: Base class automatically calls syncToStores() which uses storeHandlers
6036
6207
  */
6037
6208
  async afterFetchAll(entities) {
6038
- CoreEventManager.emit("example:store:synced", { items: entities });
6209
+ exports.CoreEventManager.emit("example:store:synced", { items: entities });
6039
6210
  }
6040
6211
  // ─────────────────────────────────────────────────────────────────────────
6041
6212
  // Optional: Manual Store Updates (Alternative to storeHandlers)
@@ -6074,7 +6245,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
6074
6245
  * ```
6075
6246
  */
6076
6247
  on(event, handler) {
6077
- return CoreEventManager.on(event, handler);
6248
+ return exports.CoreEventManager.on(event, handler);
6078
6249
  }
6079
6250
  // ─────────────────────────────────────────────────────────────────────────
6080
6251
  // Polling (Domain-Specific Feature)
@@ -6171,6 +6342,9 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
6171
6342
  // All events are emitted automatically with 'example:' prefix!
6172
6343
  // ─────────────────────────────────────────────────────────────────────────
6173
6344
  };
6345
+
6346
+ // src/base/observability/BaseAdapter.ts
6347
+ init_common();
6174
6348
  var BaseAdapter = class {
6175
6349
  constructor() {
6176
6350
  this._isInitialized = false;
@@ -6393,6 +6567,9 @@ var NoopAdapter = class extends BaseAdapter {
6393
6567
  async doFlush() {
6394
6568
  }
6395
6569
  };
6570
+
6571
+ // src/base/observability/LoggerAdapter.ts
6572
+ init_common();
6396
6573
  var LoggerAdapter = class extends BaseAdapter {
6397
6574
  constructor() {
6398
6575
  super(...arguments);
@@ -6542,6 +6719,12 @@ var LoggerAdapter = class extends BaseAdapter {
6542
6719
  async doFlush() {
6543
6720
  }
6544
6721
  };
6722
+
6723
+ // src/base/observability/CompositeAdapter.ts
6724
+ init_common();
6725
+
6726
+ // src/base/observability/DatadogAdapter.ts
6727
+ init_common();
6545
6728
  var DEFAULT_ADAPTER_TIMEOUT_MS = 5e3;
6546
6729
  var ObservabilityService = class {
6547
6730
  constructor() {
@@ -7294,10 +7477,11 @@ var ServiceRegistry = class _ServiceRegistry {
7294
7477
  if (!dbConfig) {
7295
7478
  return void 0;
7296
7479
  }
7480
+ const { DbService: DbService2 } = await Promise.resolve().then(() => (init_DbService(), DbService_exports));
7297
7481
  let dbInstance;
7298
7482
  if (isDedicated && dbConfig) {
7299
7483
  try {
7300
- dbInstance = await DbService.createInstance(dbConfig);
7484
+ dbInstance = await DbService2.createInstance(dbConfig);
7301
7485
  _ServiceRegistry.logger.debug(
7302
7486
  `Created dedicated database instance for service '${serviceKey}'`
7303
7487
  );
@@ -7311,7 +7495,7 @@ var ServiceRegistry = class _ServiceRegistry {
7311
7495
  }
7312
7496
  } else {
7313
7497
  try {
7314
- dbInstance = DbService.getInstance();
7498
+ dbInstance = DbService2.getInstance();
7315
7499
  } catch {
7316
7500
  _ServiceRegistry.logger.debug(
7317
7501
  `Global DB not initialized, service '${serviceKey}' will not have DB`
@@ -7412,10 +7596,11 @@ var ServiceRegistry = class _ServiceRegistry {
7412
7596
  if (!storageConfig) {
7413
7597
  return void 0;
7414
7598
  }
7599
+ const { StorageService: StorageService2 } = await Promise.resolve().then(() => (init_StorageService(), StorageService_exports));
7415
7600
  let storageInstance;
7416
7601
  if (isDedicated && storageConfig) {
7417
7602
  try {
7418
- storageInstance = await StorageService.createInstance(storageConfig);
7603
+ storageInstance = await StorageService2.createInstance(storageConfig);
7419
7604
  _ServiceRegistry.logger.debug(
7420
7605
  `Created dedicated storage instance for service '${serviceKey}'`
7421
7606
  );
@@ -7427,7 +7612,7 @@ var ServiceRegistry = class _ServiceRegistry {
7427
7612
  }
7428
7613
  } else {
7429
7614
  try {
7430
- storageInstance = StorageService.getInstance();
7615
+ storageInstance = StorageService2.getInstance();
7431
7616
  } catch {
7432
7617
  _ServiceRegistry.logger.debug(
7433
7618
  `Global storage not initialized, service '${serviceKey}' will not have storage`
@@ -7457,10 +7642,11 @@ var ServiceRegistry = class _ServiceRegistry {
7457
7642
  if (!notificationsConfig) {
7458
7643
  return void 0;
7459
7644
  }
7645
+ const { NotificationService: NotificationService2 } = await Promise.resolve().then(() => (init_NotificationService(), NotificationService_exports));
7460
7646
  let notificationsInstance;
7461
7647
  if (isDedicated && notificationsConfig) {
7462
7648
  try {
7463
- notificationsInstance = await NotificationService.createInstance(notificationsConfig);
7649
+ notificationsInstance = await NotificationService2.createInstance(notificationsConfig);
7464
7650
  _ServiceRegistry.logger.debug(
7465
7651
  `Created dedicated notifications instance for service '${serviceKey}'`
7466
7652
  );
@@ -7472,7 +7658,7 @@ var ServiceRegistry = class _ServiceRegistry {
7472
7658
  }
7473
7659
  } else {
7474
7660
  try {
7475
- notificationsInstance = NotificationService.getInstance();
7661
+ notificationsInstance = NotificationService2.getInstance();
7476
7662
  } catch {
7477
7663
  _ServiceRegistry.logger.debug(
7478
7664
  `Global notifications not initialized, service '${serviceKey}' will not have notifications`
@@ -8050,8 +8236,9 @@ var Core = class _Core {
8050
8236
  await _Core.initService(
8051
8237
  "storage",
8052
8238
  async () => {
8053
- await StorageService.initialize(storageConfig);
8054
- _Core._coreServices.storage = StorageService.getInstance();
8239
+ const { StorageService: StorageService2 } = await Promise.resolve().then(() => (init_StorageService(), StorageService_exports));
8240
+ await StorageService2.initialize(storageConfig);
8241
+ _Core._coreServices.storage = StorageService2.getInstance();
8055
8242
  _Core.log("Storage service initialized", verbose);
8056
8243
  },
8057
8244
  verbose
@@ -8075,8 +8262,9 @@ var Core = class _Core {
8075
8262
  await _Core.initService(
8076
8263
  "notifications",
8077
8264
  async () => {
8078
- await NotificationService.initialize(notificationsConfig);
8079
- _Core._coreServices.notifications = NotificationService.getInstance();
8265
+ const { NotificationService: NotificationService2 } = await Promise.resolve().then(() => (init_NotificationService(), NotificationService_exports));
8266
+ await NotificationService2.initialize(notificationsConfig);
8267
+ _Core._coreServices.notifications = NotificationService2.getInstance();
8080
8268
  _Core.log("Notifications service initialized", verbose);
8081
8269
  },
8082
8270
  verbose
@@ -8219,7 +8407,7 @@ var Core = class _Core {
8219
8407
  * @example Core.events.on('example:created', handler)
8220
8408
  */
8221
8409
  static get events() {
8222
- return CoreEventManager;
8410
+ return exports.CoreEventManager;
8223
8411
  }
8224
8412
  /**
8225
8413
  * Get database service instance
@@ -8641,11 +8829,13 @@ var Core = class _Core {
8641
8829
  _Core._observabilityConfig = {};
8642
8830
  if (_Core._coreServices.storage) {
8643
8831
  await _Core._coreServices.storage.close();
8644
- await StorageService.reset();
8832
+ const { StorageService: StorageService2 } = await Promise.resolve().then(() => (init_StorageService(), StorageService_exports));
8833
+ await StorageService2.reset();
8645
8834
  }
8646
8835
  if (_Core._coreServices.notifications) {
8647
8836
  await _Core._coreServices.notifications.close();
8648
- await NotificationService.reset();
8837
+ const { NotificationService: NotificationService2 } = await Promise.resolve().then(() => (init_NotificationService(), NotificationService_exports));
8838
+ await NotificationService2.reset();
8649
8839
  }
8650
8840
  if (_Core._errorHandler) {
8651
8841
  _Core._errorHandler.destroy();
@@ -8667,7 +8857,7 @@ var Core = class _Core {
8667
8857
  }
8668
8858
  _Core._flagConfig = {};
8669
8859
  ServiceRegistry.disposeAll();
8670
- CoreEventManager.dispose();
8860
+ exports.CoreEventManager.dispose();
8671
8861
  _Core._coreServices = {
8672
8862
  db: null,
8673
8863
  api: null,
@@ -8696,20 +8886,19 @@ var Core = class _Core {
8696
8886
  */
8697
8887
  static shouldSkipDbService(skipDb, verbose) {
8698
8888
  if (skipDb === true) {
8699
- if (verbose) {
8700
- console.log("[Core] Database service skipped (skipDb: true)");
8701
- }
8889
+ _Core.log("Database service skipped (skipDb: true)", verbose);
8702
8890
  return true;
8703
8891
  }
8704
8892
  const isFrontend = _Core.isFrontend;
8705
8893
  if (isFrontend) {
8706
8894
  if (skipDb === false) {
8707
- console.warn(
8708
- "[Core] Warning: DbService cannot be initialized on frontend runtime. DbService is backend-only and requires Node.js. Use API calls from frontend instead. Skipping database initialization."
8895
+ _Core.logger.warn(
8896
+ "DbService cannot be initialized on frontend runtime. DbService is backend-only and requires Node.js. Use API calls from frontend instead. Skipping database initialization."
8709
8897
  );
8710
8898
  } else if (verbose) {
8711
- console.log(
8712
- "[Core] Database service skipped (frontend runtime detected). DbService is only available on backend."
8899
+ _Core.log(
8900
+ "Database service skipped (frontend runtime detected). DbService is only available on backend.",
8901
+ verbose
8713
8902
  );
8714
8903
  }
8715
8904
  return true;
@@ -8721,10 +8910,9 @@ var Core = class _Core {
8721
8910
  * Config validation is handled by DbService
8722
8911
  */
8723
8912
  static async initializeDb(config, verbose) {
8724
- if (verbose) {
8725
- console.log(`[Core] Initializing database with adapter: ${config?.adapter ?? "drizzle"}`);
8726
- }
8727
- return DbService.initialize({
8913
+ _Core.log(`Initializing database with adapter: ${config?.adapter ?? "drizzle"}`, verbose);
8914
+ const { DbService: DbService2 } = await Promise.resolve().then(() => (init_DbService(), DbService_exports));
8915
+ return DbService2.initialize({
8728
8916
  adapter: "drizzle",
8729
8917
  ...config
8730
8918
  });
@@ -8736,9 +8924,7 @@ var Core = class _Core {
8736
8924
  static async initializeApi(config, globalEnvironment, verbose) {
8737
8925
  const { env: apiEnv, setAsDefault, ...apiClientOptions } = config ?? {};
8738
8926
  const resolvedEnv = apiEnv ?? globalEnvironment ?? "development";
8739
- if (verbose) {
8740
- console.log(`[Core] Initializing API client for environment: ${resolvedEnv}`);
8741
- }
8927
+ _Core.log(`Initializing API client for environment: ${resolvedEnv}`, verbose);
8742
8928
  await ApiClientService.init(
8743
8929
  {
8744
8930
  env: resolvedEnv,
@@ -8752,9 +8938,7 @@ var Core = class _Core {
8752
8938
  * Config validation is handled by CacheService
8753
8939
  */
8754
8940
  static async initializeCache(config, verbose) {
8755
- if (verbose) {
8756
- console.log(`[Core] Initializing cache with strategy: ${config.strategy}`);
8757
- }
8941
+ _Core.log(`Initializing cache with strategy: ${config.strategy}`, verbose);
8758
8942
  await CacheService.initialize(config);
8759
8943
  }
8760
8944
  /**
@@ -8762,9 +8946,7 @@ var Core = class _Core {
8762
8946
  * Always includes LoggerAdapter as failover for console output.
8763
8947
  */
8764
8948
  static async initializeObservability(config, verbose, environment) {
8765
- if (verbose) {
8766
- console.log(`[Core] Initializing observability with provider: ${config.provider ?? "auto"}`);
8767
- }
8949
+ _Core.log(`Initializing observability with provider: ${config.provider ?? "auto"}`, verbose);
8768
8950
  const env = config.environment ?? environment ?? "development";
8769
8951
  _Core._observabilityConfig = { ...config, environment: env };
8770
8952
  const adapters = [];
@@ -8788,11 +8970,10 @@ var Core = class _Core {
8788
8970
  flushInterval: config.flushInterval,
8789
8971
  adapterTimeout: config.flushInterval
8790
8972
  });
8791
- if (verbose) {
8792
- console.log(
8793
- `[Core] ObservabilityService initialized with ${adapters.length} adapters (env: ${env})`
8794
- );
8795
- }
8973
+ _Core.log(
8974
+ `ObservabilityService initialized with ${adapters.length} adapters (env: ${env})`,
8975
+ verbose
8976
+ );
8796
8977
  _Core._coreServices.observability = observability;
8797
8978
  ServiceRegistry.setObservabilityInstance(observability);
8798
8979
  }
@@ -8803,10 +8984,10 @@ var Core = class _Core {
8803
8984
  static initializeRootStore(config, verbose) {
8804
8985
  const isFrontend = typeof window !== "undefined";
8805
8986
  if (isFrontend) {
8806
- if (verbose) console.log("[Core] Using frontend root store (Zustand)");
8987
+ _Core.log("Using frontend root store (Zustand)", verbose);
8807
8988
  _Core._rootStore = store.useRootStore;
8808
8989
  } else {
8809
- if (verbose) console.log("[Core] Creating backend composite store (in-memory)");
8990
+ _Core.log("Creating backend composite store (in-memory)", verbose);
8810
8991
  const backendErrorStore = middleware.ServerErrorMiddleware.createErrorStore({
8811
8992
  maxErrors: config?.maxErrors ?? DEFAULT_MAX_ERRORS,
8812
8993
  onErrorAdded: config?.onError
@@ -8854,11 +9035,11 @@ var Core = class _Core {
8854
9035
  // eslint-disable-next-line complexity
8855
9036
  static async initializeErrorHandler(config, verbose) {
8856
9037
  if (config?.enabled === false) {
8857
- if (verbose) console.log("[Core] Error handler disabled by configuration");
9038
+ _Core.log("Error handler disabled by configuration", verbose);
8858
9039
  return;
8859
9040
  }
8860
9041
  _Core._errorConfig = config ?? {};
8861
- if (verbose) console.log("[Core] Initializing global error handler...");
9042
+ _Core.log("Initializing global error handler...", verbose);
8862
9043
  errors.initializeErrorSystem({
8863
9044
  defaultLocale: _Core._errorConfig.localization?.defaultLocale,
8864
9045
  fallbackLocale: _Core._errorConfig.localization?.fallbackLocale,
@@ -8866,13 +9047,13 @@ var Core = class _Core {
8866
9047
  replaceBuiltIn: _Core._errorConfig.localization?.replaceBuiltIn
8867
9048
  });
8868
9049
  _Core.initializeRootStore(_Core._errorConfig, verbose);
8869
- middleware.setEventEmitter(CoreEventManager.emit.bind(CoreEventManager));
9050
+ middleware.setEventEmitter(exports.CoreEventManager.emit.bind(exports.CoreEventManager));
8870
9051
  const errorStore = _Core.getErrorStoreActions();
8871
9052
  _Core._errorHandler = middleware.initializeGlobalErrorHandler(
8872
9053
  errorStore,
8873
9054
  _Core.buildErrorHandlerConfig(_Core._errorConfig)
8874
9055
  );
8875
- const errorEventCleanup = CoreEventManager.on(
9056
+ const errorEventCleanup = exports.CoreEventManager.on(
8876
9057
  core.CORE_EVENTS.SYSTEM.ERROR,
8877
9058
  (event) => {
8878
9059
  if (!_Core._rootStore) return;
@@ -8880,16 +9061,15 @@ var Core = class _Core {
8880
9061
  const { errors } = event.data;
8881
9062
  if (errors && errors.length > 0) {
8882
9063
  _Core._rootStore.getState().errors.addErrors(errors);
8883
- if (verbose) console.log(`[Core] Added ${errors.length} error(s) to store`);
9064
+ _Core.log(`Added ${errors.length} error(s) to store`, verbose);
8884
9065
  }
8885
9066
  } catch (e) {
8886
- console.error("[Core] Failed to handle error event:", e);
9067
+ _Core.logger.error("Failed to handle error event", { error: e });
8887
9068
  }
8888
9069
  }
8889
9070
  );
8890
9071
  _Core._eventCleanupFns.push(errorEventCleanup);
8891
- if (verbose)
8892
- console.log("[Core] Global error handler initialized with CoreEventManager integration");
9072
+ _Core.log("Global error handler initialized with CoreEventManager integration", verbose);
8893
9073
  if (_Core._errorConfig.httpHandler !== false) {
8894
9074
  _Core.createHttpErrorHandler(_Core._errorConfig, verbose);
8895
9075
  }
@@ -8911,11 +9091,11 @@ var Core = class _Core {
8911
9091
  switch (runtime) {
8912
9092
  case "express":
8913
9093
  _Core._httpErrorHandler = middleware.ServerErrorMiddleware.createHttpErrorHandler(httpConfig);
8914
- if (verbose) console.log("[Core] Created Express error handler middleware");
9094
+ _Core.log("Created Express error handler middleware", verbose);
8915
9095
  break;
8916
9096
  case "nestjs":
8917
9097
  _Core._httpErrorHandler = middleware.ServerErrorMiddleware.createNestJsExceptionFilter(httpConfig);
8918
- if (verbose) console.log("[Core] Created NestJS exception filter");
9098
+ _Core.log("Created NestJS exception filter", verbose);
8919
9099
  break;
8920
9100
  case "nextjs":
8921
9101
  _Core._httpErrorHandler = {
@@ -8927,7 +9107,7 @@ var Core = class _Core {
8927
9107
  /** For Pages Router: export default createNextApiErrorHandler()(handler) */
8928
9108
  createNextApiErrorHandler: /* @__PURE__ */ __name((overrideConfig = {}) => middleware.ServerErrorMiddleware.createNextApiErrorHandler({ ...httpConfig, ...overrideConfig }), "createNextApiErrorHandler")
8929
9109
  };
8930
- if (verbose) console.log("[Core] Created Next.js error handlers");
9110
+ _Core.log("Created Next.js error handlers", verbose);
8931
9111
  break;
8932
9112
  case "node":
8933
9113
  case "bun":
@@ -8944,15 +9124,15 @@ var Core = class _Core {
8944
9124
  /** Create middleware for use with native http */
8945
9125
  createMiddleware: /* @__PURE__ */ __name(() => middleware.ServerErrorMiddleware.createHttpErrorHandler(httpConfig), "createMiddleware")
8946
9126
  };
8947
- if (verbose) console.log(`[Core] Created ${runtime} error handler`);
9127
+ _Core.log(`Created ${runtime} error handler`, verbose);
8948
9128
  break;
8949
9129
  case "browser":
8950
9130
  _Core._httpErrorHandler = null;
8951
- if (verbose) console.log("[Core] Skipping HTTP handler for browser runtime");
9131
+ _Core.log("Skipping HTTP handler for browser runtime", verbose);
8952
9132
  break;
8953
9133
  default:
8954
9134
  _Core._httpErrorHandler = middleware.ServerErrorMiddleware.createHttpErrorHandler(httpConfig);
8955
- if (verbose) console.log(`[Core] Created generic HTTP error handler for ${runtime}`);
9135
+ _Core.log(`Created generic HTTP error handler for ${runtime}`, verbose);
8956
9136
  }
8957
9137
  }
8958
9138
  /**
@@ -8966,37 +9146,35 @@ var Core = class _Core {
8966
9146
  if (!_Core._errorHandler) {
8967
9147
  return;
8968
9148
  }
8969
- if (verbose) {
8970
- console.log("[Core] Subscribing to error events...");
8971
- }
8972
- const cleanupSystemError = CoreEventManager.on(core.CORE_EVENTS.SYSTEM.ERROR, (event) => {
9149
+ _Core.log("Subscribing to error events...", verbose);
9150
+ const cleanupSystemError = exports.CoreEventManager.on(core.CORE_EVENTS.SYSTEM.ERROR, (event) => {
8973
9151
  if (_Core._errorHandler && event.data?.errors?.length) {
8974
9152
  for (const err of event.data.errors) {
8975
9153
  _Core._errorHandler.captureError(err, "system");
8976
9154
  }
8977
9155
  }
8978
9156
  });
8979
- const cleanupEntityError = CoreEventManager.on(core.CORE_EVENTS.ENTITY.ERROR, (event) => {
9157
+ const cleanupEntityError = exports.CoreEventManager.on(core.CORE_EVENTS.ENTITY.ERROR, (event) => {
8980
9158
  if (_Core._errorHandler && event.data) {
8981
9159
  _Core._errorHandler.captureError(event.data.error, "entity");
8982
9160
  }
8983
9161
  });
8984
- const cleanupApiError = CoreEventManager.on(core.CORE_EVENTS.API.REQUEST_ERROR, (event) => {
9162
+ const cleanupApiError = exports.CoreEventManager.on(core.CORE_EVENTS.API.REQUEST_ERROR, (event) => {
8985
9163
  if (_Core._errorHandler && event.data) {
8986
9164
  _Core._errorHandler.captureError(event.data.error, "api");
8987
9165
  }
8988
9166
  });
8989
- const cleanupValidationError = CoreEventManager.on(core.CORE_EVENTS.VALIDATION.FAILED, (event) => {
9167
+ const cleanupValidationError = exports.CoreEventManager.on(core.CORE_EVENTS.VALIDATION.FAILED, (event) => {
8990
9168
  if (_Core._errorHandler && event.data) {
8991
9169
  _Core._errorHandler.captureError(event.data.error, "validation");
8992
9170
  }
8993
9171
  });
8994
- const cleanupAuthUnauthorized = CoreEventManager.on(core.CORE_EVENTS.AUTH.UNAUTHORIZED, (event) => {
9172
+ const cleanupAuthUnauthorized = exports.CoreEventManager.on(core.CORE_EVENTS.AUTH.UNAUTHORIZED, (event) => {
8995
9173
  if (_Core._errorHandler && event.data?.error) {
8996
9174
  _Core._errorHandler.captureError(event.data.error, "auth");
8997
9175
  }
8998
9176
  });
8999
- const cleanupAuthSessionExpired = CoreEventManager.on(
9177
+ const cleanupAuthSessionExpired = exports.CoreEventManager.on(
9000
9178
  core.CORE_EVENTS.AUTH.SESSION_EXPIRED,
9001
9179
  (event) => {
9002
9180
  if (_Core._errorHandler && event.data?.error) {
@@ -9013,19 +9191,19 @@ var Core = class _Core {
9013
9191
  cleanupAuthSessionExpired
9014
9192
  );
9015
9193
  if (_Core.isRuntimeCompatible("backend")) {
9016
- const cleanupDatabaseError = CoreEventManager.on(core.CORE_EVENTS.DATABASE.ERROR, (event) => {
9194
+ const cleanupDatabaseError = exports.CoreEventManager.on(core.CORE_EVENTS.DATABASE.ERROR, (event) => {
9017
9195
  if (_Core._errorHandler && event.data) {
9018
9196
  _Core._errorHandler.captureError(event.data.error, "database");
9019
9197
  }
9020
9198
  });
9021
9199
  _Core._eventCleanupFns.push(cleanupDatabaseError);
9022
- const cleanupStorageError = CoreEventManager.on(core.CORE_EVENTS.STORAGE.ERROR, (event) => {
9200
+ const cleanupStorageError = exports.CoreEventManager.on(core.CORE_EVENTS.STORAGE.ERROR, (event) => {
9023
9201
  if (_Core._errorHandler && event.data) {
9024
9202
  _Core._errorHandler.captureError(event.data.error, "storage");
9025
9203
  }
9026
9204
  });
9027
9205
  _Core._eventCleanupFns.push(cleanupStorageError);
9028
- const cleanupNotificationError = CoreEventManager.on(
9206
+ const cleanupNotificationError = exports.CoreEventManager.on(
9029
9207
  core.CORE_EVENTS.NOTIFICATION.ERROR,
9030
9208
  (event) => {
9031
9209
  if (_Core._errorHandler && event.data) {
@@ -9034,21 +9212,17 @@ var Core = class _Core {
9034
9212
  }
9035
9213
  );
9036
9214
  _Core._eventCleanupFns.push(cleanupNotificationError);
9037
- if (verbose) {
9038
- console.log("[Core] Subscribed to backend error events (database, storage, notification)");
9039
- }
9215
+ _Core.log("Subscribed to backend error events (database, storage, notification)", verbose);
9040
9216
  }
9041
- if (verbose) {
9042
- const eventTypes = ["system", "entity", "api", "validation", "auth"];
9043
- if (_Core.isRuntimeCompatible("backend")) {
9044
- eventTypes.push("database", "storage", "notification");
9045
- }
9046
- console.log(`[Core] Subscribed to error events: ${eventTypes.join(", ")}`);
9217
+ const eventTypes = ["system", "entity", "api", "validation", "auth"];
9218
+ if (_Core.isRuntimeCompatible("backend")) {
9219
+ eventTypes.push("database", "storage", "notification");
9047
9220
  }
9221
+ _Core.log(`Subscribed to error events: ${eventTypes.join(", ")}`, verbose);
9048
9222
  }
9049
9223
  /** Handle fetch flags error and return empty flags */
9050
9224
  static handleFetchFlagsError(error, config, verbose) {
9051
- if (verbose) console.error("[Core] Failed to fetch feature flags:", error);
9225
+ if (verbose) _Core.logger.error("Failed to fetch feature flags", { error });
9052
9226
  const packageError = error instanceof errors.BaseError ? error : new errors.CorePackageError(
9053
9227
  error instanceof Error ? error.message : String(error),
9054
9228
  types.ERROR_CODES.CORE_FEATURE_FLAG_PROVIDER_ERROR,
@@ -9081,7 +9255,7 @@ var Core = class _Core {
9081
9255
  */
9082
9256
  static async initializeFeatureFlags(config, verbose) {
9083
9257
  if (config?.enabled === false) {
9084
- if (verbose) console.log("[Core] Feature flags disabled by configuration");
9258
+ _Core.log("Feature flags disabled by configuration", verbose);
9085
9259
  return;
9086
9260
  }
9087
9261
  if (!_Core._rootStore) {
@@ -9091,7 +9265,7 @@ var Core = class _Core {
9091
9265
  );
9092
9266
  }
9093
9267
  _Core._flagConfig = config ?? {};
9094
- if (verbose) console.log("[Core] Initializing feature flags from root store...");
9268
+ _Core.log("Initializing feature flags from root store...", verbose);
9095
9269
  const state = _Core._rootStore.getState();
9096
9270
  await state.featureFlags.initialize({
9097
9271
  defaults: _Core._flagConfig.defaults,
@@ -9100,9 +9274,12 @@ var Core = class _Core {
9100
9274
  onFlagChange: _Core._flagConfig.onFlagChange,
9101
9275
  onError: _Core._flagConfig.onError
9102
9276
  });
9103
- if (verbose) console.log("[Core] Feature flags initialized");
9277
+ _Core.log("Feature flags initialized", verbose);
9104
9278
  }
9105
9279
  };
9280
+
9281
+ // src/entry-frontend.ts
9282
+ init_CoreEventManager();
9106
9283
  var errorContainerStyle = {
9107
9284
  padding: "20px",
9108
9285
  color: "red",
@@ -9146,6 +9323,9 @@ function InitializationLoading({ loading }) {
9146
9323
  return /* @__PURE__ */ jsxRuntime.jsx("div", { style: loadingContainerStyle, children: /* @__PURE__ */ jsxRuntime.jsx("p", { style: loadingMessageStyle, children: "Initializing..." }) });
9147
9324
  }
9148
9325
  __name(InitializationLoading, "InitializationLoading");
9326
+
9327
+ // src/engine/featureFlags/engine.ts
9328
+ init_common();
9149
9329
  var FeatureFlagContextBuilder = class _FeatureFlagContextBuilder {
9150
9330
  constructor() {
9151
9331
  this.context = {};
@@ -10264,11 +10444,19 @@ var ApiFeatureFlagProvider = class extends FeatureFlagProvider {
10264
10444
  return this.engine.getRules();
10265
10445
  }
10266
10446
  };
10447
+ init_DbService();
10448
+
10449
+ // src/models/featureFlags/FeatureFlagRepository.ts
10450
+ init_common();
10451
+ init_DbService();
10267
10452
  ({
10268
10453
  flagsTable: core.FEATURE_FLAG_TABLE.FeatureFlags,
10269
10454
  rulesTable: core.FEATURE_FLAG_TABLE.FeatureFlagRules,
10270
10455
  evaluationsTable: core.FEATURE_FLAG_TABLE.FeatureFlagEvaluations,
10271
10456
  overridesTable: core.FEATURE_FLAG_TABLE.FeatureFlagOverrides});
10457
+
10458
+ // src/domain/featureFlags/FrontendFeatureFlagDomainService.ts
10459
+ init_CoreEventManager();
10272
10460
  var DEFAULT_CACHE_TTL_SECONDS2 = 300;
10273
10461
  var DEFAULT_REFRESH_INTERVAL_MS = 6e4;
10274
10462
  var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService extends BaseFrontendDomainService {
@@ -10289,7 +10477,7 @@ var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService e
10289
10477
  this.provider = config.provider;
10290
10478
  this._initialized = true;
10291
10479
  this.logInfo("Service initialized", { storeCount: this.connectedStoreCount });
10292
- CoreEventManager.emit("featureFlag:provider:initialized", { providerType: "api" });
10480
+ exports.CoreEventManager.emit("featureFlag:provider:initialized", { providerType: "api" });
10293
10481
  }
10294
10482
  static {
10295
10483
  __name(this, "FrontendFeatureFlagDomainService");
@@ -10344,7 +10532,7 @@ var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService e
10344
10532
  }
10345
10533
  dispose() {
10346
10534
  this.provider?.dispose();
10347
- CoreEventManager.emit("featureFlag:provider:disposed", {});
10535
+ exports.CoreEventManager.emit("featureFlag:provider:disposed", {});
10348
10536
  this.logInfo("Service disposed");
10349
10537
  }
10350
10538
  // ─────────────────────────────────────────────────────────────────────────
@@ -10355,7 +10543,7 @@ var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService e
10355
10543
  this.setStoresLoading(true);
10356
10544
  try {
10357
10545
  await this.provider.refresh();
10358
- CoreEventManager.emit("featureFlag:provider:refreshed", {});
10546
+ exports.CoreEventManager.emit("featureFlag:provider:refreshed", {});
10359
10547
  if (this.hasConnectedStores) {
10360
10548
  const evaluations = await this.provider.getAllFlags(this.config.defaultContext);
10361
10549
  this.syncToStores(this.toValues(evaluations));
@@ -10371,16 +10559,16 @@ var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService e
10371
10559
  async evaluate(key, context) {
10372
10560
  this.assertReady();
10373
10561
  const ctx = context ?? this.config.defaultContext;
10374
- CoreEventManager.emit("featureFlag:evaluating", { key, context: ctx });
10562
+ exports.CoreEventManager.emit("featureFlag:evaluating", { key, context: ctx });
10375
10563
  try {
10376
10564
  const result = await this.provider.getFlag(key, ctx);
10377
- CoreEventManager.emit("featureFlag:evaluated", { key, result });
10565
+ exports.CoreEventManager.emit("featureFlag:evaluated", { key, result });
10378
10566
  if (this.hasConnectedStores) {
10379
10567
  this.syncToStores({ [key]: result.value });
10380
10568
  }
10381
10569
  return result;
10382
10570
  } catch (error) {
10383
- CoreEventManager.emit("featureFlag:evaluate:error", { key, error });
10571
+ exports.CoreEventManager.emit("featureFlag:evaluate:error", { key, error });
10384
10572
  throw error;
10385
10573
  }
10386
10574
  }
@@ -10417,49 +10605,49 @@ var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService e
10417
10605
  // ─────────────────────────────────────────────────────────────────────────
10418
10606
  async createFlag(data) {
10419
10607
  this.assertReady();
10420
- CoreEventManager.emit("featureFlag:creating", { data });
10608
+ exports.CoreEventManager.emit("featureFlag:creating", { data });
10421
10609
  try {
10422
10610
  const flag = await this.provider.createFlag(data);
10423
- CoreEventManager.emit("featureFlag:created", { flag });
10611
+ exports.CoreEventManager.emit("featureFlag:created", { flag });
10424
10612
  this.logInfo("Flag created", { key: data.key });
10425
10613
  if (this.hasConnectedStores) {
10426
10614
  this.syncToStores({ [data.key]: flag.value });
10427
10615
  }
10428
10616
  return flag;
10429
10617
  } catch (error) {
10430
- CoreEventManager.emit("featureFlag:create:error", { error, data });
10618
+ exports.CoreEventManager.emit("featureFlag:create:error", { error, data });
10431
10619
  throw error;
10432
10620
  }
10433
10621
  }
10434
10622
  async updateFlag(key, data) {
10435
10623
  this.assertReady();
10436
- CoreEventManager.emit("featureFlag:updating", { key, data });
10624
+ exports.CoreEventManager.emit("featureFlag:updating", { key, data });
10437
10625
  try {
10438
10626
  const flag = await this.provider.updateFlag(key, data);
10439
- CoreEventManager.emit("featureFlag:updated", { flag });
10627
+ exports.CoreEventManager.emit("featureFlag:updated", { flag });
10440
10628
  this.logInfo("Flag updated", { key });
10441
10629
  if (this.hasConnectedStores) {
10442
10630
  this.syncToStores({ [key]: flag.value });
10443
10631
  }
10444
10632
  return flag;
10445
10633
  } catch (error) {
10446
- CoreEventManager.emit("featureFlag:update:error", { error, key });
10634
+ exports.CoreEventManager.emit("featureFlag:update:error", { error, key });
10447
10635
  throw error;
10448
10636
  }
10449
10637
  }
10450
10638
  async deleteFlag(key) {
10451
10639
  this.assertReady();
10452
- CoreEventManager.emit("featureFlag:deleting", { key });
10640
+ exports.CoreEventManager.emit("featureFlag:deleting", { key });
10453
10641
  try {
10454
10642
  await this.provider.deleteFlag(key);
10455
- CoreEventManager.emit("featureFlag:deleted", { key });
10643
+ exports.CoreEventManager.emit("featureFlag:deleted", { key });
10456
10644
  this.logInfo("Flag deleted", { key });
10457
10645
  if (this.hasConnectedStores) {
10458
10646
  const evaluations = await this.provider.getAllFlags(this.config.defaultContext);
10459
10647
  this.syncToStores(this.toValues(evaluations), true);
10460
10648
  }
10461
10649
  } catch (error) {
10462
- CoreEventManager.emit("featureFlag:delete:error", { error, key });
10650
+ exports.CoreEventManager.emit("featureFlag:delete:error", { error, key });
10463
10651
  throw error;
10464
10652
  }
10465
10653
  }
@@ -10479,15 +10667,15 @@ var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService e
10479
10667
  // ─────────────────────────────────────────────────────────────────────────
10480
10668
  setOverride(key, value) {
10481
10669
  this.assertReady();
10482
- CoreEventManager.emit("featureFlag:override:setting", { key, value });
10670
+ exports.CoreEventManager.emit("featureFlag:override:setting", { key, value });
10483
10671
  this.provider.setOverride(key, value);
10484
- CoreEventManager.emit("featureFlag:override:set", { key, value });
10672
+ exports.CoreEventManager.emit("featureFlag:override:set", { key, value });
10485
10673
  }
10486
10674
  removeOverride(key) {
10487
10675
  this.assertReady();
10488
- CoreEventManager.emit("featureFlag:override:removing", { key });
10676
+ exports.CoreEventManager.emit("featureFlag:override:removing", { key });
10489
10677
  this.provider.removeOverride(key);
10490
- CoreEventManager.emit("featureFlag:override:removed", { key });
10678
+ exports.CoreEventManager.emit("featureFlag:override:removed", { key });
10491
10679
  }
10492
10680
  clearOverrides() {
10493
10681
  this.assertReady();
@@ -10501,7 +10689,7 @@ var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService e
10501
10689
  return this.provider.subscribe(callback);
10502
10690
  }
10503
10691
  on(event, handler) {
10504
- return CoreEventManager.on(event, handler);
10692
+ return exports.CoreEventManager.on(event, handler);
10505
10693
  }
10506
10694
  // ─────────────────────────────────────────────────────────────────────────
10507
10695
  // Protected: Store Sync Override
@@ -10747,6 +10935,7 @@ function ApiProvider({
10747
10935
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
10748
10936
  }
10749
10937
  __name(ApiProvider, "ApiProvider");
10938
+ init_CoreEventManager();
10750
10939
  var PlyazContext = react.createContext(null);
10751
10940
  var FeatureFlagStore = class {
10752
10941
  constructor(config = {}) {
@@ -10858,7 +11047,7 @@ __name(initializeFeatureFlags, "initializeFeatureFlags");
10858
11047
  function createServicesObject(config, featureFlagStore) {
10859
11048
  return {
10860
11049
  api: ApiClientService,
10861
- events: CoreEventManager,
11050
+ events: exports.CoreEventManager,
10862
11051
  core: Core,
10863
11052
  featureFlags: {
10864
11053
  get: /* @__PURE__ */ __name((key, def) => featureFlagStore.get(key, def), "get"),
@@ -10917,7 +11106,7 @@ function PlyazProvider({
10917
11106
  const contextValue = react.useMemo(
10918
11107
  () => ({
10919
11108
  api: isReady ? ApiClientService : null,
10920
- events: CoreEventManager,
11109
+ events: exports.CoreEventManager,
10921
11110
  core: Core,
10922
11111
  featureFlags: {
10923
11112
  get: /* @__PURE__ */ __name((key, def) => featureFlagStore.get(key, def), "get"),
@@ -11114,7 +11303,6 @@ exports.BaseFrontendDomainService = BaseFrontendDomainService;
11114
11303
  exports.BaseMapper = BaseMapper;
11115
11304
  exports.BaseValidator = BaseValidator;
11116
11305
  exports.Core = Core;
11117
- exports.CoreEventManager = CoreEventManager;
11118
11306
  exports.FrontendExampleDomainService = FrontendExampleDomainService;
11119
11307
  exports.FrontendFeatureFlagDomainService = FrontendFeatureFlagDomainService;
11120
11308
  exports.InitializationError = InitializationError;