@dylandepass/helix-product-pipeline 2.2.0 → 2.3.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [2.3.0](https://github.com/adobe-rnd/helix-product-pipeline/compare/v2.2.0...v2.3.0) (2026-02-12)
2
+
3
+
4
+ ### Features
5
+
6
+ * add limit/offset pagination and deterministic sort to product index ([#71](https://github.com/adobe-rnd/helix-product-pipeline/issues/71)) ([28499dd](https://github.com/adobe-rnd/helix-product-pipeline/commit/28499dd2140c830ed46ecec03bad4cee1fdd1ba5))
7
+
1
8
  # [2.2.0](https://github.com/adobe-rnd/helix-product-pipeline/compare/v2.1.0...v2.2.0) (2026-02-04)
2
9
 
3
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dylandepass/helix-product-pipeline",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Helix Product Pipeline",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
@@ -17,22 +17,33 @@ import initConfig from './steps/init-config.js';
17
17
  import fetchProductBusContent from './steps/fetch-productbus.js';
18
18
  import { setLastModified } from './utils/last-modified.js';
19
19
  import { set404CacheHeaders } from './steps/set-cache-headers.js';
20
- import { getIncludes } from './steps/utils.js';
20
+ import { getIncludes, getPaginationParams } from './steps/utils.js';
21
21
 
22
22
  /**
23
- * Returns index as spreadsheet
23
+ * Returns index as spreadsheet with pagination support.
24
24
  * @param {SharedTypes.StoredIndex} index
25
25
  * @param {Record<string, boolean>} includes
26
+ * @param {{ hasParams?: boolean, limit?: number, offset?: number }} [pagination={}]
27
+ * - Pagination options
26
28
  * @returns {{
27
29
  * ':type': 'sheet',
30
+ * total: number,
31
+ * offset: number,
32
+ * limit: number,
28
33
  * columns: string[],
29
34
  * data: Record<string, string>[]
30
35
  * }}
31
36
  */
32
- export function toSpreadsheet(index, includes) {
37
+ export function toSpreadsheet(index, includes, pagination = {}) {
38
+ const {
39
+ limit = pagination.hasParams ? 1000 : Infinity,
40
+ offset = 0,
41
+ } = pagination;
42
+
33
43
  const columns = new Set(['sku']);
34
44
 
35
45
  const products = Object.entries(index)
46
+ .sort(([a], [b]) => a.localeCompare(b))
36
47
  .filter(([_, entry]) => includes.all || !entry.filters?.noindex || includes.noindex)
37
48
  .reduce((acc, [sluggedSku, entry]) => {
38
49
  const product = entry.data;
@@ -80,10 +91,17 @@ export function toSpreadsheet(index, includes) {
80
91
  return acc;
81
92
  }, []);
82
93
 
94
+ const total = products.length;
95
+ const len = Math.min(limit, total - offset);
96
+ const paginatedData = products.slice(offset, offset + len);
97
+
83
98
  return {
84
99
  ':type': 'sheet',
100
+ total,
101
+ offset,
102
+ limit: paginatedData.length,
85
103
  columns: Array.from(columns),
86
- data: products,
104
+ data: paginatedData,
87
105
  };
88
106
  }
89
107
 
@@ -135,7 +153,9 @@ export async function productIndexPipe(state, req) {
135
153
 
136
154
  setLastModified(state, res);
137
155
 
138
- res.body = JSON.stringify(toSpreadsheet(state.content.data, getIncludes(req)), null, 2);
156
+ const pagination = getPaginationParams(req);
157
+ const spreadsheet = toSpreadsheet(state.content.data, getIncludes(req), pagination);
158
+ res.body = JSON.stringify(spreadsheet, null, 2);
139
159
  } catch (e) {
140
160
  const errorRes = new PipelineResponse('', {
141
161
  /* c8 ignore next 6 */
@@ -125,3 +125,36 @@ export function getIncludes(req) {
125
125
  }
126
126
  return includes;
127
127
  }
128
+
129
+ /**
130
+ * Get pagination params from request URL.
131
+ * @param {PipelineRequest} req
132
+ * @returns {{ hasParams?: boolean, limit?: number, offset?: number }}
133
+ */
134
+ export function getPaginationParams(req) {
135
+ const { searchParams } = req.url;
136
+ const hasParams = searchParams.has('limit') || searchParams.has('offset');
137
+ if (!hasParams) {
138
+ return {};
139
+ }
140
+
141
+ const result = { hasParams: true };
142
+
143
+ const limitStr = searchParams.get('limit');
144
+ if (limitStr !== null) {
145
+ const limit = parseInt(limitStr, 10);
146
+ if (!Number.isNaN(limit) && limit >= 0) {
147
+ result.limit = limit;
148
+ }
149
+ }
150
+
151
+ const offsetStr = searchParams.get('offset');
152
+ if (offsetStr !== null) {
153
+ const offset = parseInt(offsetStr, 10);
154
+ if (!Number.isNaN(offset) && offset >= 0) {
155
+ result.offset = offset;
156
+ }
157
+ }
158
+
159
+ return result;
160
+ }