@teleporthq/teleport-plugin-next-data-source 0.43.55 → 0.43.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/__tests__/array-mapper-cache-wiring.test.ts +425 -0
  2. package/__tests__/data-source-cache-wrapping.test.ts +152 -0
  3. package/__tests__/ecommerce-product-storefront-tax.test.ts +118 -0
  4. package/dist/cjs/cache/ast.d.ts +71 -0
  5. package/dist/cjs/cache/ast.d.ts.map +1 -0
  6. package/dist/cjs/cache/ast.js +229 -0
  7. package/dist/cjs/cache/ast.js.map +1 -0
  8. package/dist/cjs/cache/config.d.ts +22 -0
  9. package/dist/cjs/cache/config.d.ts.map +1 -0
  10. package/dist/cjs/cache/config.js +67 -0
  11. package/dist/cjs/cache/config.js.map +1 -0
  12. package/dist/cjs/cache/types.d.ts +31 -0
  13. package/dist/cjs/cache/types.d.ts.map +1 -0
  14. package/dist/cjs/cache/types.js +3 -0
  15. package/dist/cjs/cache/types.js.map +1 -0
  16. package/dist/cjs/data-source-fetchers.d.ts +5 -3
  17. package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
  18. package/dist/cjs/data-source-fetchers.js +51 -8
  19. package/dist/cjs/data-source-fetchers.js.map +1 -1
  20. package/dist/cjs/fetchers/teleport.d.ts +2 -2
  21. package/dist/cjs/fetchers/teleport.d.ts.map +1 -1
  22. package/dist/cjs/fetchers/teleport.js +3 -2
  23. package/dist/cjs/fetchers/teleport.js.map +1 -1
  24. package/dist/cjs/index.d.ts +2 -0
  25. package/dist/cjs/index.d.ts.map +1 -1
  26. package/dist/cjs/index.js +14 -9
  27. package/dist/cjs/index.js.map +1 -1
  28. package/dist/cjs/loading-state.d.ts.map +1 -1
  29. package/dist/cjs/loading-state.js +74 -2
  30. package/dist/cjs/loading-state.js.map +1 -1
  31. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  32. package/dist/cjs/pagination-plugin.js +204 -64
  33. package/dist/cjs/pagination-plugin.js.map +1 -1
  34. package/dist/cjs/transformations/ecommerce-product.d.ts +15 -1
  35. package/dist/cjs/transformations/ecommerce-product.d.ts.map +1 -1
  36. package/dist/cjs/transformations/ecommerce-product.js +7 -3
  37. package/dist/cjs/transformations/ecommerce-product.js.map +1 -1
  38. package/dist/cjs/transformations/index.d.ts +13 -2
  39. package/dist/cjs/transformations/index.d.ts.map +1 -1
  40. package/dist/cjs/transformations/index.js +21 -3
  41. package/dist/cjs/transformations/index.js.map +1 -1
  42. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  43. package/dist/cjs/utils.d.ts +4 -3
  44. package/dist/cjs/utils.d.ts.map +1 -1
  45. package/dist/cjs/utils.js +6 -4
  46. package/dist/cjs/utils.js.map +1 -1
  47. package/dist/esm/cache/ast.d.ts +71 -0
  48. package/dist/esm/cache/ast.d.ts.map +1 -0
  49. package/dist/esm/cache/ast.js +196 -0
  50. package/dist/esm/cache/ast.js.map +1 -0
  51. package/dist/esm/cache/config.d.ts +22 -0
  52. package/dist/esm/cache/config.d.ts.map +1 -0
  53. package/dist/esm/cache/config.js +62 -0
  54. package/dist/esm/cache/config.js.map +1 -0
  55. package/dist/esm/cache/types.d.ts +31 -0
  56. package/dist/esm/cache/types.d.ts.map +1 -0
  57. package/dist/esm/cache/types.js +2 -0
  58. package/dist/esm/cache/types.js.map +1 -0
  59. package/dist/esm/data-source-fetchers.d.ts +5 -3
  60. package/dist/esm/data-source-fetchers.d.ts.map +1 -1
  61. package/dist/esm/data-source-fetchers.js +51 -8
  62. package/dist/esm/data-source-fetchers.js.map +1 -1
  63. package/dist/esm/fetchers/teleport.d.ts +2 -2
  64. package/dist/esm/fetchers/teleport.d.ts.map +1 -1
  65. package/dist/esm/fetchers/teleport.js +3 -2
  66. package/dist/esm/fetchers/teleport.js.map +1 -1
  67. package/dist/esm/index.d.ts +2 -0
  68. package/dist/esm/index.d.ts.map +1 -1
  69. package/dist/esm/index.js +12 -8
  70. package/dist/esm/index.js.map +1 -1
  71. package/dist/esm/loading-state.d.ts.map +1 -1
  72. package/dist/esm/loading-state.js +74 -2
  73. package/dist/esm/loading-state.js.map +1 -1
  74. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  75. package/dist/esm/pagination-plugin.js +205 -65
  76. package/dist/esm/pagination-plugin.js.map +1 -1
  77. package/dist/esm/transformations/ecommerce-product.d.ts +15 -1
  78. package/dist/esm/transformations/ecommerce-product.d.ts.map +1 -1
  79. package/dist/esm/transformations/ecommerce-product.js +7 -3
  80. package/dist/esm/transformations/ecommerce-product.js.map +1 -1
  81. package/dist/esm/transformations/index.d.ts +13 -2
  82. package/dist/esm/transformations/index.d.ts.map +1 -1
  83. package/dist/esm/transformations/index.js +20 -3
  84. package/dist/esm/transformations/index.js.map +1 -1
  85. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  86. package/dist/esm/utils.d.ts +4 -3
  87. package/dist/esm/utils.d.ts.map +1 -1
  88. package/dist/esm/utils.js +6 -4
  89. package/dist/esm/utils.js.map +1 -1
  90. package/package.json +5 -5
  91. package/src/cache/ast.ts +265 -0
  92. package/src/cache/config.ts +79 -0
  93. package/src/cache/types.ts +31 -0
  94. package/src/data-source-fetchers.ts +66 -12
  95. package/src/fetchers/teleport.ts +3 -3
  96. package/src/index.ts +10 -4
  97. package/src/loading-state.ts +65 -2
  98. package/src/pagination-plugin.ts +315 -116
  99. package/src/transformations/ecommerce-product.ts +53 -2
  100. package/src/transformations/index.ts +25 -4
  101. package/src/utils.ts +10 -5
