@teleporthq/teleport-plugin-next-data-source 0.43.68 → 0.43.70

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 (68) hide show
  1. package/__tests__/browser-row-policy.test.ts +21 -1
  2. package/__tests__/rest-list-edge-cases.test.ts +211 -0
  3. package/__tests__/shared-resource-prefetch.test.ts +111 -0
  4. package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
  5. package/dist/cjs/fetchers/rest-api.js +25 -1
  6. package/dist/cjs/fetchers/rest-api.js.map +1 -1
  7. package/dist/cjs/fetchers/utils/browser-row-policy.d.ts +5 -2
  8. package/dist/cjs/fetchers/utils/browser-row-policy.d.ts.map +1 -1
  9. package/dist/cjs/fetchers/utils/browser-row-policy.js +6 -3
  10. package/dist/cjs/fetchers/utils/browser-row-policy.js.map +1 -1
  11. package/dist/cjs/index.d.ts.map +1 -1
  12. package/dist/cjs/index.js +3 -2
  13. package/dist/cjs/index.js.map +1 -1
  14. package/dist/cjs/infinite-scroll.d.ts +7 -1
  15. package/dist/cjs/infinite-scroll.d.ts.map +1 -1
  16. package/dist/cjs/infinite-scroll.js +57 -8
  17. package/dist/cjs/infinite-scroll.js.map +1 -1
  18. package/dist/cjs/items-path.d.ts.map +1 -1
  19. package/dist/cjs/items-path.js +4 -3
  20. package/dist/cjs/items-path.js.map +1 -1
  21. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  22. package/dist/cjs/pagination-plugin.js +5 -2
  23. package/dist/cjs/pagination-plugin.js.map +1 -1
  24. package/dist/cjs/repeater-page-size.d.ts +16 -0
  25. package/dist/cjs/repeater-page-size.d.ts.map +1 -0
  26. package/dist/cjs/repeater-page-size.js +27 -0
  27. package/dist/cjs/repeater-page-size.js.map +1 -0
  28. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  29. package/dist/cjs/utils.d.ts.map +1 -1
  30. package/dist/cjs/utils.js +31 -4
  31. package/dist/cjs/utils.js.map +1 -1
  32. package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
  33. package/dist/esm/fetchers/rest-api.js +25 -1
  34. package/dist/esm/fetchers/rest-api.js.map +1 -1
  35. package/dist/esm/fetchers/utils/browser-row-policy.d.ts +5 -2
  36. package/dist/esm/fetchers/utils/browser-row-policy.d.ts.map +1 -1
  37. package/dist/esm/fetchers/utils/browser-row-policy.js +6 -3
  38. package/dist/esm/fetchers/utils/browser-row-policy.js.map +1 -1
  39. package/dist/esm/index.d.ts.map +1 -1
  40. package/dist/esm/index.js +3 -2
  41. package/dist/esm/index.js.map +1 -1
  42. package/dist/esm/infinite-scroll.d.ts +7 -1
  43. package/dist/esm/infinite-scroll.d.ts.map +1 -1
  44. package/dist/esm/infinite-scroll.js +57 -8
  45. package/dist/esm/infinite-scroll.js.map +1 -1
  46. package/dist/esm/items-path.d.ts.map +1 -1
  47. package/dist/esm/items-path.js +4 -3
  48. package/dist/esm/items-path.js.map +1 -1
  49. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  50. package/dist/esm/pagination-plugin.js +5 -2
  51. package/dist/esm/pagination-plugin.js.map +1 -1
  52. package/dist/esm/repeater-page-size.d.ts +16 -0
  53. package/dist/esm/repeater-page-size.d.ts.map +1 -0
  54. package/dist/esm/repeater-page-size.js +23 -0
  55. package/dist/esm/repeater-page-size.js.map +1 -0
  56. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  57. package/dist/esm/utils.d.ts.map +1 -1
  58. package/dist/esm/utils.js +31 -4
  59. package/dist/esm/utils.js.map +1 -1
  60. package/package.json +4 -4
  61. package/src/fetchers/rest-api.ts +27 -1
  62. package/src/fetchers/utils/browser-row-policy.ts +7 -3
  63. package/src/index.ts +3 -2
  64. package/src/infinite-scroll.ts +107 -43
  65. package/src/items-path.ts +3 -2
  66. package/src/pagination-plugin.ts +6 -2
  67. package/src/repeater-page-size.ts +24 -0
  68. package/src/utils.ts +54 -6
@@ -261,7 +261,6 @@ describe('blog posts: a visitor reads the published posts, never an author email
261
261
  { filters },
262
262
  { sorts: JSON.stringify([{ field: 'author_email', order: 'asc' }]) },
263
263
  { sortBy: 'author_email' },
264
- { query: 'ana', queryColumns: JSON.stringify(['author_email']) },
265
264
  ]) {
266
265
  const refused = await posts.run({ query })
267
266
  expect(refused.status).toBe(403)
@@ -273,6 +272,27 @@ describe('blog posts: a visitor reads the published posts, never an author email
273
272
  expect((await posts.run({ query: { filters }, session: { role: 'admin' } })).status).toBe(200)
274
273
  })
275
274
 
