@teleporthq/teleport-plugin-next-data-source 0.43.75 → 0.44.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.
Files changed (199) hide show
  1. package/__tests__/_helpers/first-page-runtime.ts +184 -0
  2. package/__tests__/_helpers/pagination-widget-fixture.ts +154 -5
  3. package/__tests__/booking-item-transform.test.ts +120 -0
  4. package/__tests__/browser-row-policy.test.ts +210 -4
  5. package/__tests__/data-source-request-locale.test.ts +4 -3
  6. package/__tests__/fetchers.test.ts +7 -3
  7. package/__tests__/fixed-list-sort.test.ts +1 -1
  8. package/__tests__/infinite-scroll.test.ts +363 -9
  9. package/__tests__/list-sort-order.test.ts +61 -0
  10. package/__tests__/null-filter-where.test.ts +132 -0
  11. package/__tests__/page-data-visitor-read.test.ts +196 -0
  12. package/__tests__/pg-date-parser.test.ts +73 -0
  13. package/__tests__/plain-list-sort.test.ts +2 -2
  14. package/__tests__/plain-list-starting-sort.test.ts +323 -0
  15. package/__tests__/product-price-sort.ts +11 -6
  16. package/__tests__/range-control.test.ts +159 -0
  17. package/__tests__/refetch-loading-state.test.ts +158 -2
  18. package/__tests__/search-input-marker.test.ts +86 -0
  19. package/__tests__/search-url-sync.test.ts +34 -8
  20. package/__tests__/starting-sort-first-page.test.ts +285 -0
  21. package/__tests__/table-read-route-protected-tables.test.ts +33 -3
  22. package/dist/cjs/cache/ast.d.ts +2 -0
  23. package/dist/cjs/cache/ast.d.ts.map +1 -1
  24. package/dist/cjs/cache/ast.js +5 -2
  25. package/dist/cjs/cache/ast.js.map +1 -1
  26. package/dist/cjs/count-effect.d.ts +7 -1
  27. package/dist/cjs/count-effect.d.ts.map +1 -1
  28. package/dist/cjs/count-effect.js +15 -5
  29. package/dist/cjs/count-effect.js.map +1 -1
  30. package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
  31. package/dist/cjs/data-source-fetchers.js +10 -2
  32. package/dist/cjs/data-source-fetchers.js.map +1 -1
  33. package/dist/cjs/fetchers/pg-client-import.d.ts +12 -0
  34. package/dist/cjs/fetchers/pg-client-import.d.ts.map +1 -0
  35. package/dist/cjs/fetchers/pg-client-import.js +15 -0
  36. package/dist/cjs/fetchers/pg-client-import.js.map +1 -0
  37. package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
  38. package/dist/cjs/fetchers/postgresql.js +3 -1
  39. package/dist/cjs/fetchers/postgresql.js.map +1 -1
  40. package/dist/cjs/fetchers/raw-query.d.ts.map +1 -1
  41. package/dist/cjs/fetchers/raw-query.js +2 -1
  42. package/dist/cjs/fetchers/raw-query.js.map +1 -1
  43. package/dist/cjs/fetchers/teleport.d.ts.map +1 -1
  44. package/dist/cjs/fetchers/teleport.js +4 -2
  45. package/dist/cjs/fetchers/teleport.js.map +1 -1
  46. package/dist/cjs/fetchers/utils/browser-row-policy.d.ts.map +1 -1
  47. package/dist/cjs/fetchers/utils/browser-row-policy.js +5 -1
  48. package/dist/cjs/fetchers/utils/browser-row-policy.js.map +1 -1
  49. package/dist/cjs/index.d.ts.map +1 -1
  50. package/dist/cjs/index.js +14 -2
  51. package/dist/cjs/index.js.map +1 -1
  52. package/dist/cjs/infinite-scroll.d.ts +89 -4
  53. package/dist/cjs/infinite-scroll.d.ts.map +1 -1
  54. package/dist/cjs/infinite-scroll.js +243 -33
  55. package/dist/cjs/infinite-scroll.js.map +1 -1
  56. package/dist/cjs/list-sort-order.d.ts +14 -0
  57. package/dist/cjs/list-sort-order.d.ts.map +1 -0
  58. package/dist/cjs/list-sort-order.js +36 -0
  59. package/dist/cjs/list-sort-order.js.map +1 -0
  60. package/dist/cjs/loading-state.d.ts +23 -2
  61. package/dist/cjs/loading-state.d.ts.map +1 -1
  62. package/dist/cjs/loading-state.js +50 -15
  63. package/dist/cjs/loading-state.js.map +1 -1
  64. package/dist/cjs/pagination-controls.d.ts +22 -3
  65. package/dist/cjs/pagination-controls.d.ts.map +1 -1
  66. package/dist/cjs/pagination-controls.js +29 -3
  67. package/dist/cjs/pagination-controls.js.map +1 -1
  68. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  69. package/dist/cjs/pagination-plugin.js +336 -164
  70. package/dist/cjs/pagination-plugin.js.map +1 -1
  71. package/dist/cjs/range-control.d.ts +45 -0
  72. package/dist/cjs/range-control.d.ts.map +1 -0
  73. package/dist/cjs/range-control.js +165 -0
  74. package/dist/cjs/range-control.js.map +1 -0
  75. package/dist/cjs/row-order.d.ts +3 -2
  76. package/dist/cjs/row-order.d.ts.map +1 -1
  77. package/dist/cjs/row-order.js +5 -4
  78. package/dist/cjs/row-order.js.map +1 -1
  79. package/dist/cjs/search-input.d.ts +42 -0
  80. package/dist/cjs/search-input.d.ts.map +1 -0
  81. package/dist/cjs/search-input.js +158 -0
  82. package/dist/cjs/search-input.js.map +1 -0
  83. package/dist/cjs/sort-utils.d.ts +53 -1
  84. package/dist/cjs/sort-utils.d.ts.map +1 -1
  85. package/dist/cjs/sort-utils.js +105 -13
  86. package/dist/cjs/sort-utils.js.map +1 -1
  87. package/dist/cjs/transformations/booking-item.d.ts +24 -0
  88. package/dist/cjs/transformations/booking-item.d.ts.map +1 -0
  89. package/dist/cjs/transformations/booking-item.js +27 -0
  90. package/dist/cjs/transformations/booking-item.js.map +1 -0
  91. package/dist/cjs/transformations/index.d.ts +4 -2
  92. package/dist/cjs/transformations/index.d.ts.map +1 -1
  93. package/dist/cjs/transformations/index.js +14 -5
  94. package/dist/cjs/transformations/index.js.map +1 -1
  95. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  96. package/dist/cjs/utils.d.ts +3 -2
  97. package/dist/cjs/utils.d.ts.map +1 -1
  98. package/dist/cjs/utils.js +48 -18
  99. package/dist/cjs/utils.js.map +1 -1
  100. package/dist/esm/cache/ast.d.ts +2 -0
  101. package/dist/esm/cache/ast.d.ts.map +1 -1
  102. package/dist/esm/cache/ast.js +3 -1
  103. package/dist/esm/cache/ast.js.map +1 -1
  104. package/dist/esm/count-effect.d.ts +7 -1
  105. package/dist/esm/count-effect.d.ts.map +1 -1
  106. package/dist/esm/count-effect.js +15 -5
  107. package/dist/esm/count-effect.js.map +1 -1
  108. package/dist/esm/data-source-fetchers.d.ts.map +1 -1
  109. package/dist/esm/data-source-fetchers.js +10 -2
  110. package/dist/esm/data-source-fetchers.js.map +1 -1
  111. package/dist/esm/fetchers/pg-client-import.d.ts +12 -0
  112. package/dist/esm/fetchers/pg-client-import.d.ts.map +1 -0
  113. package/dist/esm/fetchers/pg-client-import.js +12 -0
  114. package/dist/esm/fetchers/pg-client-import.js.map +1 -0
  115. package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
  116. package/dist/esm/fetchers/postgresql.js +3 -1
  117. package/dist/esm/fetchers/postgresql.js.map +1 -1
  118. package/dist/esm/fetchers/raw-query.d.ts.map +1 -1
  119. package/dist/esm/fetchers/raw-query.js +2 -1
  120. package/dist/esm/fetchers/raw-query.js.map +1 -1
  121. package/dist/esm/fetchers/teleport.d.ts.map +1 -1
  122. package/dist/esm/fetchers/teleport.js +4 -2
  123. package/dist/esm/fetchers/teleport.js.map +1 -1
  124. package/dist/esm/fetchers/utils/browser-row-policy.d.ts.map +1 -1
  125. package/dist/esm/fetchers/utils/browser-row-policy.js +6 -2
  126. package/dist/esm/fetchers/utils/browser-row-policy.js.map +1 -1
  127. package/dist/esm/index.d.ts.map +1 -1
  128. package/dist/esm/index.js +14 -2
  129. package/dist/esm/index.js.map +1 -1
  130. package/dist/esm/infinite-scroll.d.ts +89 -4
  131. package/dist/esm/infinite-scroll.d.ts.map +1 -1
  132. package/dist/esm/infinite-scroll.js +237 -32
  133. package/dist/esm/infinite-scroll.js.map +1 -1
  134. package/dist/esm/list-sort-order.d.ts +14 -0
  135. package/dist/esm/list-sort-order.d.ts.map +1 -0
  136. package/dist/esm/list-sort-order.js +32 -0
  137. package/dist/esm/list-sort-order.js.map +1 -0
  138. package/dist/esm/loading-state.d.ts +23 -2
  139. package/dist/esm/loading-state.d.ts.map +1 -1
  140. package/dist/esm/loading-state.js +50 -15
  141. package/dist/esm/loading-state.js.map +1 -1
  142. package/dist/esm/pagination-controls.d.ts +22 -3
  143. package/dist/esm/pagination-controls.d.ts.map +1 -1
  144. package/dist/esm/pagination-controls.js +28 -2
  145. package/dist/esm/pagination-controls.js.map +1 -1
  146. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  147. package/dist/esm/pagination-plugin.js +340 -168
  148. package/dist/esm/pagination-plugin.js.map +1 -1
  149. package/dist/esm/range-control.d.ts +45 -0
  150. package/dist/esm/range-control.d.ts.map +1 -0
  151. package/dist/esm/range-control.js +137 -0
  152. package/dist/esm/range-control.js.map +1 -0
  153. package/dist/esm/row-order.d.ts +3 -2
  154. package/dist/esm/row-order.d.ts.map +1 -1
  155. package/dist/esm/row-order.js +5 -4
  156. package/dist/esm/row-order.js.map +1 -1
  157. package/dist/esm/search-input.d.ts +42 -0
  158. package/dist/esm/search-input.d.ts.map +1 -0
  159. package/dist/esm/search-input.js +129 -0
  160. package/dist/esm/search-input.js.map +1 -0
  161. package/dist/esm/sort-utils.d.ts +53 -1
  162. package/dist/esm/sort-utils.d.ts.map +1 -1
  163. package/dist/esm/sort-utils.js +100 -12
  164. package/dist/esm/sort-utils.js.map +1 -1
  165. package/dist/esm/transformations/booking-item.d.ts +24 -0
  166. package/dist/esm/transformations/booking-item.d.ts.map +1 -0
  167. package/dist/esm/transformations/booking-item.js +23 -0
  168. package/dist/esm/transformations/booking-item.js.map +1 -0
  169. package/dist/esm/transformations/index.d.ts +4 -2
  170. package/dist/esm/transformations/index.d.ts.map +1 -1
  171. package/dist/esm/transformations/index.js +14 -5
  172. package/dist/esm/transformations/index.js.map +1 -1
  173. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  174. package/dist/esm/utils.d.ts +3 -2
  175. package/dist/esm/utils.d.ts.map +1 -1
  176. package/dist/esm/utils.js +49 -19
  177. package/dist/esm/utils.js.map +1 -1
  178. package/package.json +5 -5
  179. package/src/cache/ast.ts +4 -1
  180. package/src/count-effect.ts +31 -8
  181. package/src/data-source-fetchers.ts +33 -14
  182. package/src/fetchers/pg-client-import.ts +16 -0
  183. package/src/fetchers/postgresql.ts +15 -9
  184. package/src/fetchers/raw-query.ts +2 -1
  185. package/src/fetchers/teleport.ts +19 -10
  186. package/src/fetchers/utils/browser-row-policy.ts +79 -5
  187. package/src/index.ts +8 -2
  188. package/src/infinite-scroll.ts +420 -81
  189. package/src/list-sort-order.ts +34 -0
  190. package/src/loading-state.ts +85 -13
  191. package/src/pagination-controls.ts +26 -3
  192. package/src/pagination-plugin.ts +532 -218
  193. package/src/range-control.ts +207 -0
  194. package/src/row-order.ts +5 -4
  195. package/src/search-input.ts +190 -0
  196. package/src/sort-utils.ts +164 -21
  197. package/src/transformations/booking-item.ts +71 -0
  198. package/src/transformations/index.ts +25 -2
  199. package/src/utils.ts +55 -18