@@ -1,4 +1,14 @@
1
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
2
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
3
+ if (ar || !(i in from)) {
4
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
5
+ ar[i] = from[i];
6
+ }
7
+ }
8
+ return to.concat(ar || Array.prototype.slice.call(from));
9
+ };
1
10
  import * as types from '@babel/types';
11
+ import { findCachedFetchNetworkChain } from './cache/ast';
2
12
  export function getLoadingStateVars(index) {
3
13
  return {
4
14
  isFetchingVar: "ds_".concat(index, "_isFetching"),
@@ -56,13 +66,75 @@ dataProvider, vars) {
56
66
  return false;
57
67
  }
58
68
  var fetchArrow = findMemoizedFetchDataArrow(fetchDataAttr);
59
- if (!fetchArrow || fetchArrow.body.type !== 'CallExpression') {
69
+ if (!fetchArrow) {
70
+ return false;
71
+ }
72
+ if (fetchArrow.body.type === 'CallExpression') {
73
+ fetchArrow.body = buildTrackedFetchBody(fetchArrow.body, vars);
74
+ }
75
+ else if (fetchArrow.body.type === 'BlockStatement') {
76
+ if (!injectTrackingIntoCachedBody(fetchArrow.body, vars)) {
77
+ return false;
78
+ }
79
+ }
80
+ else {
60
81
  return false;
61
82
  }
62
- fetchArrow.body = buildTrackedFetchBody(fetchArrow.body, vars);
63
83
  setPersistDataDuringLoading(attributes, vars);
64
84
  return true;
65
85
  }
86
+ /**
87
+ * Adds the in-flight bookkeeping to a CACHED `fetchData` body.
88
+ *
89
+ * The body already returns early with `Promise.resolve(hit)` on a cache hit, so
90
+ * the tracking is attached to the network chain BELOW that — never to the early
91
+ * return. That is the whole point: a hit must not raise `isFetching`, because
92
+ * `persistDataDuringLoading={!isFetching}` would then drop the provider into its
93
+ * loading slot for a frame and produce exactly the skeleton flash the cache
94
+ * exists to remove.
95
+ *
96
+ * Returns `false` when the body is not the shape this module knows how to wrap,
97
+ * so the caller emits no state declarations rather than half-wiring it.
98
+ */
99
+ function injectTrackingIntoCachedBody(body, vars) {
100
+ var _a;
101
+ // Idempotent: a second pass over the same AST must not double-count.
102
+ if (containsIdentifier(body, vars.setIsFetchingVar)) {
103
+ return false;
104
+ }
105
+ var networkChain = findCachedFetchNetworkChain(body);
106
+ if (!networkChain) {
107
+ return false;
108
+ }
109
+ var tracked = buildTrackedFetchBody(networkChain.statement.argument, vars);
110
+ (_a = body.body).splice.apply(_a, __spreadArray([networkChain.index, 1], tracked.body, false));
111
+ return true;
112
+ }
113
+ // tslint:disable-next-line:no-any
114
+ function containsIdentifier(node, name) {
115
+ if (!node || typeof node !== 'object') {
116
+ return false;
117
+ }
118
+ if (node.type === 'Identifier' && node.name === name) {
119
+ return true;
120
+ }
121
+ for (var _i = 0, _a = Object.keys(node); _i < _a.length; _i++) {
122
+ var key = _a[_i];
123
+ if (key === 'loc' || key === 'start' || key === 'end') {
124
+ continue;
125
+ }
126
+ var value = node[key];
127
+ if (Array.isArray(value)) {
128
+ if (value.some(function (entry) { return containsIdentifier(entry, name); })) {
129
+ return true;
130
+ }
131
+ }
132
+ else if (value && typeof value === 'object' && containsIdentifier(value, name)) {
133
+ return true;
134
+ }
135
+ }
136
+ return false;
137
+ }
66
138
  // tslint:disable-next-line:no-any
67
139
  function findAttribute(attributes, name) {
68
140
  return attributes.find(
@@ -1 +1 @@
1
- {"version":3,"file":"loading-state.js","sourceRoot":"","sources":["../../src/loading-state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loading-state.js","sourceRoot":"","sources":["../../src/loading-state.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pagination-plugin.d.ts","sourceRoot":"","sources":["../../src/pagination-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EAIvB,MAAM,4BAA4B,CAAA;AA+tBnC,eAAO,MAAM,qCAAqC,EAAE,sBAAsB,CAAC,EAAE,CAy3B5E,CAAA"}
1
+ {"version":3,"file":"pagination-plugin.d.ts","sourceRoot":"","sources":["../../src/pagination-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EAGvB,MAAM,4BAA4B,CAAA;AAivBnC,eAAO,MAAM,qCAAqC,EAAE,sBAAsB,CAAC,EAAE,CAi6B5E,CAAA"}
@@ -37,13 +37,16 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
37
37
  import { ChunkType, FileType, } from '@teleporthq/teleport-types';
38
38
  import * as types from '@babel/types';
39
39
  import { parseExpression } from '@babel/parser';
40
- import { StringUtils } from '@teleporthq/teleport-shared';
40
+ import { ASTStatementOrder, StringUtils } from '@teleporthq/teleport-shared';
41
41
  import { ASTUtils, URLSearchParamSync } from '@teleporthq/teleport-plugin-common';
42
42
  import { generateSafeFileName } from './utils';
43
43
  import { generateDataSourceFetcherWithCore } from './data-source-fetchers';
44
+ import { buildProductTransformOptions, } from './transformations';
44
45
  import { appendSortsParam, extractDynamicSort } from './sort-utils';
45
46
  import { appendFiltersParam, pushStateIdsAsDeps, pushPropIdsAsDeps } from './filter-utils';
46
47
  import { applyLoadingStateToDataProvider, buildLoadingStateDeclarations, getLoadingStateVars, } from './loading-state';
48
+ import { mergeServerCacheOptions, resolveCacheFromRepeaterContent } from './cache/config';
49
+ import { buildCacheHydrationEffect, buildCacheStoreThen, buildCachedFetchBody, buildCachedParamsDeclarations, registerCacheClientImports, } from './cache/ast';
47
50
  // tslint:disable-next-line:no-any
48
51
  function parseSearchDefaultValue(raw) {
49
52
  if (!raw || typeof raw !== 'object') {
@@ -419,6 +422,7 @@ function buildStateRegistry(uidlNode) {
419
422
  filterStateIds: filterStateIds,
420
423
  filterPropIds: filterPropIds,
421
424
  filterUrlSearchParamKeys: filterUrlSearchParamKeys,
425
+ cache: resolveCacheFromRepeaterContent(content.cache, parentDataSource.resourceDef),
422
426
  category: 'plain',
423
427
  };
424
428
  // Determine category
@@ -552,9 +556,9 @@ function pushSearchUrlSyncEffects(effectStatements, usage, vars) {
552
556
  // ==================== MAIN PLUGIN ====================
553
557
  export var createNextArrayMapperPaginationPlugin = function () {
554
558
  var paginationPlugin = function (structure) { return __awaiter(void 0, void 0, void 0, function () {
555
- var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, registry, getStaticPropsChunk, isPage, stateDeclarations, effectStatements, needsUseRouter, hasRouterDecl, returnIndex, insertIndex, dataProviders, dataProvidersWithRepeaters, usageIndexByDataSourceId, loadingStateDeclarations, dataProvidersWithoutRepeaters, searchInputs, searchEnabledUsages, paginationNodes, paginatedUsages;
556
- var _a;
557
- return __generator(this, function (_b) {
559
+ var uidl, chunks, dependencies, options, componentChunk, variableDeclaration, declarator, arrowFunction, blockStatement, registry, getStaticPropsChunk, isPage, stateDeclarations, effectStatements, needsUseRouter, hasRouterDecl, returnIndex, insertIndex, dataProviders, dataProvidersWithRepeaters, usageIndexByDataSourceId, loadingStateDeclarations, cacheDeclarations, sharedOptions, cachedScopes, dataProvidersWithoutRepeaters, searchInputs, searchEnabledUsages, paginationNodes, paginatedUsages;
560
+ var _a, _b;
561
+ return __generator(this, function (_c) {
558
562
  uidl = structure.uidl, chunks = structure.chunks, dependencies = structure.dependencies, options = structure.options;
559
563
  componentChunk = chunks.find(function (chunk) { return chunk.name === 'jsx-component'; });
560
564
  if (!componentChunk || componentChunk.type !== ChunkType.AST) {
@@ -916,8 +920,9 @@ export var createNextArrayMapperPaginationPlugin = function () {
916
920
  });
917
921
  usageIndexByDataSourceId = new Map();
918
922
  loadingStateDeclarations = [];
923
+ cacheDeclarations = [];
919
924
  dataProvidersWithRepeaters.forEach(function (dp) {
920
- var _a, _b, _c;
925
+ var _a, _b;
921
926
  var nameAttr = dp.openingElement.attributes.find(function (attr) { return attr.type === 'JSXAttribute' && attr.name.name === 'name'; });
922
927
  if (!((_b = (_a = nameAttr === null || nameAttr === void 0 ? void 0 : nameAttr.value) === null || _a === void 0 ? void 0 : _a.expression) === null || _b === void 0 ? void 0 : _b.value)) {
923
928
  return;
@@ -935,13 +940,13 @@ export var createNextArrayMapperPaginationPlugin = function () {
935
940
  var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
936
941
  // Update DataProvider based on category
937
942
  if (usage.category === 'paginated+search') {
938
- updateDataProviderForPaginatedSearch(dp, usage, vars, fileName);
943
+ updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDeclarations);
939
944
  }
940
945
  else if (usage.category === 'paginated-only') {
941
- updateDataProviderForPaginationOnly(dp, usage, vars, fileName);
946
+ updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDeclarations);
942
947
  }
943
948
  else if (usage.category === 'search-only') {
944
- updateDataProviderForSearchOnly(dp, usage, vars, fileName);
949
+ updateDataProviderForSearchOnly(dp, usage, vars, fileName, cacheDeclarations);
945
950
  }
946
951
  else if (usage.category === 'plain') {
947
952
  updateDataProviderForPlain(dp, fileName, usage);
@@ -955,12 +960,37 @@ export var createNextArrayMapperPaginationPlugin = function () {
955
960
  loadingStateDeclarations.push.apply(loadingStateDeclarations, buildLoadingStateDeclarations(loadingVars));
956
961
  }
957
962
  // Create API route for all categories (including 'plain' for components)
958
- ensureAPIRouteExists(options.extractedResources, usage, options.dataSources, (_c = options.ecommerceSettings) === null || _c === void 0 ? void 0 : _c.categories);
963
+ ensureAPIRouteExists(options.extractedResources, usage, options.dataSources, buildProductTransformOptions(options));
959
964
  });
965
+ sharedOptions = options;
966
+ if (!sharedOptions.serverCacheByFile) {
967
+ sharedOptions.serverCacheByFile = new Map();
968
+ }
969
+ applyServerCacheToDataSourceModules(options.extractedResources, registry, options.dataSources, buildProductTransformOptions(options), sharedOptions.serverCacheByFile);
960
970
  // Declare the loading-state hooks alongside the other data-source state, at
961
971
  // the top of the component body. Unconditional and in a fixed order, so the
962
972
  // hook order stays stable across renders.
963
973
  loadingStateDeclarations.reverse().forEach(function (s) { return blockStatement.body.unshift(s); });
974
+ cachedScopes = Array.from(new Set(registry.usages
975
+ .filter(function (usage) { var _a; return (_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client; })
976
+ .map(function (usage) { return usage.cache.scope; })));
977
+ if (cacheDeclarations.length || cachedScopes.length) {
978
+ // One effect per page covering every scope on it: flips the hydration
979
+ // latch, then asks once whether any of this page's tables changed while
980
+ // the visitor was away. Without it a browser serving everything from its
981
+ // own cache would never learn about a write at all. It has to land
982
+ // BEFORE the component's `return` — a plain `push` at this point in the
983
+ // pipeline appends after it, where React never registers the hook.
984
+ ASTStatementOrder.insertStatementsBeforeReturn(blockStatement, [
985
+ buildCacheHydrationEffect(cachedScopes),
986
+ ]);
987
+ // `ds_N_params` / `ds_N_cached` read the `ds_N_state` hooks declared
988
+ // above, so they are placed at the earliest point where everything they
989
+ // reference is already in scope — never blindly at the top, which is
990
+ // exactly the `Cannot access 'ds_0_state' before initialization` crash.
991
+ ASTStatementOrder.insertStatementsAfterDependencies(blockStatement, cacheDeclarations);
992
+ registerCacheClientImports(dependencies, (_a = uidl.outputOptions) === null || _a === void 0 ? void 0 : _a.folderPath);
993
+ }
964
994
  dataProvidersWithoutRepeaters = dataProviders.filter(function (dp) {
965
995
  var hasRepeater = findArrayMapperRenderPropInDataProvider(dp) !== undefined;
966
996
  return !hasRepeater;
@@ -992,7 +1022,7 @@ export var createNextArrayMapperPaginationPlugin = function () {
992
1022
  });
993
1023
  // STEP 6: Update getStaticProps if this is a page
994
1024
  if (isPage) {
995
- updateGetStaticProps(chunks, registry, dependencies, (_a = uidl.outputOptions) === null || _a === void 0 ? void 0 : _a.folderPath);
1025
+ updateGetStaticProps(chunks, registry, dependencies, (_b = uidl.outputOptions) === null || _b === void 0 ? void 0 : _b.folderPath);
996
1026
  }
997
1027
  return [2 /*return*/, structure];
998
1028
  });
@@ -1160,7 +1190,40 @@ function findAllPaginationNodesInJSX(blockStatement) {
1160
1190
  traverse(blockStatement);
1161
1191
  return results;
1162
1192
  }
1163
- function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
1193
+ /**
1194
+ * Emits the provider's `params` and, for a cached mapper, the peek beside it.
1195
+ *
1196
+ * An uncached mapper keeps the inline `params={useMemo(...)}` it has always had,
1197
+ * byte for byte. A cached one hoists that memo into a component const so the
1198
+ * peek can depend on the same object identity instead of rebuilding it.
1199
+ *
1200
+ * Returns the identifier holding the peeked rows, or `undefined` when this
1201
+ * mapper does not cache.
1202
+ */
1203
+ function pushParamsAttribute(
1204
+ // tslint:disable-next-line:no-any
1205
+ dp, usage, paramsProps, memoDeps, cacheDeclarations) {
1206
+ var _a;
1207
+ var paramsMemo = types.callExpression(types.identifier('useMemo'), [
1208
+ types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
1209
+ types.arrayExpression(memoDeps),
1210
+ ]);
1211
+ // A state-bound sort deliberately suppresses `initialData` (see the comment at
1212
+ // the call site): the prefetch ran without sort params, so reusing anything on
1213
+ // mount would mask the current sort. The cache peek is `initialData` by
1214
+ // another name, so it has to be suppressed for exactly the same reason.
1215
+ var cache = ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) && !usage.dynamicSort ? usage.cache : undefined;
1216
+ if (!cache) {
1217
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(paramsMemo)));
1218
+ return undefined;
1219
+ }
1220
+ var hoisted = buildCachedParamsDeclarations({ index: usage.index, paramsMemo: paramsMemo, cache: cache });
1221
+ cacheDeclarations.push.apply(cacheDeclarations, hoisted.declarations);
1222
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.identifier(hoisted.paramsIdentifier))));
1223
+ return hoisted.cachedIdentifier;
1224
+ }
1225
+ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName, cacheDeclarations) {
1226
+ var _a;
1164
1227
  var attrs = dp.openingElement.attributes;
1165
1228
  // Remove existing params, key, initialData, fetchData, persistDataDuringLoading
1166
1229
  dp.openingElement.attributes = attrs.filter(function (attr) {
@@ -1189,10 +1252,7 @@ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
1189
1252
  pushStateIdsAsDeps(memoDeps, seenDeps, usage.dynamicSort.depStateIds);
1190
1253
  }
1191
1254
  pushUrlSearchParamMemoDeps(memoDeps, usage);
1192
- dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
1193
- types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
1194
- types.arrayExpression(memoDeps),
1195
- ]))));
1255
+ var cachedInitialData = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations);
1196
1256
  // Add initialData. Skip the server-prefetched data entirely when a dynamic
1197
1257
  // state-bound sort is active — the prefetch ran without sort parameters, so
1198
1258
  // reusing it would mask the current sort state AND cause DataProvider to skip
@@ -1201,7 +1261,7 @@ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
1201
1261
  // refetch via the useMemo params dependency chain.
1202
1262
  if (!usage.dynamicSort) {
1203
1263
  var initialDataCondition = wrapInitialDataWithUrlFilterGuard(types.logicalExpression('&&', types.binaryExpression('===', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('page')), types.numericLiteral(1)), types.unaryExpression('!', types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')), true)), usage);
1204
- dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(initialDataCondition, types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
1264
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(initialDataCondition, types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), cachedInitialData ? types.identifier(cachedInitialData) : types.identifier('undefined')))));
1205
1265
  }
1206
1266
  // Add key. Sort is intentionally NOT part of the key — a key change would
1207
1267
  // remount the DataProvider, and a fresh mount re-arms the internal
@@ -1220,11 +1280,12 @@ function updateDataProviderForPaginatedSearch(dp, usage, vars, fileName) {
1220
1280
  types.memberExpression(types.identifier(vars.combinedStateVar), types.identifier('debouncedQuery')),
1221
1281
  ]))));
1222
1282
  // Add fetchData
1223
- dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
1283
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName, ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined));
1224
1284
  // Add persistDataDuringLoading
1225
1285
  dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
1226
1286
  }
