@plyaz/core 1.7.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2590,6 +2590,13 @@ var Core = class _Core {
2590
2590
  _Core._logger = null;
2591
2591
  }
2592
2592
  }
2593
+ /**
2594
+ * Get the configured logger transport.
2595
+ * Used by services to create loggers with the same transport setting.
2596
+ */
2597
+ static get loggerTransport() {
2598
+ return _Core._loggerTransport;
2599
+ }
2593
2600
  /**
2594
2601
  * Log a message during initialization.
2595
2602
  * Uses PackageLogger, respects verbose flag.
@@ -3901,7 +3908,8 @@ var BaseDomainService = class {
3901
3908
  this._setAsDefaultClient = config.setAsDefaultClient ?? false;
3902
3909
  this.logger = new logger$1.PackageLogger({
3903
3910
  packageName: "core",
3904
- service: this.serviceName
3911
+ service: this.serviceName,
3912
+ transport: Core.loggerTransport
3905
3913
  });
3906
3914
  this._apiClientConfig = config.apiClientConfig;
3907
3915
  this.cacheManager = config.injected?.cache;
@@ -4682,6 +4690,94 @@ var BaseFrontendDomainService = class extends BaseDomainService {
4682
4690
  }
4683
4691
  return result;
4684
4692
  }
4693
+ /**
4694
+ * Check if a response indicates success.
4695
+ *
4696
+ * Uses `responseSuccessKey` config if set, otherwise auto-detects from:
4697
+ * - `isSuccess` (internal format)
4698
+ * - `success` (alternative internal format)
4699
+ * - `ok` (fetchff/fetch standard)
4700
+ * - HTTP status code 200-299
4701
+ *
4702
+ * Supports nested keys via dot notation (e.g., `'meta.success'`).
4703
+ *
4704
+ * @param response - Response object from fetcher
4705
+ * @returns true if response indicates success
4706
+ */
4707
+ // eslint-disable-next-line complexity
4708
+ isResponseSuccess(response) {
4709
+ if (!response || typeof response !== "object") {
4710
+ return false;
4711
+ }
4712
+ const resp = response;
4713
+ const successKey = this.config.responseSuccessKey;
4714
+ if (successKey) {
4715
+ const keys = successKey.split(".");
4716
+ let result = resp;
4717
+ for (const k of keys) {
4718
+ if (result && typeof result === "object" && k in result) {
4719
+ result = result[k];
4720
+ } else {
4721
+ break;
4722
+ }
4723
+ }
4724
+ if (typeof result === "boolean") {
4725
+ return result;
4726
+ }
4727
+ }
4728
+ if ("isSuccess" in resp && typeof resp.isSuccess === "boolean") {
4729
+ return resp.isSuccess;
4730
+ }
4731
+ if ("success" in resp && typeof resp.success === "boolean") {
4732
+ return resp.success;
4733
+ }
4734
+ if ("ok" in resp && typeof resp.ok === "boolean") {
4735
+ return resp.ok;
4736
+ }
4737
+ if ("status" in resp && typeof resp.status === "number") {
4738
+ return resp.status >= types.HTTP_STATUS.OK && resp.status < types.HTTP_STATUS.MULTIPLE_CHOICES;
4739
+ }
4740
+ return "data" in resp && !("error" in resp && resp.error);
4741
+ }
4742
+ /**
4743
+ * Extract error from API response.
4744
+ *
4745
+ * Uses `responseErrorKey` config if set, otherwise auto-detects from:
4746
+ * - `error` (common format)
4747
+ * - `errors` (array format, e.g., GraphQL)
4748
+ *
4749
+ * Supports nested keys via dot notation (e.g., `'meta.error'`).
4750
+ *
4751
+ * @param response - Response object from fetcher
4752
+ * @returns Extracted error or undefined if not found
4753
+ */
4754
+ // eslint-disable-next-line complexity
4755
+ extractResponseError(response) {
4756
+ if (!response || typeof response !== "object") {
4757
+ return void 0;
4758
+ }
4759
+ const resp = response;
4760
+ const errorKey = this.config.responseErrorKey;
4761
+ if (errorKey) {
4762
+ const keys = errorKey.split(".");
4763
+ let result = resp;
4764
+ for (const k of keys) {
4765
+ if (result && typeof result === "object" && k in result) {
4766
+ result = result[k];
4767
+ } else {
4768
+ return void 0;
4769
+ }
4770
+ }
4771
+ return result;
4772
+ }
4773
+ if ("error" in resp && resp.error) {
4774
+ return resp.error;
4775
+ }
4776
+ if ("errors" in resp && resp.errors) {
4777
+ return resp.errors;
4778
+ }
4779
+ return void 0;
4780
+ }
4685
4781
  // ─────────────────────────────────────────────────────────────────────────
