resora 1.2.12 → 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();
@@ -1561,6 +1562,18 @@ var BaseSerializer = class {
1561
1562
  return extractResponseFromCtx(getCtx() ?? this.constructor.ctx);
1562
1563
  }
1563
1564
  /**
1565
+ * Resolve the active request context for data transformation hooks.
1566
+ */
1567
+ resolveSerializationContext() {
1568
+ return getCtx() ?? this.constructor.ctx;
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
+ }
1576
+ /**
1564
1577
  * Dispatch a body to a raw response object when it exposes a send() transport method.
1565
1578
  *
1566
1579
  * @param raw
@@ -1635,27 +1648,28 @@ var BaseSerializer = class {
1635
1648
  runThen(input) {
1636
1649
  this.called.then = true;
1637
1650
  input.ensureJson();
1638
- const initialBody = input.body();
1639
- let response;
1640
- if (typeof input.rawResponse !== "undefined") {
1641
- response = input.createServerResponse(input.rawResponse, initialBody);
1642
- this.called.withResponse = true;
1643
- input.callWithResponse(response, input.rawResponse);
1644
- } else {
1645
- this.called.withResponse = true;
1646
- input.callWithResponse();
1647
- }
1648
- const resolvedBody = input.body();
1649
- if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1650
- const dispatchedBody = this.applyResponsePlugins({
1651
- body: resolvedBody,
1652
- rawResponse: input.rawResponse,
1653
- response
1654
- });
1655
- const resolved = Promise.resolve(dispatchedBody).then(input.onfulfilled, input.onrejected);
1656
- if (typeof response?.send === "function") response.send(dispatchedBody);
1657
- else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1658
- 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);
1659
1673
  }
1660
1674
  /**
1661
1675
  * Get or set the resource-level configuration for this serializer instance.
@@ -1781,7 +1795,7 @@ var GenericResource = class GenericResource extends BaseSerializer {
1781
1795
  /**
1782
1796
  * Get the original resource data
1783
1797
  */