1227
- function updateDataProviderForPaginationOnly(dp, usage, vars, fileName) {
1287
+ function updateDataProviderForPaginationOnly(dp, usage, vars, fileName, cacheDeclarations) {
1288
+ var _a;
1228
1289
  var attrs = dp.openingElement.attributes;
1229
1290
  dp.openingElement.attributes = attrs.filter(function (attr) {
1230
1291
  var _a;
@@ -1249,14 +1310,11 @@ function updateDataProviderForPaginationOnly(dp, usage, vars, fileName) {
1249
1310
  }
1250
1311
  pushUrlSearchParamMemoDeps(memoDeps, usage);
1251
1312
  // Add params
1252
- dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
1253
- types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
1254
- types.arrayExpression(memoDeps),
1255
- ]))));
1313
+ var cachedInitialData = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations);
1256
1314
  // Add initialData. See paginated+search updater for why we skip prefetch
1257
1315
  // reuse when a dynamic state-bound sort is active.
1258
1316
  if (!usage.dynamicSort) {
1259
- dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(types.binaryExpression('===', types.identifier(vars.pageStateVar), types.numericLiteral(1)), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
1317
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(types.binaryExpression('===', types.identifier(vars.pageStateVar), types.numericLiteral(1)), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), cachedInitialData ? types.identifier(cachedInitialData) : types.identifier('undefined')))));
1260
1318
  }