@@ -0,0 +1,71 @@
1
+ import type { UIDLEcommerceCategory } from '@teleporthq/teleport-types'
2
+ import { generateCategoryTaxonomyCode } from './category-taxonomy'
3
+
4
+ export interface BookingItemTransformOptions {
5
+ /** The booking items' category taxonomy — see `bookingSettings.categories`. */
6
+ categories?: UIDLEcommerceCategory[]
7
+ }
8
+
9
+ /**
10
+ * Generates JavaScript code for the `teleport_booking_items` row
11
+ * transformation — the things a Bookings site lets people book.
12
+ *
13
+ * The row is kept whole (every column, snake_case: the booking pages bind
14
+ * them as stored) and its translatable texts — `name`, `description` (rich
15
+ * text) and `location` — are the page's language when the row has them there
16
+ * (`es_name`, …), the main language otherwise. Its `category` is the name its
17
+ * first category has in the page's language, read off the taxonomy baked in
18
+ * here (the row's stored main name while none of its ids is a category). That
19
+ * is all a booking page needs to show an item in the visitor's language; the
20
+ * booking statements localise what they read on their own.
21
+ *
22
+ * MUST mirror `localizeBookingItem` in the editor
23
+ * (teleport-gui features/bookings/utils/localize-booking-item.ts), which is
24
+ * what the canvas renders from.
25
+ */
26
+ export const generateBookingItemTransformationCode = (
27
+ options: BookingItemTransformOptions = {}
28
+ ): string => {
29
+ return `
30
+ // ============================================================
31
+ // Booking Item Transformation
32
+ // ============================================================
33
+
34
+ var BOOKING_ITEM_TRANSLATABLE_COLUMNS = ['name', 'description', 'location']
35
+ ${generateCategoryTaxonomyCode('BOOKING_CATEGORIES_BY_ID', options.categories)}
36
+
37
+ function buildBookingItem(record, options) {
38
+ if (!record || typeof record !== 'object') return record
39
+ options = options || {}
40
+ var currentLang = options.currentLanguage || null
41
+ var mainLang = options.mainLanguage || null
42
+
43
+ var out = {}
44
+ for (var key in record) {
45
+ if (Object.prototype.hasOwnProperty.call(record, key)) out[key] = record[key]
46
+ }
47
+ for (var i = 0; i < BOOKING_ITEM_TRANSLATABLE_COLUMNS.length; i++) {
48
+ var column = BOOKING_ITEM_TRANSLATABLE_COLUMNS[i]
49
+ var value = resolveI18nField(record, column, column, currentLang, mainLang)
50
+ out[column] = value === null || value === undefined ? record[column] : value
51
+ }
52
+ if ('category' in record || 'category_ids' in record) {
53
+ var stored = typeof record.category === 'string' ? record.category : ''
54
+ var assigned = resolveAssignedCategories(
55
+ record.category_ids,
56
+ BOOKING_CATEGORIES_BY_ID,
57
+ currentLang,
58
+ mainLang,
59
+ stored
60
+ )
61
+ out.category = assigned.length > 0 ? assigned[0].name : stored
62
+ }
63
+ return out
64
+ }
65
+
66
+ function transformBookingItems(records, options) {
67
+ if (!Array.isArray(records)) return []
68
+ return records.map(function(record) { return buildBookingItem(record, options) })
69
+ }
70
+ `
71
+ }
@@ -8,6 +8,7 @@ import { ContentTables, StorefrontTax, TableAccess } from '@teleporthq/teleport-
8
8
  import { generateSharedTransformationCode } from './shared-utils'
