@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
@@ -1,5 +1,6 @@
1
1
  import { SessionCookieResolver } from '@teleporthq/teleport-shared'
2
2
  import { replaceSecretReference } from '../utils'
3
+ import { PG_CLIENT_IMPORT } from './pg-client-import'
3
4
 
4
5
  interface PostgreSQLConfig {
5
6
  host?: string
@@ -109,7 +110,7 @@ function sessionUserField(user, field) {
109
110
  : '{ rejectUnauthorized: false }'
110
111
  : 'false'
111
112
 
112
- return `import { Client } from 'pg'
113
+ return `${PG_CLIENT_IMPORT}
113
114
 
114
115
  const FORBIDDEN_KEYWORDS = ${JSON.stringify(FORBIDDEN_KEYWORDS)}
115
116
  ${sessionHelpers}
@@ -12,6 +12,7 @@ import {
12
12
  type EntityTransformOptions,
13
13
  } from '../transformations'
14
14
  import { generateSortFallbackFieldHelper, generateSortFieldSqlHelper } from '../product-price-sort'
15
+ import { SORT_NULLS_LAST_SQL } from '../list-sort-order'
15
16
  import { generateRowOrderTiebreakHelper, rowIdentityColumn } from '../row-order'
16
17
  import { generateProductFilterClauseHelper } from '../product-filter-fields'
17
18
  import { collectLocalizedColumns, generateLocalizedColumnsHelper } from '../localized-columns'
@@ -19,6 +20,7 @@ import { REQUEST_LOCALE_PARAM } from '../request-locale'
19
20
  import { generateReadGuardCall, generateTableAccessPreamble } from './utils/table-access-guard'
20
21
  import { generateRequestSqlGuardsCode } from './utils/request-sql-guards'
21
22
  import { generateArrayOverlapSqlCode } from '../array-overlap-sql'
23
+ import { PG_CLIENT_IMPORT } from './pg-client-import'
22
24
 
23
25
  interface TeleportDBConfig {
24
26
  host?: string
@@ -102,7 +104,7 @@ export const generateTeleportFetcher = (
102
104
  }`
103
105
  : `(process.env.${DEFAULT_ENV_KEYS.ssl} === 'false' ? false : process.env.${DEFAULT_ENV_KEYS.ssl} === 'true' ? { rejectUnauthorized: false } : undefined)`
104
106
 
105
- return `import { Client } from 'pg'
107
+ return `${PG_CLIENT_IMPORT}
106
108
 
107
109
  ${generateTableAccessPreamble(transformOptions.trustedReaderRoles || [])}
108
110
  function normalizePostgresConnectionString(connectionString) {
@@ -314,7 +316,10 @@ ${generateReadGuardCall(tableName, 'req.query && req.query.rawQuery')}
314
316
  // \`fetchData({ rawQuery })\` and expect it to execute verbatim.
315
317
  if (req.query && typeof req.query.rawQuery === 'string' && req.query.rawQuery.length > 0) {
316
318
  assertRawQuerySafe(req.query.rawQuery)
317
- const rawResult = await client.query(req.query.rawQuery)
319
+ // A page's own statement, read for a visitor, runs over the rows a
320
+ // visitor is served of every narrowed table it names.
321
+ const rawSql = __rowAccess.narrowRaw ? __brpNarrowRawQuery(req.query.rawQuery) : req.query.rawQuery
322
+ const rawResult = await client.query(rawSql)
318
323
  const rawRows = Array.isArray(rawResult?.rows) ? rawResult.rows : []
319
324
  const rawPlain = rawRows.map((row) =>
320
325
  row && typeof row.toJSON === 'function' ? row.toJSON() : row
@@ -324,7 +329,10 @@ ${generateReadGuardCall(tableName, 'req.query && req.query.rawQuery')}
324
329
  success: true,
325
330
  // Every row here ends up in a browser (a page's props or a client
326
331
  // refetch), so no credential column survives, whatever joined it.
327
- data: __taWithoutCredentials(rawSafe, null),
332
+ data: __taWithoutCredentials(
333
+ __rowAccess.narrowRaw ? __brpStripHiddenOfRaw(req.query.rawQuery, rawSafe) : rawSafe,
334
+ null
335
+ ),
328
336
  timestamp: Date.now()
329
337
  })
330
338
  }
@@ -391,8 +399,8 @@ ${generateReadGuardCall(tableName, 'req.query && req.query.rawQuery')}
391
399
 
392
400
  // Handle sorts - new array format. Two ORDER BY clauses are built: the one
393
401
  // actually used (a translatable column in the request's language, the
394
- // products table's price rewrites), and a plain-column twin kept only as
395
- // the fallback below.
402
+ // products table's price rewrites, rows without a value last), and a
403
+ // plain-column twin kept only as the fallback below.
396
404
  let orderBySql = ''
397
405
  let plainOrderBySql = ''
398
406
  if (sorts) {
@@ -401,7 +409,7 @@ ${generateReadGuardCall(tableName, 'req.query && req.query.rawQuery')}
401
409
  const valid = parsedSorts.filter((sort) => sort && sort.field)
402
410
  valid.forEach((sort) => assertRequestColumn(sort.field, 'sort field'))
403
411
  const orderOf = (sort) => (sort.order || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'
404
- const orderClauses = valid.map((sort) => \`\${localizedSortFieldSql(sort.field, requestLocale) || sortFieldSql(sort.field)} \${orderOf(sort)}\`)
412
+ const orderClauses = valid.map((sort) => \`\${localizedSortFieldSql(sort.field, requestLocale) || sortFieldSql(sort.field)} \${orderOf(sort)}${SORT_NULLS_LAST_SQL}\`)
405
413
  const plainClauses = valid.map((sort) => \`\${sortFallbackField(sort.field)} \${orderOf(sort)}\`)
406
414
 
407
415
  if (orderClauses.length > 0) {
@@ -416,10 +424,10 @@ ${generateReadGuardCall(tableName, 'req.query && req.query.rawQuery')}
416
424
  assertRequestColumn(sortBy, 'sort field')
417
425
  const sortByDirection = (sortOrder || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'
418
426
  const tiebreak = rowOrderTiebreak([sortBy], sortByDirection)
419
- orderBySql = \` ORDER BY \${localizedSortFieldSql(sortBy, requestLocale) || sortBy} \${sortByDirection}\${tiebreak}\`
427
+ orderBySql = \` ORDER BY \${localizedSortFieldSql(sortBy, requestLocale) || sortBy} \${sortByDirection}${SORT_NULLS_LAST_SQL}\${tiebreak}\`
420
428
  plainOrderBySql = \` ORDER BY \${sortBy} \${sortByDirection}\${tiebreak}\`
421
429
  }
422
- const usedDiscountAwareSort = orderBySql !== plainOrderBySql
430
+ const usedRewrittenSort = orderBySql !== plainOrderBySql
423
431
 
424
432
  const limitValue = requestRowCount(limit || perPage)
425
433
  const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)
@@ -441,12 +449,13 @@ ${generateReadGuardCall(tableName, 'req.query && req.query.rawQuery')}
441
449
  // the whole table - so if a database ever rejects it, fall back to ordering
442
450
  // by the stored list price rather than serving an empty products page. The
443
451
  // translatable-column ordering takes the same exit: a per-language column
444
- // the schema had at generation time may have been dropped since.
452
+ // the schema had at generation time may have been dropped since. So does
453
+ // the empty-values-last ordering.
445
454
  let result
446
455
  try {
447
456
  result = await client.query(sql, queryParams)
448
457
  } catch (sortError) {
449
- if (!usedDiscountAwareSort) throw sortError
458
+ if (!usedRewrittenSort) throw sortError
450
459
  console.warn(
451
460
  'Rewritten sort failed; falling back to the plain column:',
452
461
  sortError && sortError.message
@@ -1,4 +1,4 @@
1
- import { ContentTables } from '@teleporthq/teleport-shared'
1
+ import { ContentTables, TableAccess } from '@teleporthq/teleport-shared'
2
2
 
3
3
  /**
4
4
  * What a per-table read route (`/api/teleport-<table>-<source>` and its count
@@ -42,9 +42,19 @@ export const generateBrowserRowPolicyCode =
42
42
  (): string => `// GENERATED — see browser-row-policy.ts in teleport-plugin-next-data-source.
43
43
  var __BRP_POLICIES = ${JSON.stringify(BROWSER_ROW_POLICIES)};
44
44
 
45
+ // What a page's own data carries of a member, read for a visitor: the public
46
+ // profile (TableAccess.PUBLIC_PROFILE_COLUMNS) — an allow-list, so a column the
47
+ // account row gains later stays out too. A browser reads the table not at all.
48
+ var __BRP_PUBLIC_PROFILE = ${JSON.stringify({
49
+ predicate: 'TRUE',
50
+ hiddenColumns: [],
51
+ visibleColumns: TableAccess.PUBLIC_PROFILE_COLUMNS,
52
+ })};
53
+
45
54
  // Who is asking: the store's own server code and its administrators read every
46
- // row; anyone else is a visitor.
55
+ // row; anyone else is a visitor — a page's own data included (\`__taIsVisitorView\`).
47
56
  async function __brpReader(req) {
57
+ if (__taIsVisitorView(req)) return { trusted: false };
48
58
  if (__taIsInternalRequest(req)) return { trusted: true };
49
59
  var token = null;
50
60
  try {
@@ -63,11 +73,15 @@ function __brpMentionsAny(rawQuery, tables) {
63
73
  return false;
64
74
  }
65
75
 
66
- // A raw statement cannot be narrowed, so a visitor's statement that names a
67
- // narrowed table is refused whole. The session is only decoded when the read
68
- // touches one of these tables.
76
+ // A visitor's browser may not send a statement that names a narrowed table: it
77
+ // is refused whole. A page's own statement, read for a visitor, is run over the
78
+ // rows a visitor is served instead (\`narrowRaw\`, see \`__brpNarrowRawQuery\`).
79
+ // The session is only decoded when the read touches one of these tables.
69
80
  async function __brpAccess(req, tableName, rawQuery) {
70
81
  var raw = typeof rawQuery === 'string' && rawQuery.length > 0 ? rawQuery : null;
82
+ if (!raw && __taIsVisitorView(req) && __taIsCredentialTable(tableName)) {
83
+ return { denied: null, policy: __BRP_PUBLIC_PROFILE };
84
+ }
71
85
  var bare = __taNormalizeTable(tableName);
72
86
  var rawNarrowed = !!raw && __brpMentionsAny(raw, Object.keys(__BRP_POLICIES));
73
87
  var policy = raw ? null : (Object.prototype.hasOwnProperty.call(__BRP_POLICIES, bare) ? __BRP_POLICIES[bare] : null);
@@ -75,18 +89,78 @@ async function __brpAccess(req, tableName, rawQuery) {
75
89
  var reader = await __brpReader(req);
76
90
  if (reader.trusted) return { denied: null, policy: null };
77
91
  if (rawNarrowed) {
92
+ if (__taIsVisitorView(req)) return { denied: null, policy: null, narrowRaw: true };
78
93
  return { denied: { status: 403, message: 'Forbidden: raw queries over this table are only available to server-side calls' }, policy: null };
79
94
  }
80
95
  return { denied: null, policy: policy };
81
96
  }
82
97
 
98
+ function __brpRefuseRaw(what) {
99
+ var err = new Error('Forbidden: ' + what + ' cannot be read for a visitor');
100
+ err.status = 403;
101
+ return err;
102
+ }
103
+
104
+ // A page's own statement over the rows a visitor is served: every narrowed
105
+ // table it reads becomes a WITH entry of the same name, ahead of the
106
+ // statement, which its own references — and its own WITH entries — resolve to:
107
+ //
108
+ // WITH "teleport_products" AS (SELECT * FROM "teleport_products" AS __brp_rows WHERE (<predicate>)) <statement>
109
+ //
110
+ // Inside its own definition the entry names the table itself (a WITH that is
111
+ // not RECURSIVE does not see itself). A hidden column reads NULL however the
112
+ // statement spells it — an alias, a whole-row value. A statement this cannot
113
+ // vouch for is refused: unreadable or opaque, RECURSIVE (its entries would see
114
+ // themselves), or naming a narrowed table through a schema, which reaches the
115
+ // table past the entry.
116
+ function __brpNarrowRawQuery(sql) {
117
+ var cleaned = __taCleanSql(sql);
118
+ if (!cleaned.ok || __TA_OPAQUE_SQL_RE.test(cleaned.text)) throw __brpRefuseRaw('this statement');
119
+ var tables = Object.keys(__BRP_POLICIES).filter(function(table) {
120
+ return new RegExp('(?:^|[^A-Za-z0-9_])"?' + table + '"?(?![A-Za-z0-9_])', 'i').test(cleaned.text);
121
+ });
122
+ if (tables.length === 0) return sql;
123
+ var leading = /^\\s*with\\b(\\s+recursive\\b)?/i.exec(cleaned.text);
124
+ if (leading && leading[1]) throw __brpRefuseRaw('a recursive statement');
125
+ tables.forEach(function(table) {
126
+ if (new RegExp('\\\\.\\\\s*"?' + table + '"?(?![A-Za-z0-9_])', 'i').test(cleaned.text)) throw __brpRefuseRaw(table);
127
+ });
128
+ var entries = tables.map(function(table) {
129
+ var policy = __BRP_POLICIES[table];
130
+ var hidden = {};
131
+ policy.hiddenColumns.forEach(function(column) { hidden[column] = null; });
132
+ var columns = policy.hiddenColumns.length > 0
133
+ ? '(jsonb_populate_record(__brp_rows, ' + "'" + JSON.stringify(hidden) + "'" + '::jsonb)).*'
134
+ : '*';
135
+ return '"' + table + '" AS (SELECT ' + columns + ' FROM "' + table + '" AS __brp_rows WHERE (' + policy.predicate + '))';
136
+ });
137
+ var statement = String(sql).trim().replace(/;\\s*$/, '');
138
+ if (!leading) return 'WITH ' + entries.join(', ') + ' ' + statement;
139
+ // The statement's own WITH list follows ours, so its entries read ours too.
140
+ var own = /^with\\b/i.exec(statement);
141
+ if (!own) throw __brpRefuseRaw('this statement');
142
+ return 'WITH ' + entries.join(', ') + ', ' + statement.slice(own[0].length);
143
+ }
144
+
145
+ // The rows of a statement narrowed for a visitor, without the hidden columns
146
+ // of the tables it read.
147
+ function __brpStripHiddenOfRaw(sql, rows) {
148
+ var cleaned = __taCleanSql(sql);
149
+ return Object.keys(__BRP_POLICIES).reduce(function(current, table) {
150
+ return cleaned.ok && __taSqlMentionsTable(sql, table) ? __brpStripHidden(__BRP_POLICIES[table], current) : current;
151
+ }, rows);
152
+ }
153
+
83
154
  function __brpColumnName(field) {
84
155
  var parts = String(field == null ? '' : field).replace(/"/g, '').trim().split('.');
85
156
  return parts[parts.length - 1];
86
157
  }
87
158
 
159
+ // A column the policy keeps from the reader: one it hides, or — for a policy
160
+ // that names the only columns it serves (\`visibleColumns\`) — any other.
88
161
  function __brpIsHidden(policy, field) {
89
162
  var name = __brpColumnName(field).toLowerCase();
163
+ if (policy.visibleColumns) return policy.visibleColumns.indexOf(name) === -1;
90
164
  for (var i = 0; i < policy.hiddenColumns.length; i++) {
91
165
  if (policy.hiddenColumns[i].toLowerCase() === name) return true;
92
166
  }
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  UIDLDynamicReference,
9
9
  } from '@teleporthq/teleport-types'
10
10
  import { UIDLUtils, StringUtils } from '@teleporthq/teleport-shared'
11
+ import { RouteUtils } from '@teleporthq/teleport-plugin-common'
11
12
  import {
12
13
  extractDataSourceIntoNextAPIFolder,
13
14
  extractDataSourceIntoGetStaticProps,
@@ -652,7 +653,9 @@ export const createNextPagesDataSourcePlugin: ComponentPluginFactory<{}> = () =>
652
653
  dependencies,
653
654
  dynamicRouteAttr,
654
655
  uidl.outputOptions?.folderPath,
655
- transformOptions
656
+ transformOptions,
657
+ () => RouteUtils.pageDataReadArguments(uidl, options.auth),
658
+ uidl.stateDefinitions
656
659
  )
657
660
 
658
661
  if (result.success && result.chunk) {
@@ -794,7 +797,10 @@ export const createNextPagesDataSourcePlugin: ComponentPluginFactory<{}> = () =>
794
797
  types.identifier(fetcherImportName),
795
798
  types.identifier('fetchData')
796
799
  ),
797
- [types.objectExpression([])]
800
+ [
801
+ types.objectExpression([]),
802
+ ...RouteUtils.pageDataReadArguments(uidl, options.auth),
803
+ ]
798
804
  )
799
805
 
800
806
  const safeFetchExpression = types.callExpression(