@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,17 +1,17 @@
1
- import { CoreLogger, PackageLogger } from '@plyaz/logger';
2
- import { createDatabaseService, BaseRepository } from '@plyaz/db';
3
- import { DatabasePackageError, generateRequestId, CorePackageError, StoragePackageError, NotificationPackageError, BaseError, ValidateAndFormatErrors, ValidationError, initializeErrorSystem } from '@plyaz/errors';
4
- import { DATABASE_ERROR_CODES, ERROR_CODES as ERROR_CODES$1, STORAGE_ERROR_CODES, NOTIFICATION_ERROR_CODES, API_ERROR_CODES as API_ERROR_CODES$1 } from '@plyaz/types/errors';
5
- import { CORE_EVENTS, SERVICE_KEYS, FEATURE_FLAG_TABLE } from '@plyaz/types/core';
6
- import { EventEmitter } from 'events';
7
1
  import { CACHE_MAX_SIZE_DEFAULT, CACHE_CLEANUP_INTERVAL_DEFAULT, TIME_CONSTANTS, HTTP_STATUS as HTTP_STATUS$1, DEVELOPMENT_CONFIG, STAGING_CONFIG, PRODUCTION_CONFIG, MATH_CONSTANTS, ISO_STANDARDS, FNV_CONSTANTS } from '@plyaz/config';
8
- import { HTTP_STATUS, ERROR_CATEGORY, ERROR_CODES, CORE_EVENTS as CORE_EVENTS$1, PACKAGE_STATUS_CODES, API_ERROR_CODES, OPERATIONS, BACKEND_RUNTIMES, FRONTEND_RUNTIMES } from '@plyaz/types';
2
+ import { HTTP_STATUS, ERROR_CATEGORY, ERROR_CODES, CORE_EVENTS, PACKAGE_STATUS_CODES, API_ERROR_CODES, OPERATIONS, BACKEND_RUNTIMES, FRONTEND_RUNTIMES } from '@plyaz/types';
3
+ import { EventEmitter } from 'events';
4
+ import { BaseRepository, createDatabaseService } from '@plyaz/db';
5
+ import { generateRequestId, CorePackageError, BaseError, ValidateAndFormatErrors, ValidationError, DatabasePackageError, initializeErrorSystem, StoragePackageError, NotificationPackageError } from '@plyaz/errors';
6
+ import { ERROR_CODES as ERROR_CODES$1, API_ERROR_CODES as API_ERROR_CODES$1, DATABASE_ERROR_CODES, STORAGE_ERROR_CODES, NOTIFICATION_ERROR_CODES } from '@plyaz/types/errors';
7
+ import { SERVICE_KEYS, CORE_EVENTS as CORE_EVENTS$1, FEATURE_FLAG_TABLE } from '@plyaz/types/core';
8
+ import { StorageService as StorageService$1 } from '@plyaz/storage';
9
+ import { NotificationService as NotificationService$1 } from '@plyaz/notifications';
10
+ import { CoreLogger, PackageLogger } from '@plyaz/logger';
9
11
  import { mergeConfigs, createApiClient, ApiPackageError, setDefaultApiClient, evaluateAllFeatureFlags, createFeatureFlag, updateFeatureFlag, deleteFeatureFlag, fetchFeatureFlagRules, ApiProvider as ApiProvider$1 } from '@plyaz/api';
10
12
  import { Injectable } from '@nestjs/common';
11
13
  import { of, tap } from 'rxjs';
12
14
  import { CACHE_STRATEGIES } from '@plyaz/types/features';
13
- import { StorageService as StorageService$1 } from '@plyaz/storage';
14
- import { NotificationService as NotificationService$1 } from '@plyaz/notifications';
15
15
  import { STORE_KEYS, useRootStore, createStandaloneFeatureFlagStore } from '@plyaz/store';
16
16
  import { OBSERVABILITY_METRICS } from '@plyaz/types/observability';
17
17
  import { QueryExampleSchema, DeleteExampleSchema, PatchExampleSchema, UpdateExampleSchema, CreateExampleSchema } from '@plyaz/types/examples';
@@ -28,7 +28,15 @@ import { createEncryptionConfig } from '@plyaz/config/api';
28
28
  // @plyaz package - Built with tsup
29
29
  var __defProp = Object.defineProperty;
30
30
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
31
+ var __getOwnPropNames = Object.getOwnPropertyNames;
31
32
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
33
+ var __esm = (fn, res) => function __init() {
34
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
35
+ };
36
+ var __export = (target, all) => {
37
+ for (var name in all)
38
+ __defProp(target, name, { get: all[name], enumerable: true });
39
+ };
32
40
  var __decorateClass = (decorators, target, key, kind) => {
33
41
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
34
42
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
@@ -45,29 +53,26 @@ function hashString(str) {
45
53
  }
46
54
  return hash >>> 0;
47
55
  }
48
- __name(hashString, "hashString");
49
56
  function isInRollout(identifier, percentage) {
50
57
  if (percentage >= MATH_CONSTANTS.PERCENTAGE_MAX) return true;
51
58
  if (percentage <= 0) return false;
52
59
  const hash = hashString(identifier);
53
60
  return hash % MATH_CONSTANTS.PERCENTAGE_MAX < percentage;
54
61
  }
55
- __name(isInRollout, "isInRollout");
56
62
  function createRolloutIdentifier(featureKey, userId) {
57
63
  const trimmedUserId = userId?.trim();
58
64
  const effectiveUserId = trimmedUserId && trimmedUserId.length > 0 ? trimmedUserId : "anonymous";
59
65
  return `${featureKey}:${effectiveUserId}`;
60
66
  }
61
- __name(createRolloutIdentifier, "createRolloutIdentifier");
67
+ var init_hash = __esm({
68
+ "src/utils/common/hash.ts"() {
69
+ __name(hashString, "hashString");
70
+ __name(isInRollout, "isInRollout");
71
+ __name(createRolloutIdentifier, "createRolloutIdentifier");
72
+ }
73
+ });
62
74
 
63
75
  // src/utils/common/id.ts