275
+ it('drops the hidden column from the search columns the blog list sends', async () => {
276
+ // The generated blog list names every text column of the table, the
277
+ // author's email among them, on every read — with or without a search term.
278
+ const queryColumns = JSON.stringify(['title', 'author_email'])
279
+ for (const query of [{ queryColumns }, { query: 'ana', queryColumns }]) {
280
+ const guest = await posts.run({ query })
281
+ expect(guest.status).toBe(200)
282
+ expect(mainQuery(guest)).not.toContain('"author_email"')
283
+ expect(JSON.stringify(guest.body.data)).not.toContain('ana@example.com')
284
+ expect((await posts.run({ handler: 'getCount', query })).status).toBe(200)
285
+ }
286
+ const searched = await posts.run({ query: { query: 'ana', queryColumns } })
287
+ expect(mainQuery(searched)).toContain('"title"::text ILIKE')
288
+
289
+ const admin = await posts.run({
290
+ query: { query: 'ana', queryColumns },
291
+ session: { role: 'admin' },
292
+ })
293
+ expect(mainQuery(admin)).toContain('"author_email"::text ILIKE')
294
+ })
295
+
276
296
  it('searches a visitor only through the columns it is served', async () => {
277
297
  const guest = await posts.run({ query: { query: 'ana' } })
278
298
  expect(guest.status).toBe(200)
@@ -0,0 +1,211 @@
1
+ import * as types from '@babel/types'
2
+ import generator from '@babel/generator'
3
+ import { ComponentStructure } from '@teleporthq/teleport-types'
4
+ import { createNextArrayMapperPaginationPlugin } from '../src/pagination-plugin'
5
+ import { extractItemsPath } from '../src/items-path'
6
+ import { generateRESTAPIFetcher } from '../src/fetchers/rest-api'
7
+ import { buildAccumulatingResponseHandler, getInfiniteScrollVars } from '../src/infinite-scroll'
8
+ import { DEFAULT_REPEATER_PER_PAGE, resolveRepeaterPerPage } from '../src/repeater-page-size'
9
+ import {
10
+ makeUidlNode,
11
+ makeWidgetComponentChunk,
12
+ type RepeaterOptions,
13
+ } from './_helpers/pagination-widget-fixture'
14
+
15
+ /**
16
+ * A list bound to a REST API payload, in the shapes the editor lets a builder
17
+ * bind: a list wrapped in an object, a list inside an item of a list, an
18
+ * appending list, a list whose page size was never set.
19
+ */
20
+
21
+ const runHandler = async (
22
+ code: string,
23
+ query: Record<string, unknown>,
24
+ body: unknown
25
+ ): Promise<{ data?: unknown; url?: string }> => {
26
+ let requestedURL: string | undefined
27
+ const fetchImpl = (url: string) => {
28
+ requestedURL = url
29
+ return Promise.resolve({
30
+ ok: true,
31
+ status: 200,
32
+ statusText: 'OK',
33
+ json: () => Promise.resolve(JSON.parse(JSON.stringify(body))),
34
+ })
35
+ }
36
+ const handler = new Function(
37
+ 'fetch',
38
+ `${code
39
+ .replace(/^import\s+.*?$/gm, '')
40
+ .replace('export default async function handler', 'async function handler')}
41
+ return handler`
42
+ )(fetchImpl)
43
+
44
+ let payload: { data?: unknown } = {}
45
+ const res = {
46
+ status: () => res,
47
+ json: (data: { data?: unknown }) => {
48
+ payload = data
49
+ return res
50
+ },
51
+ }
52
+ await handler({ query, body: undefined }, res)
53
+ return { data: payload.data, url: requestedURL }
54
+ }
55
+
56
+ const rows = Array.from({ length: 25 }, (_, index) => ({ id: index + 1 }))
57
+ const restFetcher = (config: Record<string, unknown> = {}) =>
58
+ generateRESTAPIFetcher({ url: 'https://api.test/items', method: 'GET', ...config })
59
+
60
+ describe('a list inside an item of a list (`source?.[0]?.items`)', () => {
61
+ it('reads the index as a path segment', () => {
62
+ expect(extractItemsPath('ds?.[0]?.items || []', 'ds', 'rest-api')).toEqual(['0', 'items'])
63
+ expect(extractItemsPath('ds?.data?.[2]?.["my list"]', 'ds', 'rest-api')).toEqual([
64
+ 'data',
65
+ '2',
66
+ 'my list',
67
+ ])
68
+ })
69
+
70
+ it('pages that inner list and keeps the list around it', async () => {
71
+ const { data } = await runHandler(
72
+ restFetcher(),
73
+ { page: '2', perPage: '10', itemsPath: JSON.stringify(['0', 'items']) },
74
+ [{ items: rows }, { items: [] }]
75
+ )
76
+
77
+ const payload = data as Array<{ items: Array<{ id: number }> }>
78
+ expect(payload).toHaveLength(2)
79
+ expect(payload[0].items.map((row) => row.id)).toEqual([11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
80
+ expect(payload[1].items).toEqual([])
81
+ })
82
+
83
+ it('leaves the payload alone when the index is past the end of the list', async () => {
84
+ const { data } = await runHandler(
85
+ restFetcher(),
86
+ { limit: '10', itemsPath: JSON.stringify(['3', 'items']) },
87
+ [{ items: rows }]
88
+ )
89
+
90
+ expect((data as Array<{ items: unknown[] }>)[0].items).toHaveLength(25)
91
+ })
92
+ })
93
+
94
+ describe('an appending (infinite scroll) list over a wrapped payload', () => {
95
+ const runAccumulator = (itemsPath: string[] | undefined) => {
96
+ const vars = getInfiniteScrollVars(0)
97
+ const source = generator(buildAccumulatingResponseHandler(vars, 2, itemsPath)).code
98
+ const accumRef = { current: { sig: '', pages: {} } }
99
+ const hasMore: boolean[] = []
100
+ return (params: Record<string, unknown>, data: unknown) =>
101
+ new Function(vars.accumRefVar, vars.setHasMoreFlagVar, 'params', `return (${source})`)(
102
+ accumRef,
103
+ (value: boolean) => hasMore.push(value),
104
+ params
105
+ )({ data }) as unknown
106
+ }
107
+
108
+ it('reads the rows at the path and puts every page back there', () => {
109
+ const accumulate = runAccumulator(['data', 'items'])
110
+
111
+ accumulate({ page: 1 }, { data: { items: [{ id: 1 }, { id: 2 }] }, total: 3 })
112
+ const second = accumulate({ page: 2 }, { data: { items: [{ id: 3 }] }, total: 3 }) as {
113
+ data: { items: Array<{ id: number }> }
114
+ total: number
115
+ }
116
+
117
+ expect(second.data.items.map((row) => row.id)).toEqual([1, 2, 3])
118
+ expect(second.total).toBe(3)
119
+ })
120
+
121
+ it('still accumulates a payload that IS the list', () => {
122
+ const accumulate = runAccumulator(undefined)
123
+
124
+ accumulate({ page: 1 }, [{ id: 1 }, { id: 2 }])
125
+ expect(accumulate({ page: 2 }, [{ id: 3 }])).toEqual([{ id: 1 }, { id: 2 }, { id: 3 }])
126
+ })
127
+
128
+ it('is wired for a list bound inside a REST payload', async () => {
129
+ const code = await runPaginationPlugin({ infiniteScroll: true }, 'items?.templates || []')
130
+
131
+ expect(code).toContain('const rows = response?.data?.templates || []')
132
+ expect(code).toContain('...response?.data,')
133
+ expect(code).toContain('templates: Object.keys(ds_0_accumRef.current.pages)')
134
+ })
135
+ })
136
+
137
+ describe('a paginated list with no page size', () => {
138
+ it('pages by the editor default instead of failing the project', async () => {
139
+ const code = await runPaginationPlugin({}, 'items?.templates || []', (node) => {
140
+ delete node.content.nodes.success.content.perPage
141
+ })
142
+
143
+ expect(code).toContain(`perPage: ${DEFAULT_REPEATER_PER_PAGE}`)
144
+ })
145
+
146
+ it.each([
147
+ [undefined, DEFAULT_REPEATER_PER_PAGE],
148
+ [null, DEFAULT_REPEATER_PER_PAGE],
149
+ ['', DEFAULT_REPEATER_PER_PAGE],
150
+ [0, DEFAULT_REPEATER_PER_PAGE],
151
+ [-5, DEFAULT_REPEATER_PER_PAGE],
152
+ [NaN, DEFAULT_REPEATER_PER_PAGE],
153
+ ['abc', DEFAULT_REPEATER_PER_PAGE],
154
+ [12, 12],
155
+ ['24', 24],
156
+ [7.9, 7],
157
+ ])('reads %p as %p', (perPage, expected) => {
158
+ expect(resolveRepeaterPerPage(perPage)).toBe(expected)
159
+ })
160
+ })
161
+
162
+ describe('the query params configured on a REST API data source', () => {
163
+ it('are sent with every request, as the editor sends them', async () => {
164
+ const { url } = await runHandler(
165
+ restFetcher({ queryParams: { per_page: '10', category: 'a b' } }),
166
+ {},
167
+ rows
168
+ )
169
+
170
+ expect(url).toBe('https://api.test/items?per_page=10&category=a+b')
171
+ })
172
+
173
+ it('join the params already in the URL', async () => {
174
+ const { url } = await runHandler(
175
+ generateRESTAPIFetcher({
176
+ url: 'https://api.test/items?sort=new',
177
+ method: 'GET',
178
+ queryParams: { page: '2' },
179
+ }),
180
+ {},
181
+ rows
182
+ )
183
+
184
+ expect(url).toBe('https://api.test/items?sort=new&page=2')
185
+ })
186
+
187
+ it('leave the URL exactly as configured when there are none', () => {
188
+ expect(restFetcher({ queryParams: {} })).toBe(restFetcher())
189
+ expect(restFetcher()).toContain('const url = "https://api.test/items"')
190
+ })
191
+ })
192
+
193
+ async function runPaginationPlugin(
194
+ repeater: RepeaterOptions,
195
+ source: string,
196
+ adjust: (node: ReturnType<typeof makeUidlNode>) => void = () => undefined
197
+ ): Promise<string> {
198
+ const node = makeUidlNode(repeater)
199
+ node.content.resourceDefinition.dataSourceType = 'rest-api'
200
+ node.content.nodes.success.content.source = source
201
+ adjust(node)
202
+ const chunk = makeWidgetComponentChunk({ controls: ['previous', 'next'] })
203
+ const structure: ComponentStructure = {
204
+ uidl: { name: 'TestComponent', node },
205
+ chunks: [chunk],
206
+ dependencies: {},
207
+ options: { dataSources: {}, extractedResources: {} },
208
+ } as never
209
+ await createNextArrayMapperPaginationPlugin()(structure)
210
+ return generator(chunk.content as types.Node).code
211
+ }
@@ -0,0 +1,111 @@
1
+ import * as types from '@babel/types'
2
+ import generator from '@babel/generator'
3
+ import { UIDLDataSourceItemNode } from '@teleporthq/teleport-types'
4
+ import { extractDataSourceIntoGetStaticProps } from '../src/utils'
5
+ import {
6
+ createComponentChunk,
7
+ createDataSourceNode,
8
+ createJavaScriptDataSource,
9
+ createMockJSXElementWithResourceDef,
10
+ } from './mocks'
11
+
12
+ /**
13
+ * Every provider bound to one table carries the SAME resource id
14
+ * (`TQ_<source><table>`) — the editor derives it from the source and the table
15
+ * only — and its own params. A list showing 10 rows and a text bound to the
16
+ * same source therefore asked for one prefetch, and the second provider
17
+ * rendered the first one's rows (`initialData` skips its own first fetch).
18
+ */
19
+
20
+ const DS_ID = 'ds-js'
21
+ const RESOURCE_ID = 'TQ_dsjsdata'
22
+
23
+ const nodeWithParams = (params: Record<string, unknown>): UIDLDataSourceItemNode => {
24
+ const node = createDataSourceNode(DS_ID, 'data', 'javascript')
25
+ ;(node.content as { resource: unknown }).resource = { id: RESOURCE_ID, params }
26
+ return node
27
+ }
28
+
29
+ const providerWithLimit = (limit?: number): types.JSXElement => {
30
+ const element = createMockJSXElementWithResourceDef(DS_ID, 'data', 'javascript')
31
+ if (limit !== undefined) {
32
+ element.openingElement.attributes.push(
33
+ types.jsxAttribute(
34
+ types.jsxIdentifier('params'),
35
+ types.jsxExpressionContainer(
36
+ types.objectExpression([
37
+ types.objectProperty(types.stringLiteral('limit'), types.numericLiteral(limit)),
38
+ ])
39
+ )
40
+ )
41
+ )
42
+ }
43
+ return element
44
+ }
45
+
46
+ const initialDataOf = (element: types.JSXElement): string => {
47
+ const attr = element.openingElement.attributes.find(
48
+ (attribute) => (attribute as types.JSXAttribute).name?.name === 'initialData'
49
+ ) as types.JSXAttribute | undefined
50
+ return attr ? generator(attr.value as types.Node).code : ''
51
+ }
52
+
53
+ const prefetch = (
54
+ providers: Array<{ node: UIDLDataSourceItemNode }>,
55
+ elements: types.JSXElement[]
56
+ ) => {
57
+ const componentChunk = createComponentChunk()
58
+ componentChunk.content = types.jsxFragment(
59
+ types.jsxOpeningFragment(),
60
+ types.jsxClosingFragment(),
61
+ elements
62
+ )
63
+ let getStaticPropsChunk = null
64
+ for (const { node } of providers) {
65
+ const result = extractDataSourceIntoGetStaticProps(
66
+ node,
67
+ { [DS_ID]: createJavaScriptDataSource(DS_ID) },
68
+ componentChunk,
69
+ getStaticPropsChunk,
70
+ [],
71
+ {},
72
+ {}
73
+ )
74
+ getStaticPropsChunk = result.chunk
75
+ }
76
+ return generator(getStaticPropsChunk.content as types.Node).code.replace(/\s+/g, ' ')
77
+ }
78
+
79
+ describe('getStaticProps prefetch of providers sharing one resource', () => {
80
+ it('gives providers with different params their own prefetch', () => {
81
+ const limitedList = providerWithLimit(10)
82
+ const text = providerWithLimit()
83
+
84
+ const code = prefetch(
85
+ [
86
+ { node: nodeWithParams({ limit: { type: 'static', content: 10 } }) },
87
+ { node: nodeWithParams({}) },
88
+ ],
89
+ [limitedList, text]
90
+ )
91
+
92
+ expect(initialDataOf(limitedList)).toBe('{props.data_dsjsdata}')
93
+ expect(initialDataOf(text)).toBe('{props.data_dsjsdata_2}')
94
+ expect(code).toContain('fetchData({ "limit": 10 })')
95
+ expect(code).toContain('fetchData({})')
96
+ })
97
+
98
+ it('keeps ONE prefetch for providers with the same params', () => {
99
+ const first = providerWithLimit()
100
+ const second = providerWithLimit()
101
+
102
+ const code = prefetch(
103
+ [{ node: nodeWithParams({}) }, { node: nodeWithParams({}) }],
104
+ [first, second]
105
+ )
106
+
107
+ expect(initialDataOf(first)).toBe('{props.data_dsjsdata}')
108
+ expect(initialDataOf(second)).toBe('{props.data_dsjsdata}')
109
+ expect(code.match(/fetchData\(/g)).toHaveLength(1)
110
+ })
111
+ })
@@ -1 +1 @@
1
- {"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,qBAAqB,WACxB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CA0BpC,CAAA;AA6CD,eAAO,MAAM,sBAAsB,WAAY,OAAO,MAAM,EAAE,OAAO,CAAC,KAAG,MAyOxE,CAAA"}
1
+ {"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,qBAAqB,WACxB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CA0BpC,CAAA;AAuED,eAAO,MAAM,sBAAsB,WAAY,OAAO,MAAM,EAAE,OAAO,CAAC,KAAG,MAyOxE,CAAA"}
@@ -47,6 +47,30 @@ var generateAuthCode = function (authorization) {
47
47
  return '';
48
48
  }
49
49
  };
50
+ /**
51
+ * The URL with the data source's query params appended, built the way the
52
+ * editor's own fetch builds it (`RestApiService.constructUrl` in the
53
+ * data-fetcher worker: `searchParams.append` per param).
54
+ *
55
+ * The params used to be dropped here, so the published site asked the API a
56
+ * different question than the editor did — `?per_page=10` or `?category=x`
57
+ * configured on the source, and every row of the unfiltered response came back.
58
+ */
59
+ var buildRequestURL = function (url, queryParams) {
60
+ var params = Object.entries(queryParams || {}).filter(function (_a) {
61
+ var key = _a[0], value = _a[1];
62
+ return key.trim() !== '' && typeof value === 'string';
63
+ });
64
+ if (!url || params.length === 0) {
65
+ return url;
66
+ }
67
+ var requestURL = new URL(url);
68
+ params.forEach(function (_a) {
69
+ var key = _a[0], value = _a[1];
70
+ return requestURL.searchParams.append(key, value);
71
+ });
72
+ return requestURL.toString();
73
+ };
50
74
  var generateRESTAPIFetcher = function (config) {
51
75
  var restConfig = config;
52
76
  var authCode = generateAuthCode(restConfig.authorization || {});
@@ -54,7 +78,7 @@ var generateRESTAPIFetcher = function (config) {
54
78
  // uncached data source keeps generating byte-identical output.
55
79
  var cacheTTLSeconds = (0, rest_api_response_cache_1.resolveRESTAPICacheTTLSeconds)(restConfig.cache);
56
80
  var cached = cacheTTLSeconds !== undefined;
57
- return "import fetch from 'node-fetch'\n\n".concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateDateFormatterCode)(), "\n\n").concat((0, utils_1.generateSortFilterHelperCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, utils_1.generateCollectionPathHelperCode)()).concat(cached ? "\n\n".concat((0, rest_api_response_cache_1.generateRESTAPIResponseCacheCode)(cacheTTLSeconds)) : '', "\n\nexport default async function handler(req, res) {\n try {\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset, collectionPath, itemsPath } = req.query\n \n const url = ").concat(JSON.stringify(restConfig.url), "\n const method = ").concat(JSON.stringify(restConfig.method || 'GET'), "\n \n const headers = ").concat(JSON.stringify(restConfig.headers || {}), "\n ").concat(authCode, "\n \n const options = {\n method,\n headers\n }\n \n ").concat(restConfig.method === 'POST' || restConfig.method === 'PUT' || restConfig.method === 'PATCH'
81
+ return "import fetch from 'node-fetch'\n\n".concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateDateFormatterCode)(), "\n\n").concat((0, utils_1.generateSortFilterHelperCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, utils_1.generateCollectionPathHelperCode)()).concat(cached ? "\n\n".concat((0, rest_api_response_cache_1.generateRESTAPIResponseCacheCode)(cacheTTLSeconds)) : '', "\n\nexport default async function handler(req, res) {\n try {\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset, collectionPath, itemsPath } = req.query\n \n const url = ").concat(JSON.stringify(buildRequestURL(restConfig.url, restConfig.queryParams)), "\n const method = ").concat(JSON.stringify(restConfig.method || 'GET'), "\n \n const headers = ").concat(JSON.stringify(restConfig.headers || {}), "\n ").concat(authCode, "\n \n const options = {\n method,\n headers\n }\n \n ").concat(restConfig.method === 'POST' || restConfig.method === 'PUT' || restConfig.method === 'PATCH'
58
82
  ? "\n if (req.body) {\n options.body = ".concat(restConfig.bodyType === 'json' || !restConfig.bodyType
59
83
  ? 'JSON.stringify(req.body)'
60
84
  : 'req.body', "\n }").concat(
@@ -1 +1 @@
1
- {"version":3,"file":"rest-api.js","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rest-api.js","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"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"}
@@ -11,8 +11,11 @@
11
11
  * without them. So a caller that is not the store itself (its server code, or a
12
12
  * signed-in administrator — the generated admin edits drafts through these
13
13
  * routes) is served only the rows the storefront publishes, never a hidden
14
- * column, and may neither filter, sort nor search by a hidden column: a filter
15
- * is an oracle for a column it never returns.
14
+ * column, and may neither filter nor sort by a hidden column: a filter is an
15
+ * oracle for a column it never returns. A hidden SEARCH column is dropped from
16
+ * the search instead (`__brpVisibleColumns`), because the storefront's own list
17
+ * bindings name every text column of the table — the blog list asks to search
18
+ * `author_email` — and refusing them emptied the blog for every visitor.
16
19
  */
17
20
  export interface BrowserRowPolicy {
18
21
  /** SQL every browser read of the table is narrowed with. */
@@ -1 +1 @@
1
- {"version":3,"file":"browser-row-policy.d.ts","sourceRoot":"","sources":["../../../../src/fetchers/utils/browser-row-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAA;IACjB,8FAA8F;IAC9F,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACrC;AAED,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAa3E,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,QACnC,MA8HL,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,cACpB,MAAM,mBACA,cAAc,MAAM,CAAC,KACrC,OAUF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,cAC5B,MAAM,gBACH,MAAM,GAAG,IAAI,KAC1B,MASF,CAAA"}
1
+ {"version":3,"file":"browser-row-policy.d.ts","sourceRoot":"","sources":["../../../../src/fetchers/utils/browser-row-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,SAAS,EAAE,MAAM,CAAA;IACjB,8FAA8F;IAC9F,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CACrC;AAED,eAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAa3E,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,4BAA4B,QACnC,MA+HL,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,oBAAoB,cACpB,MAAM,mBACA,cAAc,MAAM,CAAC,KACrC,OAUF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,cAC5B,MAAM,gBACH,MAAM,GAAG,IAAI,KAC1B,MASF,CAAA"}
@@ -12,8 +12,11 @@
12
12
  * without them. So a caller that is not the store itself (its server code, or a
13
13
  * signed-in administrator — the generated admin edits drafts through these
14
14
  * routes) is served only the rows the storefront publishes, never a hidden
15
- * column, and may neither filter, sort nor search by a hidden column: a filter
16
- * is an oracle for a column it never returns.
15
+ * column, and may neither filter nor sort by a hidden column: a filter is an
16
+ * oracle for a column it never returns. A hidden SEARCH column is dropped from
17
+ * the search instead (`__brpVisibleColumns`), because the storefront's own list
18
+ * bindings name every text column of the table — the blog list asks to search
19
+ * `author_email` — and refusing them emptied the blog for every visitor.
17
20
  */
18
21
  Object.defineProperty(exports, "__esModule", { value: true });
19
22
  exports.generateBrowserRowAccessCall = exports.isViewDependentTable = exports.generateBrowserRowPolicyCode = exports.BROWSER_ROW_POLICIES = void 0;
@@ -39,7 +42,7 @@ exports.BROWSER_ROW_POLICIES = {
39
42
  * the table whole). Plus the helpers that apply a policy to a request and to
40
43
  * its rows.
41
44
  */
42
- var generateBrowserRowPolicyCode = function () { return "// GENERATED \u2014 see browser-row-policy.ts in teleport-plugin-next-data-source.\nvar __BRP_POLICIES = ".concat(JSON.stringify(exports.BROWSER_ROW_POLICIES), ";\n\n// Who is asking: the store's own server code and its administrators read every\n// row; anyone else is a visitor.\nasync function __brpReader(req) {\n if (__taIsInternalRequest(req)) return { trusted: true };\n var token = null;\n try {\n token = await __tqSessionToken(req);\n } catch (e) {\n token = null;\n }\n var role = token ? __taRoleOf(token) : null;\n return { trusted: !!role && __TA_TRUSTED_READER_ROLES.indexOf(role) !== -1 };\n}\n\nfunction __brpMentionsAny(rawQuery, tables) {\n for (var i = 0; i < tables.length; i++) {\n if (__taSqlMentionsTable(rawQuery, tables[i])) return true;\n }\n return false;\n}\n\n// A raw statement cannot be narrowed, so a visitor's statement that names a\n// narrowed table is refused whole. The session is only decoded when the read\n// touches one of these tables.\nasync function __brpAccess(req, tableName, rawQuery) {\n var raw = typeof rawQuery === 'string' && rawQuery.length > 0 ? rawQuery : null;\n var bare = __taNormalizeTable(tableName);\n var rawNarrowed = !!raw && __brpMentionsAny(raw, Object.keys(__BRP_POLICIES));\n var policy = raw ? null : (Object.prototype.hasOwnProperty.call(__BRP_POLICIES, bare) ? __BRP_POLICIES[bare] : null);\n if (!rawNarrowed && !policy) return { denied: null, policy: null };\n var reader = await __brpReader(req);\n if (reader.trusted) return { denied: null, policy: null };\n if (rawNarrowed) {\n return { denied: { status: 403, message: 'Forbidden: raw queries over this table are only available to server-side calls' }, policy: null };\n }\n return { denied: null, policy: policy };\n}\n\nfunction __brpColumnName(field) {\n var parts = String(field == null ? '' : field).replace(/\"/g, '').trim().split('.');\n return parts[parts.length - 1];\n}\n\nfunction __brpIsHidden(policy, field) {\n var name = __brpColumnName(field).toLowerCase();\n for (var i = 0; i < policy.hiddenColumns.length; i++) {\n if (policy.hiddenColumns[i].toLowerCase() === name) return true;\n }\n return false;\n}\n\n// Every field a request filters, sorts or searches by, however deep a filter\n// group nests it. A condition's value is data, not a field.\nfunction __brpRequestFields(value, out) {\n if (Array.isArray(value)) {\n for (var i = 0; i < value.length; i++) __brpRequestFields(value[i], out);\n } else if (value && typeof value === 'object') {\n if (typeof value.source === 'string') out.push(value.source);\n if (typeof value.field === 'string') out.push(value.field);\n var keys = Object.keys(value);\n for (var k = 0; k < keys.length; k++) {\n if (keys[k] === 'destination' || keys[k] === 'value') continue;\n if (value[keys[k]] && typeof value[keys[k]] === 'object') __brpRequestFields(value[keys[k]], out);\n }\n } else if (typeof value === 'string' && value) {\n out.push(value);\n }\n return out;\n}\n\nfunction __brpParse(value) {\n if (typeof value !== 'string') return value;\n try {\n return JSON.parse(value);\n } catch (e) {\n return value;\n }\n}\n\nfunction __brpAssertVisibleFields(policy, query) {\n var q = query || {};\n var fields = [];\n __brpRequestFields(__brpParse(q.filters), fields);\n __brpRequestFields(__brpParse(q.sorts), fields);\n __brpRequestFields(__brpParse(q.queryColumns), fields);\n if (typeof q.sortBy === 'string') fields.push(q.sortBy);\n for (var i = 0; i < fields.length; i++) {\n if (__brpIsHidden(policy, fields[i])) {\n var err = new Error('Forbidden: ' + __brpColumnName(fields[i]) + ' is not readable');\n err.status = 403;\n throw err;\n }\n }\n}\n\nfunction __brpVisibleColumns(policy, columns) {\n return columns.filter(function(column) { return !__brpIsHidden(policy, column); });\n}\n\n// The rows without a hidden key, at any depth: a transformed row nests related\n// rows (a post's related and adjacent posts) built the same way.\nfunction __brpStripHidden(policy, value) {\n if (Array.isArray(value)) {\n return value.map(function(entry) { return __brpStripHidden(policy, entry); });\n }\n if (!value || typeof value !== 'object') return value;\n var copy = {};\n Object.keys(value).forEach(function(key) {\n if (!__brpIsHidden(policy, key)) copy[key] = __brpStripHidden(policy, value[key]);\n });\n return copy;\n}\n\n// Whether this request is answered exactly as an anonymous visitor's would be,\n// so a response cached for one may serve the other. A read whose answer depends\n// on who asks (`viewDependent`: a narrowed, protected or admin-only table) or\n// that runs a raw statement differs for the store's own server code and its\n// administrators, and must never share a cache entry with a visitor.\nasync function __brpSharesPublicView(req, viewDependent) {\n var raw = !!(req && req.query && typeof req.query.rawQuery === 'string' && req.query.rawQuery.length > 0);\n if (!viewDependent && !raw) return true;\n return !(await __brpReader(req)).trusted;\n}\n"); };
45
+ var generateBrowserRowPolicyCode = function () { return "// GENERATED \u2014 see browser-row-policy.ts in teleport-plugin-next-data-source.\nvar __BRP_POLICIES = ".concat(JSON.stringify(exports.BROWSER_ROW_POLICIES), ";\n\n// Who is asking: the store's own server code and its administrators read every\n// row; anyone else is a visitor.\nasync function __brpReader(req) {\n if (__taIsInternalRequest(req)) return { trusted: true };\n var token = null;\n try {\n token = await __tqSessionToken(req);\n } catch (e) {\n token = null;\n }\n var role = token ? __taRoleOf(token) : null;\n return { trusted: !!role && __TA_TRUSTED_READER_ROLES.indexOf(role) !== -1 };\n}\n\nfunction __brpMentionsAny(rawQuery, tables) {\n for (var i = 0; i < tables.length; i++) {\n if (__taSqlMentionsTable(rawQuery, tables[i])) return true;\n }\n return false;\n}\n\n// A raw statement cannot be narrowed, so a visitor's statement that names a\n// narrowed table is refused whole. The session is only decoded when the read\n// touches one of these tables.\nasync function __brpAccess(req, tableName, rawQuery) {\n var raw = typeof rawQuery === 'string' && rawQuery.length > 0 ? rawQuery : null;\n var bare = __taNormalizeTable(tableName);\n var rawNarrowed = !!raw && __brpMentionsAny(raw, Object.keys(__BRP_POLICIES));\n var policy = raw ? null : (Object.prototype.hasOwnProperty.call(__BRP_POLICIES, bare) ? __BRP_POLICIES[bare] : null);\n if (!rawNarrowed && !policy) return { denied: null, policy: null };\n var reader = await __brpReader(req);\n if (reader.trusted) return { denied: null, policy: null };\n if (rawNarrowed) {\n return { denied: { status: 403, message: 'Forbidden: raw queries over this table are only available to server-side calls' }, policy: null };\n }\n return { denied: null, policy: policy };\n}\n\nfunction __brpColumnName(field) {\n var parts = String(field == null ? '' : field).replace(/\"/g, '').trim().split('.');\n return parts[parts.length - 1];\n}\n\nfunction __brpIsHidden(policy, field) {\n var name = __brpColumnName(field).toLowerCase();\n for (var i = 0; i < policy.hiddenColumns.length; i++) {\n if (policy.hiddenColumns[i].toLowerCase() === name) return true;\n }\n return false;\n}\n\n// Every field a request filters, sorts or searches by, however deep a filter\n// group nests it. A condition's value is data, not a field.\nfunction __brpRequestFields(value, out) {\n if (Array.isArray(value)) {\n for (var i = 0; i < value.length; i++) __brpRequestFields(value[i], out);\n } else if (value && typeof value === 'object') {\n if (typeof value.source === 'string') out.push(value.source);\n if (typeof value.field === 'string') out.push(value.field);\n var keys = Object.keys(value);\n for (var k = 0; k < keys.length; k++) {\n if (keys[k] === 'destination' || keys[k] === 'value') continue;\n if (value[keys[k]] && typeof value[keys[k]] === 'object') __brpRequestFields(value[keys[k]], out);\n }\n } else if (typeof value === 'string' && value) {\n out.push(value);\n }\n return out;\n}\n\nfunction __brpParse(value) {\n if (typeof value !== 'string') return value;\n try {\n return JSON.parse(value);\n } catch (e) {\n return value;\n }\n}\n\n// Search columns are not checked here: the read drops the hidden ones from the\n// search (`__brpVisibleColumns`), and the storefront's own list bindings name them.\nfunction __brpAssertVisibleFields(policy, query) {\n var q = query || {};\n var fields = [];\n __brpRequestFields(__brpParse(q.filters), fields);\n __brpRequestFields(__brpParse(q.sorts), fields);\n if (typeof q.sortBy === 'string') fields.push(q.sortBy);\n for (var i = 0; i < fields.length; i++) {\n if (__brpIsHidden(policy, fields[i])) {\n var err = new Error('Forbidden: ' + __brpColumnName(fields[i]) + ' is not readable');\n err.status = 403;\n throw err;\n }\n }\n}\n\nfunction __brpVisibleColumns(policy, columns) {\n return columns.filter(function(column) { return !__brpIsHidden(policy, column); });\n}\n\n// The rows without a hidden key, at any depth: a transformed row nests related\n// rows (a post's related and adjacent posts) built the same way.\nfunction __brpStripHidden(policy, value) {\n if (Array.isArray(value)) {\n return value.map(function(entry) { return __brpStripHidden(policy, entry); });\n }\n if (!value || typeof value !== 'object') return value;\n var copy = {};\n Object.keys(value).forEach(function(key) {\n if (!__brpIsHidden(policy, key)) copy[key] = __brpStripHidden(policy, value[key]);\n });\n return copy;\n}\n\n// Whether this request is answered exactly as an anonymous visitor's would be,\n// so a response cached for one may serve the other. A read whose answer depends\n// on who asks (`viewDependent`: a narrowed, protected or admin-only table) or\n// that runs a raw statement differs for the store's own server code and its\n// administrators, and must never share a cache entry with a visitor.\nasync function __brpSharesPublicView(req, viewDependent) {\n var raw = !!(req && req.query && typeof req.query.rawQuery === 'string' && req.query.rawQuery.length > 0);\n if (!viewDependent && !raw) return true;\n return !(await __brpReader(req)).trusted;\n}\n"); };
43
46
  exports.generateBrowserRowPolicyCode = generateBrowserRowPolicyCode;
44
47
  /**
45
48
  * Whether a per-table read route's answer depends on who asks — the rows it
@@ -1 +1 @@
1
- {"version":3,"file":"browser-row-policy.js","sourceRoot":"","sources":["../../../../src/fetchers/utils/browser-row-policy.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AASU,QAAA,oBAAoB,GAA+C;IAC9E,kEAAkE;IAClE,wEAAwE;IACxE,mBAAmB,EAAE;QACnB,SAAS,EAAE,sBAAsB;QACjC,aAAa,EAAE,CAAC,cAAc,EAAE,aAAa,CAAC;KAC/C;IACD,yEAAyE;IACzE,+DAA+D;IAC/D,iBAAiB,EAAE;QACjB,SAAS,EAAE,gCAAgC;QAC3C,aAAa,EAAE,EAAE;KAClB;CACF,CAAA;AAED;;;;;;;GAOG;AACI,IAAM,4BAA4B,GACvC,cAAc,OAAA,mHACO,IAAI,CAAC,SAAS,CAAC,4BAAoB,CAAC,y1JA6H1D,EA9He,CA8Hf,CAAA;AA/HY,QAAA,4BAA4B,gCA+HxC;AAED;;;GAGG;AACI,IAAM,oBAAoB,GAAG,UAClC,SAAiB,EACjB,eAAsC;IAEtC,IAAM,KAAK,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;SAClC,IAAI,EAAE;SACN,WAAW,EAAE;SACb,KAAK,CAAC,GAAG,CAAC,CAAA;IACb,IAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACtD,OAAO,CACL,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,4BAAoB,EAAE,IAAI,CAAC;QAChE,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CACrC,CAAA;AACH,CAAC,CAAA;AAbY,QAAA,oBAAoB,wBAahC;AAED;;;GAGG;AACI,IAAM,4BAA4B,GAAG,UAC1C,SAAiB,EACjB,YAA2B;IAE3B,OAAO,uDAAgD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,eAC9E,YAAY,IAAI,MAAM,yNAMzB,CAAA;AACD,CAAC,CAAA;AAZY,QAAA,4BAA4B,gCAYxC"}
1
+ {"version":3,"file":"browser-row-policy.js","sourceRoot":"","sources":["../../../../src/fetchers/utils/browser-row-policy.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;GAkBG;;;AASU,QAAA,oBAAoB,GAA+C;IAC9E,kEAAkE;IAClE,wEAAwE;IACxE,mBAAmB,EAAE;QACnB,SAAS,EAAE,sBAAsB;QACjC,aAAa,EAAE,CAAC,cAAc,EAAE,aAAa,CAAC;KAC/C;IACD,yEAAyE;IACzE,+DAA+D;IAC/D,iBAAiB,EAAE;QACjB,SAAS,EAAE,gCAAgC;QAC3C,aAAa,EAAE,EAAE;KAClB;CACF,CAAA;AAED;;;;;;;GAOG;AACI,IAAM,4BAA4B,GACvC,cAAc,OAAA,mHACO,IAAI,CAAC,SAAS,CAAC,4BAAoB,CAAC,q8JA8H1D,EA/He,CA+Hf,CAAA;AAhIY,QAAA,4BAA4B,gCAgIxC;AAED;;;GAGG;AACI,IAAM,oBAAoB,GAAG,UAClC,SAAiB,EACjB,eAAsC;IAEtC,IAAM,KAAK,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;SAClC,IAAI,EAAE;SACN,WAAW,EAAE;SACb,KAAK,CAAC,GAAG,CAAC,CAAA;IACb,IAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IACtD,OAAO,CACL,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,4BAAoB,EAAE,IAAI,CAAC;QAChE,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CACrC,CAAA;AACH,CAAC,CAAA;AAbY,QAAA,oBAAoB,wBAahC;AAED;;;GAGG;AACI,IAAM,4BAA4B,GAAG,UAC1C,SAAiB,EACjB,YAA2B;IAE3B,OAAO,uDAAgD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,eAC9E,YAAY,IAAI,MAAM,yNAMzB,CAAA;AACD,CAAC,CAAA;AAZY,QAAA,4BAA4B,gCAYxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EAMvB,MAAM,4BAA4B,CAAA;AAmdnC,eAAO,MAAM,+BAA+B,EAAE,sBAAsB,CAAC,EAAE,CAyftE,CAAA;AAiOD,eAAO,MAAM,mCAAmC,EAAE,sBAAsB,CAAC,EAAE,CA0P1E,CAAA;AAED,cAAc,wBAAwB,CAAA;AACtC,cAAc,SAAS,CAAA;AACvB,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAChC,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AAIvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAA;AAChE,YAAY,EAAE,gCAAgC,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAGjG,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AACvF,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EAMvB,MAAM,4BAA4B,CAAA;AAodnC,eAAO,MAAM,+BAA+B,EAAE,sBAAsB,CAAC,EAAE,CAyftE,CAAA;AAiOD,eAAO,MAAM,mCAAmC,EAAE,sBAAsB,CAAC,EAAE,CA0P1E,CAAA;AAED,cAAc,wBAAwB,CAAA;AACtC,cAAc,SAAS,CAAA;AACvB,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAChC,cAAc,sBAAsB,CAAA;AACpC,cAAc,yBAAyB,CAAA;AAIvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAA;AAChE,YAAY,EAAE,gCAAgC,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAGjG,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAA;AACvF,YAAY,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA"}
package/dist/cjs/index.js CHANGED
@@ -67,6 +67,7 @@ var teleport_types_1 = require("@teleporthq/teleport-types");
67
67
  var teleport_shared_1 = require("@teleporthq/teleport-shared");
68
68
  var utils_1 = require("./utils");
69
69
  var pagination_plugin_1 = require("./pagination-plugin");
70
+ var repeater_page_size_1 = require("./repeater-page-size");
70
71
  var transformations_1 = require("./transformations");
71
72
  var isr_1 = require("./isr");
72
73
  var request_locale_1 = require("./request-locale");
@@ -289,8 +290,8 @@ function extractPaginationConfigEarly(uidlNode, resources) {
289
290
  var renderProp = (_t = node.content) === null || _t === void 0 ? void 0 : _t.renderPropIdentifier;
290
291
  var searchEnabled = (_u = node.content) === null || _u === void 0 ? void 0 : _u.searchEnabled;
291
292
  var searchDebounce = (_v = node.content) === null || _v === void 0 ? void 0 : _v.searchDebounce;
292
- if (paginated && perPage && renderProp) {
293
- perPageMap.set(renderProp, perPage);
293
+ if (paginated && renderProp) {
294
+ perPageMap.set(renderProp, (0, repeater_page_size_1.resolveRepeaterPerPage)(perPage));
294
295
  }
295
296
  if (searchEnabled && renderProp) {
296
297
  searchConfigMap.set(renderProp, {