resora 1.3.0 → 1.3.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.
package/dist/index.cjs CHANGED
@@ -1466,6 +1466,7 @@ var BaseSerializer = class {
1466
1466
  static ctx;
1467
1467
  instanceConfig;
1468
1468
  additionalMeta;
1469
+ serializationPromise;
1469
1470
  called = {};
1470
1471
  constructor() {
1471
1472
  loadRuntimeConfig();
@@ -1566,6 +1567,12 @@ var BaseSerializer = class {
1566
1567
  resolveSerializationContext() {
1567
1568
  return getCtx() ?? this.constructor.ctx;
1568
1569
  }
1570
+ isPromiseLike(value) {
1571
+ return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
1572
+ }
1573
+ waitForSerialization() {
1574
+ return this.serializationPromise ?? Promise.resolve();
1575
+ }
1569
1576
  /**
1570
1577
  * Dispatch a body to a raw response object when it exposes a send() transport method.
1571
1578
  *
@@ -1641,27 +1648,28 @@ var BaseSerializer = class {
1641
1648
  runThen(input) {
1642
1649
  this.called.then = true;
1643
1650
  input.ensureJson();
1644
- const initialBody = input.body();
1645
- let response;
1646
- if (typeof input.rawResponse !== "undefined") {
1647
- response = input.createServerResponse(input.rawResponse, initialBody);
1648
- this.called.withResponse = true;
1649
- input.callWithResponse(response, input.rawResponse);
1650
- } else {
1651
- this.called.withResponse = true;
1652
- input.callWithResponse();
1653
- }
1654
- const resolvedBody = input.body();
1655
- if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1656
- const dispatchedBody = this.applyResponsePlugins({
1657
- body: resolvedBody,
1658
- rawResponse: input.rawResponse,
1659
- response
1660
- });
1661
- const resolved = Promise.resolve(dispatchedBody).then(input.onfulfilled, input.onrejected);
1662
- if (typeof response?.send === "function") response.send(dispatchedBody);
1663
- else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1664
- return resolved;
1651
+ return this.waitForSerialization().then(() => {
1652
+ const initialBody = input.body();
1653
+ let response;
1654
+ if (typeof input.rawResponse !== "undefined") {
1655
+ response = input.createServerResponse(input.rawResponse, initialBody);
1656
+ this.called.withResponse = true;
1657
+ input.callWithResponse(response, input.rawResponse);
1658
+ } else {
1659
+ this.called.withResponse = true;
1660
+ input.callWithResponse();
1661
+ }
1662
+ const resolvedBody = input.body();
1663
+ if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1664
+ const dispatchedBody = this.applyResponsePlugins({
1665
+ body: resolvedBody,
1666
+ rawResponse: input.rawResponse,
1667
+ response
1668
+ });
1669
+ if (typeof response?.send === "function") response.send(dispatchedBody);
1670
+ else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1671
+ return dispatchedBody;
1672
+ }).then(input.onfulfilled, input.onrejected);
1665
1673
  }
1666
1674
  /**
1667
1675
  * Get or set the resource-level configuration for this serializer instance.
@@ -1851,17 +1859,10 @@ var GenericResource = class GenericResource extends BaseSerializer {
1851
1859
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
1852
1860
  return factory || !wrap ? void 0 : rootKey;
1853
1861
  }
1854
- /**
1855
- * Convert resource to JSON response format
1856
- *
1857
- * @returns
1858
- */
1859
- json() {
1860
- if (!this.called.json) {
1861
- this.called.json = true;
1862
- const ctx = this.resolveSerializationContext();
1863
- let data = normalizeSerializableData(this.data(ctx));
1864
- if (Array.isArray(data) && this.collects) data = data.map((item) => new this.collects(item).data(ctx));
1862
+ serializeGenericResource(resource, ctx) {
1863
+ let data = normalizeSerializableData(resource);
1864
+ const serialize = (resolvedData) => {
1865
+ data = resolvedData;
1865
1866
  if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
1866
1867
  data = sanitizeConditionalAttributes(data);
1867
1868
  const paginationExtras = buildPaginationExtras(this.resource);
@@ -1892,6 +1893,32 @@ var GenericResource = class GenericResource extends BaseSerializer {
1892
1893
  ...customMeta || {}
1893
1894
  }, rootKey);
1894
1895
  this.body = this.applySerializePlugins(this.body);
1896
+ };
1897
+ if (Array.isArray(data) && this.collects) {
1898
+ const collected = data.map((item) => new this.collects(item).data(ctx));
1899
+ if (collected.some((item) => this.isPromiseLike(item))) return Promise.all(collected).then(serialize);
1900
+ data = collected;
1901
+ }
1902
+ serialize(data);
1903
+ }
1904
+ /**
1905
+ * Convert resource to JSON response format
1906
+ *
1907
+ * @returns
1908
+ */
1909
+ json() {
1910
+ if (!this.called.json) {
1911
+ this.called.json = true;
1912
+ const ctx = this.resolveSerializationContext();
1913
+ const resource = this.data(ctx);
1914
+ if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
1915
+ const result = this.serializeGenericResource(resolved, ctx);
1916
+ if (this.isPromiseLike(result)) return result;
1917
+ });
1918
+ else {
1919
+ const result = this.serializeGenericResource(resource, ctx);
1920
+ if (this.isPromiseLike(result)) this.serializationPromise = Promise.resolve(result);
1921
+ }
1895
1922
  }
1896
1923
  return this;
1897
1924
  }
@@ -2185,6 +2212,46 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2185
2212
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2186
2213
  return factory || !wrap ? void 0 : rootKey;
2187
2214
  }
2215
+ serializeCollectionData(items) {
2216
+ let data = normalizeSerializableData(items);
2217
+ data = sanitizeConditionalAttributes(data);
2218
+ const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2219
+ const { metaKey } = getPaginationExtraKeys();
2220
+ const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2221
+ if (metaKey) delete paginationExtras[metaKey];
2222
+ const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2223
+ if (caseStyle) {
2224
+ const transformer = getCaseTransformer(caseStyle);
2225
+ data = transformKeys(data, transformer);
2226
+ }
2227
+ const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2228
+ const { wrap, rootKey, factory } = this.resolveResponseStructure();
2229
+ this.body = buildResponseEnvelope({
2230
+ payload: data,
2231
+ meta: configuredMeta,
2232
+ metaKey,
2233
+ wrap,
2234
+ rootKey,
2235
+ factory,
2236
+ context: {
2237
+ type: "collection",
2238
+ resource: this.resource
2239
+ }
2240
+ });
2241
+ this.body = appendRootProperties(this.body, {
2242
+ ...paginationExtras,
2243
+ ...customMeta || {}
2244
+ }, rootKey);
2245
+ this.body = this.applySerializePlugins(this.body);
2246
+ }
2247
+ resolveCollectionDataForSerialization(items, ctx) {
2248
+ if (this.collects && this.data === ResourceCollection.prototype.data) {
2249
+ const collected = items.map((item) => new this.collects(item).data(ctx));
2250
+ if (collected.some((item) => this.isPromiseLike(item))) return Promise.all(collected);
2251
+ return collected;
2252
+ }
2253
+ return items;
2254
+ }
2188
2255
  /**
2189
2256
  * Convert resource to JSON response format
2190
2257
  *
@@ -2194,38 +2261,19 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2194
2261
  if (!this.called.json) {
2195
2262
  this.called.json = true;
2196
2263
  const ctx = this.resolveSerializationContext();
2197
- let data = this.data(ctx);
2198
- if (this.collects && this.data === ResourceCollection.prototype.data) data = data.map((item) => new this.collects(item).data(ctx));
2199
- data = normalizeSerializableData(data);
2200
- data = sanitizeConditionalAttributes(data);
2201
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2202
- const { metaKey } = getPaginationExtraKeys();
2203
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2204
- if (metaKey) delete paginationExtras[metaKey];
2205
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2206
- if (caseStyle) {
2207
- const transformer = getCaseTransformer(caseStyle);
2208
- data = transformKeys(data, transformer);
2264
+ const data = this.data(ctx);
2265
+ const serialize = (items) => {
2266
+ const resolvedData = this.resolveCollectionDataForSerialization(items, ctx);
2267
+ if (this.isPromiseLike(resolvedData)) return resolvedData.then((resolved) => {
2268
+ this.serializeCollectionData(resolved);
2269
+ });
2270
+ this.serializeCollectionData(resolvedData);
2271
+ };
2272
+ if (this.isPromiseLike(data)) this.serializationPromise = Promise.resolve(data).then(serialize);
2273
+ else {
2274
+ const result = serialize(data);
2275
+ if (this.isPromiseLike(result)) this.serializationPromise = Promise.resolve(result);
2209
2276
  }
2210
- const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2211
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2212
- this.body = buildResponseEnvelope({
2213
- payload: data,
2214
- meta: configuredMeta,
2215
- metaKey,
2216
- wrap,
2217
- rootKey,
2218
- factory,
2219
- context: {
2220
- type: "collection",
2221
- resource: this.resource
2222
- }
2223
- });
2224
- this.body = appendRootProperties(this.body, {
2225
- ...paginationExtras,
2226
- ...customMeta || {}
2227
- }, rootKey);
2228
- this.body = this.applySerializePlugins(this.body);
2229
2277
  }
2230
2278
  return this;
2231
2279
  }
@@ -2496,6 +2544,30 @@ var Resource = class Resource extends BaseSerializer {
2496
2544
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2497
2545
  return factory || !wrap ? void 0 : rootKey;
2498
2546
  }
2547
+ serializeResource(resource) {
2548
+ let data = normalizeSerializableData(resource);
2549
+ if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2550
+ data = sanitizeConditionalAttributes(data);
2551
+ const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2552
+ if (caseStyle) {
2553
+ const transformer = getCaseTransformer(caseStyle);
2554
+ data = transformKeys(data, transformer);
2555
+ }
2556
+ const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2557
+ const { wrap, rootKey, factory } = this.resolveResponseStructure();
2558
+ this.body = buildResponseEnvelope({
2559
+ payload: data,
2560
+ wrap,
2561
+ rootKey,
2562
+ factory,
2563
+ context: {
2564
+ type: "resource",
2565
+ resource: this.resource
2566
+ }
2567
+ });
2568
+ this.body = appendRootProperties(this.body, customMeta, rootKey);
2569
+ this.body = this.applySerializePlugins(this.body);
2570
+ }
2499
2571
  /**
2500
2572
  * Convert resource to JSON response format
2501
2573
  *
@@ -2505,28 +2577,11 @@ var Resource = class Resource extends BaseSerializer {
2505
2577
  if (!this.called.json) {
2506
2578
  this.called.json = true;
2507
2579
  const ctx = this.resolveSerializationContext();
2508
- let data = normalizeSerializableData(this.data(ctx));
2509
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2510
- data = sanitizeConditionalAttributes(data);
2511
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2512
- if (caseStyle) {
2513
- const transformer = getCaseTransformer(caseStyle);
2514
- data = transformKeys(data, transformer);
2515
- }
2516
- const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2517
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2518
- this.body = buildResponseEnvelope({
2519
- payload: data,
2520
- wrap,
2521
- rootKey,
2522
- factory,
2523
- context: {
2524
- type: "resource",
2525
- resource: this.resource
2526
- }
2580
+ const resource = this.data(ctx);
2581
+ if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
2582
+ this.serializeResource(resolved);
2527
2583
  });
2528
- this.body = appendRootProperties(this.body, customMeta, rootKey);
2529
- this.body = this.applySerializePlugins(this.body);
2584
+ else this.serializeResource(resource);
2530
2585
  }
2531
2586
  return this;
2532
2587
  }
package/dist/index.d.cts CHANGED
@@ -519,6 +519,7 @@ declare abstract class BaseSerializer<TResource = any> {
519
519
  protected static ctx?: Response | H3Event | Record<string, any>;
520
520
  protected instanceConfig?: ResourceLevelConfig;
521
521
  protected additionalMeta?: MetaData;
522
+ protected serializationPromise?: Promise<void>;
522
523
  protected called: {
523
524
  json?: boolean;
524
525
  data?: boolean;
@@ -605,6 +606,8 @@ declare abstract class BaseSerializer<TResource = any> {
605
606
  * Resolve the active request context for data transformation hooks.
606
607
  */
607
608
  protected resolveSerializationContext(): unknown;
609
+ protected isPromiseLike<T = any>(value: unknown): value is PromiseLike<T>;
610
+ protected waitForSerialization(): Promise<void>;
608
611
  /**
609
612
  * Dispatch a body to a raw response object when it exposes a send() transport method.
610
613
  *
@@ -746,7 +749,7 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
746
749
  /**
747
750
  * Get the original resource data
748
751
  */
749
- data(_ctx?: unknown): (R extends Collectible ? R["data"][number] : R extends PaginatorLike<infer TPaginatorData> ? TPaginatorData : R extends CollectionLike<infer TCollectionData> ? TCollectionData : R extends ResourceData[] ? R[number] : never)[];
752
+ data(_ctx?: any): any;
750
753
  /**
751
754
  * Get the current serialized output body.
752
755
  */
@@ -786,6 +789,8 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
786
789
  * @returns The key to use for the response payload, or undefined if no key is needed.
787
790
  */
788
791
  private getPayloadKey;
792
+ private serializeCollectionData;
793
+ private resolveCollectionDataForSerialization;
789
794
  /**
790
795
  * Convert resource to JSON response format
791
796
  *
@@ -883,7 +888,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
883
888
  /**
884
889
  * Get the original resource data
885
890
  */
886
- data(_ctx?: unknown): R extends NonCollectible ? R["data"] : R;
891
+ data(_ctx?: any): any;
887
892
  /**
888
893
  * Get the current serialized output body.
889
894
  */
@@ -903,6 +908,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
903
908
  protected getResourceForMeta(): R;
904
909
  protected getSerializerType(): "resource";
905
910
  private getPayloadKey;
911
+ private serializeResource;
906
912
  /**
907
913
  * Convert resource to JSON response format
908
914
  *
@@ -992,7 +998,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
992
998
  /**
993
999
  * Get the original resource data
994
1000
  */
995
- data(_ctx?: unknown): R;
1001
+ data(_ctx?: any): any;
996
1002
  /**
997
1003
  * Get the current serialized output body.
998
1004
  */
@@ -1024,6 +1030,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
1024
1030
  protected getResourceForMeta(): R;
1025
1031
  protected getSerializerType(): "generic";
1026
1032
  private getPayloadKey;
1033
+ private serializeGenericResource;
1027
1034
  /**
1028
1035
  * Convert resource to JSON response format
1029
1036
  *
package/dist/index.d.mts CHANGED
@@ -519,6 +519,7 @@ declare abstract class BaseSerializer<TResource = any> {
519
519
  protected static ctx?: Response | H3Event | Record<string, any>;
520
520
  protected instanceConfig?: ResourceLevelConfig;
521
521
  protected additionalMeta?: MetaData;
522
+ protected serializationPromise?: Promise<void>;
522
523
  protected called: {
523
524
  json?: boolean;
524
525
  data?: boolean;
@@ -605,6 +606,8 @@ declare abstract class BaseSerializer<TResource = any> {
605
606
  * Resolve the active request context for data transformation hooks.
606
607
  */
607
608
  protected resolveSerializationContext(): unknown;
609
+ protected isPromiseLike<T = any>(value: unknown): value is PromiseLike<T>;
610
+ protected waitForSerialization(): Promise<void>;
608
611
  /**
609
612
  * Dispatch a body to a raw response object when it exposes a send() transport method.
610
613
  *
@@ -746,7 +749,7 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
746
749
  /**
747
750
  * Get the original resource data
748
751
  */
749
- data(_ctx?: unknown): (R extends Collectible ? R["data"][number] : R extends PaginatorLike<infer TPaginatorData> ? TPaginatorData : R extends CollectionLike<infer TCollectionData> ? TCollectionData : R extends ResourceData[] ? R[number] : never)[];
752
+ data(_ctx?: any): any;
750
753
  /**
751
754
  * Get the current serialized output body.
752
755
  */
@@ -786,6 +789,8 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
786
789
  * @returns The key to use for the response payload, or undefined if no key is needed.
787
790
  */
788
791
  private getPayloadKey;
792
+ private serializeCollectionData;
793
+ private resolveCollectionDataForSerialization;
789
794
  /**
790
795
  * Convert resource to JSON response format
791
796
  *
@@ -883,7 +888,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
883
888
  /**
884
889
  * Get the original resource data
885
890
  */
886
- data(_ctx?: unknown): R extends NonCollectible ? R["data"] : R;
891
+ data(_ctx?: any): any;
887
892
  /**
888
893
  * Get the current serialized output body.
889
894
  */
@@ -903,6 +908,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
903
908
  protected getResourceForMeta(): R;
904
909
  protected getSerializerType(): "resource";
905
910
  private getPayloadKey;
911
+ private serializeResource;
906
912
  /**
907
913
  * Convert resource to JSON response format
908
914
  *
@@ -992,7 +998,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
992
998
  /**
993
999
  * Get the original resource data
994
1000
  */
995
- data(_ctx?: unknown): R;
1001
+ data(_ctx?: any): any;
996
1002
  /**
997
1003
  * Get the current serialized output body.
998
1004
  */
@@ -1024,6 +1030,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
1024
1030
  protected getResourceForMeta(): R;
1025
1031
  protected getSerializerType(): "generic";
1026
1032
  private getPayloadKey;
1033
+ private serializeGenericResource;
1027
1034
  /**
1028
1035
  * Convert resource to JSON response format
1029
1036
  *
package/dist/index.mjs CHANGED
@@ -1437,6 +1437,7 @@ var BaseSerializer = class {
1437
1437
  static ctx;
1438
1438
  instanceConfig;
1439
1439
  additionalMeta;
1440
+ serializationPromise;
1440
1441
  called = {};
1441
1442
  constructor() {
1442
1443
  loadRuntimeConfig();
@@ -1537,6 +1538,12 @@ var BaseSerializer = class {
1537
1538
  resolveSerializationContext() {
1538
1539
  return getCtx() ?? this.constructor.ctx;
1539
1540
  }
1541
+ isPromiseLike(value) {
1542
+ return !!value && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
1543
+ }
1544
+ waitForSerialization() {
1545
+ return this.serializationPromise ?? Promise.resolve();
1546
+ }
1540
1547
  /**
1541
1548
  * Dispatch a body to a raw response object when it exposes a send() transport method.
1542
1549
  *
@@ -1612,27 +1619,28 @@ var BaseSerializer = class {
1612
1619
  runThen(input) {
1613
1620
  this.called.then = true;
1614
1621
  input.ensureJson();
1615
- const initialBody = input.body();
1616
- let response;
1617
- if (typeof input.rawResponse !== "undefined") {
1618
- response = input.createServerResponse(input.rawResponse, initialBody);
1619
- this.called.withResponse = true;
1620
- input.callWithResponse(response, input.rawResponse);
1621
- } else {
1622
- this.called.withResponse = true;
1623
- input.callWithResponse();
1624
- }
1625
- const resolvedBody = input.body();
1626
- if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1627
- const dispatchedBody = this.applyResponsePlugins({
1628
- body: resolvedBody,
1629
- rawResponse: input.rawResponse,
1630
- response
1631
- });
1632
- const resolved = Promise.resolve(dispatchedBody).then(input.onfulfilled, input.onrejected);
1633
- if (typeof response?.send === "function") response.send(dispatchedBody);
1634
- else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1635
- return resolved;
1622
+ return this.waitForSerialization().then(() => {
1623
+ const initialBody = input.body();
1624
+ let response;
1625
+ if (typeof input.rawResponse !== "undefined") {
1626
+ response = input.createServerResponse(input.rawResponse, initialBody);
1627
+ this.called.withResponse = true;
1628
+ input.callWithResponse(response, input.rawResponse);
1629
+ } else {
1630
+ this.called.withResponse = true;
1631
+ input.callWithResponse();
1632
+ }
1633
+ const resolvedBody = input.body();
1634
+ if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1635
+ const dispatchedBody = this.applyResponsePlugins({
1636
+ body: resolvedBody,
1637
+ rawResponse: input.rawResponse,
1638
+ response
1639
+ });
1640
+ if (typeof response?.send === "function") response.send(dispatchedBody);
1641
+ else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1642
+ return dispatchedBody;
1643
+ }).then(input.onfulfilled, input.onrejected);
1636
1644
  }
1637
1645
  /**
1638
1646
  * Get or set the resource-level configuration for this serializer instance.
@@ -1822,17 +1830,10 @@ var GenericResource = class GenericResource extends BaseSerializer {
1822
1830
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
1823
1831
  return factory || !wrap ? void 0 : rootKey;
1824
1832
  }
1825
- /**
1826
- * Convert resource to JSON response format
1827
- *
1828
- * @returns
1829
- */
1830
- json() {
1831
- if (!this.called.json) {
1832
- this.called.json = true;
1833
- const ctx = this.resolveSerializationContext();
1834
- let data = normalizeSerializableData(this.data(ctx));
1835
- if (Array.isArray(data) && this.collects) data = data.map((item) => new this.collects(item).data(ctx));
1833
+ serializeGenericResource(resource, ctx) {
1834
+ let data = normalizeSerializableData(resource);
1835
+ const serialize = (resolvedData) => {
1836
+ data = resolvedData;
1836
1837
  if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
1837
1838
  data = sanitizeConditionalAttributes(data);
1838
1839
  const paginationExtras = buildPaginationExtras(this.resource);
@@ -1863,6 +1864,32 @@ var GenericResource = class GenericResource extends BaseSerializer {
1863
1864
  ...customMeta || {}
1864
1865
  }, rootKey);
1865
1866
  this.body = this.applySerializePlugins(this.body);
1867
+ };
1868
+ if (Array.isArray(data) && this.collects) {
1869
+ const collected = data.map((item) => new this.collects(item).data(ctx));
1870
+ if (collected.some((item) => this.isPromiseLike(item))) return Promise.all(collected).then(serialize);
1871
+ data = collected;
1872
+ }
1873
+ serialize(data);
1874
+ }
1875
+ /**
1876
+ * Convert resource to JSON response format
1877
+ *
1878
+ * @returns
1879
+ */
1880
+ json() {
1881
+ if (!this.called.json) {
1882
+ this.called.json = true;
1883
+ const ctx = this.resolveSerializationContext();
1884
+ const resource = this.data(ctx);
1885
+ if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
1886
+ const result = this.serializeGenericResource(resolved, ctx);
1887
+ if (this.isPromiseLike(result)) return result;
1888
+ });
1889
+ else {
1890
+ const result = this.serializeGenericResource(resource, ctx);
1891
+ if (this.isPromiseLike(result)) this.serializationPromise = Promise.resolve(result);
1892
+ }
1866
1893
  }
1867
1894
  return this;
1868
1895
  }