1784
- data() {
1798
+ data(_ctx) {
1785
1799
  return this.resource;
1786
1800
  }
1787
1801
  /**
@@ -1845,16 +1859,10 @@ var GenericResource = class GenericResource extends BaseSerializer {
1845
1859
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
1846
1860
  return factory || !wrap ? void 0 : rootKey;
1847
1861
  }
1848
- /**
1849
- * Convert resource to JSON response format
1850
- *
1851
- * @returns
1852
- */
1853
- json() {
1854
- if (!this.called.json) {
1855
- this.called.json = true;
1856
- let data = normalizeSerializableData(this.data());
1857
- if (Array.isArray(data) && this.collects) data = data.map((item) => new this.collects(item).data());
1862
+ serializeGenericResource(resource, ctx) {
1863
+ let data = normalizeSerializableData(resource);
1864
+ const serialize = (resolvedData) => {
1865
+ data = resolvedData;
1858
1866
  if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
1859
1867
  data = sanitizeConditionalAttributes(data);
1860
1868
  const paginationExtras = buildPaginationExtras(this.resource);
@@ -1885,6 +1893,32 @@ var GenericResource = class GenericResource extends BaseSerializer {
1885
1893
  ...customMeta || {}
1886
1894
  }, rootKey);
1887
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
+ }
1888
1922
  }
1889
1923
  return this;
1890
1924
  }
@@ -2098,15 +2132,15 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2098
2132
  getSourceData() {
2099
2133
  return Array.isArray(this.resource) ? this.resource : isArkormLikeCollection(this.resource) ? this.resource.all() : this.resource.data;
2100
2134
  }
2101
- resolveObjectData() {
2135
+ resolveObjectData(ctx) {
2102
2136
  let data = this.getSourceData();
2103
- if (this.collects) data = data.map((item) => new this.collects(item).data());
2137
+ if (this.collects) data = data.map((item) => new this.collects(item).data(ctx));
2104
2138
  return normalizeSerializableData(data);
2105
2139
  }
2106
2140
  /**
2107
2141
  * Get the original resource data
2108
2142
  */
2109
- data() {
2143
+ data(_ctx) {
2110
2144
  return this.getSourceData();
2111
2145
  }
2112
2146
  /**
@@ -2178,6 +2212,46 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2178
2212
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2179
2213
  return factory || !wrap ? void 0 : rootKey;
2180
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
+ }
2181
2255
  /**
2182
2256
  * Convert resource to JSON response format
2183
2257
  *
@@ -2186,38 +2260,20 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2186
2260
  json() {
2187
2261
  if (!this.called.json) {
2188
2262
  this.called.json = true;
2189
- let data = this.data();
2190
- if (this.collects && this.data === ResourceCollection.prototype.data) data = data.map((item) => new this.collects(item).data());
2191
- data = normalizeSerializableData(data);
2192
- data = sanitizeConditionalAttributes(data);
2193
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2194
- const { metaKey } = getPaginationExtraKeys();
2195
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2196
- if (metaKey) delete paginationExtras[metaKey];
2197
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2198
- if (caseStyle) {
2199
- const transformer = getCaseTransformer(caseStyle);
2200
- data = transformKeys(data, transformer);
2263
+ const ctx = this.resolveSerializationContext();
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);
2201
2276
  }
2202
- const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2203
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2204
- this.body = buildResponseEnvelope({
2205
- payload: data,
2206
- meta: configuredMeta,
2207
- metaKey,
2208
- wrap,
2209
- rootKey,
2210
- factory,
2211
- context: {
2212
- type: "collection",
2213
- resource: this.resource
2214
- }
2215
- });
2216
- this.body = appendRootProperties(this.body, {
2217
- ...paginationExtras,
2218
- ...customMeta || {}
2219
- }, rootKey);
2220
- this.body = this.applySerializePlugins(this.body);
2221
2277
  }
2222
2278
  return this;
2223
2279
  }
@@ -2228,7 +2284,7 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2228
2284
  */
2229
2285
  toObject() {
2230
2286
  this.called.toObject = true;
2231
- return this.resolveObjectData();
2287
+ return this.resolveObjectData(this.resolveSerializationContext());
2232
2288
  }
2233
2289
  /**
2234
2290
  * Convert resource to object format and return original data.
@@ -2447,7 +2503,7 @@ var Resource = class Resource extends BaseSerializer {
2447
2503
  /**
2448
2504
  * Get the original resource data
2449
2505
  */
2450
- data() {
2506
+ data(_ctx) {
2451
2507
  return this.toObject();
2452
2508
  }
2453
2509
  /**
@@ -2488,6 +2544,30 @@ var Resource = class Resource extends BaseSerializer {
2488
2544
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2489
2545
  return factory || !wrap ? void 0 : rootKey;
2490
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
+ }
2491
2571
  /**
2492
2572
  * Convert resource to JSON response format
2493
2573
  *
@@ -2496,28 +2576,12 @@ var Resource = class Resource extends BaseSerializer {
2496
2576
  json() {
2497
2577
  if (!this.called.json) {
2498
2578
  this.called.json = true;
2499
- let data = normalizeSerializableData(this.data());
2500
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2501
- data = sanitizeConditionalAttributes(data);
2502
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2503
- if (caseStyle) {
2504
- const transformer = getCaseTransformer(caseStyle);
2505
- data = transformKeys(data, transformer);
2506
- }
2507
- const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2508
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2509
- this.body = buildResponseEnvelope({
2510
- payload: data,
2511
- wrap,
2512
- rootKey,
2513
- factory,
2514
- context: {
2515
- type: "resource",
2516
- resource: this.resource
2517
- }
2579
+ const ctx = this.resolveSerializationContext();
2580
+ const resource = this.data(ctx);
2581
+ if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
2582
+ this.serializeResource(resolved);
2518
2583
  });
2519
- this.body = appendRootProperties(this.body, customMeta, rootKey);
2520
- this.body = this.applySerializePlugins(this.body);
2584
+ else this.serializeResource(resource);
2521
2585
  }
2522
2586
  return this;
2523
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;
@@ -601,6 +602,12 @@ declare abstract class BaseSerializer<TResource = any> {
601
602
  * @returns
602
603
  */
603
604
  protected resolveRawResponse<TRawResponse>(response?: TRawResponse): TRawResponse | undefined;
605
+ /**
606
+ * Resolve the active request context for data transformation hooks.
607
+ */
608
+ protected resolveSerializationContext(): unknown;
609
+ protected isPromiseLike<T = any>(value: unknown): value is PromiseLike<T>;
610
+ protected waitForSerialization(): Promise<void>;
604
611
  /**
605
612
  * Dispatch a body to a raw response object when it exposes a send() transport method.
606
613
  *
@@ -742,7 +749,7 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
742
749
  /**
743
750
  * Get the original resource data
744
751
  */
745
- data(): (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;
746
753
  /**
747
754
  * Get the current serialized output body.
748
755
  */
@@ -782,6 +789,8 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
782
789
  * @returns The key to use for the response payload, or undefined if no key is needed.
783
790
  */
784
791
  private getPayloadKey;
792
+ private serializeCollectionData;
793
+ private resolveCollectionDataForSerialization;
785
794
  /**
786
795
  * Convert resource to JSON response format
787
796
  *
@@ -879,7 +888,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
879
888
  /**
880
889
  * Get the original resource data
881
890
  */
882
- data(): R extends NonCollectible ? R["data"] : R;
891
+ data(_ctx?: any): any;
883
892
  /**
884
893
  * Get the current serialized output body.
885
894
  */
@@ -899,6 +908,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
899
908
  protected getResourceForMeta(): R;
900
909
  protected getSerializerType(): "resource";
901
910
  private getPayloadKey;
911
+ private serializeResource;
902
912
  /**
903
913
  * Convert resource to JSON response format
904
914
  *
@@ -988,7 +998,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
988
998
  /**
989
999
  * Get the original resource data
990
1000
  */
991
- data(): R;
1001
+ data(_ctx?: any): any;
992
1002
  /**
993
1003
  * Get the current serialized output body.
994
1004
  */
@@ -1020,6 +1030,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
1020
1030
  protected getResourceForMeta(): R;
1021
1031
  protected getSerializerType(): "generic";
1022
1032
  private getPayloadKey;
1033
+ private serializeGenericResource;
1023
1034
  /**
1024
1035
  * Convert resource to JSON response format
1025
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;
@@ -601,6 +602,12 @@ declare abstract class BaseSerializer<TResource = any> {
601
602
  * @returns
602
603
  */
603
604
  protected resolveRawResponse<TRawResponse>(response?: TRawResponse): TRawResponse | undefined;
605
+ /**
606
+ * Resolve the active request context for data transformation hooks.
607
+ */
608
+ protected resolveSerializationContext(): unknown;
609
+ protected isPromiseLike<T = any>(value: unknown): value is PromiseLike<T>;
610
+ protected waitForSerialization(): Promise<void>;
604
611
  /**
605
612
  * Dispatch a body to a raw response object when it exposes a send() transport method.
606
613
  *
@@ -742,7 +749,7 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
742
749
  /**
743
750
  * Get the original resource data
744
751
  */
745
- data(): (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;
746
753
  /**
747
754
  * Get the current serialized output body.
748
755
  */
@@ -782,6 +789,8 @@ declare class ResourceCollection<R extends ResourceData[] | Collectible | Collec
782
789
  * @returns The key to use for the response payload, or undefined if no key is needed.
783
790
  */
784
791
  private getPayloadKey;
792
+ private serializeCollectionData;
793
+ private resolveCollectionDataForSerialization;
785
794
  /**
786
795
  * Convert resource to JSON response format
787
796
  *
@@ -879,7 +888,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
879
888
  /**
880
889
  * Get the original resource data
881
890
  */
882
- data(): R extends NonCollectible ? R["data"] : R;
891
+ data(_ctx?: any): any;
883
892
  /**
884
893
  * Get the current serialized output body.
885
894
  */
@@ -899,6 +908,7 @@ declare class Resource<R extends ResourceData | NonCollectible = ResourceData> e
899
908
  protected getResourceForMeta(): R;
900
909
  protected getSerializerType(): "resource";
901
910
  private getPayloadKey;
911
+ private serializeResource;
902
912
  /**
903
913
  * Convert resource to JSON response format
904
914
  *
@@ -988,7 +998,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
988
998
  /**
989
999
  * Get the original resource data
990
1000
  */
991
- data(): R;
1001
+ data(_ctx?: any): any;
992
1002
  /**
993
1003
  * Get the current serialized output body.
994
1004
  */
@@ -1020,6 +1030,7 @@ declare class GenericResource<R extends NonCollectible | Collectible | Collectio
1020
1030
  protected getResourceForMeta(): R;
1021
1031
  protected getSerializerType(): "generic";
1022
1032
  private getPayloadKey;
1033
+ private serializeGenericResource;
1023
1034
  /**
1024
1035
  * Convert resource to JSON response format
1025
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();
@@ -1532,6 +1533,18 @@ var BaseSerializer = class {
1532
1533
  return extractResponseFromCtx(getCtx() ?? this.constructor.ctx);
1533
1534
  }
1534
1535
  /**
1536
+ * Resolve the active request context for data transformation hooks.
1537
+ */
1538
+ resolveSerializationContext() {
1539
+ return getCtx() ?? this.constructor.ctx;
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
+ }
1547
+ /**
1535
1548
  * Dispatch a body to a raw response object when it exposes a send() transport method.
1536
1549
  *
1537
1550
  * @param raw
@@ -1606,27 +1619,28 @@ var BaseSerializer = class {
1606
1619
  runThen(input) {
1607
1620
  this.called.then = true;
1608
1621
  input.ensureJson();
1609
- const initialBody = input.body();
1610
- let response;
1611
- if (typeof input.rawResponse !== "undefined") {
1612
- response = input.createServerResponse(input.rawResponse, initialBody);
1613
- this.called.withResponse = true;
1614
- input.callWithResponse(response, input.rawResponse);
1615
- } else {
1616
- this.called.withResponse = true;
1617
- input.callWithResponse();
1618
- }
1619
- const resolvedBody = input.body();
1620
- if (typeof response?.setBody === "function") response.setBody(resolvedBody);
1621
- const dispatchedBody = this.applyResponsePlugins({
1622
- body: resolvedBody,
1623
- rawResponse: input.rawResponse,
1624
- response
1625
- });
1626
- const resolved = Promise.resolve(dispatchedBody).then(input.onfulfilled, input.onrejected);
1627
- if (typeof response?.send === "function") response.send(dispatchedBody);
1628
- else if (typeof input.rawResponse !== "undefined" && input.sendRawResponse) input.sendRawResponse(input.rawResponse, dispatchedBody);
1629
- 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);
1630
1644
  }
1631
1645
  /**
1632
1646
  * Get or set the resource-level configuration for this serializer instance.
@@ -1752,7 +1766,7 @@ var GenericResource = class GenericResource extends BaseSerializer {
1752
1766
  /**
1753
1767
  * Get the original resource data
1754
1768
  */
1755
- data() {
1769
+ data(_ctx) {
1756
1770
  return this.resource;
1757
1771
  }
1758
1772
  /**
@@ -1816,16 +1830,10 @@ var GenericResource = class GenericResource extends BaseSerializer {
1816
1830
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
1817
1831
  return factory || !wrap ? void 0 : rootKey;
1818
1832
  }
1819
- /**
1820
- * Convert resource to JSON response format
1821
- *
1822
- * @returns
1823
- */
1824
- json() {
1825
- if (!this.called.json) {
1826
- this.called.json = true;
1827
- let data = normalizeSerializableData(this.data());
1828
- if (Array.isArray(data) && this.collects) data = data.map((item) => new this.collects(item).data());
1833
+ serializeGenericResource(resource, ctx) {
1834
+ let data = normalizeSerializableData(resource);
1835
+ const serialize = (resolvedData) => {
1836
+ data = resolvedData;
1829
1837
  if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
1830
1838
  data = sanitizeConditionalAttributes(data);
1831
1839
  const paginationExtras = buildPaginationExtras(this.resource);
@@ -1856,6 +1864,32 @@ var GenericResource = class GenericResource extends BaseSerializer {
1856
1864
  ...customMeta || {}
1857
1865
  }, rootKey);
1858
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
+ }
1859
1893
  }
1860
1894
  return this;
1861
1895
  }
@@ -2069,15 +2103,15 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2069
2103
  getSourceData() {
2070
2104
  return Array.isArray(this.resource) ? this.resource : isArkormLikeCollection(this.resource) ? this.resource.all() : this.resource.data;
2071
2105
  }
2072
- resolveObjectData() {
2106
+ resolveObjectData(ctx) {
2073
2107
  let data = this.getSourceData();
2074
- if (this.collects) data = data.map((item) => new this.collects(item).data());
2108
+ if (this.collects) data = data.map((item) => new this.collects(item).data(ctx));
2075
2109
  return normalizeSerializableData(data);
2076
2110
  }
2077
2111
  /**
2078
2112
  * Get the original resource data
2079
2113
  */
2080
- data() {
2114
+ data(_ctx) {
2081
2115
  return this.getSourceData();
2082
2116
  }
2083
2117
  /**
@@ -2149,6 +2183,46 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2149
2183
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2150
2184
  return factory || !wrap ? void 0 : rootKey;
2151
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
+ }
2152
2226
  /**
2153
2227
  * Convert resource to JSON response format
2154
2228
  *
@@ -2157,38 +2231,20 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2157
2231
  json() {
2158
2232
  if (!this.called.json) {
2159
2233
  this.called.json = true;
2160
- let data = this.data();
2161
- if (this.collects && this.data === ResourceCollection.prototype.data) data = data.map((item) => new this.collects(item).data());
2162
- data = normalizeSerializableData(data);
2163
- data = sanitizeConditionalAttributes(data);
2164
- const paginationExtras = !Array.isArray(this.resource) ? buildPaginationExtras(this.resource) : {};
2165
- const { metaKey } = getPaginationExtraKeys();
2166
- const configuredMeta = metaKey ? paginationExtras[metaKey] : void 0;
2167
- if (metaKey) delete paginationExtras[metaKey];
2168
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor, this.resolveCollectsConfig());
2169
- if (caseStyle) {
2170
- const transformer = getCaseTransformer(caseStyle);
2171
- data = transformKeys(data, transformer);
2234
+ const ctx = this.resolveSerializationContext();
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);
2172
2247
  }
2173
- const customMeta = this.resolveMergedMeta(ResourceCollection.prototype.with);
2174
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2175
- this.body = buildResponseEnvelope({
2176
- payload: data,
2177
- meta: configuredMeta,
2178
- metaKey,
2179
- wrap,
2180
- rootKey,
2181
- factory,
2182
- context: {
2183
- type: "collection",
2184
- resource: this.resource
2185
- }
2186
- });
2187
- this.body = appendRootProperties(this.body, {
2188
- ...paginationExtras,
2189
- ...customMeta || {}
2190
- }, rootKey);
2191
- this.body = this.applySerializePlugins(this.body);
2192
2248
  }
2193
2249
  return this;
2194
2250
  }
@@ -2199,7 +2255,7 @@ var ResourceCollection = class ResourceCollection extends BaseSerializer {
2199
2255
  */
2200
2256
  toObject() {
2201
2257
  this.called.toObject = true;
2202
- return this.resolveObjectData();
2258
+ return this.resolveObjectData(this.resolveSerializationContext());
2203
2259
  }
2204
2260
  /**
2205
2261
  * Convert resource to object format and return original data.
@@ -2418,7 +2474,7 @@ var Resource = class Resource extends BaseSerializer {
2418
2474
  /**
2419
2475
  * Get the original resource data
2420
2476
  */
2421
- data() {
2477
+ data(_ctx) {
2422
2478
  return this.toObject();
2423
2479
  }
2424
2480
  /**
@@ -2459,6 +2515,30 @@ var Resource = class Resource extends BaseSerializer {
2459
2515
  const { wrap, rootKey, factory } = this.resolveResponseStructure();
2460
2516
  return factory || !wrap ? void 0 : rootKey;
2461
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
+ }
2462
2542
  /**
2463
2543
  * Convert resource to JSON response format
2464
2544
  *
@@ -2467,28 +2547,12 @@ var Resource = class Resource extends BaseSerializer {
2467
2547
  json() {
2468
2548
  if (!this.called.json) {
2469
2549
  this.called.json = true;
2470
- let data = normalizeSerializableData(this.data());
2471
- if (!Array.isArray(data) && data && typeof data.data !== "undefined") data = data.data;
2472
- data = sanitizeConditionalAttributes(data);
2473
- const caseStyle = this.resolveSerializerCaseStyle(this.constructor);
2474
- if (caseStyle) {
2475
- const transformer = getCaseTransformer(caseStyle);
2476
- data = transformKeys(data, transformer);
2477
- }
2478
- const customMeta = this.resolveMergedMeta(Resource.prototype.with);
2479
- const { wrap, rootKey, factory } = this.resolveResponseStructure();
2480
- this.body = buildResponseEnvelope({
2481
- payload: data,
2482
- wrap,
2483
- rootKey,
2484
- factory,
2485
- context: {
2486
- type: "resource",
2487
- resource: this.resource
2488
- }
2550
+ const ctx = this.resolveSerializationContext();
2551
+ const resource = this.data(ctx);
2552
+ if (this.isPromiseLike(resource)) this.serializationPromise = Promise.resolve(resource).then((resolved) => {
2553
+ this.serializeResource(resolved);
2489
2554
  });
2490
- this.body = appendRootProperties(this.body, customMeta, rootKey);
2491
- this.body = this.applySerializePlugins(this.body);
2555
+ else this.serializeResource(resource);
2492
2556
  }
2493
2557
  return this;
2494
2558
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "resora",
3
- "version": "1.2.12",
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",