@teleporthq/teleport-plugin-next-data-source 0.43.62 → 0.43.64

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 (200) hide show
  1. package/__tests__/blog-post-categories.test.ts +131 -0
  2. package/__tests__/custom-page-transform.test.ts +119 -0
  3. package/__tests__/ecommerce-product-ratings.test.ts +155 -0
  4. package/__tests__/ecommerce-product-storefront-contract.test.ts +147 -0
  5. package/__tests__/filter-groups.test.ts +174 -0
  6. package/__tests__/product-reviews-structured-data.test.ts +196 -0
  7. package/dist/cjs/data-source-fetchers.d.ts +3 -3
  8. package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
  9. package/dist/cjs/data-source-fetchers.js.map +1 -1
  10. package/dist/cjs/fetchers/airtable.d.ts.map +1 -1
  11. package/dist/cjs/fetchers/airtable.js +1 -1
  12. package/dist/cjs/fetchers/airtable.js.map +1 -1
  13. package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -1
  14. package/dist/cjs/fetchers/clickhouse.js +1 -1
  15. package/dist/cjs/fetchers/clickhouse.js.map +1 -1
  16. package/dist/cjs/fetchers/csv-file.d.ts.map +1 -1
  17. package/dist/cjs/fetchers/csv-file.js +3 -3
  18. package/dist/cjs/fetchers/csv-file.js.map +1 -1
  19. package/dist/cjs/fetchers/firestore.d.ts.map +1 -1
  20. package/dist/cjs/fetchers/firestore.js +1 -1
  21. package/dist/cjs/fetchers/firestore.js.map +1 -1
  22. package/dist/cjs/fetchers/google-sheets.d.ts.map +1 -1
  23. package/dist/cjs/fetchers/google-sheets.js +1 -1
  24. package/dist/cjs/fetchers/google-sheets.js.map +1 -1
  25. package/dist/cjs/fetchers/javascript.d.ts.map +1 -1
  26. package/dist/cjs/fetchers/javascript.js +1 -1
  27. package/dist/cjs/fetchers/javascript.js.map +1 -1
  28. package/dist/cjs/fetchers/mariadb.d.ts.map +1 -1
  29. package/dist/cjs/fetchers/mariadb.js +1 -1
  30. package/dist/cjs/fetchers/mariadb.js.map +1 -1
  31. package/dist/cjs/fetchers/mongodb.d.ts.map +1 -1
  32. package/dist/cjs/fetchers/mongodb.js +1 -1
  33. package/dist/cjs/fetchers/mongodb.js.map +1 -1
  34. package/dist/cjs/fetchers/mysql.d.ts.map +1 -1
  35. package/dist/cjs/fetchers/mysql.js +1 -1
  36. package/dist/cjs/fetchers/mysql.js.map +1 -1
  37. package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
  38. package/dist/cjs/fetchers/postgresql.js +1 -1
  39. package/dist/cjs/fetchers/postgresql.js.map +1 -1
  40. package/dist/cjs/fetchers/redis.d.ts.map +1 -1
  41. package/dist/cjs/fetchers/redis.js +1 -1
  42. package/dist/cjs/fetchers/redis.js.map +1 -1
  43. package/dist/cjs/fetchers/redshift.d.ts.map +1 -1
  44. package/dist/cjs/fetchers/redshift.js +2 -2
  45. package/dist/cjs/fetchers/redshift.js.map +1 -1
  46. package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
  47. package/dist/cjs/fetchers/rest-api.js +2 -2
  48. package/dist/cjs/fetchers/rest-api.js.map +1 -1
  49. package/dist/cjs/fetchers/supabase.d.ts.map +1 -1
  50. package/dist/cjs/fetchers/supabase.js +1 -1
  51. package/dist/cjs/fetchers/supabase.js.map +1 -1
  52. package/dist/cjs/fetchers/teleport.d.ts +2 -2
  53. package/dist/cjs/fetchers/teleport.d.ts.map +1 -1
  54. package/dist/cjs/fetchers/teleport.js +1 -1
  55. package/dist/cjs/fetchers/teleport.js.map +1 -1
  56. package/dist/cjs/fetchers/turso.d.ts.map +1 -1
  57. package/dist/cjs/fetchers/turso.js +1 -1
  58. package/dist/cjs/fetchers/turso.js.map +1 -1
  59. package/dist/cjs/index.d.ts +1 -1
  60. package/dist/cjs/index.d.ts.map +1 -1
  61. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  62. package/dist/cjs/pagination-plugin.js.map +1 -1
  63. package/dist/cjs/transformations/blog-post.d.ts +7 -1
  64. package/dist/cjs/transformations/blog-post.d.ts.map +1 -1
  65. package/dist/cjs/transformations/blog-post.js +4 -2
  66. package/dist/cjs/transformations/blog-post.js.map +1 -1
  67. package/dist/cjs/transformations/category-taxonomy.d.ts +33 -0
  68. package/dist/cjs/transformations/category-taxonomy.d.ts.map +1 -0
  69. package/dist/cjs/transformations/category-taxonomy.js +42 -0
  70. package/dist/cjs/transformations/category-taxonomy.js.map +1 -0
  71. package/dist/cjs/transformations/custom-page.d.ts +18 -0
  72. package/dist/cjs/transformations/custom-page.d.ts.map +1 -0
  73. package/dist/cjs/transformations/custom-page.js +24 -0
  74. package/dist/cjs/transformations/custom-page.js.map +1 -0
  75. package/dist/cjs/transformations/ecommerce-product.d.ts.map +1 -1
  76. package/dist/cjs/transformations/ecommerce-product.js +2 -35
  77. package/dist/cjs/transformations/ecommerce-product.js.map +1 -1
  78. package/dist/cjs/transformations/index.d.ts +23 -4
  79. package/dist/cjs/transformations/index.d.ts.map +1 -1
  80. package/dist/cjs/transformations/index.js +38 -8
  81. package/dist/cjs/transformations/index.js.map +1 -1
  82. package/dist/cjs/transformations/shared-utils.d.ts.map +1 -1
  83. package/dist/cjs/transformations/shared-utils.js +1 -1
  84. package/dist/cjs/transformations/shared-utils.js.map +1 -1
  85. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  86. package/dist/cjs/utils.d.ts +35 -3
  87. package/dist/cjs/utils.d.ts.map +1 -1
  88. package/dist/cjs/utils.js +116 -18
  89. package/dist/cjs/utils.js.map +1 -1
  90. package/dist/esm/data-source-fetchers.d.ts +3 -3
  91. package/dist/esm/data-source-fetchers.d.ts.map +1 -1
  92. package/dist/esm/data-source-fetchers.js.map +1 -1
  93. package/dist/esm/fetchers/airtable.d.ts.map +1 -1
  94. package/dist/esm/fetchers/airtable.js +2 -2
  95. package/dist/esm/fetchers/airtable.js.map +1 -1
  96. package/dist/esm/fetchers/clickhouse.d.ts.map +1 -1
  97. package/dist/esm/fetchers/clickhouse.js +2 -2
  98. package/dist/esm/fetchers/clickhouse.js.map +1 -1
  99. package/dist/esm/fetchers/csv-file.d.ts.map +1 -1
  100. package/dist/esm/fetchers/csv-file.js +4 -4
  101. package/dist/esm/fetchers/csv-file.js.map +1 -1
  102. package/dist/esm/fetchers/firestore.d.ts.map +1 -1
  103. package/dist/esm/fetchers/firestore.js +2 -2
  104. package/dist/esm/fetchers/firestore.js.map +1 -1
  105. package/dist/esm/fetchers/google-sheets.d.ts.map +1 -1
  106. package/dist/esm/fetchers/google-sheets.js +2 -2
  107. package/dist/esm/fetchers/google-sheets.js.map +1 -1
  108. package/dist/esm/fetchers/javascript.d.ts.map +1 -1
  109. package/dist/esm/fetchers/javascript.js +2 -2
  110. package/dist/esm/fetchers/javascript.js.map +1 -1
  111. package/dist/esm/fetchers/mariadb.d.ts.map +1 -1
  112. package/dist/esm/fetchers/mariadb.js +2 -2
  113. package/dist/esm/fetchers/mariadb.js.map +1 -1
  114. package/dist/esm/fetchers/mongodb.d.ts.map +1 -1
  115. package/dist/esm/fetchers/mongodb.js +2 -2
  116. package/dist/esm/fetchers/mongodb.js.map +1 -1
  117. package/dist/esm/fetchers/mysql.d.ts.map +1 -1
  118. package/dist/esm/fetchers/mysql.js +2 -2
  119. package/dist/esm/fetchers/mysql.js.map +1 -1
  120. package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
  121. package/dist/esm/fetchers/postgresql.js +2 -2
  122. package/dist/esm/fetchers/postgresql.js.map +1 -1
  123. package/dist/esm/fetchers/redis.d.ts.map +1 -1
  124. package/dist/esm/fetchers/redis.js +2 -2
  125. package/dist/esm/fetchers/redis.js.map +1 -1
  126. package/dist/esm/fetchers/redshift.d.ts.map +1 -1
  127. package/dist/esm/fetchers/redshift.js +3 -3
  128. package/dist/esm/fetchers/redshift.js.map +1 -1
  129. package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
  130. package/dist/esm/fetchers/rest-api.js +3 -3
  131. package/dist/esm/fetchers/rest-api.js.map +1 -1
  132. package/dist/esm/fetchers/supabase.d.ts.map +1 -1
  133. package/dist/esm/fetchers/supabase.js +2 -2
  134. package/dist/esm/fetchers/supabase.js.map +1 -1
  135. package/dist/esm/fetchers/teleport.d.ts +2 -2
  136. package/dist/esm/fetchers/teleport.d.ts.map +1 -1
  137. package/dist/esm/fetchers/teleport.js +2 -2
  138. package/dist/esm/fetchers/teleport.js.map +1 -1
  139. package/dist/esm/fetchers/turso.d.ts.map +1 -1
  140. package/dist/esm/fetchers/turso.js +2 -2
  141. package/dist/esm/fetchers/turso.js.map +1 -1
  142. package/dist/esm/index.d.ts +1 -1
  143. package/dist/esm/index.d.ts.map +1 -1
  144. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  145. package/dist/esm/pagination-plugin.js +1 -1
  146. package/dist/esm/pagination-plugin.js.map +1 -1
  147. package/dist/esm/transformations/blog-post.d.ts +7 -1
  148. package/dist/esm/transformations/blog-post.d.ts.map +1 -1
  149. package/dist/esm/transformations/blog-post.js +4 -2
  150. package/dist/esm/transformations/blog-post.js.map +1 -1
  151. package/dist/esm/transformations/category-taxonomy.d.ts +33 -0
  152. package/dist/esm/transformations/category-taxonomy.d.ts.map +1 -0
  153. package/dist/esm/transformations/category-taxonomy.js +37 -0
  154. package/dist/esm/transformations/category-taxonomy.js.map +1 -0
  155. package/dist/esm/transformations/custom-page.d.ts +18 -0
  156. package/dist/esm/transformations/custom-page.d.ts.map +1 -0
  157. package/dist/esm/transformations/custom-page.js +20 -0
  158. package/dist/esm/transformations/custom-page.js.map +1 -0
  159. package/dist/esm/transformations/ecommerce-product.d.ts.map +1 -1
  160. package/dist/esm/transformations/ecommerce-product.js +3 -36
  161. package/dist/esm/transformations/ecommerce-product.js.map +1 -1
  162. package/dist/esm/transformations/index.d.ts +23 -4
  163. package/dist/esm/transformations/index.d.ts.map +1 -1
  164. package/dist/esm/transformations/index.js +37 -7
  165. package/dist/esm/transformations/index.js.map +1 -1
  166. package/dist/esm/transformations/shared-utils.d.ts.map +1 -1
  167. package/dist/esm/transformations/shared-utils.js +1 -1
  168. package/dist/esm/transformations/shared-utils.js.map +1 -1
  169. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  170. package/dist/esm/utils.d.ts +35 -3
  171. package/dist/esm/utils.d.ts.map +1 -1
  172. package/dist/esm/utils.js +112 -17
  173. package/dist/esm/utils.js.map +1 -1
  174. package/package.json +5 -5
  175. package/src/data-source-fetchers.ts +3 -3
  176. package/src/fetchers/airtable.ts +35 -36
  177. package/src/fetchers/clickhouse.ts +26 -36
  178. package/src/fetchers/csv-file.ts +13 -21
  179. package/src/fetchers/firestore.ts +41 -35
  180. package/src/fetchers/google-sheets.ts +15 -23
  181. package/src/fetchers/javascript.ts +11 -21
  182. package/src/fetchers/mariadb.ts +33 -44
  183. package/src/fetchers/mongodb.ts +66 -81
  184. package/src/fetchers/mysql.ts +33 -45
  185. package/src/fetchers/postgresql.ts +52 -62
  186. package/src/fetchers/redis.ts +6 -5
  187. package/src/fetchers/redshift.ts +29 -41
  188. package/src/fetchers/rest-api.ts +11 -21
  189. package/src/fetchers/supabase.ts +104 -41
  190. package/src/fetchers/teleport.ts +55 -66
  191. package/src/fetchers/turso.ts +27 -39
  192. package/src/index.ts +1 -1
  193. package/src/pagination-plugin.ts +3 -6
  194. package/src/transformations/blog-post.ts +28 -9
  195. package/src/transformations/category-taxonomy.ts +107 -0
  196. package/src/transformations/custom-page.ts +83 -0
  197. package/src/transformations/ecommerce-product.ts +177 -78
  198. package/src/transformations/index.ts +85 -11
  199. package/src/transformations/shared-utils.ts +9 -0
  200. package/src/utils.ts +191 -34
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, } from '../utils';
1
+ import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateFilterTreeHelpersCode, } from '../utils';
2
2
  export var validateRedisConfig = function (config) {
3
3
  if (!config || typeof config !== 'object') {
4
4
  return { isValid: false, error: 'Config must be a valid object' };
@@ -36,6 +36,6 @@ export var generateRedisFetcher = function (config) {
36
36
  if (!connectionString) {
37
37
  connectionString = "redis://".concat(hasUsername ? "".concat(username, ":").concat(password, "@") : '').concat(host, ":").concat(port || 6379);
38
38
  }
39
- return "import { createClient } from 'redis'\n\n".concat(generateSafeJSONParseCode(), "\n\n").concat(generateDateFormatterCode(), "\n\nexport default async function handler(req, res) {\n let client = null\n try {\n client = createClient({\n url: ").concat(replaceSecretReference(connectionString)).concat(database ? ",\n database: ".concat(database) : '', "\n })\n \n await client.connect()\n \n const { query, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n let pattern = query || '*'\n \n // Extract pattern from filters if available (new format)\n if (filters) {\n const parsedFilters = safeJSONParse(filters)\n if (Array.isArray(parsedFilters)) {\n const patternFilter = parsedFilters.find(f => f.source === 'pattern')\n if (patternFilter) {\n pattern = patternFilter.destination || pattern\n }\n } else {\n pattern = parsedFilters.pattern || pattern\n }\n }\n \n const keys = await client.keys(pattern)\n \n const limitValue = limit || perPage || 100\n const skipValue = offset !== undefined ? parseInt(offset) : ((parseInt(page) || 1) - 1) * parseInt(limitValue)\n const paginatedKeys = keys.slice(skipValue, skipValue + parseInt(limitValue))\n \n const results = []\n for (const key of paginatedKeys) {\n const type = await client.type(key)\n const ttl = await client.ttl(key)\n let value\n \n switch (type) {\n case 'string':\n value = await client.get(key)\n break\n case 'list':\n value = await client.lRange(key, 0, -1)\n break\n case 'set':\n value = await client.sMembers(key)\n break\n case 'zset':\n value = await client.zRange(key, 0, -1)\n break\n case 'hash':\n value = await client.hGetAll(key)\n break\n default:\n value = null\n }\n \n results.push({\n key,\n type,\n value,\n ttl: ttl === -1 ? null : ttl\n })\n }\n \n // Handle sorts - new array format\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n const primarySort = parsedSorts[0]\n if (primarySort.field) {\n const sortOrderValue = (primarySort.order || '').toLowerCase().startsWith('desc') ? -1 : 1\n results.sort((a, b) => {\n const aVal = a[primarySort.field]\n const bVal = b[primarySort.field]\n if (aVal < bVal) return -sortOrderValue\n if (aVal > bVal) return sortOrderValue\n return 0\n })\n }\n }\n } else if (sortBy) {\n const sortOrderValue = (sortOrder || '').toLowerCase().startsWith('desc') ? -1 : 1\n results.sort((a, b) => {\n const aVal = a[sortBy]\n const bVal = b[sortBy]\n if (aVal < bVal) return -sortOrderValue\n if (aVal > bVal) return sortOrderValue\n return 0\n })\n }\n \n const safeData = JSON.parse(JSON.stringify(results, dateReplacer))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Redis fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n } finally {\n if (client) {\n await client.quit()\n }\n }\n}\n");
39
+ return "import { createClient } from 'redis'\n\n".concat(generateSafeJSONParseCode(), "\n\n").concat(generateFilterTreeHelpersCode(), "\n\n").concat(generateDateFormatterCode(), "\n\nexport default async function handler(req, res) {\n let client = null\n try {\n client = createClient({\n url: ").concat(replaceSecretReference(connectionString)).concat(database ? ",\n database: ".concat(database) : '', "\n })\n \n await client.connect()\n \n const { query, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n let pattern = query || '*'\n \n // Extract pattern from filters if available (new format)\n if (filters) {\n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n if (filterTree) {\n const patternFilter = flattenFilterConditions(filterTree).find((f) => f.source === 'pattern')\n if (patternFilter) {\n pattern = patternFilter.destination || pattern\n }\n }\n }\n \n const keys = await client.keys(pattern)\n \n const limitValue = limit || perPage || 100\n const skipValue = offset !== undefined ? parseInt(offset) : ((parseInt(page) || 1) - 1) * parseInt(limitValue)\n const paginatedKeys = keys.slice(skipValue, skipValue + parseInt(limitValue))\n \n const results = []\n for (const key of paginatedKeys) {\n const type = await client.type(key)\n const ttl = await client.ttl(key)\n let value\n \n switch (type) {\n case 'string':\n value = await client.get(key)\n break\n case 'list':\n value = await client.lRange(key, 0, -1)\n break\n case 'set':\n value = await client.sMembers(key)\n break\n case 'zset':\n value = await client.zRange(key, 0, -1)\n break\n case 'hash':\n value = await client.hGetAll(key)\n break\n default:\n value = null\n }\n \n results.push({\n key,\n type,\n value,\n ttl: ttl === -1 ? null : ttl\n })\n }\n \n // Handle sorts - new array format\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n const primarySort = parsedSorts[0]\n if (primarySort.field) {\n const sortOrderValue = (primarySort.order || '').toLowerCase().startsWith('desc') ? -1 : 1\n results.sort((a, b) => {\n const aVal = a[primarySort.field]\n const bVal = b[primarySort.field]\n if (aVal < bVal) return -sortOrderValue\n if (aVal > bVal) return sortOrderValue\n return 0\n })\n }\n }\n } else if (sortBy) {\n const sortOrderValue = (sortOrder || '').toLowerCase().startsWith('desc') ? -1 : 1\n results.sort((a, b) => {\n const aVal = a[sortBy]\n const bVal = b[sortBy]\n if (aVal < bVal) return -sortOrderValue\n if (aVal > bVal) return sortOrderValue\n return 0\n })\n }\n \n const safeData = JSON.parse(JSON.stringify(results, dateReplacer))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Redis fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n } finally {\n if (client) {\n await client.quit()\n }\n }\n}\n");
40
40
  };
41
41
  //# sourceMappingURL=redis.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../../src/fetchers/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,UAAU,CAAA;AAEjB,MAAM,CAAC,IAAM,mBAAmB,GAAG,UACjC,MAA+B;IAE/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAA;KAClE;IAED,+CAA+C;IAC/C,IAAI,MAAM,CAAC,gBAAgB,EAAE;QAC3B,IAAI,OAAO,MAAM,CAAC,gBAAgB,KAAK,QAAQ,IAAI,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACxF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,8CAA8C,EAAE,CAAA;SACjF;QAED,uFAAuF;QACvF,IAAM,OAAO,GAAG,MAAM,CAAC,gBAA0B,CAAA;QACjD,IACE,CAAC,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC;YAC1C,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;YAC/B,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,EAChC;YACA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAA;SAC3E;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;KACzB;IAED,kEAAkE;IAClE,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE;QACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,8DAA8D,EAAE,CAAA;KACjG;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AAYD,MAAM,CAAC,IAAM,oBAAoB,GAAG,UAAC,MAA+B;IAClE,IAAM,WAAW,GAAG,MAAqB,CAAA;IACzC,IAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAA;IAC7B,IAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAA;IAC7B,IAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAA;IACrC,IAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAA;IACrC,IAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAA;IACrC,IAAM,WAAW,GAAG,QAAQ,CAAA;IAE5B,qDAAqD;IACrD,IAAI,gBAAgB,GAAG,WAAW,CAAC,gBAAgB,CAAA;IACnD,IAAI,CAAC,gBAAgB,EAAE;QACrB,gBAAgB,GAAG,kBAAW,WAAW,CAAC,CAAC,CAAC,UAAG,QAAQ,cAAI,QAAQ,MAAG,CAAC,CAAC,CAAC,EAAE,SAAG,IAAI,cAChF,IAAI,IAAI,IAAI,CACZ,CAAA;KACH;IAED,OAAO,kDAEP,yBAAyB,EAAE,iBAE3B,yBAAyB,EAAE,0IAMhB,sBAAsB,CAAC,gBAAgB,CAAC,SACjD,QAAQ,CAAC,CAAC,CAAC,6BAAsB,QAAQ,CAAE,CAAC,CAAC,CAAC,EAAE,4qGA8GnD,CAAA;AACD,CAAC,CAAA"}
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../../src/fetchers/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,UAAU,CAAA;AAEjB,MAAM,CAAC,IAAM,mBAAmB,GAAG,UACjC,MAA+B;IAE/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAA;KAClE;IAED,+CAA+C;IAC/C,IAAI,MAAM,CAAC,gBAAgB,EAAE;QAC3B,IAAI,OAAO,MAAM,CAAC,gBAAgB,KAAK,QAAQ,IAAI,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YACxF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,8CAA8C,EAAE,CAAA;SACjF;QAED,uFAAuF;QACvF,IAAM,OAAO,GAAG,MAAM,CAAC,gBAA0B,CAAA;QACjD,IACE,CAAC,OAAO,CAAC,UAAU,CAAC,qBAAqB,CAAC;YAC1C,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;YAC/B,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,EAChC;YACA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAA;SAC3E;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;KACzB;IAED,kEAAkE;IAClE,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE;QACnD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,8DAA8D,EAAE,CAAA;KACjG;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AAYD,MAAM,CAAC,IAAM,oBAAoB,GAAG,UAAC,MAA+B;IAClE,IAAM,WAAW,GAAG,MAAqB,CAAA;IACzC,IAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAA;IAC7B,IAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAA;IAC7B,IAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAA;IACrC,IAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAA;IACrC,IAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAA;IACrC,IAAM,WAAW,GAAG,QAAQ,CAAA;IAE5B,qDAAqD;IACrD,IAAI,gBAAgB,GAAG,WAAW,CAAC,gBAAgB,CAAA;IACnD,IAAI,CAAC,gBAAgB,EAAE;QACrB,gBAAgB,GAAG,kBAAW,WAAW,CAAC,CAAC,CAAC,UAAG,QAAQ,cAAI,QAAQ,MAAG,CAAC,CAAC,CAAC,EAAE,SAAG,IAAI,cAChF,IAAI,IAAI,IAAI,CACZ,CAAA;KACH;IAED,OAAO,kDAEP,yBAAyB,EAAE,iBAE3B,6BAA6B,EAAE,iBAE/B,yBAAyB,EAAE,0IAMhB,sBAAsB,CAAC,gBAAgB,CAAC,SACjD,QAAQ,CAAC,CAAC,CAAC,6BAAsB,QAAQ,CAAE,CAAC,CAAC,CAAC,EAAE,goGA4GnD,CAAA;AACD,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"redshift.d.ts","sourceRoot":"","sources":["../../../src/fetchers/redshift.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,uBAAuB,WAC1B,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,KAChB,MAwNF,CAAA"}
1
+ {"version":3,"file":"redshift.d.ts","sourceRoot":"","sources":["../../../src/fetchers/redshift.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,uBAAuB,WAC1B,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,KAChB,MA2MF,CAAA"}
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateSearchEscapeHelpersCode, } from '../utils';
1
+ import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateFilterTreeHelpersCode, generateSearchEscapeHelpersCode, } from '../utils';
2
2
  export var generateRedshiftFetcher = function (config, tableName) {
3
3
  var _a;
4
4
  var redshiftConfig = config;
@@ -15,8 +15,8 @@ export var generateRedshiftFetcher = function (config, tableName) {
15
15
  : sslConfig
16
16
  ? "{\n ".concat(sslConfig.ca ? "ca: ".concat(replaceSecretReference(sslConfig.ca), ",") : '', "\n ").concat(sslConfig.cert ? "cert: ".concat(replaceSecretReference(sslConfig.cert), ",") : '', "\n ").concat(sslConfig.key ? "key: ".concat(replaceSecretReference(sslConfig.key), ",") : '', "\n rejectUnauthorized: ").concat(sslConfig.rejectUnauthorized !== false, "\n }")
17
17
  : '{ rejectUnauthorized: false }' // Default to SSL with no cert verification for Redshift
18
- , "\n })\n}\n\n").concat(generateSafeJSONParseCode(), "\n\n").concat(generateSearchEscapeHelpersCode(), "\n\n").concat(generateDateFormatterCode(), "\n\nexport default async function handler(req, res) {\n const client = getClient()\n \n try {\n await client.connect()\n ").concat(schema ? "await client.query('SET search_path TO ".concat(schema, "')") : '', "\n \n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n const conditions = []\n const queryParams = []\n let paramIndex = 1\n \n if (query) {\n let columns = []\n \n if (queryColumns) {\n const parsed = safeJSONParse(queryColumns)\n columns = Array.isArray(parsed) ? parsed : [parsed]\n } else {\n // Fallback: Get all columns from information_schema\n try {\n const schemaQuery = 'SELECT column_name FROM information_schema.columns WHERE table_name = $1' + \n ").concat(schema ? "' AND table_schema = $2'" : "''", " + \n ' ORDER BY ordinal_position'\n const schemaParams = ").concat(schema
18
+ , "\n })\n}\n\n").concat(generateSafeJSONParseCode(), "\n\n").concat(generateFilterTreeHelpersCode(), "\n\n").concat(generateSearchEscapeHelpersCode(), "\n\n").concat(generateDateFormatterCode(), "\n\nexport default async function handler(req, res) {\n const client = getClient()\n \n try {\n await client.connect()\n ").concat(schema ? "await client.query('SET search_path TO ".concat(schema, "')") : '', "\n \n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n const conditions = []\n const queryParams = []\n let paramIndex = 1\n \n if (query) {\n let columns = []\n \n if (queryColumns) {\n const parsed = safeJSONParse(queryColumns)\n columns = Array.isArray(parsed) ? parsed : [parsed]\n } else {\n // Fallback: Get all columns from information_schema\n try {\n const schemaQuery = 'SELECT column_name FROM information_schema.columns WHERE table_name = $1' + \n ").concat(schema ? "' AND table_schema = $2'" : "''", " + \n ' ORDER BY ordinal_position'\n const schemaParams = ").concat(schema
19
19
  ? "[".concat(JSON.stringify(tableName), ", ").concat(JSON.stringify(schema), "]")
20
- : "[".concat(JSON.stringify(tableName), "]"), "\n const schemaResult = await client.query(schemaQuery, schemaParams)\n columns = schemaResult.rows.map(row => row.column_name)\n } catch (schemaError) {\n console.warn('Failed to fetch column names from information_schema:', schemaError.message)\n }\n }\n \n if (columns.length > 0) {\n const pattern = '%' + escapeLikePattern(query) + '%'\n const placeholder = '$' + paramIndex\n paramIndex++\n queryParams.push(pattern)\n const searchConditions = columns.map(\n (col) => '\"' + sanitizeSearchIdentifier(col) + '\"::text ILIKE ' + placeholder + \" ESCAPE '|'\"\n )\n conditions.push('(' + searchConditions.join(' OR ') + ')')\n }\n }\n \n // Helper to sanitize identifier (prevent SQL injection in column names)\n const sanitizeIdentifier = (name) => {\n // Only allow alphanumeric, underscore, and dot (for schema.table)\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n throw new Error(`Invalid identifier: ${name}`)\n }\n return `\"${name}\"`\n }\n \n if (filters) {\n const parsedFilters = safeJSONParse(filters)\n \n if (Array.isArray(parsedFilters)) {\n parsedFilters.forEach((filter) => {\n if (!filter.source || filter.destination === undefined) return\n \n const field = sanitizeIdentifier(filter.source)\n const value = filter.destination\n const operand = filter.operand || '='\n \n if (Array.isArray(value)) {\n if (value.length === 0) return\n const placeholders = value.map(() => `$${paramIndex++}`)\n queryParams.push(...value)\n if (operand === '!=') {\n conditions.push(`${field} NOT IN (${placeholders.join(', ')})`)\n } else {\n conditions.push(`${field} IN (${placeholders.join(', ')})`)\n }\n } else {\n if (value === null) {\n if (operand === '=') {\n conditions.push(`${field} IS NULL`)\n } else if (operand === '!=') {\n conditions.push(`${field} IS NOT NULL`)\n }\n } else {\n const validOps = ['=', '!=', '>', '<', '>=', '<=']\n const sqlOperator = validOps.includes(operand) ? operand : '='\n conditions.push(`${field} ${sqlOperator} $${paramIndex}`)\n queryParams.push(value)\n paramIndex++\n }\n }\n })\n } else {\n Object.entries(parsedFilters).forEach(([key, value]) => {\n const field = sanitizeIdentifier(key)\n if (Array.isArray(value)) {\n const placeholders = value.map(() => `$${paramIndex++}`)\n queryParams.push(...value)\n conditions.push(`${field} IN (${placeholders.join(', ')})`)\n } else {\n conditions.push(`${field} = $${paramIndex}`)\n queryParams.push(value)\n paramIndex++\n }\n })\n }\n }\n \n let sql = `SELECT * FROM ").concat(tableName, "`\n \n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`\n }\n \n // Handle sorts - new array format\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n const orderClauses = parsedSorts.map((sort) => {\n if (!sort.field) return null\n const order = (sort.order || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'\n return `${sanitizeIdentifier(sort.field)} ${order}`\n }).filter(Boolean)\n\n if (orderClauses.length > 0) {\n sql += ` ORDER BY ${orderClauses.join(', ')}`\n }\n }\n } else if (sortBy) {\n sql += ` ORDER BY ${sanitizeIdentifier(sortBy)} ${(sortOrder || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'}`\n }\n \n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n \n if (limitValue) {\n sql += ` LIMIT ${limitValue}`\n }\n \n if (offsetValue !== undefined) {\n sql += ` OFFSET ${offsetValue}`\n }\n \n const result = await client.query(sql, queryParams)\n const rows = Array.isArray(result?.rows) ? result.rows : []\n const plainRows = rows.map((row) =>\n row && typeof row.toJSON === 'function' ? row.toJSON() : row\n )\n const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))\n\n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Redshift fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n } finally {\n if (client) {\n try {\n await client.end()\n } catch (error) {\n console.error('Error closing Redshift client:', error)\n }\n }\n }\n}\n");
20
+ : "[".concat(JSON.stringify(tableName), "]"), "\n const schemaResult = await client.query(schemaQuery, schemaParams)\n columns = schemaResult.rows.map(row => row.column_name)\n } catch (schemaError) {\n console.warn('Failed to fetch column names from information_schema:', schemaError.message)\n }\n }\n \n if (columns.length > 0) {\n const pattern = '%' + escapeLikePattern(query) + '%'\n const placeholder = '$' + paramIndex\n paramIndex++\n queryParams.push(pattern)\n const searchConditions = columns.map(\n (col) => '\"' + sanitizeSearchIdentifier(col) + '\"::text ILIKE ' + placeholder + \" ESCAPE '|'\"\n )\n conditions.push('(' + searchConditions.join(' OR ') + ')')\n }\n }\n \n // Helper to sanitize identifier (prevent SQL injection in column names)\n const sanitizeIdentifier = (name) => {\n // Only allow alphanumeric, underscore, and dot (for schema.table)\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n throw new Error(`Invalid identifier: ${name}`)\n }\n return `\"${name}\"`\n }\n \n if (filters) {\n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n const buildCondition = (condition) => {\n const field = sanitizeIdentifier(condition.source)\n const value = condition.destination\n const operand = condition.operand\n \n if (Array.isArray(value)) {\n if (value.length === 0) return null\n const placeholders = value.map(() => `$${paramIndex++}`)\n queryParams.push(...value)\n return operand === '!='\n ? `${field} NOT IN (${placeholders.join(', ')})`\n : `${field} IN (${placeholders.join(', ')})`\n }\n \n if (value === null) {\n if (operand === '=') return `${field} IS NULL`\n if (operand === '!=') return `${field} IS NOT NULL`\n return null\n }\n \n const validOps = ['=', '!=', '>', '<', '>=', '<=']\n const sqlOperator = validOps.includes(operand) ? operand : '='\n const clause = `${field} ${sqlOperator} $${paramIndex}`\n queryParams.push(value)\n paramIndex++\n return clause\n }\n \n const clause = buildFilterTreeClause(filterTree, buildCondition)\n if (clause) conditions.push(clause)\n }\n }\n \n let sql = `SELECT * FROM ").concat(tableName, "`\n \n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`\n }\n \n // Handle sorts - new array format\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n const orderClauses = parsedSorts.map((sort) => {\n if (!sort.field) return null\n const order = (sort.order || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'\n return `${sanitizeIdentifier(sort.field)} ${order}`\n }).filter(Boolean)\n\n if (orderClauses.length > 0) {\n sql += ` ORDER BY ${orderClauses.join(', ')}`\n }\n }\n } else if (sortBy) {\n sql += ` ORDER BY ${sanitizeIdentifier(sortBy)} ${(sortOrder || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'}`\n }\n \n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n \n if (limitValue) {\n sql += ` LIMIT ${limitValue}`\n }\n \n if (offsetValue !== undefined) {\n sql += ` OFFSET ${offsetValue}`\n }\n \n const result = await client.query(sql, queryParams)\n const rows = Array.isArray(result?.rows) ? result.rows : []\n const plainRows = rows.map((row) =>\n row && typeof row.toJSON === 'function' ? row.toJSON() : row\n )\n const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))\n\n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Redshift fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n } finally {\n if (client) {\n try {\n await client.end()\n } catch (error) {\n console.error('Error closing Redshift client:', error)\n }\n }\n }\n}\n");
21
21
  };