1261
1319
  // Add key — sort is intentionally NOT included; see paginated+search updater.
1262
1320
  dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
@@ -1267,10 +1325,11 @@ function updateDataProviderForPaginationOnly(dp, usage, vars, fileName) {
1267
1325
  types.templateElement({ raw: '', cooked: '' }),
1268
1326
  ], [types.identifier(vars.pageStateVar)]))));
1269
1327
  // Add fetchData
1270
- dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
1328
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName, ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined));
1271
1329
  dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
1272
1330
  }
1273
- function updateDataProviderForSearchOnly(dp, usage, vars, fileName) {
1331
+ function updateDataProviderForSearchOnly(dp, usage, vars, fileName, cacheDeclarations) {
1332
+ var _a;
1274
1333
  var attrs = dp.openingElement.attributes;
1275
1334
  dp.openingElement.attributes = attrs.filter(function (attr) {
1276
1335
  var _a;
@@ -1296,14 +1355,11 @@ function updateDataProviderForSearchOnly(dp, usage, vars, fileName) {
1296
1355
  pushStateIdsAsDeps(memoDeps, seenDeps, usage.dynamicSort.depStateIds);
1297
1356
  }
1298
1357
  pushUrlSearchParamMemoDeps(memoDeps, usage);
1299
- dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(types.callExpression(types.identifier('useMemo'), [
1300
- types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
1301
- types.arrayExpression(memoDeps),
1302
- ]))));
1358
+ var cachedInitialData = pushParamsAttribute(dp, usage, paramsProps, memoDeps, cacheDeclarations);
1303
1359
  // Add initialData. See paginated+search updater for why we skip prefetch
1304
1360
  // reuse when a dynamic state-bound sort is active.
1305
1361
  if (!usage.dynamicSort) {
1306
- dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(types.unaryExpression('!', types.identifier(vars.debouncedSearchQueryVar), true), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), types.identifier('undefined')))));
1362
+ dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('initialData'), types.jsxExpressionContainer(types.conditionalExpression(wrapInitialDataWithUrlFilterGuard(types.unaryExpression('!', types.identifier(vars.debouncedSearchQueryVar), true), usage), types.optionalMemberExpression(types.identifier('props'), types.identifier(vars.propsPrefix), false, true), cachedInitialData ? types.identifier(cachedInitialData) : types.identifier('undefined')))));
1307
1363
  }
