@plyaz/core 1.8.3 → 1.9.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 (32) hide show
  1. package/dist/domain/base/BaseDomainService.d.ts +9 -4
  2. package/dist/domain/base/BaseDomainService.d.ts.map +1 -1
  3. package/dist/domain/example/FrontendExampleDomainService.d.ts.map +1 -1
  4. package/dist/domain/featureFlags/FrontendFeatureFlagDomainService.d.ts.map +1 -1
  5. package/dist/entry-backend.js +313 -207
  6. package/dist/entry-backend.js.map +1 -1
  7. package/dist/entry-backend.mjs +250 -144
  8. package/dist/entry-backend.mjs.map +1 -1
  9. package/dist/entry-frontend-browser.js +238 -141
  10. package/dist/entry-frontend-browser.js.map +1 -1
  11. package/dist/entry-frontend-browser.mjs +240 -143
  12. package/dist/entry-frontend-browser.mjs.map +1 -1
  13. package/dist/entry-frontend.js +238 -141
  14. package/dist/entry-frontend.js.map +1 -1
  15. package/dist/entry-frontend.mjs +240 -143
  16. package/dist/entry-frontend.mjs.map +1 -1
  17. package/dist/frontend/providers/PlyazProvider.d.ts.map +1 -1
  18. package/dist/index.js +315 -207
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.mjs +251 -144
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/init/CoreInitializer.d.ts +13 -2
  23. package/dist/init/CoreInitializer.d.ts.map +1 -1
  24. package/dist/init/nestjs/index.js +217 -136
  25. package/dist/init/nestjs/index.js.map +1 -1
  26. package/dist/init/nestjs/index.mjs +219 -138
  27. package/dist/init/nestjs/index.mjs.map +1 -1
  28. package/dist/services/ApiClientService.d.ts +43 -0
  29. package/dist/services/ApiClientService.d.ts.map +1 -1
  30. package/dist/services/CacheService.d.ts +5 -0
  31. package/dist/services/CacheService.d.ts.map +1 -1
  32. package/package.json +2 -2
@@ -1,10 +1,10 @@
1
1
  import { TIME_CONSTANTS, FORMAT_CONSTANTS, FILE_CHECK_INTERVAL_DEFAULT, FEATURE_FLAG_CACHE_TTL_DEFAULT, FEATURE_FLAG_FILE_PATHS, FEATURE_FLAG_PROVIDERS, NUMERIC_CONSTANTS, HTTP_STATUS as HTTP_STATUS$1, MATH_CONSTANTS, ISO_STANDARDS, CACHE_MAX_SIZE_DEFAULT, CACHE_CLEANUP_INTERVAL_DEFAULT, DEVELOPMENT_CONFIG, STAGING_CONFIG, PRODUCTION_CONFIG, FNV_CONSTANTS, FEATURES, HASH_SEED_CONSTANTS } from '@plyaz/config';
2
- import { ERROR_CODES as ERROR_CODES$1, HTTP_STATUS, NODE_ENVIRONMENTS, BACKEND_RUNTIMES, FRONTEND_RUNTIMES, ERROR_CATEGORY, CORE_EVENTS as CORE_EVENTS$1, PACKAGE_STATUS_CODES, API_ERROR_CODES, OPERATIONS, FEATURE_FLAG_PROVIDERS as FEATURE_FLAG_PROVIDERS$2, FEATURE_FLAG_METADATA } from '@plyaz/types';
2
+ import { ERROR_CODES as ERROR_CODES$1, HTTP_STATUS, NODE_ENVIRONMENTS, BACKEND_RUNTIMES, FRONTEND_RUNTIMES, ERROR_CATEGORY as ERROR_CATEGORY$1, CORE_EVENTS as CORE_EVENTS$1, PACKAGE_STATUS_CODES, API_ERROR_CODES, OPERATIONS, FEATURE_FLAG_PROVIDERS as FEATURE_FLAG_PROVIDERS$2, FEATURE_FLAG_METADATA } from '@plyaz/types';
3
3
  import { EventEmitter } from 'events';
4
4
  import { evaluateAllFeatureFlags, createFeatureFlag, updateFeatureFlag, deleteFeatureFlag, fetchFeatureFlagRules, createApiClient, mergeConfigs, ApiPackageError, setDefaultApiClient } from '@plyaz/api/frontend';
5
5
  import { CorePackageError, StoragePackageError, NotificationPackageError, BaseError, DatabasePackageError, ValidationError, initializeErrorSystem, generateRequestId, ValidateAndFormatErrors, SuccessResponseStandard } from '@plyaz/errors';
6
6
  import { CoreLogger, PackageLogger } from '@plyaz/logger';