22
22
  //# sourceMappingURL=redshift.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redshift.js","sourceRoot":"","sources":["../../../src/fetchers/redshift.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,UAAU,CAAA;AAajB,MAAM,CAAC,IAAM,uBAAuB,GAAG,UACrC,MAA+B,EAC/B,SAAiB;;IAEjB,IAAM,cAAc,GAAG,MAAwB,CAAA;IAC/C,IAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAA;IAChC,IAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAA;IAChC,IAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAA;IAChC,IAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAA;IACxC,IAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAA;IACxC,IAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAA;IAC9B,IAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAA;IAC1C,IAAM,MAAM,GAAG,MAAA,cAAc,CAAC,OAAO,0CAAE,MAAM,CAAA;IAE7C,OAAO,qGAIG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,0BACpB,IAAI,IAAI,IAAI,0BACZ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,8BAChB,sBAAsB,CAAC,QAAQ,CAAC,8BAChC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,yBAElC,GAAG,KAAK,KAAK;QACX,CAAC,CAAC,+BAA+B;QACjC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,mBACF,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,cAAO,sBAAsB,CAAC,SAAS,CAAC,EAAE,CAAC,MAAG,CAAC,CAAC,CAAC,EAAE,qBAClE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAS,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,MAAG,CAAC,CAAC,CAAC,EAAE,qBACxE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,eAAQ,sBAAsB,CAAC,SAAS,CAAC,GAAG,CAAC,MAAG,CAAC,CAAC,CAAC,EAAE,yCACjD,SAAS,CAAC,kBAAkB,KAAK,KAAK,YAC5D;YACE,CAAC,CAAC,+BAA+B,CAAC,wDAAwD;8BAKhG,yBAAyB,EAAE,iBAE3B,+BAA+B,EAAE,iBAEjC,yBAAyB,EAAE,+IAOvB,MAAM,CAAC,CAAC,CAAC,iDAA0C,MAAM,OAAI,CAAC,CAAC,CAAC,EAAE,onBAkB1D,MAAM,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,IAAI,2FAG5C,MAAM;QACJ,CAAC,CAAC,WAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,eAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAG;QAC7D,CAAC,CAAC,WAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAG,mlGAkFhB,SAAS,4/DAgExC,CAAA;AACD,CAAC,CAAA"}