9
9
  import { generateBlogPostTransformationCode } from './blog-post'
10
10
  import { generateCustomPageTransformationCode } from './custom-page'
11
+ import { generateBookingItemTransformationCode } from './booking-item'
11
12
  import {
12
13
  generateEcommerceProductTransformationCode,
13
14
  type EcommerceProductTransformOptions,
@@ -45,6 +46,8 @@ export interface EntityTransformOptions extends EcommerceProductTransformOptions
45
46
  contentSettings?: Partial<Record<ContentTables.ContentPresetKey, ContentPresetTransformSettings>>
46
47
  /** Blog post-category taxonomy — see `blogSettings.categories`. */
47
48
  blogCategories?: UIDLEcommerceCategory[]
49
+ /** The booking items' category taxonomy — see `bookingSettings.categories`. */
50
+ bookingCategories?: UIDLEcommerceCategory[]
48
51
  /** Post content headings get ids and `#` links — see `blogSettings.headingAnchors`. */
49
52
  blogHeadingAnchors?: boolean
50
53
  /**
@@ -136,7 +139,12 @@ export const contentSettingsFor = (
136
139
  export const buildProductTransformOptions = (
137
140
  options: Pick<
138
141
  GeneratorOptions,
139
- 'ecommerceSettings' | 'invoiceSettings' | 'blogSettings' | 'helpCenterSettings' | 'auth'
142
+ | 'ecommerceSettings'
143
+ | 'invoiceSettings'
144
+ | 'blogSettings'
145
+ | 'bookingSettings'
146
+ | 'helpCenterSettings'
147
+ | 'auth'
140
148
  > &
141
149
  LocalizedProjectOptions & {
142
150
  /**
@@ -157,6 +165,7 @@ export const buildProductTransformOptions = (
157
165
  help: contentPresetTransformSettings(options.helpCenterSettings),
158
166
  },
159
167
  blogCategories: options.blogSettings?.categories,
168
+ bookingCategories: options.bookingSettings?.categories,
160
169
  blogHeadingAnchors: options.blogSettings?.headingAnchors === true,
161
170
  blogComments: options.blogSettings?.comments === true,
162
171
  storefrontTaxRate: StorefrontTax.resolveStorefrontTaxRate(options.invoiceSettings),
@@ -166,7 +175,12 @@ export const buildProductTransformOptions = (
166
175
  trustedReaderRoles: TableAccess.resolveTrustedReaderRoles(options.auth || options.authentication),
167
176
  })
168
177
 
169
- export type TransformationType = 'blog-post' | 'ecommerce-product' | 'custom-page' | null
178
+ export type TransformationType =
179
+ | 'blog-post'
180
+ | 'ecommerce-product'
181
+ | 'custom-page'
182
+ | 'booking-item'
183
+ | null
170
184
 
171
185
  /**
172
186
  * Strips a leading `schema.` qualifier from a table name so that only the
@@ -207,6 +221,9 @@ export const detectTransformationType = (tableName: string): TransformationType
207
221
  if (bare === 'teleport_pages') {
208
222
  return 'custom-page'
209
223
  }
224
+ if (bare === 'teleport_booking_items') {
225
+ return 'booking-item'
226
+ }
210
227
  return null
211
228
  }
212
229
 
@@ -245,6 +262,10 @@ export const getTransformationCode = (
245
262
  return shared + generateEcommerceProductTransformationCode(options)
246
263
  case 'custom-page':
247
264
  return shared + generateCustomPageTransformationCode()
265
+ case 'booking-item':
266
+ return (
267
+ shared + generateBookingItemTransformationCode({ categories: options.bookingCategories })
268
+ )
248
269
  default:
249
270
  return ''
250
271
  }
@@ -380,6 +401,8 @@ export const getTransformWrapperCode = (
380
401
  ? 'transformBlogPosts'
381
402
  : type === 'custom-page'
382
403
  ? 'transformCustomPages'
404
+ : type === 'booking-item'
405
+ ? 'transformBookingItems'
383
406
  : 'transformEcommerceProducts'
384
407
 
385
408
  // Products additionally get their purchasable variant combinations attached in
package/src/utils.ts CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  UIDLDataSource,
8
8
  DataSourceType,
9
9
  ChunkType,
10
+ UIDLStateDefinition,
10
11
  } from '@teleporthq/teleport-types'
11
12
  import * as types from '@babel/types'
12
13
  import { ASTUtils } from '@teleporthq/teleport-plugin-common'
@@ -15,7 +16,7 @@ import { generateDataSourceFetcherWithCore } from './data-source-fetchers'
15
16
  import type { EntityTransformOptions } from './transformations'
16
17
  import { DATA_SOURCE_ISR_REVALIDATE_SECONDS } from './isr'
17
18
  import { buildServerLocaleParam, hasLocaleParam, buildClientLocaleParam } from './request-locale'
18
- import { readFixedSort } from './sort-utils'
19
+ import { buildStartingSortsValue, readRepeaterSort, type RepeaterSort } from './sort-utils'
19
20
 
20
21
  const VALID_DATA_SOURCE_TYPES: DataSourceType[] = [
21
22
  'rest-api',
@@ -1180,16 +1181,16 @@ const isSortKeyed = (properties: types.ObjectProperty[]): boolean =>
1180
1181
  (property.key.type === 'Identifier' && property.key.name === 'sorts')
1181
1182
  )
1182
1183
 
1183
- /** The fixed sort of the first list repeater inside a data-source node, if it has one. */
1184
+ /** The first list repeater inside a data-source node: the list its rows are fetched for. */
1184
1185
  // tslint:disable-next-line:no-any
1185
- const findRepeaterFixedSort = (node: any): { field: string; order: 'asc' | 'desc' } | undefined => {
1186
+ const findListRepeater = (node: any): Record<string, any> | undefined => {
1186
1187
  // tslint:disable-next-line:no-any
1187
- const visit = (current: any): { field: string; order: 'asc' | 'desc' } | null | undefined => {
1188
+ const visit = (current: any): Record<string, any> | undefined => {
1188
1189
  if (!current || typeof current !== 'object') {
1189
1190
  return undefined
1190
1191
  }
1191
1192
  if (current.type === 'cms-list-repeater') {
1192
- return readFixedSort(current.content?.sort, current.content?.sortDirection) ?? null
1193
+ return current.content ?? {}
1193
1194
  }
1194
1195
  const content = current.content
1195
1196
  const children = [
@@ -1204,9 +1205,28 @@ const findRepeaterFixedSort = (node: any): { field: string; order: 'asc' | 'desc
1204
1205
  }
1205
1206
  return undefined
1206
1207
  }
1207
- return visit(node) ?? undefined
1208
+ return visit(node)
1208
1209
  }
1209
1210
 
1211
+ /**
1212
+ * The order a list's page fetch carries, in what tells it apart from another
1213
+ * list's fetch with the same params (`claimParamsPropKey`): the column the
1214
+ * editor fixed, or a sort the visitor picks at the values they start with.
1215
+ */
1216
+ const prefetchOrderOf = (
1217
+ // tslint:disable-next-line:no-any
1218
+ repeater: Record<string, any> | undefined,
1219
+ sort: RepeaterSort
1220
+ ): unknown =>
1221
+ sort.fixed ??
1222
+ (sort.dynamic && sort.starting
1223
+ ? {
1224
+ sort: repeater?.sort,
1225
+ sortDirection: repeater?.sortDirection ?? null,
1226
+ starting: sort.starting,
1227
+ }
1228
+ : undefined)
1229
+
1210
1230
  export const extractDataSourceIntoGetStaticProps = (
1211
1231
  node: UIDLDataSourceItemNode | UIDLDataSourceListNode,
1212
1232
  dataSources: Record<string, UIDLDataSource>,
@@ -1217,7 +1237,13 @@ export const extractDataSourceIntoGetStaticProps = (
1217
1237
  dependencies: Record<string, any>,
1218
1238
  dynamicRouteAttr?: string,
1219
1239
  folderPath?: string[],
1220
- transformOptions: EntityTransformOptions = {}
1240
+ transformOptions: EntityTransformOptions = {},
1241
+ // What the read hands the module after its params: `{ as: 'visitor' }` on
1242
+ // every page but an admin page only trusted readers open (see
1243
+ // `RouteUtils.pageDataReadArguments`).
1244
+ readArguments: () => types.Expression[] = () => [],
1245
+ // The page's states: a list sorted by one is fetched by the value it starts at.
1246
+ stateDefinitions?: Record<string, UIDLStateDefinition>
1221
1247
  ): { success: boolean; chunk?: any } => {
1222
1248
  try {
1223
1249
  // Validate node content
@@ -1281,11 +1307,13 @@ export const extractDataSourceIntoGetStaticProps = (
1281
1307
  }
1282
1308
  // tslint:disable-next-line:no-any
1283
1309
  const nodeResource = (node.content as any).resource
1310
+ const repeater = findListRepeater(node)
1311
+ const repeaterSort = readRepeaterSort(repeater?.sort, repeater?.sortDirection, stateDefinitions)
1284
1312
  const propKey = claimParamsPropKey(
1285
1313
  componentChunk,
1286
1314
  resourcePropKey,
1287
1315
  nodeResource,
1288
- findRepeaterFixedSort(node)
1316
+ prefetchOrderOf(repeater, repeaterSort)
1289
1317
  )
1290
1318
 
1291
1319
  // Find matching JSX nodes for this data source
@@ -1732,11 +1760,13 @@ export const extractDataSourceIntoGetStaticProps = (
1732
1760
  }
1733
1761
  })
1734
1762
 
1735
- // The sort the list's repeater fixed, when the resource names none — the
1763
+ // The sort the list's repeater carries, when the resource names none — the
1736
1764
  // rows the page is pre-rendered with come in the order the list shows them
1737
- // (the browser keeps them: the provider skips its first fetch).
1738
- const repeaterSort = isSortKeyed(paramsProperties) ? undefined : findRepeaterFixedSort(node)
1739
- if (repeaterSort) {
1765
+ // (the browser keeps them: the provider skips its first fetch). A sort the
1766
+ // visitor picks is fetched as they start with it, by the browser's own sort
1767
+ // expression (`buildStartingSortsValue`), and the list keeps the rows only
1768
+ // while the sort stays there (`seedPlainListWhileSortStarts`).
1769
+ if (!isSortKeyed(paramsProperties) && repeaterSort.fixed) {
1740
1770
  paramsProperties.push(
1741
1771
  types.objectProperty(
1742
1772
  types.stringLiteral('sorts'),
@@ -1747,11 +1777,11 @@ export const extractDataSourceIntoGetStaticProps = (
1747
1777
  types.objectExpression([
1748
1778
  types.objectProperty(
1749
1779
  types.identifier('field'),
1750
- types.stringLiteral(repeaterSort.field)
1780
+ types.stringLiteral(repeaterSort.fixed.field)
1751
1781
  ),
1752
1782
  types.objectProperty(
1753
1783
  types.identifier('order'),
1754
- types.stringLiteral(repeaterSort.order)
1784
+ types.stringLiteral(repeaterSort.fixed.order)
1755
1785
  ),
1756
1786
  ]),
1757
1787
  ]),
@@ -1759,6 +1789,13 @@ export const extractDataSourceIntoGetStaticProps = (
1759
1789
  )
1760
1790
  )
1761
1791
  )
1792
+ } else if (!isSortKeyed(paramsProperties) && repeaterSort.dynamic && repeaterSort.starting) {
1793
+ paramsProperties.push(
1794
+ types.objectProperty(
1795
+ types.stringLiteral('sorts'),
1796
+ buildStartingSortsValue(repeaterSort.dynamic, repeaterSort.starting)
1797
+ )
1798
+ )
1762
1799
  }
1763
1800
 
1764
1801
  // getStaticProps runs once per language: the prefetch is for that language.
@@ -1768,7 +1805,7 @@ export const extractDataSourceIntoGetStaticProps = (
1768
1805
 
1769
1806
  const fetchCallExpression = types.callExpression(
1770
1807
  types.memberExpression(types.identifier(fetcherImportName), types.identifier('fetchData')),
1771
- [types.objectExpression(paramsProperties)]
1808
+ [types.objectExpression(paramsProperties), ...readArguments()]
1772
1809
  )
1773
1810
 
1774
1811
  const safeFetchExpression = createSafeFetchExpression(fetchCallExpression, propKey)
@@ -1925,12 +1962,12 @@ const claimParamsPropKey = (
1925
1962
  componentChunk: ChunkDefinition,
1926
1963
  resourcePropKey: string,
1927
1964
  resource: { params?: Record<string, unknown> } | undefined,
1928
- // The list's own fixed sort rides on its prefetch too (see the params below).
1929
- repeaterSort?: { field: string; order: string }
1965
+ // The list's own sort rides on its prefetch too (`prefetchOrderOf`).
1966
+ prefetchOrder?: unknown
1930
1967
  ): string => {
1931
1968
  const meta = componentChunk.meta as { dataSourcePropKeyParams?: Record<string, string> }
1932
1969
  const claimed = meta.dataSourcePropKeyParams ?? (meta.dataSourcePropKeyParams = {})
1933
- const signature = JSON.stringify([resource?.params ?? {}, repeaterSort ?? null])
1970
+ const signature = JSON.stringify([resource?.params ?? {}, prefetchOrder ?? null])
1934
1971
 
1935
1972
  let propKey = resourcePropKey
1936
1973
  for (let suffix = 2; claimed[propKey] !== undefined && claimed[propKey] !== signature; suffix++) {