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