@@ -2156,6 +2183,46 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2156
2183
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2157
2184
  return factory || !wrap ? void 0 : rootKey;
2158
2185
  }
2186
+ serializeCollectionData(items) {
2187
+ let data = normalizeSerializableData(items);
2188
+ data = sanitizeConditionalAttributes(data);
2189
+ const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2190
+ const { metaKey } = getPaginationExtraKeys();
2191
+ const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2192
+ if (metaKey) delete paginationExtras[metaKey];
2193
+ const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2194
+ if (caseStyle) {
2195
+ const transformer = getCaseTransformer(caseStyle);
2196
+ data = transformKeys(data, transformer);
2197
+ }
2198
+ const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2199
+ const { wrap, rootKey, factory } = this.resolveResponseStructure();
2200
+ this.body = buildResponseEnvelope({
2201
+ payload: data,
2202
+ meta: configuredMeta,
2203
+ metaKey,
2204
+ wrap,
2205
+ rootKey,
2206
+ factory,
2207
+ context: {
2208
+ type: "collection",
2209
+ resource: this.resource
2210
+ }
2211
+ });
2212
+ this.body = appendRootProperties(this.body, {
2213
+ ...paginationExtras,
2214
+ ...customMeta || {}
2215
+ }, rootKey);
2216
+ this.body = this.applySerializePlugins(this.body);
2217
+ }
2218
+ resolveCollectionDataForSerialization(items, ctx) {
2219
+ if (this.collects && this.data === ResourceCollection.prototype.data) {
2220
+ const collected = items.map((item) => new this.collects(item).data(ctx));
2221
+ if (collected.some((item) => this.isPromiseLike(item))) return Promise.all(collected);
2222
+ return collected;
2223
+ }
2224
+ return items;
2225
+ }
2159
2226
  /**
2160
2227
  * Convert resource to JSON response format
2161
2228
  *
@@ -2165,38 +2232,19 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2165
2232
  if (!this.called.json) {
2166
2233
  this.called.json = true;
2167
2234
  const ctx = this.resolveSerializationContext();
2168
- let data = this.data(ctx);
2169
- if (this.collects && this.data === ResourceCollection.prototype.data) data = data.map((item) => new this.collects(item).data(ctx));
2170
- data = normalizeSerializableData(data);
2171
- data = sanitizeConditionalAttributes(data);
2172
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2173
- const { metaKey } = getPaginationExtraKeys();
2174
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2175
- if (metaKey) delete paginationExtras[metaKey];
2176
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2177
- if (caseStyle) {
2178
- const transformer = getCaseTransformer(caseStyle);
2179
- data = transformKeys(data, transformer);
2235
+ const data = this.data(ctx);
2236
+ const serialize = (items) => {
2237
+ const resolvedData = this.resolveCollectionDataForSerialization(items, ctx);
2238
+ if (this.isPromiseLike(resolvedData)) return resolvedData.then((resolved) => {
2239
+ this.serializeCollectionData(resolved);
2240
+ });
2241
+ this.serializeCollectionData(resolvedData);
2242
+ };
2243
+ if (this.isPromiseLike(data)) this.serializationPromise = Promise.resolve(data).then(serialize);
2244
+ else {
2245
+ const result = serialize(data);
2246
+ if (this.isPromiseLike(result)) this.serializationPromise = Promise.resolve(result);
2180
2247
  }
2181
- const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2182
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2183
- this.body = buildResponseEnvelope({
2184
- payload: data,
2185
- meta: configuredMeta,
2186
- metaKey,
2187
- wrap,
2188
- rootKey,
2189
- factory,
2190
- context: {
2191
- type: "collection",
2192
- resource: this.resource
2193
- }
2194
- });
2195
- this.body = appendRootProperties(this.body, {
2196
- ...paginationExtras,
2197
- ...customMeta || {}
2198
- }, rootKey);
2199
- this.body = this.applySerializePlugins(this.body);
2200
2248
  }
2201
2249
  return this;
2202
2250
  }
@@ -2467,6 +2515,30 @@ var Resource = class Resource extends BaseSerializer {
2467
2515
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2468
2516
  return factory || !wrap ? void 0 : rootKey;
2469
2517
  }
2518
+ serializeResource(resource) {
2519
+ let data = normalizeSerializableData(resource);
2520
+ if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2521
+ data = sanitizeConditionalAttributes(data);
2522
+ const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2523
+ if (caseStyle) {
2524
+ const transformer = getCaseTransformer(caseStyle);
2525
+ data = transformKeys(data, transformer);
2526
+ }
2527
+ const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2528
+ const { wrap, rootKey, factory } = this.resolveResponseStructure();
2529
+ this.body = buildResponseEnvelope({
2530
+ payload: data,
2531
+ wrap,
2532
+ rootKey,
2533
+ factory,
2534
+ context: {
2535
+ type: "resource",
2536
+ resource: this.resource
2537
+ }
2538
+ });
2539
+ this.body = appendRootProperties(this.body, customMeta, rootKey);
2540
+ this.body = this.applySerializePlugins(this.body);
2541
+ }
2470
2542
  /**
2471
2543
  * Convert resource to JSON response format
2472
2544
  *
@@ -2476,28 +2548,11 @@ var Resource = class Resource extends BaseSerializer {
2476
2548
  if (!this.called.json) {
2477
2549
  this.called.json = true;
2478
2550
  const ctx = this.resolveSerializationContext();
2479
- let data = normalizeSerializableData(this.data(ctx));
2480
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2481
- data = sanitizeConditionalAttributes(data);
2482
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2483
- if (caseStyle) {
2484
- const transformer = getCaseTransformer(caseStyle);
2485
- data = transformKeys(data, transformer);
2486
- }
2487
- const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2488
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2489
- this.body = buildResponseEnvelope({
2490
- payload: data,
2491
- wrap,
2492
- rootKey,
2493
- factory,
2494
- context: {
2495
- type: "resource",
2496
- resource: this.resource
2497
- }
2551
+ const resource = this.data(ctx);
2552
+ if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
2553
+ this.serializeResource(resolved);
2498
2554
  });
2499
- this.body = appendRootProperties(this.body, customMeta, rootKey);
2500
- this.body = this.applySerializePlugins(this.body);
2555
+ else this.serializeResource(resource);
2501
2556
  }
2502
2557
  return this;
2503
2558
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resora",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "A structured API response layer for Node.js and TypeScript with automatic JSON responses, collection support, and pagination handling.",
5
5
  "keywords": [
6
6
  "api",