1308
1364
  // Add key — sort is intentionally NOT included; see paginated+search updater.
1309
1365
  dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('key'), types.jsxExpressionContainer(types.templateLiteral([
@@ -1311,16 +1367,23 @@ function updateDataProviderForSearchOnly(dp, usage, vars, fileName) {
1311
1367
  types.templateElement({ raw: '', cooked: '' }),
1312
1368
  ], [types.identifier(vars.debouncedSearchQueryVar)]))));
1313
1369
  // Add fetchData
1314
- dp.openingElement.attributes.push(createFetchDataAttribute(fileName));
1370
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName, ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined));
1315
1371
  dp.openingElement.attributes.push(types.jsxAttribute(types.jsxIdentifier('persistDataDuringLoading'), types.jsxExpressionContainer(types.booleanLiteral(true))));
1316
1372
  }
1317
1373
  function updateDataProviderForPlain(dp, fileName, usage) {
1318
- var _a, _b, _c;
1374
+ var _a, _b, _c, _d;
1319
1375
  var attrs = dp.openingElement.attributes;
1376
+ var clientCache = ((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.client) ? usage.cache : undefined;
1320
1377
  // Check if fetchData already exists
1321
1378
  var hasFetchData = attrs.some(function (attr) { var _a; return attr.type === 'JSXAttribute' && ((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name) === 'fetchData'; });
1322
- // If no fetchData, add it
1323
- if (!hasFetchData) {
1379
+ if (clientCache) {
1380
+ // A plain provider may already carry the UNMEMOIZED fetcher `utils.ts`
1381
+ // emits. Caching has to replace it rather than skip: the memoized form is
1382
+ // what both the cache peek and the in-flight tracking are attached to.
1383
+ dp.openingElement.attributes = attrs.filter(function (attr) { var _a; return !(attr.type === 'JSXAttribute' && ((_a = attr.name) === null || _a === void 0 ? void 0 : _a.name) === 'fetchData'); });
1384
+ dp.openingElement.attributes.push(createFetchDataAttribute(fileName, clientCache));
1385
+ }
1386
+ else if (!hasFetchData) {
1324
1387
  attrs.push(createFetchDataAttribute(fileName));
1325
1388
  }
1326
1389
  // Check if persistDataDuringLoading already exists
@@ -1336,14 +1399,14 @@ function updateDataProviderForPlain(dp, fileName, usage) {
1336
1399
  }
1337
1400
  var paramsAttr = attrs[paramsAttrIndex];
1338
1401
  // Check if params is already wrapped in useMemo
1339
- if (((_a = paramsAttr.value) === null || _a === void 0 ? void 0 : _a.type) === 'JSXExpressionContainer' &&
1402
+ if (((_b = paramsAttr.value) === null || _b === void 0 ? void 0 : _b.type) === 'JSXExpressionContainer' &&
1340
1403
  paramsAttr.value.expression.type === 'CallExpression' &&
1341
- ((_b = paramsAttr.value.expression.callee) === null || _b === void 0 ? void 0 : _b.name) === 'useMemo') {
1404
+ ((_c = paramsAttr.value.expression.callee) === null || _c === void 0 ? void 0 : _c.name) === 'useMemo') {
1342
1405
  return;
1343
1406
  }
1344
1407
  // Get the current params value expression
1345
1408
  var paramsExpression = null;
1346
- if (((_c = paramsAttr.value) === null || _c === void 0 ? void 0 : _c.type) === 'JSXExpressionContainer') {
1409
+ if (((_d = paramsAttr.value) === null || _d === void 0 ? void 0 : _d.type) === 'JSXExpressionContainer') {
1347
1410
  paramsExpression = paramsAttr.value.expression;
1348
1411
  }
1349
1412
  if (!paramsExpression) {
@@ -1395,32 +1458,32 @@ function stabilizeDataProviderWithoutRepeater(dp) {
1395
1458
  // Replace the params attribute
1396
1459
  attrs[paramsAttrIndex] = types.jsxAttribute(types.jsxIdentifier('params'), types.jsxExpressionContainer(memoizedParams));
1397
1460
  }
1398
- function createFetchDataAttribute(fileName) {
1399
- return types.jsxAttribute(types.jsxIdentifier('fetchData'), types.jsxExpressionContainer(types.callExpression(types.identifier('useCallback'), [
1400
- types.arrowFunctionExpression([types.identifier('params')], types.callExpression(types.memberExpression(types.callExpression(types.memberExpression(types.callExpression(types.identifier('fetch'), [
1401
- types.templateLiteral([
1402
- types.templateElement({
1403
- raw: "/api/".concat(fileName, "?"),
1404
- cooked: "/api/".concat(fileName, "?"),
1405
- }),
1406
- types.templateElement({ raw: '', cooked: '' }),
1407
- ], [
1408
- types.newExpression(types.identifier('URLSearchParams'), [
1409
- types.identifier('params'),
1410
- ]),
1411
- ]),
1412
- types.objectExpression([
1413
- types.objectProperty(types.identifier('headers'), types.objectExpression([
1414
- types.objectProperty(types.stringLiteral('Content-Type'), types.stringLiteral('application/json')),
1415
- ])),
1416
- ]),
1417
- ]), types.identifier('then')), [
1418
- types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
1419
- ]), types.identifier('then')), [
1420
- types.arrowFunctionExpression([types.identifier('response')], types.optionalMemberExpression(types.identifier('response'), types.identifier('data'), false, true)),
1421
- ])),
1422
- types.arrayExpression([]),
1423
- ])));
1461
+ function createFetchDataAttribute(fileName, cache) {
1462
+ var fetchCall = types.callExpression(types.identifier('fetch'), [
1463
+ types.templateLiteral([
1464
+ types.templateElement({
1465
+ raw: "/api/".concat(fileName, "?"),
1466
+ cooked: "/api/".concat(fileName, "?"),
1467
+ }),
1468
+ types.templateElement({ raw: '', cooked: '' }),
1469
+ ], [types.newExpression(types.identifier('URLSearchParams'), [types.identifier('params')])]),
1470
+ types.objectExpression([
1471
+ types.objectProperty(types.identifier('headers'), types.objectExpression([
1472
+ types.objectProperty(types.stringLiteral('Content-Type'), types.stringLiteral('application/json')),
1473
+ ])),
1474
+ ]),
1475
+ ]);
1476
+ var parsedJson = types.callExpression(types.memberExpression(fetchCall, types.identifier('then')), [
1477
+ types.arrowFunctionExpression([types.identifier('res')], types.callExpression(types.memberExpression(types.identifier('res'), types.identifier('json')), [])),
1478
+ ]);
1479
+ // The uncached tail is left exactly as it has always been emitted, so a
1480
+ // project that does not cache produces byte-identical output.
1481
+ var uncachedTail = types.arrowFunctionExpression([types.identifier('response')], types.optionalMemberExpression(types.identifier('response'), types.identifier('data'), false, true));
1482
+ var networkChain = types.callExpression(types.memberExpression(parsedJson, types.identifier('then')), [cache ? buildCacheStoreThen(cache) : uncachedTail]);
1483
+ var arrow = cache
1484
+ ? types.arrowFunctionExpression([types.identifier('params')], buildCachedFetchBody(networkChain, cache))
1485
+ : types.arrowFunctionExpression([types.identifier('params')], networkChain);
1486
+ return types.jsxAttribute(types.jsxIdentifier('fetchData'), types.jsxExpressionContainer(types.callExpression(types.identifier('useCallback'), [arrow, types.arrayExpression([])])));
1424
1487
  }
1425
1488
  function wireSearchInput(inputNode, vars) {
1426
1489
  // Remove existing onChange and value
@@ -1527,7 +1590,84 @@ function wirePaginationButtons(paginationNode, usage, vars) {
1527
1590
  }
1528
1591
  }
1529
1592
  }
1530
- function ensureAPIRouteExists(extractedResources, usage, dataSources, categories) {
1593
+ /**
1594
+ * Applies the SERVER cache to the generated data-source modules, once, after
1595
+ * every provider has been visited.
1596
+ *
1597
+ * A post-pass rather than a parameter to `ensureAPIRouteExists` because four
1598
+ * different places race to create `utils/data-sources/<file>.js` — the
1599
+ * getStaticProps path, the component path, the client-API path and this plugin —
1600
+ * and whichever wins would otherwise decide whether the file is cached. Since
1601
+ * the generator is deterministic, regenerating the winner with the cache options
1602
+ * is order-independent and cannot half-apply.
1603
+ *
1604
+ * The config is merged per FILE, not per mapper: one module serves every mapper
1605
+ * reading that `(type, table, dataSourceId)` triple, so two mappers on two pages
1606
+ * have to agree — and the fresher one wins (see `mergeServerCacheOptions`).
1607
+ */
1608
+ function applyServerCacheToDataSourceModules(
1609
+ // tslint:disable-next-line:no-any
1610
+ extractedResources, registry,
1611
+ // tslint:disable-next-line:no-any
1612
+ dataSources, transformOptions,
1613
+ // Accumulated across every page/component this generation has processed. The
1614
+ // module is shared project-wide, so merging only the CURRENT page's usages
1615
+ // would let page ORDER decide the TTL: a page asking for 300s processed after
1616
+ // one asking for 60s would widen the window the second page was configured
1617
+ // with. Carried on the shared options object so the merge stays global.
1618
+ accumulator) {
1619
+ if (transformOptions === void 0) { transformOptions = {}; }
1620
+ var byFileName = accumulator !== null && accumulator !== void 0 ? accumulator : new Map();
1621
+ registry.usages.forEach(function (usage) {
1622
+ var _a;
1623
+ if (!((_a = usage.cache) === null || _a === void 0 ? void 0 : _a.server)) {
1624
+ return;
1625
+ }
1626
+ var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
1627
+ var bucket = byFileName.get(fileName) || { usage: usage, entries: [] };
1628
+ bucket.entries.push({
1629
+ scope: usage.cache.scope,
1630
+ ttlSeconds: usage.cache.ttlSeconds,
1631
+ sMaxAge: usage.cache.sMaxAge,
1632
+ staleWhileRevalidate: usage.cache.staleWhileRevalidate,
1633
+ });
1634
+ byFileName.set(fileName, bucket);
1635
+ });
1636
+ byFileName.forEach(function (bucket, fileName) {
1637
+ var cacheOptions = mergeServerCacheOptions(bucket.entries);
1638
+ if (!cacheOptions) {
1639
+ return;
1640
+ }
1641
+ var dataSource = dataSources[bucket.usage.resourceDefinition.dataSourceId];
1642
+ if (!dataSource) {
1643
+ return;
1644
+ }
1645
+ var tableName = bucket.usage.resourceDefinition.tableName || 'data';
1646
+ var utilsKey = "utils/".concat(fileName);
1647
+ var apiKey = "api/".concat(fileName);
1648
+ try {
1649
+ if (extractedResources[utilsKey]) {
1650
+ extractedResources[utilsKey].content = generateDataSourceFetcherWithCore(dataSource, tableName, false, transformOptions, cacheOptions);
1651
+ return;
1652
+ }
1653
+ // The variant that inlines the whole fetcher straight into `pages/api`
1654
+ // instead of re-exporting a utils module. Detected by content rather than
1655
+ // by which code path produced it, so a future fifth emitter is covered too.
1656
+ var apiEntry = extractedResources[apiKey];
1657
+ if (apiEntry &&
1658
+ typeof apiEntry.content === 'string' &&
1659
+ apiEntry.content.includes('async function handler')) {
1660
+ apiEntry.content = generateDataSourceFetcherWithCore(dataSource, tableName, true, transformOptions, cacheOptions);
1661
+ }
1662
+ }
1663
+ catch (error) {
1664
+ // Caching must never be the reason a project fails to generate; the
1665
+ // uncached module that is already in place stays exactly as it was.
1666
+ }
1667
+ });
1668
+ }
1669
+ function ensureAPIRouteExists(extractedResources, usage, dataSources, transformOptions) {
1670
+ if (transformOptions === void 0) { transformOptions = {}; }
1531
1671
  // Generate file name for the API route
1532
1672
  var fileName = generateSafeFileName(usage.resourceDefinition.dataSourceType, usage.resourceDefinition.tableName, usage.resourceDefinition.dataSourceId);
1533
1673
  // Check if the utils data source file exists - if not, create it
@@ -1537,7 +1677,7 @@ function ensureAPIRouteExists(extractedResources, usage, dataSources, categories
1537
1677
  if (dataSource) {
1538
1678
  try {
1539
1679
  // Generate the utils file with fetchData, fetchCount, handler, and getCount
1540
- var fetcherCode = generateDataSourceFetcherWithCore(dataSource, usage.resourceDefinition.tableName || 'data', false, categories);
1680
+ var fetcherCode = generateDataSourceFetcherWithCore(dataSource, usage.resourceDefinition.tableName || 'data', false, transformOptions);
1541
1681
  extractedResources["utils/".concat(fileName)] = {
1542
1682
  fileName: fileName,
1543
1683
  fileType: FileType.JS,