64
- var RANDOM_ID_RADIX = 36;
65
- var RANDOM_ID_SLICE_START = 2;
66
- var SHORT_ID_LENGTH = 8;
67
- var HEX_RADIX = 16;
68
- var HEX_SLICE_START = 2;
69
- var HEX_SLICE_END = 18;
70
- var SPAN_ID_LENGTH = 16;
71
76
  function generateId() {
72
77
  const cryptoApi = globalThis.crypto;
73
78
  if (cryptoApi?.randomUUID) {
@@ -75,7 +80,6 @@ function generateId() {
75
80
  }
76
81
  return `${Date.now()}-${Math.random().toString(RANDOM_ID_RADIX).slice(RANDOM_ID_SLICE_START)}`;
77
82
  }
78
- __name(generateId, "generateId");
79
83
  function generateShortId() {
80
84
  const cryptoApi = globalThis.crypto;
81
85
  if (cryptoApi?.randomUUID) {
@@ -83,11 +87,9 @@ function generateShortId() {
83
87
  }
84
88
  return Math.random().toString(RANDOM_ID_RADIX).slice(RANDOM_ID_SLICE_START, RANDOM_ID_SLICE_START + SHORT_ID_LENGTH);
85
89
  }
86
- __name(generateShortId, "generateShortId");
87
90
  function generateCorrelationId() {
88
91
  return `${Date.now()}-${generateShortId()}`;
89
92
  }
90
- __name(generateCorrelationId, "generateCorrelationId");
91
93
  function generateTraceId() {
92
94
  const cryptoApi = globalThis.crypto;
93
95
  if (cryptoApi?.randomUUID) {
@@ -95,7 +97,6 @@ function generateTraceId() {
95
97
  }
96
98
  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);
97
99
  }
98
- __name(generateTraceId, "generateTraceId");
99
100
  function generateSpanId() {
100
101
  const cryptoApi = globalThis.crypto;
101
102
  if (cryptoApi?.randomUUID) {
@@ -103,20 +104,34 @@ function generateSpanId() {
103
104
  }
104
105
  return Math.random().toString(HEX_RADIX).substring(HEX_SLICE_START, HEX_SLICE_END);
105
106
  }
106
- __name(generateSpanId, "generateSpanId");
107
+ var RANDOM_ID_RADIX, RANDOM_ID_SLICE_START, SHORT_ID_LENGTH, HEX_RADIX, HEX_SLICE_START, HEX_SLICE_END, SPAN_ID_LENGTH;
108
+ var init_id = __esm({
109
+ "src/utils/common/id.ts"() {
110
+ RANDOM_ID_RADIX = 36;
111
+ RANDOM_ID_SLICE_START = 2;
112
+ SHORT_ID_LENGTH = 8;
113
+ HEX_RADIX = 16;
114
+ HEX_SLICE_START = 2;
115
+ HEX_SLICE_END = 18;
116
+ SPAN_ID_LENGTH = 16;
117
+ __name(generateId, "generateId");
118
+ __name(generateShortId, "generateShortId");
119
+ __name(generateCorrelationId, "generateCorrelationId");
120
+ __name(generateTraceId, "generateTraceId");
121
+ __name(generateSpanId, "generateSpanId");
122
+ }
123
+ });
107
124
  function isStringFalsy(value) {
108
125
  if (value === "") return true;
109
126
  const lower = value.toLowerCase().trim();
110
127
  return ["false", "no", "0", "off", "disabled"].includes(lower);
111
128
  }
112
- __name(isStringFalsy, "isStringFalsy");
113
129
  function isObjectTruthy(value) {
114
130
  if (Array.isArray(value)) return value.length > 0;
115
131
  if (value instanceof Map || value instanceof Set) return value.size > 0;
116
132
  if (value.constructor === Object) return Object.keys(value).length > 0;
117
133
  return true;
118
134
  }
119
- __name(isObjectTruthy, "isObjectTruthy");
120
135
  function isTruthy(value) {
121
136
  if (value === null || value === void 0) return false;
122
137
  switch (typeof value) {
@@ -135,747 +150,1215 @@ function isTruthy(value) {
135
150
  return false;
136
151
  }
137
152
  }
138
- __name(isTruthy, "isTruthy");
139
-
140
- // src/events/CoreEventManager.ts
141
- var MAX_EVENT_LISTENERS = 100;
142
- var CoreEventManagerClass = class {
143
- constructor() {
144
- this.emitter = new EventEmitter();
145
- this.subscriptions = /* @__PURE__ */ new Map();
146
- this.emitter.setMaxListeners(MAX_EVENT_LISTENERS);
147
- }
148
- static {
149
- __name(this, "CoreEventManagerClass");
150
- }
151
- emit(eventType, data) {
152
- const [scope] = eventType.split(":");
153
- const event = {
154
- type: eventType,
155
- scope: scope ?? "system",
156
- timestamp: Date.now(),
157
- correlationId: this.getCorrelationId(),
158
- data
159
- };
160
- this.emitter.emit(eventType, event);
161
- this.emitter.emit("*", event);
162
- return true;
163
- }
164
- on(eventType, handler) {
165
- this.emitter.on(eventType, handler);
166
- if (!this.subscriptions.has(eventType)) {
167
- this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
168
- }
169
- this.subscriptions.get(eventType).add(handler);
170
- return () => {
171
- this.emitter.off(eventType, handler);
172
- this.subscriptions.get(eventType)?.delete(handler);
173
- };
174
- }
175
- once(eventType, handler) {
176
- const wrappedHandler = /* @__PURE__ */ __name((event) => {
177
- handler(event);
178
- this.emitter.off(eventType, wrappedHandler);
179
- this.subscriptions.get(eventType)?.delete(wrappedHandler);
180
- }, "wrappedHandler");
181
- this.emitter.on(eventType, wrappedHandler);
182
- if (!this.subscriptions.has(eventType)) {
183
- this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
184
- }
185
- this.subscriptions.get(eventType).add(wrappedHandler);
186
- return () => {
187
- this.emitter.off(eventType, wrappedHandler);
188
- this.subscriptions.get(eventType)?.delete(wrappedHandler);
189
- };
190
- }
191
- /**
192
- * Subscribe to all events in a scope
193
- *
194
- * @param scope - Event scope to listen to (e.g., CoreEventScope.AUTH)
195
- * @param handler - Event handler
196
- * @returns Unsubscribe function
197
- *
198
- * @example
199
- * ```typescript
200
- * CoreEventManager.onScope(CoreEventScope.AUTH, (event) => {
201
- * // Handles auth:login, auth:logout, auth:tokenRefresh, etc.
202
- * console.log(`Auth event: ${event.type}`, event.data);
203
- * });
204
- * ```
205
- */
206
- onScope(scope, handler) {
207
- const wrappedHandler = /* @__PURE__ */ __name((event) => {
208
- if (event.scope === scope) {
209
- handler(event);
210
- }
211
- }, "wrappedHandler");
212
- return this.on("*", wrappedHandler);
213
- }
214
- /**
215
- * Remove a specific handler from an event
216
- *
217
- * @param eventType - Event type
218
- * @param handler - Handler to remove
219
- */
220
- off(eventType, handler) {
221
- this.emitter.off(eventType, handler);
222
- this.subscriptions.get(eventType)?.delete(handler);
223
- }
224
- /**
225
- * Dispose all subscriptions
226
- */
227
- dispose() {
228
- this.subscriptions.forEach((handlers, eventType) => {
229
- handlers.forEach((handler) => this.emitter.off(eventType, handler));
230
- });
231
- this.subscriptions.clear();
232
- this.emitter.removeAllListeners();
153
+ var init_values = __esm({
154
+ "src/utils/common/values.ts"() {
155
+ __name(isStringFalsy, "isStringFalsy");
156
+ __name(isObjectTruthy, "isObjectTruthy");
157
+ __name(isTruthy, "isTruthy");
233
158
  }
234
- /**
235
- * Generate correlation ID for event tracing
236
- */
237
- getCorrelationId() {
238
- return generateCorrelationId();
239
- }
240
- };
241
- var CoreEventManager = new CoreEventManagerClass();
159
+ });
242
160
 
243
- // src/services/DbService.ts
244
- var DEFAULT_ENCRYPTION_FIELDS = {
245
- // User PII
246
- users: ["password_hash", "phone_number", "date_of_birth"],
247
- // KYC sensitive data
248
- "backoffice.kyc_submissions": ["tax_id", "address_line1", "address_line2"],
249
- // Connected accounts OAuth tokens
250
- connected_accounts: ["access_token_encrypted", "refresh_token_encrypted", "wallet_address"],
251
- // Payment payout accounts
252
- user_payout_accounts: ["provider_account_id", "account_holder_name"],
253
- // Sessions
254
- sessions: ["token"]
255
- };
256
- var DEFAULT_CACHE_TTL_SECONDS = 300;
257
- var DEFAULT_AUDIT_RETENTION_DAYS = 180;
258
- var DEFAULT_POOL_SIZE = 10;
259
- var DEFAULT_CONFIG = {
260
- adapter: "sql",
261
- cache: {
262
- enabled: true,
263
- provider: "memory",
264
- ttl: DEFAULT_CACHE_TTL_SECONDS
265
- },
266
- softDelete: {
267
- enabled: true,
268
- field: "deleted_at",
269
- excludeTables: [
270
- "audit_logs",
271
- "audit.audit_logs",
272
- "audit.feature_flag_evaluations",
273
- "feature_flag_evaluations",
274
- "notification_events",
275
- "payments_activity",
276
- "campaign_analytics",
277
- "admin_actions",
278
- "backoffice.admin_actions"
279
- ]
280
- },
281
- audit: {
282
- enabled: true,
283
- // Enabled by default for compliance
284
- retentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
285
- excludeFields: ["password_hash", "api_key_hash", "token_hash"],
286
- excludeTables: ["audit_logs", "audit.audit_logs"],
287
- // Don't audit the audit table itself
288
- schema: "audit",
289
- // Use dedicated audit schema
290
- usePartitionedTables: true
291
- // Use daily partitioned tables (audit_log_yyyy_mm_dd)
292
- }
293
- // NOTE: Encryption requires key from environment or DbService.initialize()
294
- // Enable via: DbService.initialize({ encryption: { enabled: true, key: process.env.ENCRYPTION_KEY!, fields: DEFAULT_ENCRYPTION_FIELDS } })
295
- };
296
- var TABLE_REGISTRY = {
297
- // Migration 008: Feature Flags (custom ID column 'key')
298
- feature_flags: { idColumn: "key" },
299
- // Test Feature Flags (custom ID column 'key')
300
- test_feature_flags: { idColumn: "key" },
301
- // Migration 010: Universal Analytics (custom ID column 'user_id')
302
- user_analytics_summary: { idColumn: "user_id" }
303
- };
304
- var DbService = class _DbService {
305
- constructor() {
306
- this.databaseService = null;
307
- this.namedAdapters = /* @__PURE__ */ new Map();
308
- this.config = null;
309
- this.initialized = false;
310
- }
311
- static {
312
- __name(this, "DbService");
161
+ // src/utils/common/object.ts
162
+ var init_object = __esm({
163
+ "src/utils/common/object.ts"() {
313
164
  }
314
- static {
315
- this.instance = null;
316
- }
317
- /**
318
- * Emits a database error event via CoreEventManager.
319
- * Called when database operations fail to integrate with global error handling.
320
- *
321
- * @param error - The error that occurred
322
- * @param operation - The operation that failed (e.g., 'transaction', 'query', 'healthCheck')
323
- * @param table - Optional table name involved in the operation
324
- * @param query - Optional query string that failed
325
- * @param recoverable - Whether the error is recoverable (default: false)
326
- */
327
- emitDatabaseError(error, operation, options) {
328
- const payload = {
329
- error,
330
- operation,
331
- table: options?.table,
332
- query: options?.query,
333
- recoverable: options?.recoverable ?? false
334
- };
335
- CoreEventManager.emit(CORE_EVENTS.DATABASE.ERROR, payload);
336
- }
337
- /**
338
- * Gets the singleton instance of DbService
339
- *
340
- * @returns {DbService} The singleton instance
341
- */
342
- static getInstance() {
343
- _DbService.instance ??= new _DbService();
344
- return _DbService.instance;
165
+ });
166
+ var init_validation = __esm({
167
+ "src/utils/common/validation.ts"() {
345
168
  }
346
- /**
347
- * Checks if the database service has been initialized
348
- *
349
- * @returns {boolean} True if initialized
350
- */
351
- static isInitialized() {
352
- return _DbService.instance?.initialized ?? false;
169
+ });
170
+
171
+ // src/utils/common/index.ts
172
+ var init_common = __esm({
173
+ "src/utils/common/index.ts"() {
174
+ init_hash();
175
+ init_id();
176
+ init_values();
177
+ init_object();
178
+ init_validation();
353
179
  }
354
- /**
355
- * Resets the database service by closing connections and clearing the singleton instance
356
- *
357
- * @description Properly closes the database connection and clears the singleton.
358
- * Useful for testing or when you need to reinitialize with different configuration.
359
- *
360
- * @example
361
- * ```typescript
362
- * await DbService.reset();
363
- * await DbService.initialize({ adapter: 'sql', ... });
364
- * ```
365
- */
366
- static async reset() {
367
- if (_DbService.instance) {
368
- try {
369
- await _DbService.instance.databaseService?.close?.();
370
- } catch {
180
+ });
181
+ var MAX_EVENT_LISTENERS, CoreEventManagerClass, CoreEventManager;
182
+ var init_CoreEventManager = __esm({
183
+ "src/events/CoreEventManager.ts"() {
184
+ init_common();
185
+ MAX_EVENT_LISTENERS = 100;
186
+ CoreEventManagerClass = class {
187
+ constructor() {
188
+ this.emitter = new EventEmitter();
189
+ this.subscriptions = /* @__PURE__ */ new Map();
190
+ this.emitter.setMaxListeners(MAX_EVENT_LISTENERS);
191
+ }
192
+ static {
193
+ __name(this, "CoreEventManagerClass");
194
+ }
195
+ emit(eventType, data) {
196
+ const [scope] = eventType.split(":");
197
+ const event = {
198
+ type: eventType,
199
+ scope: scope ?? "system",
200
+ timestamp: Date.now(),
201
+ correlationId: this.getCorrelationId(),
202
+ data
203
+ };
204
+ this.emitter.emit(eventType, event);
205
+ this.emitter.emit("*", event);
206
+ return true;
207
+ }
208
+ on(eventType, handler) {
209
+ this.emitter.on(eventType, handler);
210
+ if (!this.subscriptions.has(eventType)) {
211
+ this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
212
+ }
213
+ this.subscriptions.get(eventType).add(handler);
214
+ return () => {
215
+ this.emitter.off(eventType, handler);
216
+ this.subscriptions.get(eventType)?.delete(handler);
217
+ };
218
+ }
219
+ once(eventType, handler) {
220
+ const wrappedHandler = /* @__PURE__ */ __name((event) => {
221
+ handler(event);
222
+ this.emitter.off(eventType, wrappedHandler);
223
+ this.subscriptions.get(eventType)?.delete(wrappedHandler);
224
+ }, "wrappedHandler");
225
+ this.emitter.on(eventType, wrappedHandler);
226
+ if (!this.subscriptions.has(eventType)) {
227
+ this.subscriptions.set(eventType, /* @__PURE__ */ new Set());
228
+ }
229
+ this.subscriptions.get(eventType).add(wrappedHandler);
230
+ return () => {
231
+ this.emitter.off(eventType, wrappedHandler);
232
+ this.subscriptions.get(eventType)?.delete(wrappedHandler);
233
+ };
234
+ }
235
+ /**
236
+ * Subscribe to all events in a scope
237
+ *
238
+ * @param scope - Event scope to listen to (e.g., CoreEventScope.AUTH)
239
+ * @param handler - Event handler
240
+ * @returns Unsubscribe function
241
+ *
242
+ * @example
243
+ * ```typescript
244
+ * CoreEventManager.onScope(CoreEventScope.AUTH, (event) => {
245
+ * // Handles auth:login, auth:logout, auth:tokenRefresh, etc.
246
+ * console.log(`Auth event: ${event.type}`, event.data);
247
+ * });
248
+ * ```
249
+ */
250
+ onScope(scope, handler) {
251
+ const wrappedHandler = /* @__PURE__ */ __name((event) => {
252
+ if (event.scope === scope) {
253
+ handler(event);
254
+ }
255
+ }, "wrappedHandler");
256
+ return this.on("*", wrappedHandler);
257
+ }
258
+ /**
259
+ * Remove a specific handler from an event
260
+ *
261
+ * @param eventType - Event type
262
+ * @param handler - Handler to remove
263
+ */
264
+ off(eventType, handler) {
265
+ this.emitter.off(eventType, handler);
266
+ this.subscriptions.get(eventType)?.delete(handler);
267
+ }
268
+ /**
269
+ * Dispose all subscriptions
270
+ */
271
+ dispose() {
272
+ this.subscriptions.forEach((handlers, eventType) => {
273
+ handlers.forEach((handler) => this.emitter.off(eventType, handler));
274
+ });
275
+ this.subscriptions.clear();
276
+ this.emitter.removeAllListeners();
277
+ }
278
+ /**
279
+ * Generate correlation ID for event tracing
280
+ */
281
+ getCorrelationId() {
282
+ return generateCorrelationId();
371
283
  }
372
- _DbService.instance = null;
373
- }
374
- }
375
- /**
376
- * Initializes the database connection
377
- *
378
- * @description Sets up the database connection using the provided configuration
379
- * or environment variables. This method is idempotent - calling it multiple
380
- * times won't create additional connections.
381
- *
382
- * **Environment Variables:**
383
- * - `DATABASE_URL` - PostgreSQL connection string (for sql/drizzle adapters)
384
- * - `ENCRYPTION_KEY` - 32-byte encryption key for field encryption (optional)
385
- * - `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `SUPABASE_ANON_PUBLIC_KEY` - For supabase adapter
386
- *
387
- * **Encryption:** If `ENCRYPTION_KEY` env is set, encryption is auto-enabled
388
- * using `DEFAULT_ENCRYPTION_FIELDS`. Override via config.encryption.
389
- *
390
- * @param {DbServiceConfig} [config] - Optional configuration
391
- * @returns {Promise<DbService>} The initialized DbService instance
392
- * @throws {DatabasePackageError} When configuration is invalid or connection fails
393
- *
394
- * @example
395
- * ```typescript
396
- * // Minimal - uses DATABASE_URL env, auto-enables encryption if ENCRYPTION_KEY set
397
- * await DbService.initialize();
398
- *
399
- * // With explicit encryption
400
- * await DbService.initialize({
401
- * adapter: 'sql',
402
- * encryption: {
403
- * enabled: true,
404
- * key: 'your-32-byte-encryption-key-here!!',
405
- * fields: DEFAULT_ENCRYPTION_FIELDS,
406
- * },
407
- * });
408
- *
409
- * // Or via Core.initialize() with env:
410
- * await Core.initialize({
411
- * env: { ENCRYPTION_KEY: '...' },
412
- * db: { adapter: 'sql' },
413
- * });
414
- * ```
415
- */
416
- /** Build encryption config from user config */
417
- static buildEncryptionConfig(config) {
418
- const encryption = config?.encryption;
419
- if (!encryption?.key) return void 0;
420
- return {
421
- enabled: encryption.enabled ?? true,
422
- key: encryption.key,
423
- fields: encryption.fields ?? DEFAULT_ENCRYPTION_FIELDS,
424
- algorithm: encryption.algorithm ?? "aes-256-gcm"
425
- };
426
- }
427
- /** Merge user config with defaults */
428
- static mergeConfig(config) {
429
- return {
430
- ...DEFAULT_CONFIG,
431
- ...config,
432
- softDelete: { ...DEFAULT_CONFIG.softDelete, ...config?.softDelete },
433
- cache: { ...DEFAULT_CONFIG.cache, ...config?.cache },
434
- audit: { ...DEFAULT_CONFIG.audit, ...config?.audit },
435
- encryption: _DbService.buildEncryptionConfig(config)
436
- };
437
- }
438
- /** Initialize named adapters */
439
- async initializeNamedAdapters(mergedConfig) {
440
- if (!mergedConfig.adapters) return;
441
- for (const [name, adapterConfig] of Object.entries(mergedConfig.adapters)) {
442
- const namedDbConfig = this.buildDatabaseConfig({
443
- ...mergedConfig,
444
- adapter: adapterConfig.adapter,
445
- drizzle: adapterConfig.drizzle,
446
- supabase: adapterConfig.supabase,
447
- sql: adapterConfig.sql
448
- });
449
- const namedService = await createDatabaseService(namedDbConfig);
450
- this.namedAdapters.set(name, namedService);
451
- }
452
- }
453
- static async initialize(config) {
454
- const instance = _DbService.getInstance();
455
- if (instance.initialized) {
456
- return instance;
457
- }
458
- const mergedConfig = _DbService.mergeConfig(config);
459
- instance.config = mergedConfig;
460
- const dbConfig = instance.buildDatabaseConfig(mergedConfig);
461
- instance.databaseService = await createDatabaseService(dbConfig);
462
- await instance.initializeNamedAdapters(mergedConfig);
463
- instance.initialized = true;
464
- return instance;
465
- }
466
- /**
467
- * Builds the DatabaseServiceConfig based on the adapter type
468
- * @private
469
- */
470
- /** Builds adapter-specific config based on adapter type */
471
- buildAdapterConfig(adapter, config) {
472
- const builders = {
473
- drizzle: /* @__PURE__ */ __name(() => this.buildDrizzleConfig(config), "drizzle"),
474
- supabase: /* @__PURE__ */ __name(() => this.buildSupabaseConfig(config), "supabase"),
475
- sql: /* @__PURE__ */ __name(() => this.buildSqlConfig(config), "sql")
476
- };
477
- const builder = builders[adapter];
478
- if (!builder) {
479
- throw new DatabasePackageError(
480
- `Unsupported adapter type: ${adapter}`,
481
- DATABASE_ERROR_CODES.CONFIG_REQUIRED
482
- );
483
- }
484
- return builder();
485
- }
486
- /** Builds soft delete extension config */
487
- buildSoftDeleteExtension(config) {
488
- if (!config.softDelete?.enabled) return void 0;
489
- return {
490
- enabled: true,
491
- field: config.softDelete.field ?? "deleted_at",
492
- excludeTables: config.softDelete.excludeTables
493
- };
494
- }
495
- /** Builds cache extension config */
496
- buildCacheExtension(config) {
497
- if (!config.cache?.enabled) return void 0;
498
- return {
499
- enabled: true,
500
- ttl: config.cache.ttl ?? DEFAULT_CACHE_TTL_SECONDS,
501
- provider: config.cache.provider ?? "memory",
502
- invalidation: config.cache.invalidation ?? "write"
503
- };
504
- }
505
- /** Builds audit extension config */
506
- buildAuditExtension(config) {
507
- if (!config.audit?.enabled) return void 0;
508
- return {
509
- enabled: true,
510
- retentionDays: config.audit.retentionDays ?? DEFAULT_AUDIT_RETENTION_DAYS,
511
- excludeFields: config.audit.excludeFields,
512
- excludeTables: config.audit.excludeTables,
513
- schema: config.audit.schema ?? "audit",
514
- usePartitionedTables: config.audit.usePartitionedTables ?? true
515
- };
516
- }
517
- /** Builds encryption extension config */
518
- buildEncryptionExtension(config) {
519
- if (!config.encryption?.enabled || !config.encryption.key) return void 0;
520
- return {
521
- enabled: true,
522
- key: config.encryption.key,
523
- fields: config.encryption.fields ?? {},
524
- algorithm: config.encryption.algorithm
525
284
  };
285
+ CoreEventManager = new CoreEventManagerClass();
526
286
  }
527
- buildDatabaseConfig(config) {
528
- const adapter = config.adapter ?? "drizzle";
529
- const dbConfig = {
530
- adapter,
531
- config: this.buildAdapterConfig(adapter, config)
532
- };
533
- const softDelete = this.buildSoftDeleteExtension(config);
534
- const cache = this.buildCacheExtension(config);
535
- const audit = this.buildAuditExtension(config);
536
- const encryption = this.buildEncryptionExtension(config);
537
- if (softDelete) dbConfig.softDelete = softDelete;
538
- if (cache) dbConfig.cache = cache;
539
- if (audit) dbConfig.audit = audit;
540
- if (encryption) dbConfig.encryption = encryption;
541
- return dbConfig;
542
- }
543
- /**
544
- * Builds Drizzle adapter configuration
545
- * @private
546
- */
547
- buildDrizzleConfig(config) {
548
- const connectionString = config.drizzle?.connectionString;
549
- if (!connectionString) {
550
- throw new DatabasePackageError(
551
- "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).",
552
- DATABASE_ERROR_CODES.CONFIG_REQUIRED
553
- );
554
- }
555
- const tableIdColumns = this.buildTableIdColumns();
556
- return {
557
- connectionString,
558
- poolSize: config.drizzle?.poolSize ?? DEFAULT_POOL_SIZE,
559
- ssl: config.drizzle?.ssl,
560
- schema: config.drizzle?.schema,
561
- // Pass through schema configuration
562
- tableIdColumns
287
+ });
288
+
289
+ // src/services/DbService.ts
290
+ var DbService_exports = {};
291
+ __export(DbService_exports, {
292
+ DEFAULT_ENCRYPTION_FIELDS: () => DEFAULT_ENCRYPTION_FIELDS,
293
+ DbService: () => DbService,
294
+ TABLE_REGISTRY: () => TABLE_REGISTRY
295
+ });
296
+ var DEFAULT_ENCRYPTION_FIELDS, DEFAULT_CACHE_TTL_SECONDS, DEFAULT_AUDIT_RETENTION_DAYS, DEFAULT_POOL_SIZE, DEFAULT_CONFIG, TABLE_REGISTRY, DbService;
297
+ var init_DbService = __esm({
298
+ "src/services/DbService.ts"() {
299
+ init_CoreEventManager();
300
+ DEFAULT_ENCRYPTION_FIELDS = {
301
+ // User PII
302
+ users: ["password_hash", "phone_number", "date_of_birth"],
303
+ // KYC sensitive data
304
+ "backoffice.kyc_submissions": ["tax_id", "address_line1", "address_line2"],
305
+ // Connected accounts OAuth tokens
306
+ connected_accounts: ["access_token_encrypted", "refresh_token_encrypted", "wallet_address"],
307
+ // Payment payout accounts
308
+ user_payout_accounts: ["provider_account_id", "account_holder_name"],
309
+ // Sessions
310
+ sessions: ["token"]
563
311
  };
564
- }
565
- /**
566
- * Builds Supabase adapter configuration
567
- * @private
568
- */
569
- // eslint-disable-next-line complexity
570
- buildSupabaseConfig(config) {
571
- const supabaseUrl = config.supabase?.supabaseUrl;
572
- const supabaseServiceKey = config.supabase?.supabaseServiceKey;
573
- const supabaseAnonKey = config.supabase?.supabaseAnonKey;
574
- if (!supabaseUrl || !supabaseServiceKey) {
575
- throw new DatabasePackageError(
576
- "Supabase adapter requires supabaseUrl and supabaseServiceKey. Provide in config or use Core.initialize() with SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY in env.",
577
- DATABASE_ERROR_CODES.CONFIG_REQUIRED
578
- );
579
- }
580
- if (!supabaseAnonKey) {
581
- throw new DatabasePackageError(
582
- "Supabase adapter requires supabaseAnonKey. Provide in config or use Core.initialize() with SUPABASE_ANON_PUBLIC_KEY in env.",
583
- DATABASE_ERROR_CODES.CONFIG_REQUIRED
584
- );
585
- }
586
- const tableIdColumns = this.buildTableIdColumns();
587
- return {
588
- supabaseUrl,
589
- supabaseServiceKey,
590
- supabaseAnonKey,
591
- schema: config.supabase?.schema ?? "public",
592
- tableIdColumns
312
+ DEFAULT_CACHE_TTL_SECONDS = 300;
313
+ DEFAULT_AUDIT_RETENTION_DAYS = 180;
314
+ DEFAULT_POOL_SIZE = 10;
315
+ DEFAULT_CONFIG = {
316
+ adapter: "sql",
317
+ cache: {
318
+ enabled: true,
319
+ provider: "memory",
320
+ ttl: DEFAULT_CACHE_TTL_SECONDS
321
+ },
322
+ softDelete: {
323
+ enabled: true,
324
+ field: "deleted_at",
325
+ excludeTables: [
326
+ "audit_logs",
327
+ "audit.audit_logs",
328
+ "audit.feature_flag_evaluations",
329
+ "feature_flag_evaluations",
330
+ "notification_events",
331
+ "payments_activity",
332
+ "campaign_analytics",
333
+ "admin_actions",
334
+ "backoffice.admin_actions"
335
+ ]
336
+ },
337
+ audit: {
338
+ enabled: true,
339
+ // Enabled by default for compliance
340
+ retentionDays: DEFAULT_AUDIT_RETENTION_DAYS,
341
+ excludeFields: ["password_hash", "api_key_hash", "token_hash"],
342
+ excludeTables: ["audit_logs", "audit.audit_logs"],
343
+ // Don't audit the audit table itself
344
+ schema: "audit",
345
+ // Use dedicated audit schema
346
+ usePartitionedTables: true
347
+ // Use daily partitioned tables (audit_log_yyyy_mm_dd)
348
+ }
349
+ // NOTE: Encryption requires key from environment or DbService.initialize()
350
+ // Enable via: DbService.initialize({ encryption: { enabled: true, key: process.env.ENCRYPTION_KEY!, fields: DEFAULT_ENCRYPTION_FIELDS } })
593
351
  };
594
- }
595
- /**
596
- * Builds SQL adapter configuration
597
- * @private
598
- */
599
- buildSqlConfig(config) {
600
- const connectionString = config.sql?.connectionString;
601
- if (!connectionString) {
602
- throw new DatabasePackageError(
603
- "SQL adapter requires a connection string. Provide `sql.connectionString` in config or use Core.initialize() with DATABASE_URL in env.",
604
- DATABASE_ERROR_CODES.CONFIG_REQUIRED
605
- );
606
- }
607
- const tableIdColumns = this.buildTableIdColumns();
608
- return {
609
- connectionString,
610
- dialect: config.sql?.dialect ?? "postgresql",
611
- schema: config.sql?.schema,
612
- // Pass through schema configuration
613
- tableIdColumns
352
+ TABLE_REGISTRY = {
353
+ // Migration 008: Feature Flags (custom ID column 'key')
354
+ feature_flags: { idColumn: "key" },
355
+ // Test Feature Flags (custom ID column 'key')
356
+ test_feature_flags: { idColumn: "key" },
357
+ // Migration 010: Universal Analytics (custom ID column 'user_id')
358
+ user_analytics_summary: { idColumn: "user_id" }
614
359
  };
615
- }
616
- /**
617
- * Builds table ID column mappings from TABLE_REGISTRY
618
- * @private
619
- * @returns Record of table names to ID column names
620
- */
621
- // eslint-disable-next-line complexity
622
- buildTableIdColumns() {
623
- const tableIdColumns = {};
624
- const baseNameConflicts = /* @__PURE__ */ new Set();
625
- const baseNameMappings = /* @__PURE__ */ new Map();
626
- for (const tableName of Object.keys(TABLE_REGISTRY)) {
627
- if (tableName.includes(".")) {
628
- const baseName = tableName.split(".").pop();
629
- if (baseNameMappings.has(baseName) || TABLE_REGISTRY[baseName]) {
630
- baseNameConflicts.add(baseName);
631
- } else {
632
- baseNameMappings.set(baseName, tableName);
360
+ DbService = class _DbService {
361
+ constructor() {
362
+ this.databaseService = null;
363
+ this.namedAdapters = /* @__PURE__ */ new Map();
364
+ this.config = null;
365
+ this.initialized = false;
366
+ }
367
+ static {
368
+ __name(this, "DbService");
369
+ }
370
+ static {
371
+ this.instance = null;
372
+ }
373
+ /**
374
+ * Emits a database error event via CoreEventManager.
375
+ * Called when database operations fail to integrate with global error handling.
376
+ *
377
+ * @param error - The error that occurred
378
+ * @param operation - The operation that failed (e.g., 'transaction', 'query', 'healthCheck')
379
+ * @param table - Optional table name involved in the operation
380
+ * @param query - Optional query string that failed
381
+ * @param recoverable - Whether the error is recoverable (default: false)
382
+ */
383
+ emitDatabaseError(error, operation, options) {
384
+ const payload = {
385
+ error,
386
+ operation,
387
+ table: options?.table,
388
+ query: options?.query,
389
+ recoverable: options?.recoverable ?? false
390
+ };
391
+ CoreEventManager.emit(CORE_EVENTS$1.DATABASE.ERROR, payload);
392
+ }
393
+ /**
394
+ * Gets the singleton instance of DbService
395
+ *
396
+ * @returns {DbService} The singleton instance
397
+ */
398
+ static getInstance() {
399
+ _DbService.instance ??= new _DbService();
400
+ return _DbService.instance;
401
+ }
402
+ /**
403
+ * Checks if the database service has been initialized
404
+ *
405
+ * @returns {boolean} True if initialized
406
+ */
407
+ static isInitialized() {
408
+ return _DbService.instance?.initialized ?? false;
409
+ }
410
+ /**
411
+ * Resets the database service by closing connections and clearing the singleton instance
412
+ *
413
+ * @description Properly closes the database connection and clears the singleton.
414
+ * Useful for testing or when you need to reinitialize with different configuration.
415
+ *
416
+ * @example
417
+ * ```typescript
418
+ * await DbService.reset();
419
+ * await DbService.initialize({ adapter: 'sql', ... });
420
+ * ```
421
+ */
422
+ static async reset() {
423
+ if (_DbService.instance) {
424
+ try {
425
+ await _DbService.instance.databaseService?.close?.();
426
+ } catch {
427
+ }
428
+ _DbService.instance = null;
633
429
  }
634
430
  }
635
- }
636
- for (const [tableName, config] of Object.entries(TABLE_REGISTRY)) {
637
- const idColumn = config.idColumn ?? "id";
638
- if (idColumn === "id") continue;
639
- tableIdColumns[tableName] = idColumn;
640
- if (!tableName.includes(".")) continue;
641
- const baseName = tableName.split(".").pop();
642
- if (!baseNameConflicts.has(baseName)) {
643
- tableIdColumns[baseName] = idColumn;
431
+ /**
432
+ * Initializes the database connection
433
+ *
434
+ * @description Sets up the database connection using the provided configuration
435
+ * or environment variables. This method is idempotent - calling it multiple
436
+ * times won't create additional connections.
437
+ *
438
+ * **Environment Variables:**
439
+ * - `DATABASE_URL` - PostgreSQL connection string (for sql/drizzle adapters)
440
+ * - `ENCRYPTION_KEY` - 32-byte encryption key for field encryption (optional)
441
+ * - `SUPABASE_URL`, `SUPABASE_SERVICE_ROLE_KEY`, `SUPABASE_ANON_PUBLIC_KEY` - For supabase adapter
442
+ *
443
+ * **Encryption:** If `ENCRYPTION_KEY` env is set, encryption is auto-enabled
444
+ * using `DEFAULT_ENCRYPTION_FIELDS`. Override via config.encryption.
445
+ *
446
+ * @param {DbServiceConfig} [config] - Optional configuration
447
+ * @returns {Promise<DbService>} The initialized DbService instance
448
+ * @throws {DatabasePackageError} When configuration is invalid or connection fails
449
+ *
450
+ * @example
451
+ * ```typescript
452
+ * // Minimal - uses DATABASE_URL env, auto-enables encryption if ENCRYPTION_KEY set
453
+ * await DbService.initialize();
454
+ *
455
+ * // With explicit encryption
456
+ * await DbService.initialize({
457
+ * adapter: 'sql',
458
+ * encryption: {
459
+ * enabled: true,
460
+ * key: 'your-32-byte-encryption-key-here!!',
461
+ * fields: DEFAULT_ENCRYPTION_FIELDS,
462
+ * },
463
+ * });
464
+ *
465
+ * // Or via Core.initialize() with env:
466
+ * await Core.initialize({
467
+ * env: { ENCRYPTION_KEY: '...' },
468
+ * db: { adapter: 'sql' },
469
+ * });
470
+ * ```
471
+ */
472
+ /** Build encryption config from user config */
473
+ static buildEncryptionConfig(config) {
474
+ const encryption = config?.encryption;
475
+ if (!encryption?.key) return void 0;
476
+ return {
477
+ enabled: encryption.enabled ?? true,
478
+ key: encryption.key,
479
+ fields: encryption.fields ?? DEFAULT_ENCRYPTION_FIELDS,
480
+ algorithm: encryption.algorithm ?? "aes-256-gcm"
481
+ };
644
482
  }
645
- }
646
- return tableIdColumns;
647
- }
648
- /**
649
- * Gets the initialized database service instance
650
- *
651
- * @param {string} [adapterName] - Optional named adapter to use instead of default
652
- * @returns {DatabaseServiceInterface} The database service instance
653
- * @throws {DatabasePackageError} When database is not initialized or named adapter not found
654
- */
655
- getDatabase(adapterName) {
656
- if (adapterName) {
657
- const namedAdapter = this.namedAdapters.get(adapterName);
658
- if (!namedAdapter) {
659
- throw new DatabasePackageError(
660
- `Named adapter '${adapterName}' not found. Available adapters: ${Array.from(this.namedAdapters.keys()).join(", ")}`,
661
- DATABASE_ERROR_CODES.INIT_FAILED
662
- );
483
+ /** Merge user config with defaults */
484
+ static mergeConfig(config) {
485
+ return {
486
+ ...DEFAULT_CONFIG,
487
+ ...config,
488
+ softDelete: { ...DEFAULT_CONFIG.softDelete, ...config?.softDelete },
489
+ cache: { ...DEFAULT_CONFIG.cache, ...config?.cache },
490
+ audit: { ...DEFAULT_CONFIG.audit, ...config?.audit },
491
+ encryption: _DbService.buildEncryptionConfig(config)
492
+ };
663
493
  }
664
- return namedAdapter;
665
- }
666
- if (!this.databaseService) {
667
- throw new DatabasePackageError(
668
- "Database not initialized. Call DbService.initialize() first.",
669
- DATABASE_ERROR_CODES.INIT_FAILED
670
- );
671
- }
672
- return this.databaseService;
673
- }
674
- /**
675
- * Gets a named adapter by name
676
- *
677
- * @param {string} name - The name of the adapter
678
- * @returns {DatabaseServiceInterface} The named adapter instance
679
- * @throws {DatabasePackageError} When adapter not found
680
- */
681
- getAdapter(name) {
682
- return this.getDatabase(name);
683
- }
684
- /**
685
- * Lists all available named adapters
686
- *
687
- * @returns {string[]} Array of adapter names
688
- */
689
- getAvailableAdapters() {
690
- return ["default", ...Array.from(this.namedAdapters.keys())];
691
- }
692
- /**
693
- * Executes a database transaction with automatic rollback on failure
694
- *
695
- * @template T The return type of the transaction callback
696
- * @param {Function} callback - Function that receives transaction object
697
- * @returns {Promise<T>} The result of the transaction callback
698
- * @throws {DatabasePackageError} When transaction fails
699
- */
700
- async transaction(callback) {
701
- const db = this.getDatabase();
702
- const result = await db.transaction(callback);
703
- if (!result.success) {
704
- const errorMessage = result.error?.message ?? "Transaction failed";
705
- const error = new DatabasePackageError(errorMessage, DATABASE_ERROR_CODES.TRANSACTION_FAILED);
706
- this.emitDatabaseError(error, "transaction", { recoverable: true });
707
- throw error;
708
- }
709
- if (result.value === void 0 || result.value === null) {
710
- const error = new DatabasePackageError(
711
- "Transaction returned no value",
712
- DATABASE_ERROR_CODES.INVALID_RESULT
713
- );
714
- this.emitDatabaseError(error, "transaction", { recoverable: false });
715
- throw error;
716
- }
717
- return result.value;
718
- }
719
- /**
720
- * Sets audit context for subsequent operations
721
- *
722
- * @param context - Audit context (userId, requestId, etc.)
723
- */
724
- async setAuditContext(context) {
725
- const db = this.getDatabase();
726
- await db.setAuditContext(context);
727
- }
728
- /**
729
- * Performs a health check on the database connection
730
- *
731
- * @returns Health check result
732
- */
733
- async healthCheck() {
734
- try {
735
- const db = this.getDatabase();
736
- const result = await db.healthCheck();
737
- if (result.success && result.value) {
494
+ /** Initialize named adapters */
495
+ async initializeNamedAdapters(mergedConfig) {
496
+ if (!mergedConfig.adapters) return;
497
+ for (const [name, adapterConfig] of Object.entries(mergedConfig.adapters)) {
498
+ const namedDbConfig = this.buildDatabaseConfig({
499
+ ...mergedConfig,
500
+ adapter: adapterConfig.adapter,
501
+ drizzle: adapterConfig.drizzle,
502
+ supabase: adapterConfig.supabase,
503
+ sql: adapterConfig.sql
504
+ });
505
+ const namedService = await createDatabaseService(namedDbConfig);
506
+ this.namedAdapters.set(name, namedService);
507
+ }
508
+ }
509
+ static async initialize(config) {
510
+ const instance = _DbService.getInstance();
511
+ if (instance.initialized) {
512
+ return instance;
513
+ }
514
+ const mergedConfig = _DbService.mergeConfig(config);
515
+ instance.config = mergedConfig;
516
+ const dbConfig = instance.buildDatabaseConfig(mergedConfig);
517
+ instance.databaseService = await createDatabaseService(dbConfig);
518
+ await instance.initializeNamedAdapters(mergedConfig);
519
+ instance.initialized = true;
520
+ return instance;
521
+ }
522
+ /**
523
+ * Builds the DatabaseServiceConfig based on the adapter type
524
+ * @private
525
+ */
526
+ /** Builds adapter-specific config based on adapter type */
527
+ buildAdapterConfig(adapter, config) {
528
+ const builders = {
529
+ drizzle: /* @__PURE__ */ __name(() => this.buildDrizzleConfig(config), "drizzle"),
530
+ supabase: /* @__PURE__ */ __name(() => this.buildSupabaseConfig(config), "supabase"),
531
+ sql: /* @__PURE__ */ __name(() => this.buildSqlConfig(config), "sql")
532
+ };
533
+ const builder = builders[adapter];
534
+ if (!builder) {
535
+ throw new DatabasePackageError(
536
+ `Unsupported adapter type: ${adapter}`,
537
+ DATABASE_ERROR_CODES.CONFIG_REQUIRED
538
+ );
539
+ }
540
+ return builder();
541
+ }
542
+ /** Builds soft delete extension config */
543
+ buildSoftDeleteExtension(config) {
544
+ if (!config.softDelete?.enabled) return void 0;
738
545
  return {
739
- isHealthy: result.value.isHealthy,
740
- responseTime: result.value.responseTime
546
+ enabled: true,
547
+ field: config.softDelete.field ?? "deleted_at",
548
+ excludeTables: config.softDelete.excludeTables
741
549
  };
742
550
  }
743
- const errorMessage = result.error?.message ?? "Health check failed";
744
- this.emitDatabaseError(
745
- new DatabasePackageError(errorMessage, DATABASE_ERROR_CODES.CONNECTION_ERROR),
746
- "healthCheck",
747
- { recoverable: true }
748
- );
749
- return {
750
- isHealthy: false,
751
- error: errorMessage
752
- };
753
- } catch (error) {
754
- this.emitDatabaseError(error, "healthCheck", { recoverable: true });
755
- return {
756
- isHealthy: false,
757
- error: error instanceof Error ? error.message : "Unknown error"
758
- };
759
- }
760
- }
761
- /**
762
- * Gets the table registry with all known tables and their ID columns
763
- *
764
- * @returns The complete table registry
765
- */
766
- static getTableRegistry() {
767
- return TABLE_REGISTRY;
768
- }
769
- /**
770
- * Gets ID column for a specific table
771
- *
772
- * @param tableName - Name of the table
773
- * @returns ID column name or 'id' as default
774
- */
775
- static getTableIdColumn(tableName) {
776
- return TABLE_REGISTRY[tableName]?.idColumn ?? "id";
777
- }
778
- /**
779
- * Reinitializes the database connection with new config
780
- *
781
- * @param {DbServiceConfig} [config] - New configuration
782
- * @returns {Promise<DbService>} The reinitialized DbService instance
783
- */
784
- static async reinitialize(config) {
785
- const instance = _DbService.getInstance();
786
- await instance.close();
787
- instance.initialized = false;
788
- return _DbService.initialize(config);
789
- }
790
- /**
791
- * Closes the database connection and cleans up resources
792
- */
793
- async close() {
794
- this.databaseService = null;
795
- this.initialized = false;
796
- this.config = null;
797
- }
798
- /**
799
- * Gets the current configuration
800
- *
801
- * @returns {DbServiceConfig | null} Current config or null if not initialized
802
- */
803
- getConfig() {
804
- return this.config;
805
- }
806
- /**
807
- * Gets the current adapter type
808
- *
809
- * @returns The adapter type or null if not initialized
810
- */
811
- getAdapterType() {
812
- return this.config?.adapter ?? null;
551
+ /** Builds cache extension config */
552
+ buildCacheExtension(config) {
553
+ if (!config.cache?.enabled) return void 0;
554
+ return {
555
+ enabled: true,
556
+ ttl: config.cache.ttl ?? DEFAULT_CACHE_TTL_SECONDS,
557
+ provider: config.cache.provider ?? "memory",
558
+ invalidation: config.cache.invalidation ?? "write"
559
+ };
560
+ }
561
+ /** Builds audit extension config */
562
+ buildAuditExtension(config) {
563
+ if (!config.audit?.enabled) return void 0;
564
+ return {
565
+ enabled: true,
566
+ retentionDays: config.audit.retentionDays ?? DEFAULT_AUDIT_RETENTION_DAYS,
567
+ excludeFields: config.audit.excludeFields,
568
+ excludeTables: config.audit.excludeTables,
569
+ schema: config.audit.schema ?? "audit",
570
+ usePartitionedTables: config.audit.usePartitionedTables ?? true
571
+ };
572
+ }
573
+ /** Builds encryption extension config */
574
+ buildEncryptionExtension(config) {
575
+ if (!config.encryption?.enabled || !config.encryption.key) return void 0;
576
+ return {
577
+ enabled: true,
578
+ key: config.encryption.key,
579
+ fields: config.encryption.fields ?? {},
580
+ algorithm: config.encryption.algorithm
581
+ };
582
+ }
583
+ buildDatabaseConfig(config) {
584
+ const adapter = config.adapter ?? "drizzle";
585
+ const dbConfig = {
586
+ adapter,
587
+ config: this.buildAdapterConfig(adapter, config)
588
+ };
589
+ const softDelete = this.buildSoftDeleteExtension(config);
590
+ const cache = this.buildCacheExtension(config);
591
+ const audit = this.buildAuditExtension(config);
592
+ const encryption = this.buildEncryptionExtension(config);
593
+ if (softDelete) dbConfig.softDelete = softDelete;
594
+ if (cache) dbConfig.cache = cache;
595
+ if (audit) dbConfig.audit = audit;
596
+ if (encryption) dbConfig.encryption = encryption;
597
+ return dbConfig;
598
+ }
599
+ /**
600
+ * Builds Drizzle adapter configuration
601
+ * @private
602
+ */
603
+ buildDrizzleConfig(config) {
604
+ const connectionString = config.drizzle?.connectionString;
605
+ if (!connectionString) {
606
+ throw new DatabasePackageError(
607
+ "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).",
608
+ DATABASE_ERROR_CODES.CONFIG_REQUIRED
609
+ );
610
+ }
611
+ const tableIdColumns = this.buildTableIdColumns();
612
+ return {
613
+ connectionString,
614
+ poolSize: config.drizzle?.poolSize ?? DEFAULT_POOL_SIZE,
615
+ ssl: config.drizzle?.ssl,
616
+ schema: config.drizzle?.schema,
617
+ // Pass through schema configuration
618
+ tableIdColumns
619
+ };
620
+ }
621
+ /**
622
+ * Builds Supabase adapter configuration
623
+ * @private
624
+ */
625
+ // eslint-disable-next-line complexity
626
+ buildSupabaseConfig(config) {
627
+ const supabaseUrl = config.supabase?.supabaseUrl;
628
+ const supabaseServiceKey = config.supabase?.supabaseServiceKey;
629
+ const supabaseAnonKey = config.supabase?.supabaseAnonKey;
630
+ if (!supabaseUrl || !supabaseServiceKey) {
631
+ throw new DatabasePackageError(
632
+ "Supabase adapter requires supabaseUrl and supabaseServiceKey. Provide in config or use Core.initialize() with SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY in env.",
633
+ DATABASE_ERROR_CODES.CONFIG_REQUIRED
634
+ );
635
+ }
636
+ if (!supabaseAnonKey) {
637
+ throw new DatabasePackageError(
638
+ "Supabase adapter requires supabaseAnonKey. Provide in config or use Core.initialize() with SUPABASE_ANON_PUBLIC_KEY in env.",
639
+ DATABASE_ERROR_CODES.CONFIG_REQUIRED
640
+ );
641
+ }
642
+ const tableIdColumns = this.buildTableIdColumns();
643
+ return {
644
+ supabaseUrl,
645
+ supabaseServiceKey,
646
+ supabaseAnonKey,
647
+ schema: config.supabase?.schema ?? "public",
648
+ tableIdColumns
649
+ };
650
+ }
651
+ /**
652
+ * Builds SQL adapter configuration
653
+ * @private
654
+ */
655
+ buildSqlConfig(config) {
656
+ const connectionString = config.sql?.connectionString;
657
+ if (!connectionString) {
658
+ throw new DatabasePackageError(
659
+ "SQL adapter requires a connection string. Provide `sql.connectionString` in config or use Core.initialize() with DATABASE_URL in env.",
660
+ DATABASE_ERROR_CODES.CONFIG_REQUIRED
661
+ );
662
+ }
663
+ const tableIdColumns = this.buildTableIdColumns();
664
+ return {
665
+ connectionString,
666
+ dialect: config.sql?.dialect ?? "postgresql",
667
+ schema: config.sql?.schema,
668
+ // Pass through schema configuration
669
+ tableIdColumns
670
+ };
671
+ }
672
+ /**
673
+ * Builds table ID column mappings from TABLE_REGISTRY
674
+ * @private
675
+ * @returns Record of table names to ID column names
676
+ */
677
+ // eslint-disable-next-line complexity
678
+ buildTableIdColumns() {
679
+ const tableIdColumns = {};
680
+ const baseNameConflicts = /* @__PURE__ */ new Set();
681
+ const baseNameMappings = /* @__PURE__ */ new Map();
682
+ for (const tableName of Object.keys(TABLE_REGISTRY)) {
683
+ if (tableName.includes(".")) {
684
+ const baseName = tableName.split(".").pop();
685
+ if (baseNameMappings.has(baseName) || TABLE_REGISTRY[baseName]) {
686
+ baseNameConflicts.add(baseName);
687
+ } else {
688
+ baseNameMappings.set(baseName, tableName);
689
+ }
690
+ }
691
+ }
692
+ for (const [tableName, config] of Object.entries(TABLE_REGISTRY)) {
693
+ const idColumn = config.idColumn ?? "id";
694
+ if (idColumn === "id") continue;
695
+ tableIdColumns[tableName] = idColumn;
696
+ if (!tableName.includes(".")) continue;
697
+ const baseName = tableName.split(".").pop();
698
+ if (!baseNameConflicts.has(baseName)) {
699
+ tableIdColumns[baseName] = idColumn;
700
+ }
701
+ }
702
+ return tableIdColumns;
703
+ }
704
+ /**
705
+ * Gets the initialized database service instance
706
+ *
707
+ * @param {string} [adapterName] - Optional named adapter to use instead of default
708
+ * @returns {DatabaseServiceInterface} The database service instance
709
+ * @throws {DatabasePackageError} When database is not initialized or named adapter not found
710
+ */
711
+ getDatabase(adapterName) {
712
+ if (adapterName) {
713
+ const namedAdapter = this.namedAdapters.get(adapterName);
714
+ if (!namedAdapter) {
715
+ throw new DatabasePackageError(
716
+ `Named adapter '${adapterName}' not found. Available adapters: ${Array.from(this.namedAdapters.keys()).join(", ")}`,
717
+ DATABASE_ERROR_CODES.INIT_FAILED
718
+ );
719
+ }
720
+ return namedAdapter;
721
+ }
722
+ if (!this.databaseService) {
723
+ throw new DatabasePackageError(
724
+ "Database not initialized. Call DbService.initialize() first.",
725
+ DATABASE_ERROR_CODES.INIT_FAILED
726
+ );
727
+ }
728
+ return this.databaseService;
729
+ }
730
+ /**
731
+ * Gets a named adapter by name
732
+ *
733
+ * @param {string} name - The name of the adapter
734
+ * @returns {DatabaseServiceInterface} The named adapter instance
735
+ * @throws {DatabasePackageError} When adapter not found
736
+ */
737
+ getAdapter(name) {
738
+ return this.getDatabase(name);
739
+ }
740
+ /**
741
+ * Lists all available named adapters
742
+ *
743
+ * @returns {string[]} Array of adapter names
744
+ */
745
+ getAvailableAdapters() {
746
+ return ["default", ...Array.from(this.namedAdapters.keys())];
747
+ }
748
+ /**
749
+ * Executes a database transaction with automatic rollback on failure
750
+ *
751
+ * @template T The return type of the transaction callback
752
+ * @param {Function} callback - Function that receives transaction object
753
+ * @returns {Promise<T>} The result of the transaction callback
754
+ * @throws {DatabasePackageError} When transaction fails
755
+ */
756
+ async transaction(callback) {
757
+ const db = this.getDatabase();
758
+ const result = await db.transaction(callback);
759
+ if (!result.success) {
760
+ const errorMessage = result.error?.message ?? "Transaction failed";
761
+ const error = new DatabasePackageError(errorMessage, DATABASE_ERROR_CODES.TRANSACTION_FAILED);
762
+ this.emitDatabaseError(error, "transaction", { recoverable: true });
763
+ throw error;
764
+ }
765
+ if (result.value === void 0 || result.value === null) {
766
+ const error = new DatabasePackageError(
767
+ "Transaction returned no value",
768
+ DATABASE_ERROR_CODES.INVALID_RESULT
769
+ );
770
+ this.emitDatabaseError(error, "transaction", { recoverable: false });
771
+ throw error;
772
+ }
773
+ return result.value;
774
+ }
775
+ /**
776
+ * Sets audit context for subsequent operations
777
+ *
778
+ * @param context - Audit context (userId, requestId, etc.)
779
+ */
780
+ async setAuditContext(context) {
781
+ const db = this.getDatabase();
782
+ await db.setAuditContext(context);
783
+ }
784
+ /**
785
+ * Performs a health check on the database connection
786
+ *
787
+ * @returns Health check result
788
+ */
789
+ async healthCheck() {
790
+ try {
791
+ const db = this.getDatabase();
792
+ const result = await db.healthCheck();
793
+ if (result.success && result.value) {
794
+ return {
795
+ isHealthy: result.value.isHealthy,
796
+ responseTime: result.value.responseTime
797
+ };
798
+ }
799
+ const errorMessage = result.error?.message ?? "Health check failed";
800
+ this.emitDatabaseError(
801
+ new DatabasePackageError(errorMessage, DATABASE_ERROR_CODES.CONNECTION_ERROR),
802
+ "healthCheck",
803
+ { recoverable: true }
804
+ );
805
+ return {
806
+ isHealthy: false,
807
+ error: errorMessage
808
+ };
809
+ } catch (error) {
810
+ this.emitDatabaseError(error, "healthCheck", { recoverable: true });
811
+ return {
812
+ isHealthy: false,
813
+ error: error instanceof Error ? error.message : "Unknown error"
814
+ };
815
+ }
816
+ }
817
+ /**
818
+ * Gets the table registry with all known tables and their ID columns
819
+ *
820
+ * @returns The complete table registry
821
+ */
822
+ static getTableRegistry() {
823
+ return TABLE_REGISTRY;
824
+ }
825
+ /**
826
+ * Gets ID column for a specific table
827
+ *
828
+ * @param tableName - Name of the table
829
+ * @returns ID column name or 'id' as default
830
+ */
831
+ static getTableIdColumn(tableName) {
832
+ return TABLE_REGISTRY[tableName]?.idColumn ?? "id";
833
+ }
834
+ /**
835
+ * Reinitializes the database connection with new config
836
+ *
837
+ * @param {DbServiceConfig} [config] - New configuration
838
+ * @returns {Promise<DbService>} The reinitialized DbService instance
839
+ */
840
+ static async reinitialize(config) {
841
+ const instance = _DbService.getInstance();
842
+ await instance.close();
843
+ instance.initialized = false;
844
+ return _DbService.initialize(config);
845
+ }
846
+ /**
847
+ * Closes the database connection and cleans up resources
848
+ */
849
+ async close() {
850
+ this.databaseService = null;
851
+ this.initialized = false;
852
+ this.config = null;
853
+ }
854
+ /**
855
+ * Gets the current configuration
856
+ *
857
+ * @returns {DbServiceConfig | null} Current config or null if not initialized
858
+ */
859
+ getConfig() {
860
+ return this.config;
861
+ }
862
+ /**
863
+ * Gets the current adapter type
864
+ *
865
+ * @returns The adapter type or null if not initialized
866
+ */
867
+ getAdapterType() {
868
+ return this.config?.adapter ?? null;
869
+ }
870
+ /**
871
+ * Creates a dedicated database service instance (NOT the singleton)
872
+ *
873
+ * Use this when you need an isolated database connection with its own configuration
874
+ * that doesn't affect or get affected by the shared singleton instance.
875
+ *
876
+ * @param config - Database service configuration
877
+ * @returns Promise that resolves to a new dedicated DbService instance
878
+ *
879
+ * @example
880
+ * ```typescript
881
+ * // Create a dedicated instance for analytics database
882
+ * const analyticsDb = await DbService.createInstance({
883
+ * adapter: 'sql',
884
+ * sql: { connectionString: process.env.ANALYTICS_DB_URL },
885
+ * cache: { enabled: false }, // No caching for analytics
886
+ * });
887
+ *
888
+ * // This instance is independent from DbService.getInstance()
889
+ * const data = await analyticsDb.getDatabase().list('events');
890
+ *
891
+ * // Clean up when done
892
+ * await analyticsDb.close();
893
+ * ```
894
+ */
895
+ // eslint-disable-next-line complexity
896
+ static async createInstance(config) {
897
+ const dedicatedInstance = new _DbService();
898
+ const encryptionKey = config.encryption?.key;
899
+ const encryptionConfig = encryptionKey ? {
900
+ enabled: config.encryption?.enabled ?? true,
901
+ key: encryptionKey,
902
+ fields: config.encryption?.fields ?? DEFAULT_ENCRYPTION_FIELDS,
903
+ algorithm: config.encryption?.algorithm ?? "aes-256-gcm"
904
+ } : void 0;
905
+ const mergedConfig = {
906
+ ...DEFAULT_CONFIG,
907
+ ...config,
908
+ // Deep merge extensions
909
+ softDelete: { ...DEFAULT_CONFIG.softDelete, ...config.softDelete },
910
+ cache: { ...DEFAULT_CONFIG.cache, ...config.cache },
911
+ audit: { ...DEFAULT_CONFIG.audit, ...config.audit },
912
+ // Encryption only if key is available
913
+ encryption: encryptionConfig
914
+ };
915
+ dedicatedInstance.config = mergedConfig;
916
+ const dbConfig = dedicatedInstance.buildDatabaseConfig(mergedConfig);
917
+ dedicatedInstance.databaseService = await createDatabaseService(dbConfig);
918
+ if (mergedConfig.adapters) {
919
+ for (const [name, adapterConfig] of Object.entries(mergedConfig.adapters)) {
920
+ const namedDbConfig = dedicatedInstance.buildDatabaseConfig({
921
+ ...mergedConfig,
922
+ adapter: adapterConfig.adapter,
923
+ drizzle: adapterConfig.drizzle,
924
+ supabase: adapterConfig.supabase,
925
+ sql: adapterConfig.sql
926
+ });
927
+ const namedService = await createDatabaseService(namedDbConfig);
928
+ dedicatedInstance.namedAdapters.set(name, namedService);
929
+ }
930
+ }
931
+ dedicatedInstance.initialized = true;
932
+ return dedicatedInstance;
933
+ }
934
+ };
813
935
  }
814
- /**
815
- * Creates a dedicated database service instance (NOT the singleton)
816
- *
817
- * Use this when you need an isolated database connection with its own configuration
818
- * that doesn't affect or get affected by the shared singleton instance.
819
- *
820
- * @param config - Database service configuration
821
- * @returns Promise that resolves to a new dedicated DbService instance
822
- *
823
- * @example
824
- * ```typescript
825
- * // Create a dedicated instance for analytics database
826
- * const analyticsDb = await DbService.createInstance({
827
- * adapter: 'sql',
828
- * sql: { connectionString: process.env.ANALYTICS_DB_URL },
829
- * cache: { enabled: false }, // No caching for analytics
830
- * });
831
- *
832
- * // This instance is independent from DbService.getInstance()
833
- * const data = await analyticsDb.getDatabase().list('events');
834
- *
835
- * // Clean up when done
836
- * await analyticsDb.close();
837
- * ```
838
- */
839
- // eslint-disable-next-line complexity
840
- static async createInstance(config) {
841
- const dedicatedInstance = new _DbService();
842
- const encryptionKey = config.encryption?.key;
843
- const encryptionConfig = encryptionKey ? {
844
- enabled: config.encryption?.enabled ?? true,
845
- key: encryptionKey,
846
- fields: config.encryption?.fields ?? DEFAULT_ENCRYPTION_FIELDS,
847
- algorithm: config.encryption?.algorithm ?? "aes-256-gcm"
848
- } : void 0;
849
- const mergedConfig = {
850
- ...DEFAULT_CONFIG,
851
- ...config,
852
- // Deep merge extensions
853
- softDelete: { ...DEFAULT_CONFIG.softDelete, ...config.softDelete },
854
- cache: { ...DEFAULT_CONFIG.cache, ...config.cache },
855
- audit: { ...DEFAULT_CONFIG.audit, ...config.audit },
856
- // Encryption only if key is available
857
- encryption: encryptionConfig
936
+ });
937
+
938
+ // src/services/StorageService.ts
939
+ var StorageService_exports = {};
940
+ __export(StorageService_exports, {
941
+ StorageService: () => StorageService
942
+ });
943
+ var StorageService;
944
+ var init_StorageService = __esm({
945
+ "src/services/StorageService.ts"() {
946
+ init_CoreEventManager();
947
+ StorageService = class _StorageService {
948
+ constructor() {
949
+ this.storageService = null;
950
+ this.config = null;
951
+ this.initialized = false;
952
+ }
953
+ static {
954
+ __name(this, "StorageService");
955
+ }
956
+ static {
957
+ this.instance = null;
958
+ }
959
+ // ─────────────────────────────────────────────────────────────────
960
+ // Error Handling
961
+ // ─────────────────────────────────────────────────────────────────
962
+ /**
963
+ * Emits a storage error event via CoreEventManager.
964
+ * Called when storage operations fail to integrate with global error handling.
965
+ */
966
+ emitStorageError(error, operation, options) {
967
+ const payload = {
968
+ error,
969
+ operation,
970
+ fileId: options?.fileId,
971
+ filename: options?.filename,
972
+ recoverable: options?.recoverable ?? false
973
+ };
974
+ CoreEventManager.emit(CORE_EVENTS$1.STORAGE.ERROR, payload);
975
+ }
976
+ // ─────────────────────────────────────────────────────────────────
977
+ // Singleton Management
978
+ // ─────────────────────────────────────────────────────────────────
979
+ /**
980
+ * Gets the singleton instance of StorageService
981
+ */
982
+ static getInstance() {
983
+ _StorageService.instance ??= new _StorageService();
984
+ return _StorageService.instance;
985
+ }
986
+ /**
987
+ * Checks if the storage service has been initialized
988
+ */
989
+ static isInitialized() {
990
+ return _StorageService.instance?.initialized ?? false;
991
+ }
992
+ /**
993
+ * Resets the storage service by clearing the singleton instance
994
+ */
995
+ static async reset() {
996
+ if (_StorageService.instance) {
997
+ _StorageService.instance.storageService = null;
998
+ _StorageService.instance.config = null;
999
+ _StorageService.instance.initialized = false;
1000
+ _StorageService.instance = null;
1001
+ }
1002
+ }
1003
+ /**
1004
+ * Initializes the storage service
1005
+ *
1006
+ * @param config - Storage service configuration
1007
+ * @returns The initialized StorageService instance
1008
+ */
1009
+ static async initialize(config) {
1010
+ const instance = _StorageService.getInstance();
1011
+ if (instance.initialized) {
1012
+ return instance;
1013
+ }
1014
+ instance.config = config;
1015
+ instance.storageService = new StorageService$1(config);
1016
+ instance.initialized = true;
1017
+ return instance;
1018
+ }
1019
+ /**
1020
+ * Gets the raw underlying storage service instance without error handling wrapper.
1021
+ * Use this only if you need direct access to the underlying service.
1022
+ *
1023
+ * @returns The raw StorageService instance from @plyaz/storage
1024
+ * @throws {StoragePackageError} When storage is not initialized
1025
+ */
1026
+ getRawStorage() {
1027
+ if (!this.storageService) {
1028
+ throw new StoragePackageError(
1029
+ "Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
1030
+ STORAGE_ERROR_CODES.INITIALIZATION_FAILED
1031
+ );
1032
+ }
1033
+ return this.storageService;
1034
+ }
1035
+ // ─────────────────────────────────────────────────────────────────
1036
+ // Service Access
1037
+ // ─────────────────────────────────────────────────────────────────
1038
+ /**
1039
+ * Gets the storage service with automatic error handling.
1040
+ * All method calls are wrapped with try/catch and emit error events on failure.
1041
+ * Any method added to @plyaz/storage will be automatically available.
1042
+ *
1043
+ * @example
1044
+ * ```typescript
1045
+ * const storage = StorageService.getInstance().getStorage();
1046
+ * await storage.uploadFile({ file, filename: 'doc.pdf' });
1047
+ * await storage.deleteFile({ fileId: '123' });
1048
+ * ```
1049
+ *
1050
+ * @returns StorageServiceImpl with automatic error handling
1051
+ */
1052
+ getStorage() {
1053
+ const self = this;
1054
+ return new Proxy({}, {
1055
+ get(_, prop) {
1056
+ if (typeof prop === "symbol") {
1057
+ return void 0;
1058
+ }
1059
+ const storage = self.getRawStorage();
1060
+ const value = storage[prop];
1061
+ if (typeof value !== "function") {
1062
+ return value;
1063
+ }
1064
+ return (...args) => {
1065
+ try {
1066
+ const result = value.apply(storage, args);
1067
+ if (result instanceof Promise) {
1068
+ return result.catch((error) => {
1069
+ self.emitStorageError(error, prop, { recoverable: true });
1070
+ throw error;
1071
+ });
1072
+ }
1073
+ return result;
1074
+ } catch (error) {
1075
+ self.emitStorageError(error, prop, { recoverable: true });
1076
+ throw error;
1077
+ }
1078
+ };
1079
+ }
1080
+ });
1081
+ }
1082
+ // ─────────────────────────────────────────────────────────────────
1083
+ // Health Check (special handling for response transformation)
1084
+ // ─────────────────────────────────────────────────────────────────
1085
+ /**
1086
+ * Performs a health check on the storage service by checking all adapter health.
1087
+ * This method has special handling to transform the response format.
1088
+ */
1089
+ async healthCheck() {
1090
+ const startTime = Date.now();
1091
+ try {
1092
+ const storage = this.getRawStorage();
1093
+ if (typeof storage.checkAllAdaptersHealth === "function") {
1094
+ await storage.checkAllAdaptersHealth();
1095
+ }
1096
+ const summary = typeof storage.getHealthSummary === "function" ? storage.getHealthSummary() : null;
1097
+ const responseTime = Date.now() - startTime;
1098
+ return {
1099
+ // Check if all adapters are healthy (healthy count equals total count)
1100
+ isHealthy: summary ? summary.healthy === summary.total : true,
1101
+ responseTime,
1102
+ error: void 0
1103
+ };
1104
+ } catch (error) {
1105
+ this.emitStorageError(error, "healthCheck", { recoverable: true });
1106
+ return {
1107
+ isHealthy: false,
1108
+ responseTime: Date.now() - startTime,
1109
+ error: error instanceof Error ? error.message : "Unknown error"
1110
+ };
1111
+ }
1112
+ }
1113
+ // ─────────────────────────────────────────────────────────────────
1114
+ // Lifecycle
1115
+ // ─────────────────────────────────────────────────────────────────
1116
+ /**
1117
+ * Gets the current configuration
1118
+ */
1119
+ getConfig() {
1120
+ return this.config;
1121
+ }
1122
+ /**
1123
+ * Closes the storage service and cleans up resources
1124
+ */
1125
+ async close() {
1126
+ if (this.storageService) {
1127
+ await this.storageService.destroy();
1128
+ }
1129
+ this.storageService = null;
1130
+ this.initialized = false;
1131
+ this.config = null;
1132
+ }
1133
+ /**
1134
+ * Creates a dedicated storage service instance (NOT the singleton)
1135
+ *
1136
+ * Use this when you need an isolated storage connection with its own configuration.
1137
+ *
1138
+ * @param config - Storage service configuration
1139
+ * @returns Promise that resolves to a new dedicated StorageService instance
1140
+ */
1141
+ static async createInstance(config) {
1142
+ const dedicatedInstance = new _StorageService();
1143
+ dedicatedInstance.config = config;
1144
+ dedicatedInstance.storageService = new StorageService$1(config);
1145
+ dedicatedInstance.initialized = true;
1146
+ return dedicatedInstance;
1147
+ }
858
1148
  };
859
- dedicatedInstance.config = mergedConfig;
860
- const dbConfig = dedicatedInstance.buildDatabaseConfig(mergedConfig);
861
- dedicatedInstance.databaseService = await createDatabaseService(dbConfig);
862
- if (mergedConfig.adapters) {
863
- for (const [name, adapterConfig] of Object.entries(mergedConfig.adapters)) {
864
- const namedDbConfig = dedicatedInstance.buildDatabaseConfig({
865
- ...mergedConfig,
866
- adapter: adapterConfig.adapter,
867
- drizzle: adapterConfig.drizzle,
868
- supabase: adapterConfig.supabase,
869
- sql: adapterConfig.sql
1149
+ }
1150
+ });
1151
+
1152
+ // src/services/NotificationService.ts
1153
+ var NotificationService_exports = {};
1154
+ __export(NotificationService_exports, {
1155
+ NotificationService: () => NotificationService
1156
+ });
1157
+ var NotificationService;
1158
+ var init_NotificationService = __esm({
1159
+ "src/services/NotificationService.ts"() {
1160
+ init_CoreEventManager();
1161
+ NotificationService = class _NotificationService {
1162
+ constructor() {
1163
+ this.notificationService = null;
1164
+ this.config = null;
1165
+ this.initialized = false;
1166
+ }
1167
+ static {
1168
+ __name(this, "NotificationService");
1169
+ }
1170
+ static {
1171
+ this.instance = null;
1172
+ }
1173
+ // ─────────────────────────────────────────────────────────────────
1174
+ // Error Handling
1175
+ // ─────────────────────────────────────────────────────────────────
1176
+ /**
1177
+ * Emits a notification error event via CoreEventManager.
1178
+ * Called when notification operations fail to integrate with global error handling.
1179
+ */
1180
+ emitNotificationError(error, operation, options) {
1181
+ const payload = {
1182
+ error,
1183
+ operation,
1184
+ recipientId: options?.recipientId,
1185
+ channel: options?.channel,
1186
+ recoverable: options?.recoverable ?? false
1187
+ };
1188
+ CoreEventManager.emit(CORE_EVENTS$1.NOTIFICATION.ERROR, payload);
1189
+ }
1190
+ // ─────────────────────────────────────────────────────────────────
1191
+ // Singleton Management
1192
+ // ─────────────────────────────────────────────────────────────────
1193
+ /**
1194
+ * Gets the singleton instance of NotificationService
1195
+ */
1196
+ static getInstance() {
1197
+ _NotificationService.instance ??= new _NotificationService();
1198
+ return _NotificationService.instance;
1199
+ }
1200
+ /**
1201
+ * Checks if the notification service has been initialized
1202
+ */
1203
+ static isInitialized() {
1204
+ return _NotificationService.instance?.initialized ?? false;
1205
+ }
1206
+ /**
1207
+ * Resets the notification service by clearing the singleton instance
1208
+ */
1209
+ static async reset() {
1210
+ if (_NotificationService.instance) {
1211
+ _NotificationService.instance.notificationService = null;
1212
+ _NotificationService.instance.config = null;
1213
+ _NotificationService.instance.initialized = false;
1214
+ _NotificationService.instance = null;
1215
+ }
1216
+ }
1217
+ /**
1218
+ * Initializes the notification service
1219
+ *
1220
+ * @param config - Notification service configuration
1221
+ * @returns The initialized NotificationService instance
1222
+ */
1223
+ static async initialize(config) {
1224
+ const instance = _NotificationService.getInstance();
1225
+ if (instance.initialized) {
1226
+ return instance;
1227
+ }
1228
+ instance.config = config;
1229
+ instance.notificationService = new NotificationService$1(config);
1230
+ instance.initialized = true;
1231
+ return instance;
1232
+ }
1233
+ /**
1234
+ * Gets the raw underlying notification service instance without error handling wrapper.
1235
+ * Use this only if you need direct access to the underlying service.
1236
+ *
1237
+ * @returns The raw NotificationService instance from @plyaz/notifications
1238
+ * @throws {NotificationsPackageError} When notifications is not initialized
1239
+ */
1240
+ getRawNotifications() {
1241
+ if (!this.notificationService) {
1242
+ throw new NotificationPackageError(
1243
+ "Notifications not initialized. Call NotificationService.initialize() first or use Core.initialize() with notifications config.",
1244
+ NOTIFICATION_ERROR_CODES.INITIALIZATION_FAILED
1245
+ );
1246
+ }
1247
+ return this.notificationService;
1248
+ }
1249
+ // ─────────────────────────────────────────────────────────────────
1250
+ // Service Access
1251
+ // ─────────────────────────────────────────────────────────────────
1252
+ /**
1253
+ * Gets the notification service with automatic error handling.
1254
+ * All method calls are wrapped with try/catch and emit error events on failure.
1255
+ * Any method added to @plyaz/notifications will be automatically available.
1256
+ *
1257
+ * @example
1258
+ * ```typescript
1259
+ * const notifications = NotificationService.getInstance().getNotifications();
1260
+ * await notifications.sendEmail({ to: 'user@example.com', templateId: 'welcome' });
1261
+ * await notifications.sendSMS({ to: '+1234567890', message: 'Hello!' });
1262
+ * ```
1263
+ *
1264
+ * @returns NotificationServiceImpl with automatic error handling
1265
+ */
1266
+ getNotifications() {
1267
+ const self = this;
1268
+ return new Proxy({}, {
1269
+ get(_, prop) {
1270
+ if (typeof prop === "symbol") {
1271
+ return void 0;
1272
+ }
1273
+ const notifications = self.getRawNotifications();
1274
+ const value = notifications[prop];
1275
+ if (typeof value !== "function") {
1276
+ return value;
1277
+ }
1278
+ return (...args) => {
1279
+ try {
1280
+ const result = value.apply(notifications, args);
1281
+ if (result instanceof Promise) {
1282
+ return result.catch((error) => {
1283
+ self.emitNotificationError(error, prop, { recoverable: true });
1284
+ throw error;
1285
+ });
1286
+ }
1287
+ return result;
1288
+ } catch (error) {
1289
+ self.emitNotificationError(error, prop, { recoverable: true });
1290
+ throw error;
1291
+ }
1292
+ };
1293
+ }
870
1294
  });
871
- const namedService = await createDatabaseService(namedDbConfig);
872
- dedicatedInstance.namedAdapters.set(name, namedService);
873
1295
  }
874
- }
875
- dedicatedInstance.initialized = true;
876
- return dedicatedInstance;
1296
+ // ─────────────────────────────────────────────────────────────────
1297
+ // Health Check (special handling for response transformation)
1298
+ // ─────────────────────────────────────────────────────────────────
1299
+ /**
1300
+ * Performs a health check on the notification service.
1301
+ * This method has special handling to transform the response format.
1302
+ */
1303
+ async healthCheck() {
1304
+ try {
1305
+ const notifications = this.getRawNotifications();
1306
+ const result = await notifications.healthCheck();
1307
+ return {
1308
+ isHealthy: result.healthy,
1309
+ providers: result.providers,
1310
+ // Use optional chaining since error may not exist on all health check results
1311
+ error: "error" in result ? result.error : void 0
1312
+ };
1313
+ } catch (error) {
1314
+ this.emitNotificationError(error, "healthCheck", { recoverable: true });
1315
+ return {
1316
+ isHealthy: false,
1317
+ error: error instanceof Error ? error.message : "Unknown error"
1318
+ };
1319
+ }
1320
+ }
1321
+ // ─────────────────────────────────────────────────────────────────
1322
+ // Lifecycle
1323
+ // ─────────────────────────────────────────────────────────────────
1324
+ /**
1325
+ * Gets the current configuration
1326
+ */
1327
+ getConfig() {
1328
+ return this.config;
1329
+ }
1330
+ /**
1331
+ * Closes the notification service and cleans up resources
1332
+ */
1333
+ async close() {
1334
+ this.notificationService = null;
1335
+ this.initialized = false;
1336
+ this.config = null;
1337
+ }
1338
+ /**
1339
+ * Creates a dedicated notification service instance (NOT the singleton)
1340
+ *
1341
+ * Use this when you need an isolated notification service with its own configuration.
1342
+ *
1343
+ * @param config - Notification service configuration
1344
+ * @returns Promise that resolves to a new dedicated NotificationService instance
1345
+ */
1346
+ static async createInstance(config) {
1347
+ const dedicatedInstance = new _NotificationService();
1348
+ dedicatedInstance.config = config;
1349
+ dedicatedInstance.notificationService = new NotificationService$1(config);
1350
+ dedicatedInstance.initialized = true;
1351
+ return dedicatedInstance;
1352
+ }
1353
+ };
877
1354
  }
878
- };
1355
+ });
1356
+
1357
+ // src/init/CoreInitializer.ts
1358
+ init_DbService();
1359
+
1360
+ // src/services/ApiClientService.ts
1361
+ init_CoreEventManager();
879
1362
  var MIN_RETRY_ATTEMPTS_PRODUCTION = 3;
880
1363
  function getConfigForEnvironment(env) {
881
1364
  switch (env) {
@@ -1090,7 +1573,7 @@ var ApiClientService = class _ApiClientService {
1090
1573
  requestId
1091
1574
  }
1092
1575
  };
1093
- CoreEventManager.emit(CORE_EVENTS$1.SYSTEM.ERROR, { errors: [serializedError] });
1576
+ CoreEventManager.emit(CORE_EVENTS.SYSTEM.ERROR, { errors: [serializedError] });
1094
1577
  } else {
1095
1578
  const serializedErrors = errorDetails.map(
1096
1579
  (detail, index) => ({
@@ -1114,7 +1597,7 @@ var ApiClientService = class _ApiClientService {
1114
1597
  }
1115
1598
  })
1116
1599
  );
1117
- CoreEventManager.emit(CORE_EVENTS$1.SYSTEM.ERROR, { errors: serializedErrors });
1600
+ CoreEventManager.emit(CORE_EVENTS.SYSTEM.ERROR, { errors: serializedErrors });
1118
1601
  }
1119
1602
  } catch (e) {
1120
1603
  console.error("[ApiClientService] Failed to emit error event:", e);
@@ -1267,7 +1750,7 @@ var ApiClientService = class _ApiClientService {
1267
1750
  error,
1268
1751
  duration: options.duration
1269
1752
  };
1270
- CoreEventManager.emit(CORE_EVENTS$1.API.REQUEST_ERROR, payload);
1753
+ CoreEventManager.emit(CORE_EVENTS.API.REQUEST_ERROR, payload);
1271
1754
  if (options.rethrow && error instanceof Error) {
1272
1755
  throw error;
1273
1756
  }
@@ -1945,582 +2428,190 @@ var CacheManager = class {
1945
2428
  }
1946
2429
  }
1947
2430
  /**
1948
- * Disposes of the cache manager and cleans up resources.
1949
- *
1950
- * @returns Promise that resolves when cleanup is complete
1951
- */
1952
- async dispose() {
1953
- await this.strategy.dispose?.();
1954
- }
1955
- };
1956
- var CacheService = class _CacheService {
1957
- /** Private constructor to enforce singleton */
1958
- constructor() {
1959
- /** Cache manager instance */
1960
- this.cacheManager = null;
1961
- /** Configuration used to initialize cache */
1962
- this.config = null;
1963
- /** Logger instance */
1964
- this.logger = new CoreLogger({ service: "CacheService" });
1965
- }
1966
- static {
1967
- __name(this, "CacheService");
1968
- }
1969
- static {
1970
- /** Singleton instance */
1971
- this.instance = null;
1972
- }
1973
- /**
1974
- * Initialize the cache service with configuration
1975
- *
1976
- * @param config - Cache configuration
1977
- * @throws {CorePackageError} If already initialized or config is invalid
1978
- *
1979
- * @example
1980
- * ```typescript
1981
- * await CacheService.initialize({
1982
- * strategy: 'redis',
1983
- * isEnabled: true,
1984
- * ttl: 300,
1985
- * prefix: 'app',
1986
- * redis: { url: process.env.REDIS_URL },
1987
- * });
1988
- * ```
1989
- */
1990
- static async initialize(config) {
1991
- if (this.instance?.cacheManager) {
1992
- throw new CorePackageError(
1993
- "CacheService is already initialized. Call reset() first if you need to reinitialize.",
1994
- ERROR_CODES$1.VALIDATION_ERROR
1995
- );
1996
- }
1997
- const service = this.instance ?? new _CacheService();
1998
- this.instance = service;
1999
- try {
2000
- service.logger.info("[CacheService] Initializing cache...", {
2001
- strategy: config.strategy,
2002
- isEnabled: config.isEnabled,
2003
- ttl: config.ttl
2004
- });
2005
- service.validateConfig(config);
2006
- const cacheConfig = {
2007
- ...config,
2008
- ttl: config.ttl ?? TIME_CONSTANTS.DEFAULT_CACHE_TTL
2009
- };
2010
- service.cacheManager = new CacheManager(cacheConfig);
2011
- service.config = config;
2012
- service.logger.info("[CacheService] Cache initialized successfully", {
2013
- strategy: config.strategy
2014
- });
2015
- } catch (error) {
2016
- service.logger.error("[CacheService] Failed to initialize cache", { error });
2017
- throw new CorePackageError(
2018
- `Failed to initialize cache: ${error instanceof Error ? error.message : String(error)}`,
2019
- ERROR_CODES$1.VALIDATION_ERROR,
2020
- { cause: error instanceof Error ? error : void 0 }
2021
- );
2022
- }
2023
- }
2024
- /**
2025
- * Get the singleton instance
2026
- *
2027
- * @throws {CorePackageError} If not initialized
2028
- * @returns CacheService singleton instance
2029
- *
2030
- * @example
2031
- * ```typescript
2032
- * const cacheService = CacheService.getInstance();
2033
- * const cache = cacheService.getCacheManager();
2034
- * ```
2035
- */
2036
- static getInstance() {
2037
- if (!this.instance) {
2038
- throw new CorePackageError(
2039
- "CacheService not initialized. Call CacheService.initialize() first.",
2040
- ERROR_CODES$1.CLIENT_INITIALIZATION_FAILED
2041
- );
2042
- }
2043
- return this.instance;
2044
- }
2045
- /**
2046
- * Get the cache manager instance
2047
- *
2048
- * @throws {CorePackageError} If cache not initialized
2049
- * @returns CacheManager instance
2050
- *
2051
- * @example
2052
- * ```typescript
2053
- * const cache = CacheService.getInstance().getCacheManager();
2054
- * await cache.set('user:123', userData);
2055
- * const user = await cache.get('user:123');
2056
- * ```
2057
- */
2058
- getCacheManager() {
2059
- if (!this.cacheManager) {
2060
- throw new CorePackageError(
2061
- "Cache manager not initialized. Call CacheService.initialize() first.",
2062
- ERROR_CODES$1.CLIENT_INITIALIZATION_FAILED
2063
- );
2064
- }
2065
- return this.cacheManager;
2066
- }
2067
- /**
2068
- * Get current cache configuration
2069
- *
2070
- * @returns Current cache configuration or null if not initialized
2071
- */
2072
- getConfig() {
2073
- return this.config;
2074
- }
2075
- /**
2076
- * Check if cache is initialized and enabled
2077
- *
2078
- * @returns True if cache is ready to use
2079
- */
2080
- isInitialized() {
2081
- return this.cacheManager !== null && (this.config?.isEnabled ?? false);
2082
- }
2083
- /**
2084
- * Reset the cache service (useful for testing)
2085
- *
2086
- * @internal
2087
- */
2088
- static reset() {
2089
- if (this.instance?.cacheManager) {
2090
- this.instance.logger.info("[CacheService] Resetting cache service");
2091
- this.instance.cacheManager.clear().catch((error) => {
2092
- this.instance?.logger.error("[CacheService] Error clearing cache during reset", { error });
2093
- });
2094
- }
2095
- this.instance = null;
2096
- }
2097
- /**
2098
- * Validate cache configuration
2099
- *
2100
- * @param config - Configuration to validate
2101
- * @throws {CorePackageError} If configuration is invalid
2102
- * @private
2103
- */
2104
- // eslint-disable-next-line complexity
2105
- validateConfig(config) {
2106
- if (!CACHE_STRATEGIES.includes(config.strategy)) {
2107
- throw new CorePackageError(
2108
- `Invalid cache strategy: ${config.strategy}. Must be one of: ${CACHE_STRATEGIES.join(", ")}`,
2109
- ERROR_CODES$1.VALIDATION_ERROR
2110
- );
2111
- }
2112
- if (config.ttl !== void 0 && (config.ttl < 0 || !Number.isFinite(config.ttl))) {
2113
- throw new CorePackageError(
2114
- `Invalid TTL value: ${config.ttl}. Must be a positive number.`,
2115
- ERROR_CODES$1.VALIDATION_ERROR
2116
- );
2117
- }
2118
- if (config.strategy === "redis") {
2119
- if (!config.redis?.url && !config.redis?.host) {
2120
- throw new CorePackageError(
2121
- "Redis strategy requires either redis.url or redis.host configuration",
2122
- ERROR_CODES$1.VALIDATION_ERROR
2123
- );
2124
- }
2125
- }
2126
- this.logger.debug("[CacheService] Configuration validated successfully");
2127
- }
2128
- };
2129
- var StorageService = class _StorageService {
2130
- constructor() {
2131
- this.storageService = null;
2132
- this.config = null;
2133
- this.initialized = false;
2134
- }
2135
- static {
2136
- __name(this, "StorageService");
2137
- }
2138
- static {
2139
- this.instance = null;
2140
- }
2141
- // ─────────────────────────────────────────────────────────────────
2142
- // Error Handling
2143
- // ─────────────────────────────────────────────────────────────────
2144
- /**
2145
- * Emits a storage error event via CoreEventManager.
2146
- * Called when storage operations fail to integrate with global error handling.
2147
- */
2148
- emitStorageError(error, operation, options) {
2149
- const payload = {
2150
- error,
2151
- operation,
2152
- fileId: options?.fileId,
2153
- filename: options?.filename,
2154
- recoverable: options?.recoverable ?? false
2155
- };
2156
- CoreEventManager.emit(CORE_EVENTS.STORAGE.ERROR, payload);
2157
- }
2158
- // ─────────────────────────────────────────────────────────────────
2159
- // Singleton Management
2160
- // ─────────────────────────────────────────────────────────────────
2161
- /**
2162
- * Gets the singleton instance of StorageService
2163
- */
2164
- static getInstance() {
2165
- _StorageService.instance ??= new _StorageService();
2166
- return _StorageService.instance;
2167
- }
2168
- /**
2169
- * Checks if the storage service has been initialized
2170
- */
2171
- static isInitialized() {
2172
- return _StorageService.instance?.initialized ?? false;
2173
- }
2174
- /**
2175
- * Resets the storage service by clearing the singleton instance
2176
- */
2177
- static async reset() {
2178
- if (_StorageService.instance) {
2179
- _StorageService.instance.storageService = null;
2180
- _StorageService.instance.config = null;
2181
- _StorageService.instance.initialized = false;
2182
- _StorageService.instance = null;
2183
- }
2184
- }
2185
- /**
2186
- * Initializes the storage service
2187
- *
2188
- * @param config - Storage service configuration
2189
- * @returns The initialized StorageService instance
2190
- */
2191
- static async initialize(config) {
2192
- const instance = _StorageService.getInstance();
2193
- if (instance.initialized) {
2194
- return instance;
2195
- }
2196
- instance.config = config;
2197
- instance.storageService = new StorageService$1(config);
2198
- instance.initialized = true;
2199
- return instance;
2200
- }
2201
- /**
2202
- * Gets the raw underlying storage service instance without error handling wrapper.
2203
- * Use this only if you need direct access to the underlying service.
2204
- *
2205
- * @returns The raw StorageService instance from @plyaz/storage
2206
- * @throws {StoragePackageError} When storage is not initialized
2207
- */
2208
- getRawStorage() {
2209
- if (!this.storageService) {
2210
- throw new StoragePackageError(
2211
- "Storage not initialized. Call StorageService.initialize() first or use Core.initialize() with storage config.",
2212
- STORAGE_ERROR_CODES.INITIALIZATION_FAILED
2213
- );
2214
- }
2215
- return this.storageService;
2216
- }
2217
- // ─────────────────────────────────────────────────────────────────
2218
- // Service Access
2219
- // ─────────────────────────────────────────────────────────────────
2220
- /**
2221
- * Gets the storage service with automatic error handling.
2222
- * All method calls are wrapped with try/catch and emit error events on failure.
2223
- * Any method added to @plyaz/storage will be automatically available.
2224
- *
2225
- * @example
2226
- * ```typescript
2227
- * const storage = StorageService.getInstance().getStorage();
2228
- * await storage.uploadFile({ file, filename: 'doc.pdf' });
2229
- * await storage.deleteFile({ fileId: '123' });
2230
- * ```
2231
- *
2232
- * @returns StorageServiceImpl with automatic error handling
2233
- */
2234
- getStorage() {
2235
- const self = this;
2236
- return new Proxy({}, {
2237
- get(_, prop) {
2238
- if (typeof prop === "symbol") {
2239
- return void 0;
2240
- }
2241
- const storage = self.getRawStorage();
2242
- const value = storage[prop];
2243
- if (typeof value !== "function") {
2244
- return value;
2245
- }
2246
- return (...args) => {
2247
- try {
2248
- const result = value.apply(storage, args);
2249
- if (result instanceof Promise) {
2250
- return result.catch((error) => {
2251
- self.emitStorageError(error, prop, { recoverable: true });
2252
- throw error;
2253
- });
2254
- }
2255
- return result;
2256
- } catch (error) {
2257
- self.emitStorageError(error, prop, { recoverable: true });
2258
- throw error;
2259
- }
2260
- };
2261
- }
2262
- });
2263
- }
2264
- // ─────────────────────────────────────────────────────────────────
2265
- // Health Check (special handling for response transformation)
2266
- // ─────────────────────────────────────────────────────────────────
2267
- /**
2268
- * Performs a health check on the storage service by checking all adapter health.
2269
- * This method has special handling to transform the response format.
2270
- */
2271
- async healthCheck() {
2272
- const startTime = Date.now();
2273
- try {
2274
- const storage = this.getRawStorage();
2275
- if (typeof storage.checkAllAdaptersHealth === "function") {
2276
- await storage.checkAllAdaptersHealth();
2277
- }
2278
- const summary = typeof storage.getHealthSummary === "function" ? storage.getHealthSummary() : null;
2279
- const responseTime = Date.now() - startTime;
2280
- return {
2281
- // Check if all adapters are healthy (healthy count equals total count)
2282
- isHealthy: summary ? summary.healthy === summary.total : true,
2283
- responseTime,
2284
- error: void 0
2285
- };
2286
- } catch (error) {
2287
- this.emitStorageError(error, "healthCheck", { recoverable: true });
2288
- return {
2289
- isHealthy: false,
2290
- responseTime: Date.now() - startTime,
2291
- error: error instanceof Error ? error.message : "Unknown error"
2292
- };
2293
- }
2294
- }
2295
- // ─────────────────────────────────────────────────────────────────
2296
- // Lifecycle
2297
- // ─────────────────────────────────────────────────────────────────
2298
- /**
2299
- * Gets the current configuration
2300
- */
2301
- getConfig() {
2302
- return this.config;
2303
- }
2304
- /**
2305
- * Closes the storage service and cleans up resources
2306
- */
2307
- async close() {
2308
- if (this.storageService) {
2309
- await this.storageService.destroy();
2310
- }
2311
- this.storageService = null;
2312
- this.initialized = false;
2313
- this.config = null;
2314
- }
2315
- /**
2316
- * Creates a dedicated storage service instance (NOT the singleton)
2317
- *
2318
- * Use this when you need an isolated storage connection with its own configuration.
2319
- *
2320
- * @param config - Storage service configuration
2321
- * @returns Promise that resolves to a new dedicated StorageService instance
2322
- */
2323
- static async createInstance(config) {
2324
- const dedicatedInstance = new _StorageService();
2325
- dedicatedInstance.config = config;
2326
- dedicatedInstance.storageService = new StorageService$1(config);
2327
- dedicatedInstance.initialized = true;
2328
- return dedicatedInstance;
2329
- }
2330
- };
2331
- var NotificationService = class _NotificationService {
2332
- constructor() {
2333
- this.notificationService = null;
2334
- this.config = null;
2335
- this.initialized = false;
2336
- }
2337
- static {
2338
- __name(this, "NotificationService");
2339
- }
2340
- static {
2341
- this.instance = null;
2342
- }
2343
- // ─────────────────────────────────────────────────────────────────
2344
- // Error Handling
2345
- // ─────────────────────────────────────────────────────────────────
2346
- /**
2347
- * Emits a notification error event via CoreEventManager.
2348
- * Called when notification operations fail to integrate with global error handling.
2349
- */
2350
- emitNotificationError(error, operation, options) {
2351
- const payload = {
2352
- error,
2353
- operation,
2354
- recipientId: options?.recipientId,
2355
- channel: options?.channel,
2356
- recoverable: options?.recoverable ?? false
2357
- };
2358
- CoreEventManager.emit(CORE_EVENTS.NOTIFICATION.ERROR, payload);
2359
- }
2360
- // ─────────────────────────────────────────────────────────────────
2361
- // Singleton Management
2362
- // ─────────────────────────────────────────────────────────────────
2363
- /**
2364
- * Gets the singleton instance of NotificationService
2365
- */
2366
- static getInstance() {
2367
- _NotificationService.instance ??= new _NotificationService();
2368
- return _NotificationService.instance;
2369
- }
2370
- /**
2371
- * Checks if the notification service has been initialized
2372
- */
2373
- static isInitialized() {
2374
- return _NotificationService.instance?.initialized ?? false;
2375
- }
2376
- /**
2377
- * Resets the notification service by clearing the singleton instance
2378
- */
2379
- static async reset() {
2380
- if (_NotificationService.instance) {
2381
- _NotificationService.instance.notificationService = null;
2382
- _NotificationService.instance.config = null;
2383
- _NotificationService.instance.initialized = false;
2384
- _NotificationService.instance = null;
2385
- }
2386
- }
2387
- /**
2388
- * Initializes the notification service
2431
+ * Disposes of the cache manager and cleans up resources.
2389
2432
  *
2390
- * @param config - Notification service configuration
2391
- * @returns The initialized NotificationService instance
2433
+ * @returns Promise that resolves when cleanup is complete
2392
2434
  */
2393
- static async initialize(config) {
2394
- const instance = _NotificationService.getInstance();
2395
- if (instance.initialized) {
2396
- return instance;
2397
- }
2398
- instance.config = config;
2399
- instance.notificationService = new NotificationService$1(config);
2400
- instance.initialized = true;
2401
- return instance;
2435
+ async dispose() {
2436
+ await this.strategy.dispose?.();
2437
+ }
2438
+ };
2439
+ var CacheService = class _CacheService {
2440
+ /** Private constructor to enforce singleton */
2441
+ constructor() {
2442
+ /** Cache manager instance */
2443
+ this.cacheManager = null;
2444
+ /** Configuration used to initialize cache */
2445
+ this.config = null;
2446
+ /** Logger instance */
2447
+ this.logger = new CoreLogger({ service: "CacheService" });
2448
+ }
2449
+ static {
2450
+ __name(this, "CacheService");
2451
+ }
2452
+ static {
2453
+ /** Singleton instance */
2454
+ this.instance = null;
2402
2455
  }
2403
2456
  /**
2404
- * Gets the raw underlying notification service instance without error handling wrapper.
2405
- * Use this only if you need direct access to the underlying service.
2457
+ * Initialize the cache service with configuration
2458
+ *
2459
+ * @param config - Cache configuration
2460
+ * @throws {CorePackageError} If already initialized or config is invalid
2406
2461
  *
2407
- * @returns The raw NotificationService instance from @plyaz/notifications
2408
- * @throws {NotificationsPackageError} When notifications is not initialized
2462
+ * @example
2463
+ * ```typescript
2464
+ * await CacheService.initialize({
2465
+ * strategy: 'redis',
2466
+ * isEnabled: true,
2467
+ * ttl: 300,
2468
+ * prefix: 'app',
2469
+ * redis: { url: process.env.REDIS_URL },
2470
+ * });
2471
+ * ```
2409
2472
  */
2410
- getRawNotifications() {
2411
- if (!this.notificationService) {
2412
- throw new NotificationPackageError(
2413
- "Notifications not initialized. Call NotificationService.initialize() first or use Core.initialize() with notifications config.",
2414
- NOTIFICATION_ERROR_CODES.INITIALIZATION_FAILED
2473
+ static async initialize(config) {
2474
+ if (this.instance?.cacheManager) {
2475
+ throw new CorePackageError(
2476
+ "CacheService is already initialized. Call reset() first if you need to reinitialize.",
2477
+ ERROR_CODES$1.VALIDATION_ERROR
2478
+ );
2479
+ }
2480
+ const service = this.instance ?? new _CacheService();
2481
+ this.instance = service;
2482
+ try {
2483
+ service.logger.info("[CacheService] Initializing cache...", {
2484
+ strategy: config.strategy,
2485
+ isEnabled: config.isEnabled,
2486
+ ttl: config.ttl
2487
+ });
2488
+ service.validateConfig(config);
2489
+ const cacheConfig = {
2490
+ ...config,
2491
+ ttl: config.ttl ?? TIME_CONSTANTS.DEFAULT_CACHE_TTL
2492
+ };
2493
+ service.cacheManager = new CacheManager(cacheConfig);
2494
+ service.config = config;
2495
+ service.logger.info("[CacheService] Cache initialized successfully", {
2496
+ strategy: config.strategy
2497
+ });
2498
+ } catch (error) {
2499
+ service.logger.error("[CacheService] Failed to initialize cache", { error });
2500
+ throw new CorePackageError(
2501
+ `Failed to initialize cache: ${error instanceof Error ? error.message : String(error)}`,
2502
+ ERROR_CODES$1.VALIDATION_ERROR,
2503
+ { cause: error instanceof Error ? error : void 0 }
2415
2504
  );
2416
2505
  }
2417
- return this.notificationService;
2418
2506
  }
2419
- // ─────────────────────────────────────────────────────────────────
2420
- // Service Access
2421
- // ─────────────────────────────────────────────────────────────────
2422
2507
  /**
2423
- * Gets the notification service with automatic error handling.
2424
- * All method calls are wrapped with try/catch and emit error events on failure.
2425
- * Any method added to @plyaz/notifications will be automatically available.
2508
+ * Get the singleton instance
2509
+ *
2510
+ * @throws {CorePackageError} If not initialized
2511
+ * @returns CacheService singleton instance
2426
2512
  *
2427
2513
  * @example
2428
2514
  * ```typescript
2429
- * const notifications = NotificationService.getInstance().getNotifications();
2430
- * await notifications.sendEmail({ to: 'user@example.com', templateId: 'welcome' });
2431
- * await notifications.sendSMS({ to: '+1234567890', message: 'Hello!' });
2515
+ * const cacheService = CacheService.getInstance();
2516
+ * const cache = cacheService.getCacheManager();
2432
2517
  * ```
2433
- *
2434
- * @returns NotificationServiceImpl with automatic error handling
2435
2518
  */
2436
- getNotifications() {
2437
- const self = this;
2438
- return new Proxy({}, {
2439
- get(_, prop) {
2440
- if (typeof prop === "symbol") {
2441
- return void 0;
2442
- }
2443
- const notifications = self.getRawNotifications();
2444
- const value = notifications[prop];
2445
- if (typeof value !== "function") {
2446
- return value;
2447
- }
2448
- return (...args) => {
2449
- try {
2450
- const result = value.apply(notifications, args);
2451
- if (result instanceof Promise) {
2452
- return result.catch((error) => {
2453
- self.emitNotificationError(error, prop, { recoverable: true });
2454
- throw error;
2455
- });
2456
- }
2457
- return result;
2458
- } catch (error) {
2459
- self.emitNotificationError(error, prop, { recoverable: true });
2460
- throw error;
2461
- }
2462
- };
2463
- }
2464
- });
2519
+ static getInstance() {
2520
+ if (!this.instance) {
2521
+ throw new CorePackageError(
2522
+ "CacheService not initialized. Call CacheService.initialize() first.",
2523
+ ERROR_CODES$1.CLIENT_INITIALIZATION_FAILED
2524
+ );
2525
+ }
2526
+ return this.instance;
2465
2527
  }
2466
- // ─────────────────────────────────────────────────────────────────
2467
- // Health Check (special handling for response transformation)
2468
- // ─────────────────────────────────────────────────────────────────
2469
2528
  /**
2470
- * Performs a health check on the notification service.
2471
- * This method has special handling to transform the response format.
2529
+ * Get the cache manager instance
2530
+ *
2531
+ * @throws {CorePackageError} If cache not initialized
2532
+ * @returns CacheManager instance
2533
+ *
2534
+ * @example
2535
+ * ```typescript
2536
+ * const cache = CacheService.getInstance().getCacheManager();
2537
+ * await cache.set('user:123', userData);
2538
+ * const user = await cache.get('user:123');
2539
+ * ```
2472
2540
  */
2473
- async healthCheck() {
2474
- try {
2475
- const notifications = this.getRawNotifications();
2476
- const result = await notifications.healthCheck();
2477
- return {
2478
- isHealthy: result.healthy,
2479
- providers: result.providers,
2480
- // Use optional chaining since error may not exist on all health check results
2481
- error: "error" in result ? result.error : void 0
2482
- };
2483
- } catch (error) {
2484
- this.emitNotificationError(error, "healthCheck", { recoverable: true });
2485
- return {
2486
- isHealthy: false,
2487
- error: error instanceof Error ? error.message : "Unknown error"
2488
- };
2541
+ getCacheManager() {
2542
+ if (!this.cacheManager) {
2543
+ throw new CorePackageError(
2544
+ "Cache manager not initialized. Call CacheService.initialize() first.",
2545
+ ERROR_CODES$1.CLIENT_INITIALIZATION_FAILED
2546
+ );
2489
2547
  }
2548
+ return this.cacheManager;
2490
2549
  }
2491
- // ─────────────────────────────────────────────────────────────────
2492
- // Lifecycle
2493
- // ─────────────────────────────────────────────────────────────────
2494
2550
  /**
2495
- * Gets the current configuration
2551
+ * Get current cache configuration
2552
+ *
2553
+ * @returns Current cache configuration or null if not initialized
2496
2554
  */
2497
2555
  getConfig() {
2498
2556
  return this.config;
2499
2557
  }
2500
2558
  /**
2501
- * Closes the notification service and cleans up resources
2559
+ * Check if cache is initialized and enabled
2560
+ *
2561
+ * @returns True if cache is ready to use
2502
2562
  */
2503
- async close() {
2504
- this.notificationService = null;
2505
- this.initialized = false;
2506
- this.config = null;
2563
+ isInitialized() {
2564
+ return this.cacheManager !== null && (this.config?.isEnabled ?? false);
2507
2565
  }
2508
2566
  /**
2509
- * Creates a dedicated notification service instance (NOT the singleton)
2567
+ * Reset the cache service (useful for testing)
2510
2568
  *
2511
- * Use this when you need an isolated notification service with its own configuration.
2569
+ * @internal
2570
+ */
2571
+ static reset() {
2572
+ if (this.instance?.cacheManager) {
2573
+ this.instance.logger.info("[CacheService] Resetting cache service");
2574
+ this.instance.cacheManager.clear().catch((error) => {
2575
+ this.instance?.logger.error("[CacheService] Error clearing cache during reset", { error });
2576
+ });
2577
+ }
2578
+ this.instance = null;
2579
+ }
2580
+ /**
2581
+ * Validate cache configuration
2512
2582
  *
2513
- * @param config - Notification service configuration
2514
- * @returns Promise that resolves to a new dedicated NotificationService instance
2583
+ * @param config - Configuration to validate
2584
+ * @throws {CorePackageError} If configuration is invalid
2585
+ * @private
2515
2586
  */
2516
- static async createInstance(config) {
2517
- const dedicatedInstance = new _NotificationService();
2518
- dedicatedInstance.config = config;
2519
- dedicatedInstance.notificationService = new NotificationService$1(config);
2520
- dedicatedInstance.initialized = true;
2521
- return dedicatedInstance;
2587
+ // eslint-disable-next-line complexity
2588
+ validateConfig(config) {
2589
+ if (!CACHE_STRATEGIES.includes(config.strategy)) {
2590
+ throw new CorePackageError(
2591
+ `Invalid cache strategy: ${config.strategy}. Must be one of: ${CACHE_STRATEGIES.join(", ")}`,
2592
+ ERROR_CODES$1.VALIDATION_ERROR
2593
+ );
2594
+ }
2595
+ if (config.ttl !== void 0 && (config.ttl < 0 || !Number.isFinite(config.ttl))) {
2596
+ throw new CorePackageError(
2597
+ `Invalid TTL value: ${config.ttl}. Must be a positive number.`,
2598
+ ERROR_CODES$1.VALIDATION_ERROR
2599
+ );
2600
+ }
2601
+ if (config.strategy === "redis") {
2602
+ if (!config.redis?.url && !config.redis?.host) {
2603
+ throw new CorePackageError(
2604
+ "Redis strategy requires either redis.url or redis.host configuration",
2605
+ ERROR_CODES$1.VALIDATION_ERROR
2606
+ );
2607
+ }
2608
+ }
2609
+ this.logger.debug("[CacheService] Configuration validated successfully");
2522
2610
  }
2523
2611
  };
2612
+
2613
+ // src/init/CoreInitializer.ts
2614
+ init_CoreEventManager();
2524
2615
  var BaseDomainService = class {
2525
2616
  // ─────────────────────────────────────────────────────────────────────────
2526
2617
  // Constructor
@@ -2919,6 +3010,9 @@ var BaseDomainService = class {
2919
3010
  );
2920
3011
  }
2921
3012
  };
3013
+
3014
+ // src/domain/base/BaseFrontendDomainService.ts
3015
+ init_CoreEventManager();
2922
3016
  var BaseFrontendDomainService = class extends BaseDomainService {
2923
3017
  // ─────────────────────────────────────────────────────────────────────────
2924
3018
  // Constructor
@@ -3816,6 +3910,9 @@ var BaseFrontendDomainService = class extends BaseDomainService {
3816
3910
  );
3817
3911
  }
3818
3912
  };
3913
+
3914
+ // src/events/index.ts
3915
+ init_CoreEventManager();
3819
3916
  var BaseBackendDomainService = class extends BaseDomainService {
3820
3917
  static {
3821
3918
  __name(this, "BaseBackendDomainService");
@@ -5213,6 +5310,10 @@ function keysToSnake(obj) {
5213
5310
  return result;
5214
5311
  }
5215
5312
  __name(keysToSnake, "keysToSnake");
5313
+
5314
+ // src/models/example/ExampleRepository.ts
5315
+ init_DbService();
5316
+ init_common();
5216
5317
  var EXAMPLE_TABLE = "examples";
5217
5318
  var DEFAULT_PAGINATION_LIMIT = 100;
5218
5319
  var DUMMY_DATA = [
@@ -5390,31 +5491,99 @@ var ExampleRepository = class _ExampleRepository extends BaseRepository {
5390
5491
  return super.delete(id, config);
5391
5492
  }
5392
5493
  // ─────────────────────────────────────────────────────────────────────────
5393
- // Domain-Specific Query Methods
5494
+ // Domain-Specific Query Methods (using QueryBuilder fluent API)
5394
5495
  // ─────────────────────────────────────────────────────────────────────────
5395
5496
  /**
5396
- * Find entities by status
5497
+ * Find entities by status using fluent QueryBuilder
5498
+ *
5499
+ * @example
5500
+ * ```typescript
5501
+ * const result = await repo.findByStatus('active');
5502
+ * ```
5397
5503
  */
5398
5504
  async findByStatus(status) {
5399
- return this.findMany({
5400
- filter: { field: "status", operator: "eq", value: status }
5401
- });
5505
+ if (this.useDummyData) {
5506
+ return this.findMany({
5507
+ filter: { field: "status", operator: "eq", value: status }
5508
+ });
5509
+ }
5510
+ return this.query().where("status", "eq", status).execute();
5402
5511
  }
5403
5512
  /**
5404
- * Find entities by owner
5513
+ * Find entities by owner using fluent QueryBuilder
5514
+ *
5515
+ * @example
5516
+ * ```typescript
5517
+ * const result = await repo.findByOwner('user-001');
5518
+ * ```
5405
5519
  */
5406
5520
  async findByOwner(ownerId) {
5407
- return this.findMany({
5408
- filter: { field: "owner_id", operator: "eq", value: ownerId }
5409
- });
5521
+ if (this.useDummyData) {
5522
+ return this.findMany({
5523
+ filter: { field: "owner_id", operator: "eq", value: ownerId }
5524
+ });
5525
+ }
5526
+ return this.query().where("owner_id", "eq", ownerId).execute();
5410
5527
  }
5411
5528
  /**
5412
- * Find visible entities only
5529
+ * Find visible entities only using fluent QueryBuilder
5530
+ *
5531
+ * @example
5532
+ * ```typescript
5533
+ * const result = await repo.findVisible();
5534
+ * ```
5413
5535
  */
5414
5536
  async findVisible() {
5415
- return this.findMany({
5416
- filter: { field: "is_visible", operator: "eq", value: true }
5417
- });
5537
+ if (this.useDummyData) {
5538
+ return this.findMany({
5539
+ filter: { field: "is_visible", operator: "eq", value: true }
5540
+ });
5541
+ }
5542
+ return this.query().where("is_visible", "eq", true).execute();
5543
+ }
5544
+ /**
5545
+ * Find active and visible entities using complex QueryBuilder
5546
+ *
5547
+ * @example
5548
+ * ```typescript
5549
+ * const items = await repo.findActiveAndVisible();
5550
+ * ```
5551
+ */
5552
+ async findActiveAndVisible() {
5553
+ if (this.useDummyData) {
5554
+ return this.dummyStore.filter((r) => r.status === "active" && r.is_visible && !r.deleted_at);
5555
+ }
5556
+ return this.query().where("status", "eq", "active").andWhere("is_visible", "eq", true).whereNull("deleted_at").orderByDesc("created_at").getMany();
5557
+ }
5558
+ /**
5559
+ * Find entities by owner with status filter using QueryBuilder
5560
+ *
5561
+ * @example
5562
+ * ```typescript
5563
+ * const items = await repo.findByOwnerWithStatus('user-001', 'active');
5564
+ * ```
5565
+ */
5566
+ async findByOwnerWithStatus(ownerId, status) {
5567
+ if (this.useDummyData) {
5568
+ return this.dummyStore.filter(
5569
+ (r) => r.owner_id === ownerId && r.status === status && !r.deleted_at
5570
+ );
5571
+ }
5572
+ return this.query().where("owner_id", "eq", ownerId).andWhere("status", "eq", status).orderByDesc("updated_at").getMany();
5573
+ }
5574
+ /**
5575
+ * Count entities by status using QueryBuilder
5576
+ *
5577
+ * @example
5578
+ * ```typescript
5579
+ * const count = await repo.countByStatus('active');
5580
+ * ```
5581
+ */
5582
+ async countByStatus(status) {
5583
+ if (this.useDummyData) {
5584
+ return this.dummyStore.filter((r) => r.status === status && !r.deleted_at).length;
5585
+ }
5586
+ return this.query().where("status", "eq", status).count();
5418
5587
  }
5419
5588
  /**
5420
5589
  * Check if entity exists by ID
@@ -5885,6 +6054,7 @@ var BackendExampleDomainService = class _BackendExampleDomainService extends Bas
5885
6054
  // ─────────────────────────────────────────────────────────────────────────
5886
6055
  };
5887
6056
  new BackendExampleDomainService();
6057
+ init_CoreEventManager();
5888
6058
  var DEFAULT_POLLING_INTERVAL_MS = 3e4;
5889
6059
  var FrontendExampleDomainService = class _FrontendExampleDomainService extends BaseFrontendDomainService {
5890
6060
  // ─────────────────────────────────────────────────────────────────────────
@@ -5934,6 +6104,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
5934
6104
  // store.setData(data);
5935
6105
  // // Can also call domain-specific methods or other stores
5936
6106
  // // store.selectItem(data.selectedId);
6107
+ // // store.selectItem(data.selectedId);
5937
6108
  // },
5938
6109
  // updateData: (store, data) => store.updateData(data),
5939
6110
  // setLoading: (store, isLoading) => store.setLoading(isLoading),
@@ -6149,6 +6320,9 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
6149
6320
  // All events are emitted automatically with 'example:' prefix!
6150
6321
  // ─────────────────────────────────────────────────────────────────────────
6151
6322
  };
6323
+
6324
+ // src/base/observability/BaseAdapter.ts
6325
+ init_common();
6152
6326
  var BaseAdapter = class {
6153
6327
  constructor() {
6154
6328
  this._isInitialized = false;
@@ -6371,6 +6545,9 @@ var NoopAdapter = class extends BaseAdapter {
6371
6545
  async doFlush() {
6372
6546
  }
6373
6547
  };
6548
+
6549
+ // src/base/observability/LoggerAdapter.ts
6550
+ init_common();
6374
6551
  var LoggerAdapter = class extends BaseAdapter {
6375
6552
  constructor() {
6376
6553
  super(...arguments);
@@ -6520,6 +6697,12 @@ var LoggerAdapter = class extends BaseAdapter {
6520
6697
  async doFlush() {
6521
6698
  }
6522
6699
  };
6700
+
6701
+ // src/base/observability/CompositeAdapter.ts
6702
+ init_common();
6703
+
6704
+ // src/base/observability/DatadogAdapter.ts
6705
+ init_common();
6523
6706
  var DEFAULT_ADAPTER_TIMEOUT_MS = 5e3;
6524
6707
  var ObservabilityService = class {
6525
6708
  constructor() {
@@ -7272,10 +7455,11 @@ var ServiceRegistry = class _ServiceRegistry {
7272
7455
  if (!dbConfig) {
7273
7456
  return void 0;
7274
7457
  }
7458
+ const { DbService: DbService2 } = await Promise.resolve().then(() => (init_DbService(), DbService_exports));
7275
7459
  let dbInstance;
7276
7460
  if (isDedicated && dbConfig) {
7277
7461
  try {
7278
- dbInstance = await DbService.createInstance(dbConfig);
7462
+ dbInstance = await DbService2.createInstance(dbConfig);
7279
7463
  _ServiceRegistry.logger.debug(
7280
7464
  `Created dedicated database instance for service '${serviceKey}'`
7281
7465
  );
@@ -7289,7 +7473,7 @@ var ServiceRegistry = class _ServiceRegistry {
7289
7473
  }
7290
7474
  } else {
7291
7475
  try {
7292
- dbInstance = DbService.getInstance();
7476
+ dbInstance = DbService2.getInstance();
7293
7477
  } catch {
7294
7478
  _ServiceRegistry.logger.debug(
7295
7479
  `Global DB not initialized, service '${serviceKey}' will not have DB`
@@ -7390,10 +7574,11 @@ var ServiceRegistry = class _ServiceRegistry {
7390
7574
  if (!storageConfig) {
7391
7575
  return void 0;
7392
7576
  }
7577
+ const { StorageService: StorageService2 } = await Promise.resolve().then(() => (init_StorageService(), StorageService_exports));
7393
7578
  let storageInstance;
7394
7579
  if (isDedicated && storageConfig) {
7395
7580
  try {
7396
- storageInstance = await StorageService.createInstance(storageConfig);
7581
+ storageInstance = await StorageService2.createInstance(storageConfig);
7397
7582
  _ServiceRegistry.logger.debug(
7398
7583
  `Created dedicated storage instance for service '${serviceKey}'`
7399
7584
  );
@@ -7405,7 +7590,7 @@ var ServiceRegistry = class _ServiceRegistry {
7405
7590
  }
7406
7591
  } else {
7407
7592
  try {
7408
- storageInstance = StorageService.getInstance();
7593
+ storageInstance = StorageService2.getInstance();
7409
7594
  } catch {
7410
7595
  _ServiceRegistry.logger.debug(
7411
7596
  `Global storage not initialized, service '${serviceKey}' will not have storage`
@@ -7435,10 +7620,11 @@ var ServiceRegistry = class _ServiceRegistry {
7435
7620
  if (!notificationsConfig) {
7436
7621
  return void 0;
7437
7622
  }
7623
+ const { NotificationService: NotificationService2 } = await Promise.resolve().then(() => (init_NotificationService(), NotificationService_exports));
7438
7624
  let notificationsInstance;
7439
7625
  if (isDedicated && notificationsConfig) {
7440
7626
  try {
7441
- notificationsInstance = await NotificationService.createInstance(notificationsConfig);
7627
+ notificationsInstance = await NotificationService2.createInstance(notificationsConfig);
7442
7628
  _ServiceRegistry.logger.debug(
7443
7629
  `Created dedicated notifications instance for service '${serviceKey}'`
7444
7630
  );
@@ -7450,7 +7636,7 @@ var ServiceRegistry = class _ServiceRegistry {
7450
7636
  }
7451
7637
  } else {
7452
7638
  try {
7453
- notificationsInstance = NotificationService.getInstance();
7639
+ notificationsInstance = NotificationService2.getInstance();
7454
7640
  } catch {
7455
7641
  _ServiceRegistry.logger.debug(
7456
7642
  `Global notifications not initialized, service '${serviceKey}' will not have notifications`
@@ -8028,8 +8214,9 @@ var Core = class _Core {
8028
8214
  await _Core.initService(
8029
8215
  "storage",
8030
8216
  async () => {
8031
- await StorageService.initialize(storageConfig);
8032
- _Core._coreServices.storage = StorageService.getInstance();
8217
+ const { StorageService: StorageService2 } = await Promise.resolve().then(() => (init_StorageService(), StorageService_exports));
8218
+ await StorageService2.initialize(storageConfig);
8219
+ _Core._coreServices.storage = StorageService2.getInstance();
8033
8220
  _Core.log("Storage service initialized", verbose);
8034
8221
  },
8035
8222
  verbose
@@ -8053,8 +8240,9 @@ var Core = class _Core {
8053
8240
  await _Core.initService(
8054
8241
  "notifications",
8055
8242
  async () => {
8056
- await NotificationService.initialize(notificationsConfig);
8057
- _Core._coreServices.notifications = NotificationService.getInstance();
8243
+ const { NotificationService: NotificationService2 } = await Promise.resolve().then(() => (init_NotificationService(), NotificationService_exports));
8244
+ await NotificationService2.initialize(notificationsConfig);
8245
+ _Core._coreServices.notifications = NotificationService2.getInstance();
8058
8246
  _Core.log("Notifications service initialized", verbose);
8059
8247
  },
8060
8248
  verbose
@@ -8619,11 +8807,13 @@ var Core = class _Core {
8619
8807
  _Core._observabilityConfig = {};
8620
8808
  if (_Core._coreServices.storage) {
8621
8809
  await _Core._coreServices.storage.close();
8622
- await StorageService.reset();
8810
+ const { StorageService: StorageService2 } = await Promise.resolve().then(() => (init_StorageService(), StorageService_exports));
8811
+ await StorageService2.reset();
8623
8812
  }
8624
8813
  if (_Core._coreServices.notifications) {
8625
8814
  await _Core._coreServices.notifications.close();
8626
- await NotificationService.reset();
8815
+ const { NotificationService: NotificationService2 } = await Promise.resolve().then(() => (init_NotificationService(), NotificationService_exports));
8816
+ await NotificationService2.reset();
8627
8817
  }
8628
8818
  if (_Core._errorHandler) {
8629
8819
  _Core._errorHandler.destroy();
@@ -8674,20 +8864,19 @@ var Core = class _Core {
8674
8864
  */
8675
8865
  static shouldSkipDbService(skipDb, verbose) {
8676
8866
  if (skipDb === true) {
8677
- if (verbose) {
8678
- console.log("[Core] Database service skipped (skipDb: true)");
8679
- }
8867
+ _Core.log("Database service skipped (skipDb: true)", verbose);
8680
8868
  return true;
8681
8869
  }
8682
8870
  const isFrontend = _Core.isFrontend;
8683
8871
  if (isFrontend) {
8684
8872
  if (skipDb === false) {
8685
- console.warn(
8686
- "[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."
8873
+ _Core.logger.warn(
8874
+ "DbService cannot be initialized on frontend runtime. DbService is backend-only and requires Node.js. Use API calls from frontend instead. Skipping database initialization."
8687
8875
  );
8688
8876
  } else if (verbose) {
8689
- console.log(
8690
- "[Core] Database service skipped (frontend runtime detected). DbService is only available on backend."
8877
+ _Core.log(
8878
+ "Database service skipped (frontend runtime detected). DbService is only available on backend.",
8879
+ verbose
8691
8880
  );
8692
8881
  }
8693
8882
  return true;
@@ -8699,10 +8888,9 @@ var Core = class _Core {
8699
8888
  * Config validation is handled by DbService
8700
8889
  */
8701
8890
  static async initializeDb(config, verbose) {
8702
- if (verbose) {
8703
- console.log(`[Core] Initializing database with adapter: ${config?.adapter ?? "drizzle"}`);
8704
- }
8705
- return DbService.initialize({
8891
+ _Core.log(`Initializing database with adapter: ${config?.adapter ?? "drizzle"}`, verbose);
8892
+ const { DbService: DbService2 } = await Promise.resolve().then(() => (init_DbService(), DbService_exports));
8893
+ return DbService2.initialize({
8706
8894
  adapter: "drizzle",
8707
8895
  ...config
8708
8896
  });
@@ -8714,9 +8902,7 @@ var Core = class _Core {
8714
8902
  static async initializeApi(config, globalEnvironment, verbose) {
8715
8903
  const { env: apiEnv, setAsDefault, ...apiClientOptions } = config ?? {};
8716
8904
  const resolvedEnv = apiEnv ?? globalEnvironment ?? "development";
8717
- if (verbose) {
8718
- console.log(`[Core] Initializing API client for environment: ${resolvedEnv}`);
8719
- }
8905
+ _Core.log(`Initializing API client for environment: ${resolvedEnv}`, verbose);
8720
8906
  await ApiClientService.init(
8721
8907
  {
8722
8908
  env: resolvedEnv,
@@ -8730,9 +8916,7 @@ var Core = class _Core {
8730
8916
  * Config validation is handled by CacheService
8731
8917
  */
8732
8918
  static async initializeCache(config, verbose) {
8733
- if (verbose) {
8734
- console.log(`[Core] Initializing cache with strategy: ${config.strategy}`);
8735
- }
8919
+ _Core.log(`Initializing cache with strategy: ${config.strategy}`, verbose);
8736
8920
  await CacheService.initialize(config);
8737
8921
  }
8738
8922
  /**
@@ -8740,9 +8924,7 @@ var Core = class _Core {
8740
8924
  * Always includes LoggerAdapter as failover for console output.
8741
8925
  */
8742
8926
  static async initializeObservability(config, verbose, environment) {
8743
- if (verbose) {
8744
- console.log(`[Core] Initializing observability with provider: ${config.provider ?? "auto"}`);
8745
- }
8927
+ _Core.log(`Initializing observability with provider: ${config.provider ?? "auto"}`, verbose);
8746
8928
  const env = config.environment ?? environment ?? "development";
8747
8929
  _Core._observabilityConfig = { ...config, environment: env };
8748
8930
  const adapters = [];
@@ -8766,11 +8948,10 @@ var Core = class _Core {
8766
8948
  flushInterval: config.flushInterval,
8767
8949
  adapterTimeout: config.flushInterval
8768
8950
  });
8769
- if (verbose) {
8770
- console.log(
8771
- `[Core] ObservabilityService initialized with ${adapters.length} adapters (env: ${env})`
8772
- );
8773
- }
8951
+ _Core.log(
8952
+ `ObservabilityService initialized with ${adapters.length} adapters (env: ${env})`,
8953
+ verbose
8954
+ );
8774
8955
  _Core._coreServices.observability = observability;
8775
8956
  ServiceRegistry.setObservabilityInstance(observability);
8776
8957
  }
@@ -8781,10 +8962,10 @@ var Core = class _Core {
8781
8962
  static initializeRootStore(config, verbose) {
8782
8963
  const isFrontend = typeof window !== "undefined";
8783
8964
  if (isFrontend) {
8784
- if (verbose) console.log("[Core] Using frontend root store (Zustand)");
8965
+ _Core.log("Using frontend root store (Zustand)", verbose);
8785
8966
  _Core._rootStore = useRootStore;
8786
8967
  } else {
8787
- if (verbose) console.log("[Core] Creating backend composite store (in-memory)");
8968
+ _Core.log("Creating backend composite store (in-memory)", verbose);
8788
8969
  const backendErrorStore = ServerErrorMiddleware.createErrorStore({
8789
8970
  maxErrors: config?.maxErrors ?? DEFAULT_MAX_ERRORS,
8790
8971
  onErrorAdded: config?.onError
@@ -8832,11 +9013,11 @@ var Core = class _Core {
8832
9013
  // eslint-disable-next-line complexity
8833
9014
  static async initializeErrorHandler(config, verbose) {
8834
9015
  if (config?.enabled === false) {
8835
- if (verbose) console.log("[Core] Error handler disabled by configuration");
9016
+ _Core.log("Error handler disabled by configuration", verbose);
8836
9017
  return;
8837
9018
  }
8838
9019
  _Core._errorConfig = config ?? {};
8839
- if (verbose) console.log("[Core] Initializing global error handler...");
9020
+ _Core.log("Initializing global error handler...", verbose);
8840
9021
  initializeErrorSystem({
8841
9022
  defaultLocale: _Core._errorConfig.localization?.defaultLocale,
8842
9023
  fallbackLocale: _Core._errorConfig.localization?.fallbackLocale,
@@ -8851,23 +9032,22 @@ var Core = class _Core {
8851
9032
  _Core.buildErrorHandlerConfig(_Core._errorConfig)
8852
9033
  );
8853
9034
  const errorEventCleanup = CoreEventManager.on(
8854
- CORE_EVENTS.SYSTEM.ERROR,
9035
+ CORE_EVENTS$1.SYSTEM.ERROR,
8855
9036
  (event) => {
8856
9037
  if (!_Core._rootStore) return;
8857
9038
  try {
8858
9039
  const { errors } = event.data;
8859
9040
  if (errors && errors.length > 0) {
8860
9041
  _Core._rootStore.getState().errors.addErrors(errors);
8861
- if (verbose) console.log(`[Core] Added ${errors.length} error(s) to store`);
9042
+ _Core.log(`Added ${errors.length} error(s) to store`, verbose);
8862
9043
  }
8863
9044
  } catch (e) {
8864
- console.error("[Core] Failed to handle error event:", e);
9045
+ _Core.logger.error("Failed to handle error event", { error: e });
8865
9046
  }
8866
9047
  }
8867
9048
  );
8868
9049
  _Core._eventCleanupFns.push(errorEventCleanup);
8869
- if (verbose)
8870
- console.log("[Core] Global error handler initialized with CoreEventManager integration");
9050
+ _Core.log("Global error handler initialized with CoreEventManager integration", verbose);
8871
9051
  if (_Core._errorConfig.httpHandler !== false) {
8872
9052
  _Core.createHttpErrorHandler(_Core._errorConfig, verbose);
8873
9053
  }
@@ -8889,11 +9069,11 @@ var Core = class _Core {
8889
9069
  switch (runtime) {
8890
9070
  case "express":
8891
9071
  _Core._httpErrorHandler = ServerErrorMiddleware.createHttpErrorHandler(httpConfig);
8892
- if (verbose) console.log("[Core] Created Express error handler middleware");
9072
+ _Core.log("Created Express error handler middleware", verbose);
8893
9073
  break;
8894
9074
  case "nestjs":
8895
9075
  _Core._httpErrorHandler = ServerErrorMiddleware.createNestJsExceptionFilter(httpConfig);
8896
- if (verbose) console.log("[Core] Created NestJS exception filter");
9076
+ _Core.log("Created NestJS exception filter", verbose);
8897
9077
  break;
8898
9078
  case "nextjs":
8899
9079
  _Core._httpErrorHandler = {
@@ -8905,7 +9085,7 @@ var Core = class _Core {
8905
9085
  /** For Pages Router: export default createNextApiErrorHandler()(handler) */
8906
9086
  createNextApiErrorHandler: /* @__PURE__ */ __name((overrideConfig = {}) => ServerErrorMiddleware.createNextApiErrorHandler({ ...httpConfig, ...overrideConfig }), "createNextApiErrorHandler")
8907
9087
  };
8908
- if (verbose) console.log("[Core] Created Next.js error handlers");
9088
+ _Core.log("Created Next.js error handlers", verbose);
8909
9089
  break;
8910
9090
  case "node":
8911
9091
  case "bun":
@@ -8922,15 +9102,15 @@ var Core = class _Core {
8922
9102
  /** Create middleware for use with native http */
8923
9103
  createMiddleware: /* @__PURE__ */ __name(() => ServerErrorMiddleware.createHttpErrorHandler(httpConfig), "createMiddleware")
8924
9104
  };
8925
- if (verbose) console.log(`[Core] Created ${runtime} error handler`);
9105
+ _Core.log(`Created ${runtime} error handler`, verbose);
8926
9106
  break;
8927
9107
  case "browser":
8928
9108
  _Core._httpErrorHandler = null;
8929
- if (verbose) console.log("[Core] Skipping HTTP handler for browser runtime");
9109
+ _Core.log("Skipping HTTP handler for browser runtime", verbose);
8930
9110
  break;
8931
9111
  default:
8932
9112
  _Core._httpErrorHandler = ServerErrorMiddleware.createHttpErrorHandler(httpConfig);
8933
- if (verbose) console.log(`[Core] Created generic HTTP error handler for ${runtime}`);
9113
+ _Core.log(`Created generic HTTP error handler for ${runtime}`, verbose);
8934
9114
  }
8935
9115
  }
8936
9116
  /**
@@ -8944,38 +9124,36 @@ var Core = class _Core {
8944
9124
  if (!_Core._errorHandler) {
8945
9125
  return;
8946
9126
  }
8947
- if (verbose) {
8948
- console.log("[Core] Subscribing to error events...");
8949
- }
8950
- const cleanupSystemError = CoreEventManager.on(CORE_EVENTS.SYSTEM.ERROR, (event) => {
9127
+ _Core.log("Subscribing to error events...", verbose);
9128
+ const cleanupSystemError = CoreEventManager.on(CORE_EVENTS$1.SYSTEM.ERROR, (event) => {
8951
9129
  if (_Core._errorHandler && event.data?.errors?.length) {
8952
9130
  for (const err of event.data.errors) {
8953
9131
  _Core._errorHandler.captureError(err, "system");
8954
9132
  }
8955
9133
  }
8956
9134
  });
8957
- const cleanupEntityError = CoreEventManager.on(CORE_EVENTS.ENTITY.ERROR, (event) => {
9135
+ const cleanupEntityError = CoreEventManager.on(CORE_EVENTS$1.ENTITY.ERROR, (event) => {
8958
9136
  if (_Core._errorHandler && event.data) {
8959
9137
  _Core._errorHandler.captureError(event.data.error, "entity");
8960
9138
  }
8961
9139
  });
8962
- const cleanupApiError = CoreEventManager.on(CORE_EVENTS.API.REQUEST_ERROR, (event) => {
9140
+ const cleanupApiError = CoreEventManager.on(CORE_EVENTS$1.API.REQUEST_ERROR, (event) => {
8963
9141
  if (_Core._errorHandler && event.data) {
8964
9142
  _Core._errorHandler.captureError(event.data.error, "api");
8965
9143
  }
8966
9144
  });
8967
- const cleanupValidationError = CoreEventManager.on(CORE_EVENTS.VALIDATION.FAILED, (event) => {
9145
+ const cleanupValidationError = CoreEventManager.on(CORE_EVENTS$1.VALIDATION.FAILED, (event) => {
8968
9146
  if (_Core._errorHandler && event.data) {
8969
9147
  _Core._errorHandler.captureError(event.data.error, "validation");
8970
9148
  }
8971
9149
  });
8972
- const cleanupAuthUnauthorized = CoreEventManager.on(CORE_EVENTS.AUTH.UNAUTHORIZED, (event) => {
9150
+ const cleanupAuthUnauthorized = CoreEventManager.on(CORE_EVENTS$1.AUTH.UNAUTHORIZED, (event) => {
8973
9151
  if (_Core._errorHandler && event.data?.error) {
8974
9152
  _Core._errorHandler.captureError(event.data.error, "auth");
8975
9153
  }
8976
9154
  });
8977
9155
  const cleanupAuthSessionExpired = CoreEventManager.on(
8978
- CORE_EVENTS.AUTH.SESSION_EXPIRED,
9156
+ CORE_EVENTS$1.AUTH.SESSION_EXPIRED,
8979
9157
  (event) => {
8980
9158
  if (_Core._errorHandler && event.data?.error) {
8981
9159
  _Core._errorHandler.captureError(event.data.error, "auth");
@@ -8991,20 +9169,20 @@ var Core = class _Core {
8991
9169
  cleanupAuthSessionExpired
8992
9170
  );
8993
9171
  if (_Core.isRuntimeCompatible("backend")) {
8994
- const cleanupDatabaseError = CoreEventManager.on(CORE_EVENTS.DATABASE.ERROR, (event) => {
9172
+ const cleanupDatabaseError = CoreEventManager.on(CORE_EVENTS$1.DATABASE.ERROR, (event) => {
8995
9173
  if (_Core._errorHandler && event.data) {
8996
9174
  _Core._errorHandler.captureError(event.data.error, "database");
8997
9175
  }
8998
9176
  });
8999
9177
  _Core._eventCleanupFns.push(cleanupDatabaseError);
9000
- const cleanupStorageError = CoreEventManager.on(CORE_EVENTS.STORAGE.ERROR, (event) => {
9178
+ const cleanupStorageError = CoreEventManager.on(CORE_EVENTS$1.STORAGE.ERROR, (event) => {
9001
9179
  if (_Core._errorHandler && event.data) {
9002
9180
  _Core._errorHandler.captureError(event.data.error, "storage");
9003
9181
  }
9004
9182
  });
9005
9183
  _Core._eventCleanupFns.push(cleanupStorageError);
9006
9184
  const cleanupNotificationError = CoreEventManager.on(
9007
- CORE_EVENTS.NOTIFICATION.ERROR,
9185
+ CORE_EVENTS$1.NOTIFICATION.ERROR,
9008
9186
  (event) => {
9009
9187
  if (_Core._errorHandler && event.data) {
9010
9188
  _Core._errorHandler.captureError(event.data.error, "notification");
@@ -9012,21 +9190,17 @@ var Core = class _Core {
9012
9190
  }
9013
9191
  );
9014
9192
  _Core._eventCleanupFns.push(cleanupNotificationError);
9015
- if (verbose) {
9016
- console.log("[Core] Subscribed to backend error events (database, storage, notification)");
9017
- }
9193
+ _Core.log("Subscribed to backend error events (database, storage, notification)", verbose);
9018
9194
  }
9019
- if (verbose) {
9020
- const eventTypes = ["system", "entity", "api", "validation", "auth"];
9021
- if (_Core.isRuntimeCompatible("backend")) {
9022
- eventTypes.push("database", "storage", "notification");
9023
- }
9024
- console.log(`[Core] Subscribed to error events: ${eventTypes.join(", ")}`);
9195
+ const eventTypes = ["system", "entity", "api", "validation", "auth"];
9196
+ if (_Core.isRuntimeCompatible("backend")) {
9197
+ eventTypes.push("database", "storage", "notification");
9025
9198
  }
9199
+ _Core.log(`Subscribed to error events: ${eventTypes.join(", ")}`, verbose);
9026
9200
  }
9027
9201
  /** Handle fetch flags error and return empty flags */
9028
9202
  static handleFetchFlagsError(error, config, verbose) {
9029
- if (verbose) console.error("[Core] Failed to fetch feature flags:", error);
9203
+ if (verbose) _Core.logger.error("Failed to fetch feature flags", { error });
9030
9204
  const packageError = error instanceof BaseError ? error : new CorePackageError(
9031
9205
  error instanceof Error ? error.message : String(error),
9032
9206
  ERROR_CODES.CORE_FEATURE_FLAG_PROVIDER_ERROR,
@@ -9059,7 +9233,7 @@ var Core = class _Core {
9059
9233
  */
9060
9234
  static async initializeFeatureFlags(config, verbose) {
9061
9235
  if (config?.enabled === false) {
9062
- if (verbose) console.log("[Core] Feature flags disabled by configuration");
9236
+ _Core.log("Feature flags disabled by configuration", verbose);
9063
9237
  return;
9064
9238
  }
9065
9239
  if (!_Core._rootStore) {
@@ -9069,7 +9243,7 @@ var Core = class _Core {
9069
9243
  );
9070
9244
  }
9071
9245
  _Core._flagConfig = config ?? {};
9072
- if (verbose) console.log("[Core] Initializing feature flags from root store...");
9246
+ _Core.log("Initializing feature flags from root store...", verbose);
9073
9247
  const state = _Core._rootStore.getState();
9074
9248
  await state.featureFlags.initialize({
9075
9249
  defaults: _Core._flagConfig.defaults,
@@ -9078,9 +9252,12 @@ var Core = class _Core {
9078
9252
  onFlagChange: _Core._flagConfig.onFlagChange,
9079
9253
  onError: _Core._flagConfig.onError
9080
9254
  });
9081
- if (verbose) console.log("[Core] Feature flags initialized");
9255
+ _Core.log("Feature flags initialized", verbose);
9082
9256
  }
9083
9257
  };
9258
+
9259
+ // src/entry-frontend.ts
9260
+ init_CoreEventManager();
9084
9261
  var errorContainerStyle = {
9085
9262
  padding: "20px",
9086
9263
  color: "red",
@@ -9124,6 +9301,9 @@ function InitializationLoading({ loading }) {
9124
9301
  return /* @__PURE__ */ jsx("div", { style: loadingContainerStyle, children: /* @__PURE__ */ jsx("p", { style: loadingMessageStyle, children: "Initializing..." }) });
9125
9302
  }
9126
9303
  __name(InitializationLoading, "InitializationLoading");
9304
+
9305
+ // src/engine/featureFlags/engine.ts
9306
+ init_common();
9127
9307
  var FeatureFlagContextBuilder = class _FeatureFlagContextBuilder {
9128
9308
  constructor() {
9129
9309
  this.context = {};
@@ -10242,11 +10422,19 @@ var ApiFeatureFlagProvider = class extends FeatureFlagProvider {
10242
10422
  return this.engine.getRules();
10243
10423
  }
10244
10424
  };
10425
+ init_DbService();
10426
+
10427
+ // src/models/featureFlags/FeatureFlagRepository.ts
10428
+ init_common();
10429
+ init_DbService();
10245
10430
  ({
10246
10431
  flagsTable: FEATURE_FLAG_TABLE.FeatureFlags,
10247
10432
  rulesTable: FEATURE_FLAG_TABLE.FeatureFlagRules,
10248
10433
  evaluationsTable: FEATURE_FLAG_TABLE.FeatureFlagEvaluations,
10249
10434
  overridesTable: FEATURE_FLAG_TABLE.FeatureFlagOverrides});
10435
+
10436
+ // src/domain/featureFlags/FrontendFeatureFlagDomainService.ts
10437
+ init_CoreEventManager();
10250
10438
  var DEFAULT_CACHE_TTL_SECONDS2 = 300;
10251
10439
  var DEFAULT_REFRESH_INTERVAL_MS = 6e4;
10252
10440
  var FrontendFeatureFlagDomainService = class _FrontendFeatureFlagDomainService extends BaseFrontendDomainService {
@@ -10725,6 +10913,7 @@ function ApiProvider({
10725
10913
  return /* @__PURE__ */ jsx(Fragment, { children });
10726
10914
  }
10727
10915
  __name(ApiProvider, "ApiProvider");
10916
+ init_CoreEventManager();
10728
10917
  var PlyazContext = createContext(null);
10729
10918
  var FeatureFlagStore = class {
10730
10919
  constructor(config = {}) {