7
- import { ERROR_CODES, STORAGE_ERROR_CODES, NOTIFICATION_ERROR_CODES, DATABASE_ERROR_CODES, API_ERROR_CODES as API_ERROR_CODES$1 } from '@plyaz/types/errors';
7
+ import { ERROR_CODES, STORAGE_ERROR_CODES, NOTIFICATION_ERROR_CODES, DATABASE_ERROR_CODES, ERROR_CATEGORY, API_ERROR_CODES as API_ERROR_CODES$1 } from '@plyaz/types/errors';
8
8
  import { OBSERVABILITY_METRICS } from '@plyaz/types/observability';
9
9
  import { clearEventEmitter, setEventEmitter, initializeGlobalErrorHandler } from '@plyaz/errors/middleware';
10
10
  import { STORE_KEYS, useRootStore, createStandaloneFeatureFlagStore } from '@plyaz/store';
@@ -621,7 +621,7 @@ function validateEnvironmentConfig(envConfig, mergedConfig) {
621
621
  );
622
622
  }
623
623
  }
624
- var MIN_RETRY_ATTEMPTS_PRODUCTION, ApiClientService, getApiClient, initApiClient, createApiClientInstance;
624
+ var MIN_RETRY_ATTEMPTS_PRODUCTION, ApiClientService, getApiClient, initApiClient, createApiClientInstance, createStandaloneApiClient;
625
625
  var init_ApiClientService = __esm({
626
626
  "src/services/ApiClientService.ts"() {
627
627
  init_CoreEventManager();
@@ -648,6 +648,80 @@ var init_ApiClientService = __esm({
648
648
  static {
649
649
  this.initPromise = null;
650
650
  }
651
+ /**
652
+ * Build the core error handler for API clients.
653
+ * This handler emits errors to CoreEventManager for global error handling.
654
+ *
655
+ * Handles:
656
+ * - Single errors (network, timeout)
657
+ * - Array of errors from API responses (validation, business logic)
658
+ * - Serialization to unified SerializedError format
659
+ * - Event emission to CORE_EVENTS.SYSTEM.ERROR and CORE_EVENTS.API.REQUEST_ERROR
660
+ *
661
+ * @returns Error handler function compatible with ApiClientOptions.onError
662
+ */
663
+ static buildCoreErrorHandler() {
664
+ return async (error) => {
665
+ const requestId = generateRequestId();
666
+ const method = error.config?.method ?? "UNKNOWN";
667
+ const url = error.config?.url ?? "unknown";
668
+ try {
669
+ const errorDetails = Array.isArray(error.response?.data) ? error.response.data : [];
670
+ if (errorDetails.length === 0) {
671
+ const serializedError = {
672
+ id: requestId,
673
+ code: ERROR_CODES$1.CORE_API_CLIENT_REQUEST_FAILED,
674
+ message: error.message ?? "API request failed",
675
+ status: error.status,
676
+ category: ERROR_CATEGORY$1.Network,
677
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
678
+ isRetryable: error.status ? error.status >= HTTP_STATUS.INTERNAL_SERVER_ERROR : false,
679
+ source: "api-client",
680
+ dismissed: false,
681
+ context: {
682
+ method,
683
+ url,
684
+ requestId
685
+ }
686
+ };
687
+ CoreEventManager.emit(CORE_EVENTS$1.SYSTEM.ERROR, { errors: [serializedError] });
688
+ } else {
689
+ const serializedErrors = errorDetails.map(
690
+ (detail, index) => ({
691
+ id: `${requestId}-${index}`,
692
+ code: detail.errorCode ?? ERROR_CODES$1.CORE_API_CLIENT_REQUEST_FAILED,
693
+ message: detail.message ?? error.message ?? "API request failed",
694
+ status: error.status,
695
+ category: ERROR_CATEGORY$1.Network,
696
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
697
+ isRetryable: error.status ? error.status >= HTTP_STATUS.INTERNAL_SERVER_ERROR : false,
698
+ source: "api-client",
699
+ dismissed: false,
700
+ context: {
701
+ method,
702
+ url,
703
+ requestId,
704
+ field: detail.field,
705
+ valueGiven: detail.valueGiven,
706
+ allowedValues: detail.allowedValues,
707
+ constraints: detail.constraints
708
+ }
709
+ })
710
+ );
711
+ CoreEventManager.emit(CORE_EVENTS$1.SYSTEM.ERROR, { errors: serializedErrors });
712
+ }
713
+ } catch (e) {
714
+ console.error("[ApiClientService] Failed to emit error event:", e);
715
+ }
716
+ _ApiClientService.emitApiError(error, {
717
+ method,
718
+ url,
719
+ requestId,
720
+ status: error.status,
721
+ duration: 0
722
+ });
723
+ };
724
+ }
651
725
  /**
652
726
  * Initialize the API client with environment config and API options
653
727
  *
@@ -685,71 +759,12 @@ var init_ApiClientService = __esm({
685
759
  * 2. Environment metadata (envConfig - apiKey)
686
760
  * 3. API configuration (apiConfig - baseURL, encryption, timeout, etc.)
687
761
  */
688
- // eslint-disable-next-line max-lines-per-function, complexity
762
+ // eslint-disable-next-line complexity
689
763
  static async createClient(envConfig, apiConfig) {
690
764
  try {
691
765
  const envDefaults = getConfigForEnvironment(envConfig.env);
692
766
  const envMetadataMapped = mapEnvironmentMetadata(envConfig, envDefaults);
693
- const coreErrorHandler = /* @__PURE__ */ __name(async (error) => {
694
- const requestId = generateRequestId();
695
- const method = error.config?.method ?? "UNKNOWN";
696
- const url = error.config?.url ?? "unknown";
697
- try {
698
- const errorDetails = Array.isArray(error.response?.data) ? error.response.data : [];
699
- if (errorDetails.length === 0) {
700
- const serializedError = {
701
- id: requestId,
702
- code: ERROR_CODES$1.CORE_API_CLIENT_REQUEST_FAILED,
703
- message: error.message ?? "API request failed",
704
- status: error.status,
705
- category: ERROR_CATEGORY.Network,
706
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
707
- isRetryable: error.status ? error.status >= HTTP_STATUS.INTERNAL_SERVER_ERROR : false,
708
- source: "api-client",
709
- dismissed: false,
710
- context: {
711
- method,
712
- url,
713
- requestId
714
- }
715
- };
716
- CoreEventManager.emit(CORE_EVENTS$1.SYSTEM.ERROR, { errors: [serializedError] });
717
- } else {
718
- const serializedErrors = errorDetails.map(
719
- (detail, index) => ({
720
- id: `${requestId}-${index}`,
721
- code: detail.errorCode ?? ERROR_CODES$1.CORE_API_CLIENT_REQUEST_FAILED,
722
- message: detail.message ?? error.message ?? "API request failed",
723
- status: error.status,
724
- category: ERROR_CATEGORY.Network,
725
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
726
- isRetryable: error.status ? error.status >= HTTP_STATUS.INTERNAL_SERVER_ERROR : false,
727
- source: "api-client",
728
- dismissed: false,
729
- context: {
730
- method,
731
- url,
732
- requestId,
733
- field: detail.field,
734
- valueGiven: detail.valueGiven,
735
- allowedValues: detail.allowedValues,
736
- constraints: detail.constraints
737
- }
738
- })
739
- );
740
- CoreEventManager.emit(CORE_EVENTS$1.SYSTEM.ERROR, { errors: serializedErrors });
741
- }
742
- } catch (e) {
743
- console.error("[ApiClientService] Failed to emit error event:", e);
744
- }
745
- _ApiClientService.emitApiError(error, {
746
- method,
747
- url,
748
- requestId,
749
- status: error.status,
750
- duration: 0
751
- });
752
- }, "coreErrorHandler");
767
+ const coreErrorHandler = _ApiClientService.buildCoreErrorHandler();
753
768
  const userOnError = apiConfig?.onError;
754
769
  const combinedOnError = userOnError ? Array.isArray(userOnError) ? [...userOnError, coreErrorHandler] : [userOnError, coreErrorHandler] : coreErrorHandler;
755
770
  const mergedOptions = mergeConfigs(
@@ -924,11 +939,13 @@ var init_ApiClientService = __esm({
924
939
  try {
925
940
  const envDefaults = getConfigForEnvironment(envConfig.env);
926
941
  const envMetadataMapped = mapEnvironmentMetadata(envConfig, envDefaults);
927
- const mergedOptions = mergeConfigs(
928
- envDefaults,
929
- envMetadataMapped,
930
- apiConfig ?? {}
931
- );
942
+ const coreErrorHandler = _ApiClientService.buildCoreErrorHandler();
943
+ const userOnError = apiConfig?.onError;
944
+ const combinedOnError = userOnError ? Array.isArray(userOnError) ? [...userOnError, coreErrorHandler] : [userOnError, coreErrorHandler] : coreErrorHandler;
945
+ const mergedOptions = mergeConfigs(envDefaults, envMetadataMapped, {
946
+ ...apiConfig ?? {},
947
+ onError: combinedOnError
948
+ });
932
949
  validateEnvironmentConfig(envConfig, mergedOptions);
933
950
  const dedicatedClient = await createApiClient(mergedOptions);
934
951
  return dedicatedClient;
@@ -950,10 +967,66 @@ var init_ApiClientService = __esm({
950
967
  );
951
968
  }
952
969
  }
970
+ /**
971
+ * Create a standalone API client with Core error handling.
972
+ *
973
+ * This is a simpler alternative to `createInstance()` that doesn't require
974
+ * environment config. Use this when you just need the error handling without
975
+ * environment-specific defaults (production validation, etc.).
976
+ *
977
+ * **Use cases:**
978
+ * - Domain services that need their own API client
979
+ * - Testing with isolated API clients
980
+ * - Simple client creation without environment setup
981
+ *
982
+ * @param apiConfig - API configuration (baseURL, timeout, etc.)
983
+ * @returns Promise that resolves to a client with Core error handling
984
+ *
985
+ * @example
986
+ * ```typescript
987
+ * // In BaseDomainService or any service
988
+ * const client = await ApiClientService.createStandaloneClient({
989
+ * baseURL: '/api/examples',
990
+ * timeout: 10000,
991
+ * });
992
+ *
993
+ * // Errors are automatically emitted to CoreEventManager
994
+ * const response = await client.get('/items');
995
+ * ```
996
+ */
997
+ static async createStandaloneClient(apiConfig) {
998
+ try {
999
+ const coreErrorHandler = _ApiClientService.buildCoreErrorHandler();
1000
+ const userOnError = apiConfig.onError;
1001
+ const combinedOnError = userOnError ? Array.isArray(userOnError) ? [...userOnError, coreErrorHandler] : [userOnError, coreErrorHandler] : coreErrorHandler;
1002
+ const client = await createApiClient({
1003
+ ...apiConfig,
1004
+ onError: combinedOnError
1005
+ });
1006
+ return client;
1007
+ } catch (error) {
1008
+ throw new ApiPackageError(
1009
+ "service.standalone_client_creation.failed",
1010
+ PACKAGE_STATUS_CODES.INITIALIZATION_FAILED,
1011
+ API_ERROR_CODES.CLIENT_INITIALIZATION_FAILED,
1012
+ {
1013
+ cause: error instanceof Error ? error : void 0,
1014
+ context: {
1015
+ operation: OPERATIONS.INITIALIZATION,
1016
+ originalError: error instanceof Error ? error.message : String(error),
1017
+ i18n: {
1018
+ error: error instanceof Error ? error.message : String(error)
1019
+ }
1020
+ }
1021
+ }
1022
+ );
1023
+ }
1024
+ }
953
1025
  };
954
1026
  getApiClient = /* @__PURE__ */ __name(() => ApiClientService.getClient(), "getApiClient");
955
1027
  initApiClient = /* @__PURE__ */ __name((envConfig, apiConfig) => ApiClientService.init(envConfig, apiConfig), "initApiClient");
956
1028
  createApiClientInstance = /* @__PURE__ */ __name((envConfig, apiConfig) => ApiClientService.createInstance(envConfig, apiConfig), "createApiClientInstance");
1029
+ createStandaloneApiClient = /* @__PURE__ */ __name((apiConfig) => ApiClientService.createStandaloneClient(apiConfig), "createStandaloneApiClient");
957
1030
  }
958
1031
  });
959
1032
  var BaseAdapter, NoopAdapter;
@@ -2696,6 +2769,7 @@ var init_CoreInitializer = __esm({
2696
2769
  init_ObservabilityService();
2697
2770
  init_LoggerAdapter();
2698
2771
  init_runtime();
2772
+ init_common();
2699
2773
  init_dependencies();
2700
2774
  DEFAULT_MAX_ERRORS = 100;
2701
2775
  _getCoreDomainServices = null;
@@ -3572,6 +3646,7 @@ var init_CoreInitializer = __esm({
3572
3646
  _Core._errorHandler.destroy();
3573
3647
  _Core._errorHandler = null;
3574
3648
  clearEventEmitter();
3649
+ BaseError.clearEventEmitter();
3575
3650
  }
3576
3651
  _Core._errorConfig = {};
3577
3652
  _Core._httpErrorHandler = null;
@@ -3760,6 +3835,28 @@ var init_CoreInitializer = __esm({
3760
3835
  };
3761
3836
  }
3762
3837
  }
3838
+ /**
3839
+ * Serialize a PackageErrorLike to SerializedError format.
3840
+ * Used by BaseError.setEventEmitter() to convert errors for the store.
3841
+ */
3842
+ static serializePackageError(error) {
3843
+ const serviceName = typeof error.context?.service === "string" ? error.context.service : "core";
3844
+ return {
3845
+ id: generateId(),
3846
+ code: error.errorCode ?? ERROR_CODES$1.UNKNOWN_ERROR,
3847
+ message: error.message,
3848
+ status: error.statusCode,
3849
+ category: error.category ?? ERROR_CATEGORY.Server,
3850
+ timestamp: error.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
3851
+ isRetryable: error.retryable ?? false,
3852
+ source: serviceName,
3853
+ dismissed: false,
3854
+ context: {
3855
+ correlationId: error.correlationId,
3856
+ ...error.context
3857
+ }
3858
+ };
3859
+ }
3763
3860
  /** Get error store actions from root store */
3764
3861
  static getErrorStoreActions() {
3765
3862
  if (!_Core._rootStore) {
@@ -3771,12 +3868,17 @@ var init_CoreInitializer = __esm({
3771
3868
  return _Core._rootStore.getState().errors;
3772
3869
  }
3773
3870
  /** Build global error handler config */
3774
- // eslint-disable-next-line complexity
3775
3871
  static buildErrorHandlerConfig(config) {
3872
+ const baseErrorFilter = /* @__PURE__ */ __name((error) => {
3873
+ if (error instanceof BaseError) {
3874
+ return false;
3875
+ }
3876
+ return config?.filter ? config.filter(error) : true;
3877
+ }, "baseErrorFilter");
3776
3878
  return {
3777
3879
  source: config?.source ?? "global",
3778
3880
  maxErrors: config?.maxErrors ?? DEFAULT_MAX_ERRORS,
3779
- filter: config?.filter,
3881
+ filter: baseErrorFilter,
3780
3882
  onError: config?.onError,
3781
3883
  logToConsole: config?.logToConsole ?? false
3782
3884
  };
@@ -3797,6 +3899,15 @@ var init_CoreInitializer = __esm({
3797
3899
  });
3798
3900
  await _Core.initializeRootStore(_Core._errorConfig, verbose);
3799
3901
  setEventEmitter(CoreEventManager.emit.bind(CoreEventManager));
3902
+ BaseError.setEventEmitter((error) => {
3903
+ const serializedError = _Core.serializePackageError(error);
3904
+ const serviceName = serializedError.source ?? "core";
3905
+ CoreEventManager.emit(CORE_EVENTS.SYSTEM.ERROR, {
3906
+ errors: [serializedError],
3907
+ context: serviceName,
3908
+ recoverable: error.retryable ?? false
3909
+ });
3910
+ });
3800
3911
  const errorStore = _Core.getErrorStoreActions();
3801
3912
  _Core._errorHandler = initializeGlobalErrorHandler(
3802
3913
  errorStore,
@@ -3892,9 +4003,15 @@ var init_CoreInitializer = __esm({
3892
4003
  }
3893
4004
  /**
3894
4005
  * Subscribe to CoreEventManager error events
3895
- * Forwards system, entity, API, validation, database, and auth errors to the global error handler.
4006
+ * Forwards entity, API, validation, database, and auth errors to the global error handler.
4007
+ *
4008
+ * NOTE: SYSTEM.ERROR is NOT subscribed here - it's handled in initializeErrorHandler()
4009
+ * via the BaseError.setEventEmitter() + addErrors() pattern to avoid duplicate subscriptions.
3896
4010
  *
3897
- * Note: Database errors (DATABASE.ERROR) are only subscribed on backend runtimes since
4011
+ * For non-BaseError errors, domain-specific events (ENTITY.ERROR, API.REQUEST_ERROR, etc.)
4012
+ * are captured here. BaseError instances are skipped (they already auto-emit via SYSTEM.ERROR).
4013
+ *
4014
+ * Database errors (DATABASE.ERROR) are only subscribed on backend runtimes since
3898
4015
  * DbService is backend-only (skipDb: true on frontend).
3899
4016
  */
3900
4017
  static subscribeToErrorEvents(verbose) {
@@ -3902,78 +4019,36 @@ var init_CoreInitializer = __esm({
3902
4019
  return;
3903
4020
  }
3904
4021
  _Core.log("Subscribing to error events...", verbose);
3905
- const cleanupSystemError = CoreEventManager.on(CORE_EVENTS.SYSTEM.ERROR, (event) => {
3906
- if (_Core._errorHandler && event.data?.errors?.length) {
3907
- for (const err of event.data.errors) {
3908
- _Core._errorHandler.captureError(err, "system");
3909
- }
3910
- }
3911
- });
3912
- const cleanupEntityError = CoreEventManager.on(CORE_EVENTS.ENTITY.ERROR, (event) => {
3913
- if (_Core._errorHandler && event.data) {
3914
- _Core._errorHandler.captureError(event.data.error, "entity");
3915
- }
3916
- });
3917
- const cleanupApiError = CoreEventManager.on(CORE_EVENTS.API.REQUEST_ERROR, (event) => {
3918
- if (_Core._errorHandler && event.data) {
3919
- _Core._errorHandler.captureError(event.data.error, "api");
3920
- }
3921
- });
3922
- const cleanupValidationError = CoreEventManager.on(CORE_EVENTS.VALIDATION.FAILED, (event) => {
3923
- if (_Core._errorHandler && event.data) {
3924
- _Core._errorHandler.captureError(event.data.error, "validation");
3925
- }
3926
- });
3927
- const cleanupAuthUnauthorized = CoreEventManager.on(CORE_EVENTS.AUTH.UNAUTHORIZED, (event) => {
3928
- if (_Core._errorHandler && event.data?.error) {
3929
- _Core._errorHandler.captureError(event.data.error, "auth");
3930
- }
3931
- });
3932
- const cleanupAuthSessionExpired = CoreEventManager.on(
3933
- CORE_EVENTS.AUTH.SESSION_EXPIRED,
3934
- (event) => {
3935
- if (_Core._errorHandler && event.data?.error) {
3936
- _Core._errorHandler.captureError(event.data.error, "auth");
4022
+ const subscribeError = /* @__PURE__ */ __name((event, source) => {
4023
+ return CoreEventManager.on(event, (e) => {
4024
+ if (_Core._errorHandler && e.data?.error && !(e.data.error instanceof BaseError)) {
4025
+ _Core._errorHandler.captureError(e.data.error, source);
3937
4026
  }
3938
- }
3939
- );
4027
+ });
4028
+ }, "subscribeError");
3940
4029
  _Core._eventCleanupFns.push(
3941
- cleanupSystemError,
3942
- cleanupEntityError,
3943
- cleanupApiError,
3944
- cleanupValidationError,
3945
- cleanupAuthUnauthorized,
3946
- cleanupAuthSessionExpired
4030
+ subscribeError(CORE_EVENTS.ENTITY.ERROR, "entity"),
4031
+ subscribeError(CORE_EVENTS.API.REQUEST_ERROR, "api"),
4032
+ subscribeError(CORE_EVENTS.VALIDATION.FAILED, "validation"),
4033
+ subscribeError(CORE_EVENTS.AUTH.UNAUTHORIZED, "auth"),
4034
+ subscribeError(CORE_EVENTS.AUTH.SESSION_EXPIRED, "auth")
3947
4035
  );
3948
4036
  if (_Core.isRuntimeCompatible("backend")) {
3949
- const cleanupDatabaseError = CoreEventManager.on(CORE_EVENTS.DATABASE.ERROR, (event) => {
3950
- if (_Core._errorHandler && event.data) {
3951
- _Core._errorHandler.captureError(event.data.error, "database");
3952
- }
3953
- });
3954
- _Core._eventCleanupFns.push(cleanupDatabaseError);
3955
- const cleanupStorageError = CoreEventManager.on(CORE_EVENTS.STORAGE.ERROR, (event) => {
3956
- if (_Core._errorHandler && event.data) {
3957
- _Core._errorHandler.captureError(event.data.error, "storage");
3958
- }
3959
- });
3960
- _Core._eventCleanupFns.push(cleanupStorageError);
3961
- const cleanupNotificationError = CoreEventManager.on(
3962
- CORE_EVENTS.NOTIFICATION.ERROR,
3963
- (event) => {
3964
- if (_Core._errorHandler && event.data) {
3965
- _Core._errorHandler.captureError(event.data.error, "notification");
3966
- }
3967
- }
4037
+ _Core._eventCleanupFns.push(
4038
+ subscribeError(CORE_EVENTS.DATABASE.ERROR, "database"),
4039
+ subscribeError(CORE_EVENTS.STORAGE.ERROR, "storage"),
4040
+ subscribeError(CORE_EVENTS.NOTIFICATION.ERROR, "notification"),
4041
+ subscribeError(CORE_EVENTS.CACHE.ERROR, "cache")
4042
+ );
4043
+ _Core.log(
4044
+ "Subscribed to backend error events (database, storage, notification, cache)",
4045
+ verbose
3968
4046
  );
3969
- _Core._eventCleanupFns.push(cleanupNotificationError);
3970
- _Core.log("Subscribed to backend error events (database, storage, notification)", verbose);
3971
- }
3972
- const eventTypes = ["system", "entity", "api", "validation", "auth"];
3973
- if (_Core.isRuntimeCompatible("backend")) {
3974
- eventTypes.push("database", "storage", "notification");
3975
4047
  }
3976
- _Core.log(`Subscribed to error events: ${eventTypes.join(", ")}`, verbose);
4048
+ const eventTypes = ["entity", "api", "validation", "auth"];
4049
+ if (_Core.isRuntimeCompatible("backend"))
4050
+ eventTypes.push("database", "storage", "notification", "cache");
4051
+ _Core.log(`Subscribed to domain error events: ${eventTypes.join(", ")}`, verbose);
3977
4052
  }
3978
4053
  /** Handle fetch flags error and return empty flags */
3979
4054
  static handleFetchFlagsError(error, config, verbose) {
@@ -4051,6 +4126,7 @@ var BaseDomainService;
4051
4126
  var init_BaseDomainService = __esm({
4052
4127
  "src/domain/base/BaseDomainService.ts"() {
4053
4128
  init_CoreInitializer();
4129
+ init_ApiClientService();
4054
4130
  BaseDomainService = class {
4055
4131
  // ─────────────────────────────────────────────────────────────────────────
4056
4132
  // Constructor
@@ -4226,6 +4302,11 @@ var init_BaseDomainService = __esm({
4226
4302
  /**
4227
4303
  * Initialize API client asynchronously
4228
4304
  * Called from constructor if apiClientConfig is provided
4305
+ *
4306
+ * Uses ApiClientService.createStandaloneClient() which includes:
4307
+ * - Automatic error handling (single errors and arrays)
4308
+ * - Event emission to CORE_EVENTS.SYSTEM.ERROR and CORE_EVENTS.API.REQUEST_ERROR
4309
+ * - Serialization to unified SerializedError format
4229
4310
  */
4230
4311
  initializeApiClient() {
4231
4312
  if (this._clientInitPromise || !this._apiClientConfig) {
@@ -4233,7 +4314,7 @@ var init_BaseDomainService = __esm({
4233
4314
  }
4234
4315
  this._clientInitPromise = (async () => {
4235
4316
  try {
4236
- this._apiClient = await createApiClient(this._apiClientConfig);
4317
+ this._apiClient = await ApiClientService.createStandaloneClient(this._apiClientConfig);
4237
4318
  if (this._setAsDefaultClient) {
4238
4319
  setDefaultApiClient(this._apiClient);
4239
4320
  }
@@ -7830,7 +7911,7 @@ var init_FrontendExampleDomainService = __esm({
7830
7911
  // Constructor
7831
7912
  // ─────────────────────────────────────────────────────────────────────────
7832
7913
  constructor(config = {}, options) {
7833
- const apiBasePath = config.apiBasePath ?? "/api/examples";
7914
+ const apiBasePath = config.apiBasePath || "/api/examples";
7834
7915
  super({
7835
7916
  serviceName: "ExampleFrontendService",
7836
7917
  supportedRuntimes: ["frontend"],
@@ -7934,7 +8015,11 @@ var init_FrontendExampleDomainService = __esm({
7934
8015
  static async create(config, options) {
7935
8016
  const mergedConfig = {
7936
8017
  ...config,
7937
- apiBasePath: config.apiBasePath ?? options?.apiClient?.options?.baseURL ?? "/api/examples"
8018
+ // Use || instead of ?? because api.baseURL may be '' (empty string) for same-origin requests.
8019
+ // The ?? operator only falls through on null/undefined, not empty strings.
8020
+ // An empty string is not a valid API path, so we treat it as "not provided" and fall through to default.
8021
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
8022
+ apiBasePath: config.apiBasePath || options?.apiClient?.options?.baseURL || "/api/examples"
7938
8023
  };
7939
8024
  const service = new _FrontendExampleDomainService(mergedConfig, options);
7940
8025
  if (mergedConfig.autoFetch) {
@@ -9410,6 +9495,7 @@ init_DbService();
9410
9495
 
9411
9496
  // src/services/CacheService.ts
9412
9497
  init_cache();
9498
+ init_CoreEventManager();
9413
9499
  var CacheService = class _CacheService {
9414
9500
  /** Private constructor to enforce singleton */
9415
9501
  constructor() {
@@ -9427,6 +9513,22 @@ var CacheService = class _CacheService {
9427
9513
  /** Singleton instance */
9428
9514
  this.instance = null;
9429
9515
  }
9516
+ // ─────────────────────────────────────────────────────────────────
9517
+ // Error Handling
9518
+ // ─────────────────────────────────────────────────────────────────
9519
+ /**
9520
+ * Emits a cache error event via CoreEventManager.
9521
+ * Called when cache operations fail to integrate with global error handling.
9522
+ */
9523
+ emitCacheError(error, operation, options) {
9524
+ const payload = {
9525
+ error,
9526
+ operation,
9527
+ key: options?.key,
9528
+ recoverable: options?.recoverable ?? true
9529
+ };
9530
+ CoreEventManager.emit(CORE_EVENTS.CACHE.ERROR, payload);
9531
+ }
9430
9532
  /**
9431
9533
  * Initialize the cache service with configuration
9432
9534
  *
@@ -9471,6 +9573,7 @@ var CacheService = class _CacheService {
9471
9573
  });
9472
9574
  } catch (error) {
9473
9575
  service.logger.error("[CacheService] Failed to initialize cache", { error });
9576
+ service.emitCacheError(error, "initialize", { recoverable: false });
9474
9577
  throw new CorePackageError(
9475
9578
  `Failed to initialize cache: ${error instanceof Error ? error.message : String(error)}`,
9476
9579
  ERROR_CODES.VALIDATION_ERROR,
@@ -13947,7 +14050,10 @@ var DEFAULT_REFRESH_INTERVAL_MS = 6e4;
13947
14050
  }
13948
14051
  /** Build API client for feature flags */
13949
14052
  static async buildApiClient(config, options) {
13950
- const apiBasePath = config.apiBasePath ?? options?.apiClient?.options?.baseURL ?? "/feature-flags";
14053
+ const apiBasePath = (
14054
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
14055
+ config.apiBasePath || options?.apiClient?.options?.baseURL || "/feature-flags"
14056
+ );
13951
14057
  return createApiClient({ ...options?.apiClient?.options, baseURL: apiBasePath });
13952
14058
  }
13953
14059
  /** Build feature flag provider */
@@ -15391,6 +15497,6 @@ setCoreDependencies({
15391
15497
  });
15392
15498
  setGetCoreDomainServices(getCoreDomainServices);
15393
15499
 
15394
- export { ApiClientService, BACKEND_EXAMPLE_DOMAIN_SERVICE, BackendExampleDomainService, BaseBackendDomainService, BaseDomainService, BaseMapper, BaseValidator, CORE_DB_SERVICE, CORE_ENV, CORE_OPTIONS, CacheKeyBuilder, CacheManager, CacheService, Caching, ConditionUtils, ContextUtils, Core, CoreEventManager, CoreModule, DEFAULT_ENCRYPTION_FIELDS, DbService, ErrorHandlingInterceptor, ExampleController, ExampleModule, FeatureDisabled, FeatureEnabled, FeatureFlagConfigFactory, FeatureFlagConfigValidator, FeatureFlagContextBuilder, FeatureFlagController, FeatureFlagDatabaseRepository, FeatureFlagDomainService, FeatureFlagEngine, FeatureFlagGuard, FeatureFlagLoggingInterceptor, FeatureFlagMiddleware, FeatureFlagModule, FeatureFlagService, FeatureFlagServiceFactory, HashUtils, IdUtils, NotificationService, ObjectUtils, PACKAGE_NAME, ServiceRegistry, StorageService, TABLE_REGISTRY, VERSION, ValueUtils, backendExampleDomainService, backendExampleDomainService as backendExampleService, camelToSnake, clearCoreDependencies, createApiClientInstance, createBackendContext, createFrontendContext, createHandler, createRolloutIdentifier, detectRuntime, evaluateArrayOperator, evaluateConditionOperator, evaluateEqualityOperator, evaluateNumericOperator, evaluateStringOperator, backendExampleDomainService as exampleService, formatDate, generateCorrelationId, generateId, generateShortId, generateSpanId, generateTraceId, getApiClient, getCacheService, getCoreDependencies, getCoreDependency, getNestedProperty, getPackageVersion, getValidProviders, hasCoreDependency, hasNestedProperty, hashString, initApiClient, isArrayOperator, isDefined, isEqualityOperator, isInRollout, isNumber, isNumericOperator, isString, isStringOperator, isTruthy, keysToCamel, keysToSnake, loadEnvFile, createHandler as nextHandler, parseDate, pickDefined, setCoreDependencies, setNestedProperty, snakeToCamel, toBoolean, trimString };
15500
+ export { ApiClientService, BACKEND_EXAMPLE_DOMAIN_SERVICE, BackendExampleDomainService, BaseBackendDomainService, BaseDomainService, BaseMapper, BaseValidator, CORE_DB_SERVICE, CORE_ENV, CORE_OPTIONS, CacheKeyBuilder, CacheManager, CacheService, Caching, ConditionUtils, ContextUtils, Core, CoreEventManager, CoreModule, DEFAULT_ENCRYPTION_FIELDS, DbService, ErrorHandlingInterceptor, ExampleController, ExampleModule, FeatureDisabled, FeatureEnabled, FeatureFlagConfigFactory, FeatureFlagConfigValidator, FeatureFlagContextBuilder, FeatureFlagController, FeatureFlagDatabaseRepository, FeatureFlagDomainService, FeatureFlagEngine, FeatureFlagGuard, FeatureFlagLoggingInterceptor, FeatureFlagMiddleware, FeatureFlagModule, FeatureFlagService, FeatureFlagServiceFactory, HashUtils, IdUtils, NotificationService, ObjectUtils, PACKAGE_NAME, ServiceRegistry, StorageService, TABLE_REGISTRY, VERSION, ValueUtils, backendExampleDomainService, backendExampleDomainService as backendExampleService, camelToSnake, clearCoreDependencies, createApiClientInstance, createBackendContext, createFrontendContext, createHandler, createRolloutIdentifier, createStandaloneApiClient, detectRuntime, evaluateArrayOperator, evaluateConditionOperator, evaluateEqualityOperator, evaluateNumericOperator, evaluateStringOperator, backendExampleDomainService as exampleService, formatDate, generateCorrelationId, generateId, generateShortId, generateSpanId, generateTraceId, getApiClient, getCacheService, getCoreDependencies, getCoreDependency, getNestedProperty, getPackageVersion, getValidProviders, hasCoreDependency, hasNestedProperty, hashString, initApiClient, isArrayOperator, isDefined, isEqualityOperator, isInRollout, isNumber, isNumericOperator, isString, isStringOperator, isTruthy, keysToCamel, keysToSnake, loadEnvFile, createHandler as nextHandler, parseDate, pickDefined, setCoreDependencies, setNestedProperty, snakeToCamel, toBoolean, trimString };
15395
15501
  //# sourceMappingURL=entry-backend.mjs.map
15396
15502
  //# sourceMappingURL=entry-backend.mjs.map