1
+ {"version":3,"file":"redshift.js","sourceRoot":"","sources":["../../../src/fetchers/redshift.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,6BAA6B,EAC7B,+BAA+B,GAChC,MAAM,UAAU,CAAA;AAajB,MAAM,CAAC,IAAM,uBAAuB,GAAG,UACrC,MAA+B,EAC/B,SAAiB;;IAEjB,IAAM,cAAc,GAAG,MAAwB,CAAA;IAC/C,IAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAA;IAChC,IAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAA;IAChC,IAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAA;IAChC,IAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAA;IACxC,IAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAA;IACxC,IAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAA;IAC9B,IAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAA;IAC1C,IAAM,MAAM,GAAG,MAAA,cAAc,CAAC,OAAO,0CAAE,MAAM,CAAA;IAE7C,OAAO,qGAIG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,0BACpB,IAAI,IAAI,IAAI,0BACZ,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,8BAChB,sBAAsB,CAAC,QAAQ,CAAC,8BAChC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,yBAElC,GAAG,KAAK,KAAK;QACX,CAAC,CAAC,+BAA+B;QACjC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,mBACF,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,cAAO,sBAAsB,CAAC,SAAS,CAAC,EAAE,CAAC,MAAG,CAAC,CAAC,CAAC,EAAE,qBAClE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAS,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,MAAG,CAAC,CAAC,CAAC,EAAE,qBACxE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,eAAQ,sBAAsB,CAAC,SAAS,CAAC,GAAG,CAAC,MAAG,CAAC,CAAC,CAAC,EAAE,yCACjD,SAAS,CAAC,kBAAkB,KAAK,KAAK,YAC5D;YACE,CAAC,CAAC,+BAA+B,CAAC,wDAAwD;8BAKhG,yBAAyB,EAAE,iBAE3B,6BAA6B,EAAE,iBAE/B,+BAA+B,EAAE,iBAEjC,yBAAyB,EAAE,+IAOvB,MAAM,CAAC,CAAC,CAAC,iDAA0C,MAAM,OAAI,CAAC,CAAC,CAAC,EAAE,onBAkB1D,MAAM,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,IAAI,2FAG5C,MAAM;QACJ,CAAC,CAAC,WAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,eAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAG;QAC7D,CAAC,CAAC,WAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,MAAG,6+EAmEhB,SAAS,4/DAgExC,CAAA;AACD,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,WACxB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CA0BpC,CAAA;AA2CD,eAAO,MAAM,sBAAsB,WAAY,OAAO,MAAM,EAAE,OAAO,CAAC,KAAG,MAqNxE,CAAA"}
1
+ {"version":3,"file":"rest-api.d.ts","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,qBAAqB,WACxB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CA0BpC,CAAA;AA2CD,eAAO,MAAM,sBAAsB,WAAY,OAAO,MAAM,EAAE,OAAO,CAAC,KAAG,MA0MxE,CAAA"}
@@ -1,4 +1,4 @@
1
- import { generateDateFormatterCode, generateSortFilterHelperCode, generateSafeJSONParseCode, } from '../utils';
1
+ import { generateDateFormatterCode, generateSortFilterHelperCode, generateSafeJSONParseCode, generateFilterTreeHelpersCode, } from '../utils';
2
2
  export var validateRESTAPIConfig = function (config) {
3
3
  if (!config || typeof config !== 'object') {
4
4
  return { isValid: false, error: 'Config must be a valid object' };
@@ -45,10 +45,10 @@ var generateAuthCode = function (authorization) {
45
45
  export var generateRESTAPIFetcher = function (config) {
46
46
  var restConfig = config;
47
47
  var authCode = generateAuthCode(restConfig.authorization || {});
48
- return "import fetch from 'node-fetch'\n\n".concat(generateSafeJSONParseCode(), "\n\n").concat(generateDateFormatterCode(), "\n\n").concat(generateSortFilterHelperCode(), "\n\nexport default async function handler(req, res) {\n try {\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = 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'
48
+ return "import fetch from 'node-fetch'\n\n".concat(generateSafeJSONParseCode(), "\n\n").concat(generateDateFormatterCode(), "\n\n").concat(generateSortFilterHelperCode(), "\n\n").concat(generateFilterTreeHelpersCode(), "\n\nexport default async function handler(req, res) {\n try {\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = 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'
49
49
  ? "\n if (req.body) {\n options.body = ".concat(restConfig.bodyType === 'json' || !restConfig.bodyType
50
50
  ? 'JSON.stringify(req.body)'
51
51
  : 'req.body', "\n }\n ")
52
- : '', "\n \n const response = await fetch(url, options)\n \n if (!response.ok) {\n return res.status(response.status).json({\n success: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n timestamp: Date.now()\n })\n }\n \n let data = await response.json()\n \n if (Array.isArray(data)) {\n if (query && query.trim()) {\n const searchQuery = query.toLowerCase()\n \n if (queryColumns) {\n try {\n const parsed = safeJSONParse(queryColumns)\n const columns = Array.isArray(parsed) ? parsed : [parsed]\n data = data.filter((item) => {\n return columns.some((col) => {\n const value = getNestedValue(item, col)\n if (value === null || value === undefined) return false\n return String(value).toLowerCase().includes(searchQuery)\n })\n })\n } catch (err) {\n console.error('Error parsing queryColumns:', err)\n }\n } else {\n data = data.filter((item) => {\n try {\n const stringified = JSON.stringify(item).toLowerCase()\n return stringified.includes(searchQuery)\n } catch {\n return false\n }\n })\n }\n }\n \n if (filters) {\n try {\n const parsedFilters = safeJSONParse(filters)\n \n if (Array.isArray(parsedFilters)) {\n data = data.filter((item) => {\n return parsedFilters.every((filter) => {\n if (!filter.source || filter.destination === undefined) return true\n \n const field = filter.source\n const value = getNestedValue(item, field)\n const target = filter.destination\n const operand = filter.operand || '='\n \n if (Array.isArray(target)) {\n if (operand === '!=') {\n return !target.includes(value)\n }\n return target.includes(value)\n }\n \n return compareValues(value, target, operand)\n })\n })\n } else {\n data = data.filter((item) => {\n return Object.entries(parsedFilters).every(([key, value]) => {\n const itemValue = getNestedValue(item, key)\n if (Array.isArray(value)) {\n return value.includes(itemValue)\n }\n return compareValues(itemValue, value, '=')\n })\n })\n }\n } catch (err) {\n console.error('Error parsing filters:', err)\n }\n }\n \n if (sorts) {\n try {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n data.sort((a, b) => {\n for (const sort of parsedSorts) {\n if (!sort.field) continue\n const aVal = getNestedValue(a, sort.field)\n const bVal = getNestedValue(b, sort.field)\n const sortOrderValue = (sort.order || '').toLowerCase().startsWith('desc') ? -1 : 1\n \n let comparison = 0\n if (aVal === null || aVal === undefined) {\n comparison = bVal === null || bVal === undefined ? 0 : -1\n } else if (bVal === null || bVal === undefined) {\n comparison = 1\n } else if (typeof aVal === 'number' && typeof bVal === 'number') {\n comparison = aVal - bVal\n } else if (aVal instanceof Date && bVal instanceof Date) {\n comparison = aVal.getTime() - bVal.getTime()\n } else {\n const aStr = String(aVal)\n const bStr = String(bVal)\n if (aStr < bStr) comparison = -1\n else if (aStr > bStr) comparison = 1\n }\n \n if (comparison !== 0) return comparison * sortOrderValue\n }\n return 0\n })\n }\n } catch (err) {\n console.error('Error parsing sorts:', err)\n }\n } else if (sortBy && sortBy.trim()) {\n data.sort((a, b) => {\n const aVal = getNestedValue(a, sortBy)\n const bVal = getNestedValue(b, sortBy)\n const sortOrderValue = (sortOrder || '').toLowerCase().startsWith('desc') ? -1 : 1\n \n let comparison = 0\n if (aVal === null || aVal === undefined) {\n comparison = bVal === null || bVal === undefined ? 0 : -1\n } else if (bVal === null || bVal === undefined) {\n comparison = 1\n } else if (typeof aVal === 'number' && typeof bVal === 'number') {\n comparison = aVal - bVal\n } else if (aVal instanceof Date && bVal instanceof Date) {\n comparison = aVal.getTime() - bVal.getTime()\n } else {\n const aStr = String(aVal)\n const bStr = String(bVal)\n if (aStr < bStr) comparison = -1\n else if (aStr > bStr) comparison = 1\n }\n \n return comparison * sortOrderValue\n })\n }\n \n const limitValue = limit || perPage\n const pageValue = page ? Math.max(1, parseInt(page)) : undefined\n const offsetValue = offset !== undefined ? Math.max(0, parseInt(offset)) : (pageValue && perPage ? (pageValue - 1) * Math.max(1, parseInt(perPage)) : 0)\n \n if (limitValue) {\n const limitInt = Math.max(1, parseInt(limitValue))\n data = data.slice(offsetValue, offsetValue + limitInt)\n } else if (offsetValue > 0) {\n data = data.slice(offsetValue)\n }\n }\n \n const safeData = JSON.parse(JSON.stringify(data, dateReplacer))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('REST API fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n }\n}\n");
52
+ : '', "\n \n const response = await fetch(url, options)\n \n if (!response.ok) {\n return res.status(response.status).json({\n success: false,\n error: `HTTP ${response.status}: ${response.statusText}`,\n timestamp: Date.now()\n })\n }\n \n let data = await response.json()\n \n if (Array.isArray(data)) {\n if (query && query.trim()) {\n const searchQuery = query.toLowerCase()\n \n if (queryColumns) {\n try {\n const parsed = safeJSONParse(queryColumns)\n const columns = Array.isArray(parsed) ? parsed : [parsed]\n data = data.filter((item) => {\n return columns.some((col) => {\n const value = getNestedValue(item, col)\n if (value === null || value === undefined) return false\n return String(value).toLowerCase().includes(searchQuery)\n })\n })\n } catch (err) {\n console.error('Error parsing queryColumns:', err)\n }\n } else {\n data = data.filter((item) => {\n try {\n const stringified = JSON.stringify(item).toLowerCase()\n return stringified.includes(searchQuery)\n } catch {\n return false\n }\n })\n }\n }\n \n if (filters) {\n try {\n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n data = data.filter((item) =>\n evaluateFilterTree(filterTree, (condition) => {\n const value = getNestedValue(item, condition.source)\n const target = condition.destination\n const operand = condition.operand\n \n if (Array.isArray(target)) {\n if (operand === '!=') {\n return !target.includes(value)\n }\n return target.includes(value)\n }\n \n return compareValues(value, target, operand)\n })\n )\n }\n } catch (err) {\n console.error('Error parsing filters:', err)\n }\n }\n \n if (sorts) {\n try {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n data.sort((a, b) => {\n for (const sort of parsedSorts) {\n if (!sort.field) continue\n const aVal = getNestedValue(a, sort.field)\n const bVal = getNestedValue(b, sort.field)\n const sortOrderValue = (sort.order || '').toLowerCase().startsWith('desc') ? -1 : 1\n \n let comparison = 0\n if (aVal === null || aVal === undefined) {\n comparison = bVal === null || bVal === undefined ? 0 : -1\n } else if (bVal === null || bVal === undefined) {\n comparison = 1\n } else if (typeof aVal === 'number' && typeof bVal === 'number') {\n comparison = aVal - bVal\n } else if (aVal instanceof Date && bVal instanceof Date) {\n comparison = aVal.getTime() - bVal.getTime()\n } else {\n const aStr = String(aVal)\n const bStr = String(bVal)\n if (aStr < bStr) comparison = -1\n else if (aStr > bStr) comparison = 1\n }\n \n if (comparison !== 0) return comparison * sortOrderValue\n }\n return 0\n })\n }\n } catch (err) {\n console.error('Error parsing sorts:', err)\n }\n } else if (sortBy && sortBy.trim()) {\n data.sort((a, b) => {\n const aVal = getNestedValue(a, sortBy)\n const bVal = getNestedValue(b, sortBy)\n const sortOrderValue = (sortOrder || '').toLowerCase().startsWith('desc') ? -1 : 1\n \n let comparison = 0\n if (aVal === null || aVal === undefined) {\n comparison = bVal === null || bVal === undefined ? 0 : -1\n } else if (bVal === null || bVal === undefined) {\n comparison = 1\n } else if (typeof aVal === 'number' && typeof bVal === 'number') {\n comparison = aVal - bVal\n } else if (aVal instanceof Date && bVal instanceof Date) {\n comparison = aVal.getTime() - bVal.getTime()\n } else {\n const aStr = String(aVal)\n const bStr = String(bVal)\n if (aStr < bStr) comparison = -1\n else if (aStr > bStr) comparison = 1\n }\n \n return comparison * sortOrderValue\n })\n }\n \n const limitValue = limit || perPage\n const pageValue = page ? Math.max(1, parseInt(page)) : undefined\n const offsetValue = offset !== undefined ? Math.max(0, parseInt(offset)) : (pageValue && perPage ? (pageValue - 1) * Math.max(1, parseInt(perPage)) : 0)\n \n if (limitValue) {\n const limitInt = Math.max(1, parseInt(limitValue))\n data = data.slice(offsetValue, offsetValue + limitInt)\n } else if (offsetValue > 0) {\n data = data.slice(offsetValue)\n }\n }\n \n const safeData = JSON.parse(JSON.stringify(data, dateReplacer))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('REST API fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n }\n}\n");
53
53
  };
54
54
  //# sourceMappingURL=rest-api.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rest-api.js","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,GAC1B,MAAM,UAAU,CAAA;AAEjB,MAAM,CAAC,IAAM,qBAAqB,GAAG,UACnC,MAA+B;IAE/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAA;KAClE;IAED,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC7E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAA;KACpD;IAED,IAAI;QACF,IAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC/B,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YAC/C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAA;SACxE;KACF;IAAC,WAAM;QACN,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAA;KACvD;IAED,IAAI,MAAM,CAAC,MAAM,EAAE;QACjB,IAAM,YAAY,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;QAC9D,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,EAAE;YAC5F,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAA;SACxD;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AAaD,IAAM,gBAAgB,GAAG,UAAC,aAA4B;IACpD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,IAAI,KAAK,MAAM,EAAE;QACnD,OAAO,EAAE,CAAA;KACV;IAEO,IAAA,IAAI,GAAkB,aAAa,KAA/B,EAAE,WAAW,GAAK,aAAa,YAAlB,CAAkB;IAE3C,QAAQ,IAAI,EAAE;QACZ,KAAK,SAAS;YACZ,OAAO,6CAAsC,WAAW,CAAC,MAAM,MAAG,CAAA;QACpE,KAAK,cAAc,CAAC;QACpB,KAAK,YAAY;YACf,OAAO,6CAAsC,WAAW,CAAC,KAAK,MAAG,CAAA;QACnE,KAAK,YAAY;YACf,OAAO,6DAAsD,WAAW,CAAC,QAAQ,cAAI,WAAW,CAAC,QAAQ,0BAAuB,CAAA;QAClI,KAAK,QAAQ;YACX,OAAO,6CAAsC,WAAW,CAAC,YAAY,MAAG,CAAA;QAC1E;YACE,OAAO,EAAE,CAAA;KACZ;AACH,CAAC,CAAA;AAUD,MAAM,CAAC,IAAM,sBAAsB,GAAG,UAAC,MAA+B;IACpE,IAAM,UAAU,GAAG,MAAuB,CAAA;IAC1C,IAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,aAAa,IAAI,EAAE,CAAC,CAAA;IAEjE,OAAO,4CAEP,yBAAyB,EAAE,iBAE3B,yBAAyB,EAAE,iBAE3B,4BAA4B,EAAE,mNAMd,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,kCAC3B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,yCAEzC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,IAAI,EAAE,CAAC,mBACxD,QAAQ,2FAQR,UAAU,CAAC,MAAM,KAAK,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,KAAK,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO;QAC1F,CAAC,CAAC,sDAGF,UAAU,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ;YACpD,CAAC,CAAC,0BAA0B;YAC5B,CAAC,CAAC,UAAU,kBAGjB;QACG,CAAC,CAAC,EAAE,gxMA8KX,CAAA;AACD,CAAC,CAAA"}
1
+ {"version":3,"file":"rest-api.js","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,4BAA4B,EAC5B,yBAAyB,EACzB,6BAA6B,GAC9B,MAAM,UAAU,CAAA;AAEjB,MAAM,CAAC,IAAM,qBAAqB,GAAG,UACnC,MAA+B;IAE/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAA;KAClE;IAED,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC7E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAA;KACpD;IAED,IAAI;QACF,IAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAC/B,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;YAC/C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAA;SACxE;KACF;IAAC,WAAM;QACN,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAA;KACvD;IAED,IAAI,MAAM,CAAC,MAAM,EAAE;QACjB,IAAM,YAAY,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAA;QAC9D,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,EAAE;YAC5F,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAA;SACxD;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AAaD,IAAM,gBAAgB,GAAG,UAAC,aAA4B;IACpD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,IAAI,KAAK,MAAM,EAAE;QACnD,OAAO,EAAE,CAAA;KACV;IAEO,IAAA,IAAI,GAAkB,aAAa,KAA/B,EAAE,WAAW,GAAK,aAAa,YAAlB,CAAkB;IAE3C,QAAQ,IAAI,EAAE;QACZ,KAAK,SAAS;YACZ,OAAO,6CAAsC,WAAW,CAAC,MAAM,MAAG,CAAA;QACpE,KAAK,cAAc,CAAC;QACpB,KAAK,YAAY;YACf,OAAO,6CAAsC,WAAW,CAAC,KAAK,MAAG,CAAA;QACnE,KAAK,YAAY;YACf,OAAO,6DAAsD,WAAW,CAAC,QAAQ,cAAI,WAAW,CAAC,QAAQ,0BAAuB,CAAA;QAClI,KAAK,QAAQ;YACX,OAAO,6CAAsC,WAAW,CAAC,YAAY,MAAG,CAAA;QAC1E;YACE,OAAO,EAAE,CAAA;KACZ;AACH,CAAC,CAAA;AAUD,MAAM,CAAC,IAAM,sBAAsB,GAAG,UAAC,MAA+B;IACpE,IAAM,UAAU,GAAG,MAAuB,CAAA;IAC1C,IAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,CAAC,aAAa,IAAI,EAAE,CAAC,CAAA;IAEjE,OAAO,4CAEP,yBAAyB,EAAE,iBAE3B,yBAAyB,EAAE,iBAE3B,4BAA4B,EAAE,iBAE9B,6BAA6B,EAAE,mNAMf,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,kCAC3B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,yCAEzC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,IAAI,EAAE,CAAC,mBACxD,QAAQ,2FAQR,UAAU,CAAC,MAAM,KAAK,MAAM,IAAI,UAAU,CAAC,MAAM,KAAK,KAAK,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO;QAC1F,CAAC,CAAC,sDAGF,UAAU,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ;YACpD,CAAC,CAAC,0BAA0B;YAC5B,CAAC,CAAC,UAAU,kBAGjB;QACG,CAAC,CAAC,EAAE,4uLAiKX,CAAA;AACD,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../../src/fetchers/supabase.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,sBAAsB,WACzB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CA0BpC,CAAA;AAUD,eAAO,MAAM,uBAAuB,WAC1B,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,KAChB,MAyTF,CAAA;AAGD,eAAO,MAAM,4BAA4B,YAAa,GAAG,aAAa,MAAM,KAAG,MAwF9E,CAAA"}
1
+ {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../../src/fetchers/supabase.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,sBAAsB,WACzB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CA0BpC,CAAA;AAUD,eAAO,MAAM,uBAAuB,WAC1B,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,KAChB,MAuXF,CAAA;AAGD,eAAO,MAAM,4BAA4B,YAAa,GAAG,aAAa,MAAM,KAAG,MAwF9E,CAAA"}
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateSearchEscapeHelpersCode, } from '../utils';
1
+ import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateSearchEscapeHelpersCode, generateFilterTreeHelpersCode, } from '../utils';
2
2
  export var validateSupabaseConfig = function (config) {
3
3
  if (!config || typeof config !== 'object') {
4
4
  return { isValid: false, error: 'Config must be a valid object' };
@@ -87,7 +87,7 @@ export var generateSupabaseFetcher = function (config, tableName) {
87
87
  END $$;
88
88
 
89
89
  */
90
- return "import { createClient } from '@supabase/supabase-js'\n\nlet client = null\n\nconst getClient = () => {\n if (client) return client\n \n client = createClient(\n ".concat(JSON.stringify(supabaseUrl), ",\n ").concat(replaceSecretReference(apiKey), "\n )\n \n return client\n}\n\n").concat(generateSafeJSONParseCode(), "\n\n").concat(generateSearchEscapeHelpersCode(), "\n\n// Helper function to process filter values\nconst processFilterValue = (value) => {\n if (typeof value === 'string' && !isNaN(Number(value))) {\n return Number(value)\n }\n return value\n}\n\n// Helper function to apply filters to a query\nconst applyFilters = (queryRef, filters) => {\n if (!filters) return queryRef\n \n const parsedFilters = safeJSONParse(filters)\n \n if (Array.isArray(parsedFilters)) {\n parsedFilters.forEach((filter) => {\n if (!filter.source || filter.destination === undefined) return\n \n const field = filter.source\n const value = filter.destination\n const operand = filter.operand || '='\n \n if (Array.isArray(value)) {\n const processedValues = value.map(processFilterValue)\n if (operand === '!=') {\n queryRef = queryRef.not(field, 'in', processedValues)\n } else {\n queryRef = queryRef.in(field, processedValues)\n }\n } else {\n const processedValue = processFilterValue(value)\n \n // Handle null values\n if (processedValue === null) {\n if (operand === '=') {\n queryRef = queryRef.is(field, null)\n } else if (operand === '!=') {\n queryRef = queryRef.not(field, 'is', null)\n }\n } else {\n // Map operand to Supabase methods\n switch (operand) {\n case '=':\n queryRef = queryRef.eq(field, processedValue)\n break\n case '!=':\n queryRef = queryRef.neq(field, processedValue)\n break\n case '>':\n queryRef = queryRef.gt(field, processedValue)\n break\n case '>=':\n queryRef = queryRef.gte(field, processedValue)\n break\n case '<':\n queryRef = queryRef.lt(field, processedValue)\n break\n case '<=':\n queryRef = queryRef.lte(field, processedValue)\n break\n default:\n queryRef = queryRef.eq(field, processedValue)\n }\n }\n }\n })\n } else {\n // Old format: object with key-value pairs (backward compatibility)\n Object.entries(parsedFilters).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n const processedValues = value.map(processFilterValue)\n queryRef = queryRef.in(key, processedValues)\n } else if (typeof value === 'object' && value !== null) {\n const operator = Object.keys(value)[0]\n let operatorValue = value[operator]\n if (typeof operatorValue === 'string' && !isNaN(Number(operatorValue))) {\n operatorValue = Number(operatorValue)\n }\n switch (operator) {\n case 'eq': queryRef = queryRef.eq(key, operatorValue); break\n case 'neq': queryRef = queryRef.neq(key, operatorValue); break\n case 'gt': queryRef = queryRef.gt(key, operatorValue); break\n case 'gte': queryRef = queryRef.gte(key, operatorValue); break\n case 'lt': queryRef = queryRef.lt(key, operatorValue); break\n case 'lte': queryRef = queryRef.lte(key, operatorValue); break\n case 'like': queryRef = queryRef.like(key, operatorValue); break\n case 'ilike': queryRef = queryRef.ilike(key, operatorValue); break\n case 'in': queryRef = queryRef.in(key, operatorValue); break\n default: queryRef = queryRef.eq(key, operatorValue)\n }\n } else {\n let processedValue = value\n if (typeof value === 'string' && !isNaN(Number(value))) {\n processedValue = Number(value)\n }\n queryRef = queryRef.eq(key, processedValue)\n }\n })\n }\n \n return queryRef\n}\n\n").concat(generateDateFormatterCode(), "\n\nexport default async function handler(req, res) {\n try {\n const client = getClient()\n const { query, queryColumns, select, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n let queryRef = client.from('").concat(tableName, "').select(select || '*')\n \n if (query) {\n let columns = []\n \n if (queryColumns) {\n // Use specified columns. Wrap non-arrays so a single column\n // passed as a bare string doesn't get iterated as chars.\n const parsed = safeJSONParse(queryColumns)\n columns = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : [])\n } else {\n // Fallback: Get text-searchable columns from a sample row\n try {\n const { data: sampleData, error: sampleError } = await client.from('").concat(tableName, "').select('*').limit(1).single()\n if (sampleError) {\n throw sampleError\n }\n if (sampleData) {\n // Filter out columns that are likely non-text types\n // Note: This is heuristic-based since we don't have schema info\n columns = Object.keys(sampleData).filter(col => {\n const value = sampleData[col]\n const colLower = col.toLowerCase()\n \n // Exclude common timestamp/date column names\n if (colLower.includes('_at') || colLower.includes('date') || colLower === 'timestamp') {\n return false\n }\n \n // Exclude if value is a number, boolean, null, or object (non-string)\n if (value === null || value === undefined) {\n return true // Include null columns, let the query handle it\n }\n \n const type = typeof value\n return type === 'string' // Only include string values\n })\n }\n } catch (schemaError) {\n console.warn('Failed to fetch sample row for column names:', schemaError.message)\n // Continue without search if we can't get columns\n }\n }\n \n if (columns.length > 0) {\n // PostgREST .or() DSL separates conditions with comma and uses\n // dot to split field / operator / value, so we wrap the pattern\n // in double quotes and backslash-escape any embedded quotes or\n // backslashes in the user's search term. Columns go through the\n // shared identifier sanitizer to reject injection. Note:\n // PostgREST .ilike. does not expose a LIKE ESCAPE clause, so\n // raw % / _ in the user input still act as wildcards in this\n // backend; the canvas preview path escapes them explicitly.\n const rawPattern = \"%\" + String(query) + \"%\"\n const escapedForPostgrest = rawPattern\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n const searchPattern = '\"' + escapedForPostgrest + '\"'\n const orConditions = columns\n .map((col) => sanitizeSearchIdentifier(col) + \".ilike.\" + searchPattern)\n .join(\",\")\n queryRef = queryRef.or(orConditions)\n }\n }\n\n // Apply filters using helper function\n queryRef = applyFilters(queryRef, filters)\n \n // Handle sorts - new array format\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts)) {\n parsedSorts.forEach((sort) => {\n if (sort.field) {\n queryRef = queryRef.order(sort.field, {\n ascending: !(sort.order || '').toLowerCase().startsWith('desc')\n })\n }\n })\n }\n } else if (sortBy) {\n queryRef = queryRef.order(sortBy, { ascending: !(sortOrder || '').toLowerCase().startsWith('desc') })\n }\n \n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n \n if (offsetValue !== undefined && limitValue) {\n queryRef = queryRef.range(offsetValue, offsetValue + parseInt(limitValue) - 1)\n } else if (limitValue) {\n queryRef = queryRef.limit(parseInt(limitValue))\n }\n \n const { data, error } = await queryRef\n \n if (error) {\n return res.status(500).json({\n success: false,\n error: error.message,\n timestamp: Date.now()\n })\n }\n \n const safeData = JSON.parse(JSON.stringify(data, dateReplacer))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Supabase fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n }\n}\n");
90
+ return "import { createClient } from '@supabase/supabase-js'\n\nlet client = null\n\nconst getClient = () => {\n if (client) return client\n \n client = createClient(\n ".concat(JSON.stringify(supabaseUrl), ",\n ").concat(replaceSecretReference(apiKey), "\n )\n \n return client\n}\n\n").concat(generateSafeJSONParseCode(), "\n\n").concat(generateFilterTreeHelpersCode(), "\n\n").concat(generateSearchEscapeHelpersCode(), "\n\n// Helper function to process filter values\nconst processFilterValue = (value) => {\n if (typeof value === 'string' && !isNaN(Number(value))) {\n return Number(value)\n }\n return value\n}\n\n// Helper function to apply filters to a query\nconst applyFilters = (queryRef, filters) => {\n if (!filters) return queryRef\n \n const parsedFilters = safeJSONParse(filters)\n \n if (Array.isArray(parsedFilters)) {\n const filterTree = normalizeFilterTree(parsedFilters)\n \n const applyCondition = (condition) => {\n const field = condition.source\n const value = condition.destination\n const operand = condition.operand\n \n if (Array.isArray(value)) {\n const processedValues = value.map(processFilterValue)\n if (operand === '!=') {\n queryRef = queryRef.not(field, 'in', processedValues)\n } else {\n queryRef = queryRef.in(field, processedValues)\n }\n return\n }\n \n const processedValue = processFilterValue(value)\n \n // Handle null values\n if (processedValue === null) {\n if (operand === '=') {\n queryRef = queryRef.is(field, null)\n } else if (operand === '!=') {\n queryRef = queryRef.not(field, 'is', null)\n }\n return\n }\n \n // Map operand to Supabase methods\n switch (operand) {\n case '!=':\n queryRef = queryRef.neq(field, processedValue)\n break\n case '>':\n queryRef = queryRef.gt(field, processedValue)\n break\n case '>=':\n queryRef = queryRef.gte(field, processedValue)\n break\n case '<':\n queryRef = queryRef.lt(field, processedValue)\n break\n case '<=':\n queryRef = queryRef.lte(field, processedValue)\n break\n default:\n queryRef = queryRef.eq(field, processedValue)\n }\n }\n \n // An OR group cannot be expressed by chaining (chained filters are ANDed),\n // so it is emitted as one PostgREST or=(...) expression instead.\n const POSTGREST_OPERANDS = { '=': 'eq', '!=': 'neq', '>': 'gt', '>=': 'gte', '<': 'lt', '<=': 'lte' }\n \n const toExprValue = (value) => {\n if (value === null || value === undefined) return 'null'\n const asString = String(value)\n return /[,.:()\"\\s]/.test(asString) ? '\"' + asString.replace(/\"/g, '\\\\\"') + '\"' : asString\n }\n \n const conditionToExpr = (condition) => {\n const field = condition.source\n const value = condition.destination\n const operand = condition.operand\n \n if (Array.isArray(value)) {\n const list = '(' + value.map((entry) => toExprValue(processFilterValue(entry))).join(',') + ')'\n return operand === '!=' ? field + '.not.in.' + list : field + '.in.' + list\n }\n \n const processedValue = processFilterValue(value)\n if (processedValue === null) {\n return operand === '!=' ? field + '.not.is.null' : field + '.is.null'\n }\n \n return field + '.' + (POSTGREST_OPERANDS[operand] || 'eq') + '.' + toExprValue(processedValue)\n }\n \n const nodeToExpr = (node) => {\n if (node.type === 'group') {\n const parts = node.children.map(nodeToExpr).filter(Boolean)\n if (parts.length === 0) return null\n if (parts.length === 1) return parts[0]\n return (node.operator === 'or' ? 'or' : 'and') + '(' + parts.join(',') + ')'\n }\n return conditionToExpr(node)\n }\n \n const applyNode = (node) => {\n if (node.type !== 'group') {\n applyCondition(node)\n return\n }\n if (node.operator === 'and') {\n node.children.forEach(applyNode)\n return\n }\n if (node.children.length === 1) {\n applyNode(node.children[0])\n return\n }\n const parts = node.children.map(nodeToExpr).filter(Boolean)\n if (parts.length > 0) {\n queryRef = queryRef.or(parts.join(','))\n }\n }\n \n if (filterTree) {\n applyNode(filterTree)\n }\n } else {\n // Old format: object with key-value pairs (backward compatibility)\n Object.entries(parsedFilters).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n const processedValues = value.map(processFilterValue)\n queryRef = queryRef.in(key, processedValues)\n } else if (typeof value === 'object' && value !== null) {\n const operator = Object.keys(value)[0]\n let operatorValue = value[operator]\n if (typeof operatorValue === 'string' && !isNaN(Number(operatorValue))) {\n operatorValue = Number(operatorValue)\n }\n switch (operator) {\n case 'eq': queryRef = queryRef.eq(key, operatorValue); break\n case 'neq': queryRef = queryRef.neq(key, operatorValue); break\n case 'gt': queryRef = queryRef.gt(key, operatorValue); break\n case 'gte': queryRef = queryRef.gte(key, operatorValue); break\n case 'lt': queryRef = queryRef.lt(key, operatorValue); break\n case 'lte': queryRef = queryRef.lte(key, operatorValue); break\n case 'like': queryRef = queryRef.like(key, operatorValue); break\n case 'ilike': queryRef = queryRef.ilike(key, operatorValue); break\n case 'in': queryRef = queryRef.in(key, operatorValue); break\n default: queryRef = queryRef.eq(key, operatorValue)\n }\n } else {\n let processedValue = value\n if (typeof value === 'string' && !isNaN(Number(value))) {\n processedValue = Number(value)\n }\n queryRef = queryRef.eq(key, processedValue)\n }\n })\n }\n \n return queryRef\n}\n\n").concat(generateDateFormatterCode(), "\n\nexport default async function handler(req, res) {\n try {\n const client = getClient()\n const { query, queryColumns, select, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n let queryRef = client.from('").concat(tableName, "').select(select || '*')\n \n if (query) {\n let columns = []\n \n if (queryColumns) {\n // Use specified columns. Wrap non-arrays so a single column\n // passed as a bare string doesn't get iterated as chars.\n const parsed = safeJSONParse(queryColumns)\n columns = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : [])\n } else {\n // Fallback: Get text-searchable columns from a sample row\n try {\n const { data: sampleData, error: sampleError } = await client.from('").concat(tableName, "').select('*').limit(1).single()\n if (sampleError) {\n throw sampleError\n }\n if (sampleData) {\n // Filter out columns that are likely non-text types\n // Note: This is heuristic-based since we don't have schema info\n columns = Object.keys(sampleData).filter(col => {\n const value = sampleData[col]\n const colLower = col.toLowerCase()\n \n // Exclude common timestamp/date column names\n if (colLower.includes('_at') || colLower.includes('date') || colLower === 'timestamp') {\n return false\n }\n \n // Exclude if value is a number, boolean, null, or object (non-string)\n if (value === null || value === undefined) {\n return true // Include null columns, let the query handle it\n }\n \n const type = typeof value\n return type === 'string' // Only include string values\n })\n }\n } catch (schemaError) {\n console.warn('Failed to fetch sample row for column names:', schemaError.message)\n // Continue without search if we can't get columns\n }\n }\n \n if (columns.length > 0) {\n // PostgREST .or() DSL separates conditions with comma and uses\n // dot to split field / operator / value, so we wrap the pattern\n // in double quotes and backslash-escape any embedded quotes or\n // backslashes in the user's search term. Columns go through the\n // shared identifier sanitizer to reject injection. Note:\n // PostgREST .ilike. does not expose a LIKE ESCAPE clause, so\n // raw % / _ in the user input still act as wildcards in this\n // backend; the canvas preview path escapes them explicitly.\n const rawPattern = \"%\" + String(query) + \"%\"\n const escapedForPostgrest = rawPattern\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n const searchPattern = '\"' + escapedForPostgrest + '\"'\n const orConditions = columns\n .map((col) => sanitizeSearchIdentifier(col) + \".ilike.\" + searchPattern)\n .join(\",\")\n queryRef = queryRef.or(orConditions)\n }\n }\n\n // Apply filters using helper function\n queryRef = applyFilters(queryRef, filters)\n \n // Handle sorts - new array format\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts)) {\n parsedSorts.forEach((sort) => {\n if (sort.field) {\n queryRef = queryRef.order(sort.field, {\n ascending: !(sort.order || '').toLowerCase().startsWith('desc')\n })\n }\n })\n }\n } else if (sortBy) {\n queryRef = queryRef.order(sortBy, { ascending: !(sortOrder || '').toLowerCase().startsWith('desc') })\n }\n \n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n \n if (offsetValue !== undefined && limitValue) {\n queryRef = queryRef.range(offsetValue, offsetValue + parseInt(limitValue) - 1)\n } else if (limitValue) {\n queryRef = queryRef.limit(parseInt(limitValue))\n }\n \n const { data, error } = await queryRef\n \n if (error) {\n return res.status(500).json({\n success: false,\n error: error.message,\n timestamp: Date.now()\n })\n }\n \n const safeData = JSON.parse(JSON.stringify(data, dateReplacer))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Supabase fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n }\n}\n");
91
91
  };
92
92
  // tslint:disable-next-line:variable-name
93
93
  export var generateSupabaseCountFetcher = function (_config, tableName) {
@@ -1 +1 @@
1
- {"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../../src/fetchers/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,UAAU,CAAA;AAEjB,MAAM,CAAC,IAAM,sBAAsB,GAAG,UACpC,MAA+B;IAE/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAA;KAClE;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QACjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAA;KAC7D;IAED,IAAI;QACF,IAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACvC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE;YACpF,OAAO,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAA;SACnF;KACF;IAAC,WAAM;QACN,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAA;KAChE;IAED,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;QAClD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,+DAA+D;SACvE,CAAA;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AAUD,MAAM,CAAC,IAAM,uBAAuB,GAAG,UACrC,MAA+B,EAC/B,SAAiB;IAEjB,IAAM,cAAc,GAAG,MAAwB,CAAA;IAC/C,IAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAA;IAC9C,IAAM,MAAM,GAAG,cAAc,CAAC,cAAc,IAAI,cAAc,CAAC,YAAY,CAAA;IAC3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2DA;IACA,OAAO,iLAQH,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,oBAC3B,sBAAsB,CAAC,MAAM,CAAC,8CAMlC,yBAAyB,EAAE,iBAE3B,+BAA+B,EAAE,uuHAyGjC,yBAAyB,EAAE,2QAOK,SAAS,qjBAaqC,SAAS,2+HA0GxF,CAAA;AACD,CAAC,CAAA;AAED,yCAAyC;AACzC,MAAM,CAAC,IAAM,4BAA4B,GAAG,UAAC,OAAY,EAAE,SAAiB;IAC1E,OAAO,wLAM6B,SAAS,kdAYmC,SAAS,o+EAoE1F,CAAA;AACD,CAAC,CAAA"}
1
+ {"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../../src/fetchers/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,+BAA+B,EAC/B,6BAA6B,GAC9B,MAAM,UAAU,CAAA;AAEjB,MAAM,CAAC,IAAM,sBAAsB,GAAG,UACpC,MAA+B;IAE/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAA;KAClE;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QACjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAA;KAC7D;IAED,IAAI;QACF,IAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACvC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE;YACpF,OAAO,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAA;SACnF;KACF;IAAC,WAAM;QACN,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAA;KAChE;IAED,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;QAClD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,+DAA+D;SACvE,CAAA;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AAUD,MAAM,CAAC,IAAM,uBAAuB,GAAG,UACrC,MAA+B,EAC/B,SAAiB;IAEjB,IAAM,cAAc,GAAG,MAAwB,CAAA;IAC/C,IAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAA;IAC9C,IAAM,MAAM,GAAG,cAAc,CAAC,cAAc,IAAI,cAAc,CAAC,YAAY,CAAA;IAC3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2DA;IACA,OAAO,iLAQH,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,oBAC3B,sBAAsB,CAAC,MAAM,CAAC,8CAMlC,yBAAyB,EAAE,iBAE3B,6BAA6B,EAAE,iBAE/B,+BAA+B,EAAE,irLAqKjC,yBAAyB,EAAE,2QAOK,SAAS,qjBAaqC,SAAS,2+HA0GxF,CAAA;AACD,CAAC,CAAA;AAED,yCAAyC;AACzC,MAAM,CAAC,IAAM,4BAA4B,GAAG,UAAC,OAAY,EAAE,SAAiB;IAC1E,OAAO,wLAM6B,SAAS,kdAYmC,SAAS,o+EAoE1F,CAAA;AACD,CAAC,CAAA"}
@@ -1,8 +1,8 @@
1
- import { type EcommerceProductTransformOptions } from '../transformations';
1
+ import { type EntityTransformOptions } from '../transformations';
2
2
  export declare const validateTeleportConfig: (config: Record<string, unknown>) => {
3
3
  isValid: boolean;
4
4
  error?: string;
5
5
  };
6
- export declare const generateTeleportFetcher: (config: Record<string, unknown>, tableName: string, transformOptions?: EcommerceProductTransformOptions) => string;
6
+ export declare const generateTeleportFetcher: (config: Record<string, unknown>, tableName: string, transformOptions?: EntityTransformOptions) => string;
7
7
  export declare const generateTeleportCountFetcher: (config: Record<string, unknown>, tableName: string) => string;
8
8
  //# sourceMappingURL=teleport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"teleport.d.ts","sourceRoot":"","sources":["../../../src/fetchers/teleport.ts"],"names":[],"mappings":"AAMA,OAAO,EAIL,KAAK,gCAAgC,EACtC,MAAM,oBAAoB,CAAA;AAmC3B,eAAO,MAAM,sBAAsB,WACzB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAMpC,CAAA;AAED,eAAO,MAAM,uBAAuB,WAC1B,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,qBACC,gCAAgC,KACjD,MAoZF,CAAA;AAED,eAAO,MAAM,4BAA4B,WAC/B,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,KAChB,MA0FF,CAAA"}
1
+ {"version":3,"file":"teleport.d.ts","sourceRoot":"","sources":["../../../src/fetchers/teleport.ts"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,oBAAoB,CAAA;AAmC3B,eAAO,MAAM,sBAAsB,WACzB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAMpC,CAAA;AAED,eAAO,MAAM,uBAAuB,WAC1B,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,qBACC,sBAAsB,KACvC,MAwYF,CAAA;AAED,eAAO,MAAM,4BAA4B,WAC/B,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,KAChB,MA0FF,CAAA"}
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateSearchEscapeHelpersCode, } from '../utils';
1
+ import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateFilterTreeHelpersCode, generateSearchEscapeHelpersCode, } from '../utils';
2
2
  import { getTransformationCode, getTransformExpression, getTransformWrapperCode, } from '../transformations';
3
3
  import { generateSortFallbackFieldHelper, generateSortFieldSqlHelper, generateSortTiebreakSql, } from '../product-price-sort';
4
4
  var DEFAULT_ENV_KEYS = {
@@ -42,7 +42,7 @@ export var generateTeleportFetcher = function (config, tableName, transformOptio
42
42
  ? "key: ".concat(resolveEnvReference(dbConfig.sslConfig.key, 'TELEPORT_DB_SSL_KEY'), ",")
43
43
  : '', "\n rejectUnauthorized: false\n }")
44
44
  : "(process.env.".concat(DEFAULT_ENV_KEYS.ssl, " === 'false' ? false : process.env.").concat(DEFAULT_ENV_KEYS.ssl, " === 'true' ? { rejectUnauthorized: false } : undefined)");
45
- return "import { Client } from 'pg'\n\nfunction normalizePostgresConnectionString(connectionString) {\n if (!connectionString || typeof connectionString !== 'string') return connectionString;\n if (/^postgresql:\\/(?!\\/)/i.test(connectionString)) {\n return connectionString.replace(/^postgresql:\\//i, 'postgresql://');\n }\n return connectionString;\n}\n\nfunction stripSslQueryParamsFromConnectionString(connectionString) {\n if (!connectionString || typeof connectionString !== 'string') return connectionString;\n try {\n var u = new URL(connectionString.replace(/^postgresql:/i, 'postgres:'));\n u.searchParams.delete('sslmode');\n u.searchParams.delete('ssl');\n u.searchParams.delete('sslrootcert');\n u.searchParams.delete('sslcert');\n u.searchParams.delete('sslkey');\n return u.toString().replace(/^postgres:/i, 'postgresql:');\n } catch (e) {\n return connectionString;\n }\n}\n\nconst getClient = () => {\n var ssl = ".concat(sslCode, ";\n var connStr = process.env.TELEPORT_DB_CONNECTION_STRING;\n if (connStr) {\n connStr = normalizePostgresConnectionString(connStr);\n }\n if (ssl === false && connStr) {\n connStr = stripSslQueryParamsFromConnectionString(connStr);\n }\n if (connStr) {\n return new Client(Object.assign(\n { connectionString: connStr },\n ssl !== undefined ? { ssl: ssl } : {}\n ));\n }\n return new Client(Object.assign(\n {\n host: ").concat(hostRef, ",\n port: parseInt(").concat(portRef, " || '5432', 10),\n user: ").concat(userRef, ",\n password: ").concat(passwordRef, ",\n database: ").concat(databaseRef, ",\n },\n ssl !== undefined ? { ssl: ssl } : {}\n ));\n}\n\n").concat(generateSafeJSONParseCode(), "\n\n").concat(generateSearchEscapeHelpersCode(), "\n").concat(getTransformationCode(tableName, transformOptions), "\n").concat(getTransformWrapperCode(tableName), "\nconst processFilters = (filters, conditions, queryParams, paramIndex) => {\n if (!filters) return paramIndex\n \n const parsedFilters = safeJSONParse(filters)\n \n if (Array.isArray(parsedFilters)) {\n parsedFilters.forEach((filter) => {\n if (!filter.source || filter.destination === undefined) return\n \n const field = filter.source\n const value = filter.destination\n const operand = filter.operand || '='\n \n if (Array.isArray(value)) {\n if (value.length === 0) return\n if (operand === 'array_overlap') {\n // Row column is a JSON array (e.g. category_ids). Match when it\n // shares any element with the destination set. jsonb ?| (function\n // form) avoids the '?' placeholder-token ambiguity some drivers hit.\n conditions.push(`jsonb_exists_any(NULLIF(${field}, '')::jsonb, $${paramIndex}::text[])`)\n queryParams.push(value.map((entry) => String(entry)))\n paramIndex++\n return\n }\n const placeholders = value.map(() => `$${paramIndex++}`)\n queryParams.push(...value)\n if (operand === '!=') {\n conditions.push(`${field} NOT IN (${placeholders.join(', ')})`)\n } else {\n conditions.push(`${field} IN (${placeholders.join(', ')})`)\n }\n } else {\n if (operand === 'array_overlap') {\n if (value === '' || value === null || value === undefined) return\n // A single comma-joined string (the multi-select Category Filter's\n // ?categoryFilter=a,b,c) expands to multiple ids; one id stays one.\n const overlapValues = String(value).split(',').map((entry) => entry.trim()).filter(Boolean)\n if (overlapValues.length === 0) return\n conditions.push(`jsonb_exists_any(NULLIF(${field}, '')::jsonb, $${paramIndex}::text[])`)\n queryParams.push(overlapValues)\n paramIndex++\n return\n }\n if (value === null) {\n if (operand === '=') {\n conditions.push(`${field} IS NULL`)\n } else if (operand === '!=') {\n conditions.push(`${field} IS NOT NULL`)\n }\n } else {\n const validOps = ['=', '!=', '>', '<', '>=', '<=']\n const sqlOperator = validOps.includes(operand) ? operand : '='\n conditions.push(`${field} ${sqlOperator} $${paramIndex}`)\n queryParams.push(value)\n paramIndex++\n }\n }\n })\n } else {\n Object.entries(parsedFilters).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n const placeholders = value.map(() => `$${paramIndex++}`)\n queryParams.push(...value)\n conditions.push(`${key} IN (${placeholders.join(', ')})`)\n } else {\n conditions.push(`${key} = $${paramIndex}`)\n queryParams.push(value)\n paramIndex++\n }\n })\n }\n \n return paramIndex\n}\n\n").concat(generateDateFormatterCode(), "\n\n").concat(generateSortFieldSqlHelper(tableName), "\n\n").concat(generateSortFallbackFieldHelper(tableName), "\n\n// Matches DDL / dangerous statements the raw-query branch should refuse.\n// Keep this list conservative \u2014 anything destructive or schema-changing is\n// out of scope for a client-triggered fetch. SELECT and CTEs (WITH ...) are\n// the only shapes consumers legitimately need.\nconst BLOCKED_RAW_QUERY_PATTERNS = [\n /\\bcreate\\s+(?:temporary\\s+|temp\\s+|unlogged\\s+|global\\s+|local\\s+)?table\\b/i,\n /\\bcreate\\s+(?:unique\\s+)?index\\b/i,\n /\\bcreate\\s+(?:or\\s+replace\\s+)?(?:materialized\\s+)?view\\b/i,\n /\\bcreate\\s+(?:or\\s+replace\\s+)?trigger\\b/i,\n /\\bcreate\\s+(?:or\\s+replace\\s+)?(?:aggregate\\s+)?function\\b/i,\n /\\bcreate\\s+(?:or\\s+replace\\s+)?procedure\\b/i,\n /\\bcreate\\s+(?:database|schema|sequence|extension|type|role|user)\\b/i,\n /\\bdrop\\s+(?:table|view|index|schema|database|sequence|trigger|function|procedure|role|user|extension|type|materialized)\\b/i,\n /\\balter\\s+(?:table|view|index|schema|database|sequence|role|user|system)\\b/i,\n /\\btruncate\\b/i,\n /\\bgrant\\b/i,\n /\\brevoke\\b/i,\n /\\binsert\\b/i,\n /\\bupdate\\b/i,\n /\\bdelete\\b/i,\n /\\bcopy\\b/i,\n /\\bvacuum\\b/i,\n /\\breindex\\b/i,\n /\\bcluster\\b/i,\n]\n\nfunction assertRawQuerySafe(rawQuery) {\n if (typeof rawQuery !== 'string' || rawQuery.length === 0) {\n throw new Error('rawQuery must be a non-empty string')\n }\n // Reject multi-statement payloads \u2014 only single SELECT / WITH statements.\n // A trailing semicolon is tolerated but any content after it fails.\n var trimmed = rawQuery.trim().replace(/;\\s*$/, '')\n if (trimmed.indexOf(';') !== -1) {\n throw new Error('rawQuery must contain exactly one statement')\n }\n for (var i = 0; i < BLOCKED_RAW_QUERY_PATTERNS.length; i++) {\n if (BLOCKED_RAW_QUERY_PATTERNS[i].test(trimmed)) {\n throw new Error('rawQuery contains a blocked statement')\n }\n }\n}\n\nexport default async function handler(req, res) {\n const client = getClient()\n\n try {\n await client.connect()\n ").concat(schema ? "await client.query('SET search_path TO ".concat(schema, "')") : '', "\n\n // If the caller supplied a rawQuery, run it verbatim (after a safety\n // guard). The schema-driven branch below builds `SELECT * FROM ").concat(tableName, "`\n // with optional filters \u2014 it's the default read path and ignores\n // rawQuery. Page-load workflows and other consumers that need a JOIN\n // or a user-scoped filter pass their fully-rendered SQL here via\n // `fetchData({ rawQuery })` and expect it to execute verbatim.\n if (req.query && typeof req.query.rawQuery === 'string' && req.query.rawQuery.length > 0) {\n assertRawQuerySafe(req.query.rawQuery)\n const rawResult = await client.query(req.query.rawQuery)\n const rawRows = Array.isArray(rawResult?.rows) ? rawResult.rows : []\n const rawPlain = rawRows.map((row) =>\n row && typeof row.toJSON === 'function' ? row.toJSON() : row\n )\n const rawSafe = JSON.parse(JSON.stringify(rawPlain, dateReplacer))\n return res.status(200).json({\n success: true,\n data: rawSafe,\n timestamp: Date.now()\n })\n }\n\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n const conditions = []\n const queryParams = []\n let paramIndex = 1\n \n if (query) {\n let columns = []\n \n if (queryColumns) {\n const parsed = safeJSONParse(queryColumns)\n columns = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : [])\n } else {\n try {\n const schemaQuery = `\n SELECT column_name \n FROM information_schema.columns \n WHERE table_name = $1\n ").concat(schema ? "AND table_schema = $2" : '', "\n ORDER BY ordinal_position\n `\n const schemaParams = ").concat(schema
45
+ return "import { Client } from 'pg'\n\nfunction normalizePostgresConnectionString(connectionString) {\n if (!connectionString || typeof connectionString !== 'string') return connectionString;\n if (/^postgresql:\\/(?!\\/)/i.test(connectionString)) {\n return connectionString.replace(/^postgresql:\\//i, 'postgresql://');\n }\n return connectionString;\n}\n\nfunction stripSslQueryParamsFromConnectionString(connectionString) {\n if (!connectionString || typeof connectionString !== 'string') return connectionString;\n try {\n var u = new URL(connectionString.replace(/^postgresql:/i, 'postgres:'));\n u.searchParams.delete('sslmode');\n u.searchParams.delete('ssl');\n u.searchParams.delete('sslrootcert');\n u.searchParams.delete('sslcert');\n u.searchParams.delete('sslkey');\n return u.toString().replace(/^postgres:/i, 'postgresql:');\n } catch (e) {\n return connectionString;\n }\n}\n\nconst getClient = () => {\n var ssl = ".concat(sslCode, ";\n var connStr = process.env.TELEPORT_DB_CONNECTION_STRING;\n if (connStr) {\n connStr = normalizePostgresConnectionString(connStr);\n }\n if (ssl === false && connStr) {\n connStr = stripSslQueryParamsFromConnectionString(connStr);\n }\n if (connStr) {\n return new Client(Object.assign(\n { connectionString: connStr },\n ssl !== undefined ? { ssl: ssl } : {}\n ));\n }\n return new Client(Object.assign(\n {\n host: ").concat(hostRef, ",\n port: parseInt(").concat(portRef, " || '5432', 10),\n user: ").concat(userRef, ",\n password: ").concat(passwordRef, ",\n database: ").concat(databaseRef, ",\n },\n ssl !== undefined ? { ssl: ssl } : {}\n ));\n}\n\n").concat(generateSafeJSONParseCode(), "\n\n").concat(generateFilterTreeHelpersCode(), "\n\n").concat(generateSearchEscapeHelpersCode(), "\n").concat(getTransformationCode(tableName, transformOptions), "\n").concat(getTransformWrapperCode(tableName), "\nconst processFilters = (filters, conditions, queryParams, paramIndex) => {\n if (!filters) return paramIndex\n \n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n if (!filterTree) return paramIndex\n \n const buildCondition = (condition) => {\n const field = condition.source\n const value = condition.destination\n const operand = condition.operand\n \n if (Array.isArray(value)) {\n if (value.length === 0) return null\n if (operand === 'array_overlap') {\n // Row column is a JSON array (e.g. category_ids). Match when it\n // shares any element with the destination set. jsonb ?| (function\n // form) avoids the '?' placeholder-token ambiguity some drivers hit.\n const clause = `jsonb_exists_any(NULLIF(${field}, '')::jsonb, $${paramIndex}::text[])`\n queryParams.push(value.map((entry) => String(entry)))\n paramIndex++\n return clause\n }\n const placeholders = value.map(() => `$${paramIndex++}`)\n queryParams.push(...value)\n return operand === '!='\n ? `${field} NOT IN (${placeholders.join(', ')})`\n : `${field} IN (${placeholders.join(', ')})`\n }\n \n if (operand === 'array_overlap') {\n if (value === '' || value === null || value === undefined) return null\n // A single comma-joined string (the multi-select Category Filter's\n // ?categoryFilter=a,b,c) expands to multiple ids; one id stays one.\n const overlapValues = String(value).split(',').map((entry) => entry.trim()).filter(Boolean)\n if (overlapValues.length === 0) return null\n const clause = `jsonb_exists_any(NULLIF(${field}, '')::jsonb, $${paramIndex}::text[])`\n queryParams.push(overlapValues)\n paramIndex++\n return clause\n }\n \n if (value === null) {\n if (operand === '=') return `${field} IS NULL`\n if (operand === '!=') return `${field} IS NOT NULL`\n return null\n }\n \n const validOps = ['=', '!=', '>', '<', '>=', '<=']\n const sqlOperator = validOps.includes(operand) ? operand : '='\n const clause = `${field} ${sqlOperator} $${paramIndex}`\n queryParams.push(value)\n paramIndex++\n return clause\n }\n \n const clause = buildFilterTreeClause(filterTree, buildCondition)\n if (clause) conditions.push(clause)\n \n return paramIndex\n}\n\n").concat(generateDateFormatterCode(), "\n\n").concat(generateSortFieldSqlHelper(tableName), "\n\n").concat(generateSortFallbackFieldHelper(tableName), "\n\n// Matches DDL / dangerous statements the raw-query branch should refuse.\n// Keep this list conservative \u2014 anything destructive or schema-changing is\n// out of scope for a client-triggered fetch. SELECT and CTEs (WITH ...) are\n// the only shapes consumers legitimately need.\nconst BLOCKED_RAW_QUERY_PATTERNS = [\n /\\bcreate\\s+(?:temporary\\s+|temp\\s+|unlogged\\s+|global\\s+|local\\s+)?table\\b/i,\n /\\bcreate\\s+(?:unique\\s+)?index\\b/i,\n /\\bcreate\\s+(?:or\\s+replace\\s+)?(?:materialized\\s+)?view\\b/i,\n /\\bcreate\\s+(?:or\\s+replace\\s+)?trigger\\b/i,\n /\\bcreate\\s+(?:or\\s+replace\\s+)?(?:aggregate\\s+)?function\\b/i,\n /\\bcreate\\s+(?:or\\s+replace\\s+)?procedure\\b/i,\n /\\bcreate\\s+(?:database|schema|sequence|extension|type|role|user)\\b/i,\n /\\bdrop\\s+(?:table|view|index|schema|database|sequence|trigger|function|procedure|role|user|extension|type|materialized)\\b/i,\n /\\balter\\s+(?:table|view|index|schema|database|sequence|role|user|system)\\b/i,\n /\\btruncate\\b/i,\n /\\bgrant\\b/i,\n /\\brevoke\\b/i,\n /\\binsert\\b/i,\n /\\bupdate\\b/i,\n /\\bdelete\\b/i,\n /\\bcopy\\b/i,\n /\\bvacuum\\b/i,\n /\\breindex\\b/i,\n /\\bcluster\\b/i,\n]\n\nfunction assertRawQuerySafe(rawQuery) {\n if (typeof rawQuery !== 'string' || rawQuery.length === 0) {\n throw new Error('rawQuery must be a non-empty string')\n }\n // Reject multi-statement payloads \u2014 only single SELECT / WITH statements.\n // A trailing semicolon is tolerated but any content after it fails.\n var trimmed = rawQuery.trim().replace(/;\\s*$/, '')\n if (trimmed.indexOf(';') !== -1) {\n throw new Error('rawQuery must contain exactly one statement')\n }\n for (var i = 0; i < BLOCKED_RAW_QUERY_PATTERNS.length; i++) {\n if (BLOCKED_RAW_QUERY_PATTERNS[i].test(trimmed)) {\n throw new Error('rawQuery contains a blocked statement')\n }\n }\n}\n\nexport default async function handler(req, res) {\n const client = getClient()\n\n try {\n await client.connect()\n ").concat(schema ? "await client.query('SET search_path TO ".concat(schema, "')") : '', "\n\n // If the caller supplied a rawQuery, run it verbatim (after a safety\n // guard). The schema-driven branch below builds `SELECT * FROM ").concat(tableName, "`\n // with optional filters \u2014 it's the default read path and ignores\n // rawQuery. Page-load workflows and other consumers that need a JOIN\n // or a user-scoped filter pass their fully-rendered SQL here via\n // `fetchData({ rawQuery })` and expect it to execute verbatim.\n if (req.query && typeof req.query.rawQuery === 'string' && req.query.rawQuery.length > 0) {\n assertRawQuerySafe(req.query.rawQuery)\n const rawResult = await client.query(req.query.rawQuery)\n const rawRows = Array.isArray(rawResult?.rows) ? rawResult.rows : []\n const rawPlain = rawRows.map((row) =>\n row && typeof row.toJSON === 'function' ? row.toJSON() : row\n )\n const rawSafe = JSON.parse(JSON.stringify(rawPlain, dateReplacer))\n return res.status(200).json({\n success: true,\n data: rawSafe,\n timestamp: Date.now()\n })\n }\n\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n const conditions = []\n const queryParams = []\n let paramIndex = 1\n \n if (query) {\n let columns = []\n \n if (queryColumns) {\n const parsed = safeJSONParse(queryColumns)\n columns = Array.isArray(parsed) ? parsed : (parsed ? [parsed] : [])\n } else {\n try {\n const schemaQuery = `\n SELECT column_name \n FROM information_schema.columns \n WHERE table_name = $1\n ").concat(schema ? "AND table_schema = $2" : '', "\n ORDER BY ordinal_position\n `\n const schemaParams = ").concat(schema
46
46
  ? "[".concat(JSON.stringify(tableName), ", ").concat(JSON.stringify(schema), "]")
47
47
  : "[".concat(JSON.stringify(tableName), "]"), "\n \n const schemaResult = await client.query(schemaQuery, schemaParams)\n columns = schemaResult.rows.map(row => row.column_name)\n } catch (schemaError) {\n console.warn('Failed to fetch column names from information_schema:', schemaError.message)\n }\n }\n \n if (columns.length > 0) {\n const pattern = '%' + escapeLikePattern(query) + '%'\n const placeholder = '$' + paramIndex\n paramIndex++\n queryParams.push(pattern)\n const searchConditions = columns.map(\n (col) => '\"' + sanitizeSearchIdentifier(col) + '\"::text ILIKE ' + placeholder + \" ESCAPE '|'\"\n )\n conditions.push('(' + searchConditions.join(' OR ') + ')')\n }\n }\n \n paramIndex = processFilters(filters, conditions, queryParams, paramIndex)\n \n let sql = `SELECT * FROM ").concat(tableName, "`\n \n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(' AND ')}`\n }\n \n // Handle sorts - new array format. Two ORDER BY clauses are built: the one\n // actually used, and a plain-column twin kept only as the fallback below.\n let orderBySql = ''\n let plainOrderBySql = ''\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n const valid = parsedSorts.filter((sort) => sort && sort.field)\n const orderOf = (sort) => (sort.order || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'\n const orderClauses = valid.map((sort) => `${sortFieldSql(sort.field)} ${orderOf(sort)}`)\n const plainClauses = valid.map((sort) => `${sortFallbackField(sort.field)} ${orderOf(sort)}`)\n\n if (orderClauses.length > 0) {\n // A deterministic tiebreaker keeps pagination stable: \"sort by\n // discount\" ties every undiscounted product at zero, and equal rows\n // with no defined order can repeat across pages or vanish between them.\n orderBySql = ` ORDER BY ${orderClauses.join(', ')}").concat(generateSortTiebreakSql(tableName), "`\n plainOrderBySql = ` ORDER BY ${plainClauses.join(', ')}").concat(generateSortTiebreakSql(tableName), "`\n }\n }\n } else if (sortBy) {\n orderBySql = ` ORDER BY ${sortBy} ${(sortOrder || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'}`\n plainOrderBySql = orderBySql\n }\n const usedDiscountAwareSort = orderBySql !== plainOrderBySql\n\n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n\n let sqlTail = ''\n if (limitValue) {\n sqlTail += ` LIMIT ${limitValue}`\n }\n \n if (offsetValue !== undefined) {\n sqlTail += ` OFFSET ${offsetValue}`\n }\n\n const baseSql = sql\n sql = baseSql + orderBySql + sqlTail\n\n // The discount-aware price ordering is an inline sub-select over a JSON\n // column. It is written to be unraisable, but it runs inside ORDER BY for\n // the whole table - so if a database ever rejects it, fall back to ordering\n // by the stored list price rather than serving an empty products page.\n let result\n try {\n result = await client.query(sql, queryParams)\n } catch (sortError) {\n if (!usedDiscountAwareSort) throw sortError\n console.warn(\n 'Discount-aware price sort failed; falling back to the list price:',\n sortError && sortError.message\n )\n result = await client.query(baseSql + plainOrderBySql + sqlTail, queryParams)\n }\n const rows = Array.isArray(result?.rows) ? result.rows : []\n const plainRows = rows.map((row) =>\n row && typeof row.toJSON === 'function' ? row.toJSON() : row\n )\n const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))\n ").concat(getTransformExpression(tableName)
48
48
  ? "const transformedData = ".concat(getTransformExpression(tableName))
@@ -1 +1 @@
1
- {"version":3,"file":"teleport.js","sourceRoot":"","sources":["../../../src/fetchers/teleport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"teleport.js","sourceRoot":"","sources":["../../../src/fetchers/teleport.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"turso.d.ts","sourceRoot":"","sources":["../../../src/fetchers/turso.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,mBAAmB,WACtB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAcpC,CAAA;AASD,eAAO,MAAM,oBAAoB,WACvB,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,KAChB,MA8MF,CAAA"}
1
+ {"version":3,"file":"turso.d.ts","sourceRoot":"","sources":["../../../src/fetchers/turso.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,mBAAmB,WACtB,OAAO,MAAM,EAAE,OAAO,CAAC,KAC9B;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAcpC,CAAA;AASD,eAAO,MAAM,oBAAoB,WACvB,OAAO,MAAM,EAAE,OAAO,CAAC,aACpB,MAAM,KAChB,MAiMF,CAAA"}
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateSearchEscapeHelpersCode, } from '../utils';
1
+ import { replaceSecretReference, generateDateFormatterCode, generateSafeJSONParseCode, generateFilterTreeHelpersCode, generateSearchEscapeHelpersCode, } from '../utils';
2
2
  export var validateTursoConfig = function (config) {
3
3
  if (!config || typeof config !== 'object') {
4
4
  return { isValid: false, error: 'Config must be a valid object' };
@@ -15,6 +15,6 @@ export var generateTursoFetcher = function (config, tableName) {
15
15
  var tursoConfig = config;
16
16
  var databaseUrl = tursoConfig.databaseUrl;
17
17
  var token = tursoConfig.token;
18
- return "import { createClient } from '@libsql/client'\n\n".concat(generateSafeJSONParseCode(), "\n\n").concat(generateSearchEscapeHelpersCode(), "\n\n").concat(generateDateFormatterCode(), "\n\nexport default async function handler(req, res) {\n let client = null\n try {\n client = createClient({\n url: ").concat(JSON.stringify(databaseUrl), ",\n authToken: ").concat(replaceSecretReference(token), "\n })\n \n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n let sql = `SELECT * FROM ").concat(tableName, "`\n const whereClauses = []\n const queryParams = []\n let searchQueryColumns = null\n \n if (query) {\n if (queryColumns) {\n const parsed = safeJSONParse(queryColumns)\n const columns = Array.isArray(parsed) ? parsed : [parsed]\n // Cast columns to TEXT and LOWER both sides so the match is\n // case-insensitive regardless of SQLite collation.\n const pattern = \"%\" + escapeLikePattern(query) + \"%\"\n const searchConditions = columns.map(\n (col) =>\n 'LOWER(CAST(\"' + sanitizeSearchIdentifier(col) + '\" AS TEXT)) LIKE LOWER(?) ESCAPE ' + \"'|'\"\n )\n whereClauses.push(\"(\" + searchConditions.join(\" OR \") + \")\")\n columns.forEach(() => {\n queryParams.push(pattern)\n })\n } else {\n // Store query for post-filtering if columns not specified\n searchQueryColumns = query\n }\n }\n \n // Helper to sanitize identifier (prevent SQL injection in column names)\n const sanitizeIdentifier = (name) => {\n // Only allow alphanumeric and underscore\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n throw new Error(`Invalid identifier: ${name}`)\n }\n return `\"${name}\"`\n }\n \n if (filters) {\n const parsedFilters = safeJSONParse(filters)\n \n if (Array.isArray(parsedFilters)) {\n parsedFilters.forEach((filter) => {\n if (!filter.source || filter.destination === undefined) return\n \n const field = sanitizeIdentifier(filter.source)\n const value = filter.destination\n const operand = filter.operand || '='\n \n if (Array.isArray(value)) {\n if (value.length === 0) return\n const placeholders = value.map(() => '?').join(', ')\n queryParams.push(...value)\n if (operand === '!=') {\n whereClauses.push(`${field} NOT IN (${placeholders})`)\n } else {\n whereClauses.push(`${field} IN (${placeholders})`)\n }\n } else {\n if (value === null) {\n if (operand === '=') {\n whereClauses.push(`${field} IS NULL`)\n } else if (operand === '!=') {\n whereClauses.push(`${field} IS NOT NULL`)\n }\n } else {\n const validOps = ['=', '!=', '>', '<', '>=', '<=']\n const sqlOperator = validOps.includes(operand) ? operand : '='\n whereClauses.push(`${field} ${sqlOperator} ?`)\n queryParams.push(value)\n }\n }\n })\n } else {\n Object.entries(parsedFilters).forEach(([key, value]) => {\n const field = sanitizeIdentifier(key)\n if (Array.isArray(value)) {\n const placeholders = value.map(() => '?').join(', ')\n queryParams.push(...value)\n whereClauses.push(`${field} IN (${placeholders})`)\n } else {\n whereClauses.push(`${field} = ?`)\n queryParams.push(value)\n }\n })\n }\n }\n \n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(' AND ')}`\n }\n \n // Handle sorts - new array format\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n const orderClauses = parsedSorts.map((sort) => {\n if (!sort.field) return null\n const order = (sort.order || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'\n return `${sanitizeIdentifier(sort.field)} ${order}`\n }).filter(Boolean)\n\n if (orderClauses.length > 0) {\n sql += ` ORDER BY ${orderClauses.join(', ')}`\n }\n }\n } else if (sortBy) {\n const sortOrderValue = (sortOrder || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'\n sql += ` ORDER BY ${sanitizeIdentifier(sortBy)} ${sortOrderValue}`\n }\n \n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n \n // Only apply SQL pagination if we're not doing post-filtering\n if (!searchQueryColumns) {\n if (limitValue) {\n sql += ` LIMIT ?`\n queryParams.push(parseInt(limitValue))\n }\n \n if (offsetValue !== undefined) {\n sql += ` OFFSET ?`\n queryParams.push(offsetValue)\n }\n }\n \n const result = await client.execute({\n sql,\n args: queryParams\n })\n \n let data = result.rows.map((row) => {\n const obj = {}\n result.columns.forEach((col, idx) => {\n obj[col] = row[col]\n })\n return obj\n })\n \n // Apply post-filtering for search without queryColumns\n if (searchQueryColumns) {\n const searchQuery = searchQueryColumns.toLowerCase()\n data = data.filter((item) => {\n try {\n const stringified = JSON.stringify(item).toLowerCase()\n return stringified.includes(searchQuery)\n } catch {\n return false\n }\n })\n \n // Apply pagination after filtering\n if (limitValue) {\n const start = offsetValue || 0\n data = data.slice(start, start + parseInt(limitValue))\n } else if (offsetValue) {\n data = data.slice(offsetValue)\n }\n }\n \n const safeData = JSON.parse(JSON.stringify(data, dateReplacer))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Turso fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n } finally {\n if (client) {\n try {\n await client.close()\n } catch (error) {\n console.error('Error closing Turso client:', error)\n }\n }\n }\n}\n");
18
+ return "import { createClient } from '@libsql/client'\n\n".concat(generateSafeJSONParseCode(), "\n\n").concat(generateFilterTreeHelpersCode(), "\n\n").concat(generateSearchEscapeHelpersCode(), "\n\n").concat(generateDateFormatterCode(), "\n\nexport default async function handler(req, res) {\n let client = null\n try {\n client = createClient({\n url: ").concat(JSON.stringify(databaseUrl), ",\n authToken: ").concat(replaceSecretReference(token), "\n })\n \n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n let sql = `SELECT * FROM ").concat(tableName, "`\n const whereClauses = []\n const queryParams = []\n let searchQueryColumns = null\n \n if (query) {\n if (queryColumns) {\n const parsed = safeJSONParse(queryColumns)\n const columns = Array.isArray(parsed) ? parsed : [parsed]\n // Cast columns to TEXT and LOWER both sides so the match is\n // case-insensitive regardless of SQLite collation.\n const pattern = \"%\" + escapeLikePattern(query) + \"%\"\n const searchConditions = columns.map(\n (col) =>\n 'LOWER(CAST(\"' + sanitizeSearchIdentifier(col) + '\" AS TEXT)) LIKE LOWER(?) ESCAPE ' + \"'|'\"\n )\n whereClauses.push(\"(\" + searchConditions.join(\" OR \") + \")\")\n columns.forEach(() => {\n queryParams.push(pattern)\n })\n } else {\n // Store query for post-filtering if columns not specified\n searchQueryColumns = query\n }\n }\n \n // Helper to sanitize identifier (prevent SQL injection in column names)\n const sanitizeIdentifier = (name) => {\n // Only allow alphanumeric and underscore\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n throw new Error(`Invalid identifier: ${name}`)\n }\n return `\"${name}\"`\n }\n \n if (filters) {\n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n const buildCondition = (condition) => {\n const field = sanitizeIdentifier(condition.source)\n const value = condition.destination\n const operand = condition.operand\n \n if (Array.isArray(value)) {\n if (value.length === 0) return null\n const placeholders = value.map(() => '?').join(', ')\n queryParams.push(...value)\n return operand === '!='\n ? `${field} NOT IN (${placeholders})`\n : `${field} IN (${placeholders})`\n }\n \n if (value === null) {\n if (operand === '=') return `${field} IS NULL`\n if (operand === '!=') return `${field} IS NOT NULL`\n return null\n }\n \n const validOps = ['=', '!=', '>', '<', '>=', '<=']\n const sqlOperator = validOps.includes(operand) ? operand : '='\n queryParams.push(value)\n return `${field} ${sqlOperator} ?`\n }\n \n const clause = buildFilterTreeClause(filterTree, buildCondition)\n if (clause) whereClauses.push(clause)\n }\n }\n \n if (whereClauses.length > 0) {\n sql += ` WHERE ${whereClauses.join(' AND ')}`\n }\n \n // Handle sorts - new array format\n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n const orderClauses = parsedSorts.map((sort) => {\n if (!sort.field) return null\n const order = (sort.order || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'\n return `${sanitizeIdentifier(sort.field)} ${order}`\n }).filter(Boolean)\n\n if (orderClauses.length > 0) {\n sql += ` ORDER BY ${orderClauses.join(', ')}`\n }\n }\n } else if (sortBy) {\n const sortOrderValue = (sortOrder || '').toUpperCase().startsWith('DESC') ? 'DESC' : 'ASC'\n sql += ` ORDER BY ${sanitizeIdentifier(sortBy)} ${sortOrderValue}`\n }\n \n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n \n // Only apply SQL pagination if we're not doing post-filtering\n if (!searchQueryColumns) {\n if (limitValue) {\n sql += ` LIMIT ?`\n queryParams.push(parseInt(limitValue))\n }\n \n if (offsetValue !== undefined) {\n sql += ` OFFSET ?`\n queryParams.push(offsetValue)\n }\n }\n \n const result = await client.execute({\n sql,\n args: queryParams\n })\n \n let data = result.rows.map((row) => {\n const obj = {}\n result.columns.forEach((col, idx) => {\n obj[col] = row[col]\n })\n return obj\n })\n \n // Apply post-filtering for search without queryColumns\n if (searchQueryColumns) {\n const searchQuery = searchQueryColumns.toLowerCase()\n data = data.filter((item) => {\n try {\n const stringified = JSON.stringify(item).toLowerCase()\n return stringified.includes(searchQuery)\n } catch {\n return false\n }\n })\n \n // Apply pagination after filtering\n if (limitValue) {\n const start = offsetValue || 0\n data = data.slice(start, start + parseInt(limitValue))\n } else if (offsetValue) {\n data = data.slice(offsetValue)\n }\n }\n \n const safeData = JSON.parse(JSON.stringify(data, dateReplacer))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Turso fetch error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to fetch data',\n timestamp: Date.now()\n })\n } finally {\n if (client) {\n try {\n await client.close()\n } catch (error) {\n console.error('Error closing Turso client:', error)\n }\n }\n }\n}\n");
19
19
  };
20
20
  //# sourceMappingURL=turso.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"turso.js","sourceRoot":"","sources":["../../../src/fetchers/turso.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,UAAU,CAAA;AAEjB,MAAM,CAAC,IAAM,mBAAmB,GAAG,UACjC,MAA+B;IAE/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAA;KAClE;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QACjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAA;KACnE;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE;QACrD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAA;KAC3E;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AASD,MAAM,CAAC,IAAM,oBAAoB,GAAG,UAClC,MAA+B,EAC/B,SAAiB;IAEjB,IAAM,WAAW,GAAG,MAAqB,CAAA;IACzC,IAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAA;IAC3C,IAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAA;IAE/B,OAAO,2DAEP,yBAAyB,EAAE,iBAE3B,+BAA+B,EAAE,iBAEjC,yBAAyB,EAAE,0IAMhB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,iCACrB,sBAAsB,CAAC,KAAK,CAAC,gLAKhB,SAAS,g/LAsLxC,CAAA;AACD,CAAC,CAAA"}
1
+ {"version":3,"file":"turso.js","sourceRoot":"","sources":["../../../src/fetchers/turso.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EACzB,6BAA6B,EAC7B,+BAA+B,GAChC,MAAM,UAAU,CAAA;AAEjB,MAAM,CAAC,IAAM,mBAAmB,GAAG,UACjC,MAA+B;IAE/B,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QACzC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAA;KAClE;IAED,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,QAAQ,EAAE;QACjE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAA;KACnE;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,EAAE;QACrD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,wCAAwC,EAAE,CAAA;KAC3E;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AASD,MAAM,CAAC,IAAM,oBAAoB,GAAG,UAClC,MAA+B,EAC/B,SAAiB;IAEjB,IAAM,WAAW,GAAG,MAAqB,CAAA;IACzC,IAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAA;IAC3C,IAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAA;IAE/B,OAAO,2DAEP,yBAAyB,EAAE,iBAE3B,6BAA6B,EAAE,iBAE/B,+BAA+B,EAAE,iBAEjC,yBAAyB,EAAE,0IAMhB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,iCACrB,sBAAsB,CAAC,KAAK,CAAC,gLAKhB,SAAS,u5KAuKxC,CAAA;AACD,CAAC,CAAA"}
@@ -7,5 +7,5 @@ export * from './array-mapper-pagination';
7
7
  export * from './pagination-plugin';
8
8
  export * from './count-fetchers';
9
9
  export { buildProductTransformOptions } from './transformations';
10
- export type { EcommerceProductTransformOptions } from './transformations';
10
+ export type { EcommerceProductTransformOptions, EntityTransformOptions } from './transformations';
11
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EAKvB,MAAM,4BAA4B,CAAA;AA+anC,eAAO,MAAM,+BAA+B,EAAE,sBAAsB,CAAC,EAAE,CA8etE,CAAA;AAiOD,eAAO,MAAM,mCAAmC,EAAE,sBAAsB,CAAC,EAAE,CA6O1E,CAAA;AAED,cAAc,wBAAwB,CAAA;AACtC,cAAc,SAAS,CAAA;AACvB,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAIhC,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAA;AAChE,YAAY,EAAE,gCAAgC,EAAE,MAAM,mBAAmB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EAKvB,MAAM,4BAA4B,CAAA;AA+anC,eAAO,MAAM,+BAA+B,EAAE,sBAAsB,CAAC,EAAE,CA8etE,CAAA;AAiOD,eAAO,MAAM,mCAAmC,EAAE,sBAAsB,CAAC,EAAE,CA6O1E,CAAA;AAED,cAAc,wBAAwB,CAAA;AACtC,cAAc,SAAS,CAAA;AACvB,cAAc,2BAA2B,CAAA;AACzC,cAAc,qBAAqB,CAAA;AACnC,cAAc,kBAAkB,CAAA;AAIhC,OAAO,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAA;AAChE,YAAY,EAAE,gCAAgC,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"pagination-plugin.d.ts","sourceRoot":"","sources":["../../src/pagination-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EAGvB,MAAM,4BAA4B,CAAA;AA+iCnC,eAAO,MAAM,qCAAqC,EAAE,sBAAsB,CAAC,EAAE,CA40B5E,CAAA"}
1
+ {"version":3,"file":"pagination-plugin.d.ts","sourceRoot":"","sources":["../../src/pagination-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,sBAAsB,EAGvB,MAAM,4BAA4B,CAAA;AA4iCnC,eAAO,MAAM,qCAAqC,EAAE,sBAAsB,CAAC,EAAE,CA40B5E,CAAA"}
@@ -50,7 +50,7 @@ import { ASTStatementOrder, GenericUtils, StringUtils } from '@teleporthq/telepo
50
50
  import { ASTUtils, URLQueryWriter, URLSearchParamSync } from '@teleporthq/teleport-plugin-common';
51
51
  import { generateSafeFileName } from './utils';
52
52
  import { generateDataSourceFetcherWithCore } from './data-source-fetchers';
53
- import { buildProductTransformOptions, } from './transformations';
53
+ import { buildProductTransformOptions } from './transformations';
54
54
  import { appendSortsParam, extractDynamicSort } from './sort-utils';
55
55
  import { appendFiltersParam, pushStateIdsAsDeps, pushPropIdsAsDeps } from './filter-utils';
56
56
  import { applyLoadingStateToDataProvider, buildLoadingStateDeclarations, getLoadingStateVars, } from './loading-state';