4686
4782
  // Generic CRUD Operations
4687
4783
  // ─────────────────────────────────────────────────────────────────────────
@@ -4737,13 +4833,15 @@ var BaseFrontendDomainService = class extends BaseDomainService {
4737
4833
  try {
4738
4834
  await this.beforeFetchAll?.(query);
4739
4835
  const response = await this.config.fetchers.fetchAll(query, options);
4740
- if (!response.isSuccess) {
4836
+ if (!this.isResponseSuccess(response)) {
4837
+ const extractedError = this.extractResponseError(response);
4741
4838
  throw new errors.CorePackageError(
4742
4839
  "Failed to fetch entities",
4743
4840
  errors$1.ERROR_CODES.CONTEXT_OPERATION_FAILED,
4744
4841
  {
4745
4842
  context: { operation: "fetchAll", query },
4746
- cause: response.error ?? void 0
4843
+ cause: extractedError instanceof Error ? extractedError : void 0,
4844
+ details: extractedError
4747
4845
  }
4748
4846
  );
4749
4847
  }
@@ -4791,13 +4889,16 @@ var BaseFrontendDomainService = class extends BaseDomainService {
4791
4889
  try {
4792
4890
  await this.beforeFetchById?.(id);
4793
4891
  const response = await this.config.fetchers.fetchById(String(id), options);
4794
- if (!response.isSuccess) {
4795
- if (response.error?.message?.includes("404")) {
4892
+ if (!this.isResponseSuccess(response)) {
4893
+ const extractedError = this.extractResponseError(response);
4894
+ const errorMessage = extractedError instanceof Error ? extractedError.message : String(extractedError ?? "");
4895
+ if (errorMessage.includes("404") || response.status === types.HTTP_STATUS.NOT_FOUND) {
4796
4896
  return null;
4797
4897
  }
4798
4898
  throw new errors.CorePackageError("Failed to fetch entity", errors$1.ERROR_CODES.CONTEXT_OPERATION_FAILED, {
4799
4899
  context: { operation: "fetchById", entityId: String(id) },
4800
- cause: response.error ?? void 0
4900
+ cause: extractedError instanceof Error ? extractedError : void 0,
4901
+ details: extractedError
4801
4902
  });
4802
4903
  }
4803
4904
  const rawData = this.unwrapResponseData(response.data);
@@ -4873,15 +4974,14 @@ var BaseFrontendDomainService = class extends BaseDomainService {
4873
4974
  });
4874
4975
  }
4875
4976
  const response = await this.config.fetchers.create(createDTO, options);
4876
- if (!response.isSuccess) {
4877
- throw new errors.CorePackageError(
4878
- response.error?.message ?? "Failed to create entity",
4879
- errors$1.ERROR_CODES.CONTEXT_OPERATION_FAILED,
4880
- {
4881
- context: { operation: "create" },
4882
- cause: response.error ?? void 0
4883
- }
4884
- );
4977
+ if (!this.isResponseSuccess(response)) {
4978
+ const extractedError = this.extractResponseError(response);
4979
+ const errorMessage = extractedError instanceof Error ? extractedError.message : typeof extractedError === "string" ? extractedError : "Failed to create entity";
4980
+ throw new errors.CorePackageError(errorMessage, errors$1.ERROR_CODES.CONTEXT_OPERATION_FAILED, {
4981
+ context: { operation: "create" },
4982
+ cause: extractedError instanceof Error ? extractedError : void 0,
4983
+ details: extractedError
4984
+ });
4885
4985
  }
4886
4986
  const rawData = this.unwrapResponseData(response.data);
4887
4987
  const entity = this.mapper.toDomain(rawData);
@@ -4967,15 +5067,14 @@ var BaseFrontendDomainService = class extends BaseDomainService {
4967
5067
  });
4968
5068
  }
4969
5069
  const response = await this.config.fetchers.update({ id, data: patchDTO }, options);
4970
- if (!response.isSuccess) {
4971
- throw new errors.CorePackageError(
4972
- response.error?.message ?? "Failed to update entity",
4973
- errors$1.ERROR_CODES.CONTEXT_OPERATION_FAILED,
4974
- {
4975
- context: { operation: "update", entityId: id },
4976
- cause: response.error ?? void 0
4977
- }
4978
- );
5070
+ if (!this.isResponseSuccess(response)) {
5071
+ const extractedError = this.extractResponseError(response);
5072
+ const errorMessage = extractedError instanceof Error ? extractedError.message : typeof extractedError === "string" ? extractedError : "Failed to update entity";
5073
+ throw new errors.CorePackageError(errorMessage, errors$1.ERROR_CODES.CONTEXT_OPERATION_FAILED, {
5074
+ context: { operation: "update", entityId: id },
5075
+ cause: extractedError instanceof Error ? extractedError : void 0,
5076
+ details: extractedError
5077
+ });
4979
5078
  }
4980
5079
  const rawData = this.unwrapResponseData(response.data);
4981
5080
  const serverEntity = this.mapper.toDomain(rawData);
@@ -5047,15 +5146,14 @@ var BaseFrontendDomainService = class extends BaseDomainService {
5047
5146
  });
5048
5147
  }
5049
5148
  const response = await this.config.fetchers.delete(String(id), options);
5050
- if (!response.isSuccess) {
5051
- throw new errors.CorePackageError(
5052
- response.error?.message ?? "Failed to delete entity",
5053
- errors$1.ERROR_CODES.CONTEXT_OPERATION_FAILED,
5054
- {
5055
- context: { operation: "delete", entityId: String(id) },
5056
- cause: response.error ?? void 0
5057
- }
5058
- );
5149
+ if (!this.isResponseSuccess(response)) {
5150
+ const extractedError = this.extractResponseError(response);
5151
+ const errorMessage = extractedError instanceof Error ? extractedError.message : typeof extractedError === "string" ? extractedError : "Failed to delete entity";
5152
+ throw new errors.CorePackageError(errorMessage, errors$1.ERROR_CODES.CONTEXT_OPERATION_FAILED, {
5153
+ context: { operation: "delete", entityId: String(id) },
5154
+ cause: extractedError instanceof Error ? extractedError : void 0,
5155
+ details: extractedError
5156
+ });
5059
5157
  }
5060
5158
  if (!isOptimistic) {
5061
5159
  this.removeEntityFromStore(String(id));
@@ -5864,6 +5962,8 @@ var ExampleMapperClass = class extends BaseMapper {
5864
5962
  * API DTO → Domain Model
5865
5963
  */
5866
5964
  toDomain(dto) {
5965
+ const createdAt = dto.created_at ? new Date(dto.created_at) : /* @__PURE__ */ new Date();
5966
+ const updatedAt = dto.updated_at ? new Date(dto.updated_at) : /* @__PURE__ */ new Date();
5867
5967
  return {
5868
5968
  id: dto.id,
5869
5969
  name: dto.name,
@@ -5872,8 +5972,8 @@ var ExampleMapperClass = class extends BaseMapper {
5872
5972
  status: dto.status,
5873
5973
  amount: dto.amount,
5874
5974
  isVisible: dto.is_visible,
5875
- createdAt: new Date(dto.created_at),
5876
- updatedAt: new Date(dto.updated_at),
5975
+ createdAt: isNaN(createdAt.getTime()) ? /* @__PURE__ */ new Date() : createdAt,
5976
+ updatedAt: isNaN(updatedAt.getTime()) ? /* @__PURE__ */ new Date() : updatedAt,
5877
5977
  // Computed properties
5878
5978
  isActive: dto.status === "active",
5879
5979
  hasDescription: /* @__PURE__ */ __name(() => Boolean(dto.description), "hasDescription")
@@ -5992,6 +6092,7 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
5992
6092
  // ─────────────────────────────────────────────────────────────────────────
5993
6093
  // Constructor
5994
6094
  // ─────────────────────────────────────────────────────────────────────────
6095
+ // eslint-disable-next-line complexity
5995
6096
  constructor(config = {}, options) {
5996
6097
  const apiBasePath = config.apiBasePath ?? "/api/examples";
5997
6098
  super({
@@ -6005,8 +6106,12 @@ var FrontendExampleDomainService = class _FrontendExampleDomainService extends B
6005
6106
  autoFetch: false,
6006
6107
  pollingInterval: 0,
6007
6108
  ...config,
6008
- // Unwrap SuccessResponseStandard: { success, message, data, codeStatus }
6009
- // Base class will extract 'data' property automatically
6109
+ // Fetchff response format: { ok, status, data: { success, message, data, codeStatus }, error }
6110
+ // Use 'ok' for success check (HTTP level)
6111
+ responseSuccessKey: "ok",
6112
+ // Extract error from fetchff response
6113
+ responseErrorKey: "error",
6114
+ // Unwrap SuccessResponseStandard: extract 'data' from response.data
6010
6115
  responseDataKey: "data",
6011
6116
  // Fetchers - using apiClient directly for testing/example purposes
6012
6117
  // In production, these would be imported from @plyaz/api services