@teleporthq/teleport-plugin-next-data-source 0.44.5 → 0.44.11

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 (34) hide show
  1. package/__tests__/items-path.test.ts +3 -2
  2. package/dist/cjs/fetchers/csv-file.js +1 -1
  3. package/dist/cjs/fetchers/csv-file.js.map +1 -1
  4. package/dist/cjs/fetchers/firestore.js +1 -1
  5. package/dist/cjs/fetchers/firestore.js.map +1 -1
  6. package/dist/cjs/fetchers/google-sheets.js +1 -1
  7. package/dist/cjs/fetchers/google-sheets.js.map +1 -1
  8. package/dist/cjs/fetchers/javascript.js +1 -1
  9. package/dist/cjs/fetchers/javascript.js.map +1 -1
  10. package/dist/cjs/fetchers/rest-api.js +1 -1
  11. package/dist/cjs/fetchers/rest-api.js.map +1 -1
  12. package/dist/cjs/fetchers/turso.js +1 -1
  13. package/dist/cjs/fetchers/turso.js.map +1 -1
  14. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  15. package/dist/esm/fetchers/csv-file.js +1 -1
  16. package/dist/esm/fetchers/csv-file.js.map +1 -1
  17. package/dist/esm/fetchers/firestore.js +1 -1
  18. package/dist/esm/fetchers/firestore.js.map +1 -1
  19. package/dist/esm/fetchers/google-sheets.js +1 -1
  20. package/dist/esm/fetchers/google-sheets.js.map +1 -1
  21. package/dist/esm/fetchers/javascript.js +1 -1
  22. package/dist/esm/fetchers/javascript.js.map +1 -1
  23. package/dist/esm/fetchers/rest-api.js +1 -1
  24. package/dist/esm/fetchers/rest-api.js.map +1 -1
  25. package/dist/esm/fetchers/turso.js +1 -1
  26. package/dist/esm/fetchers/turso.js.map +1 -1
  27. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  28. package/package.json +5 -5
  29. package/src/fetchers/csv-file.ts +5 -5
  30. package/src/fetchers/firestore.ts +2 -2
  31. package/src/fetchers/google-sheets.ts +5 -5
  32. package/src/fetchers/javascript.ts +5 -5
  33. package/src/fetchers/rest-api.ts +5 -5
  34. package/src/fetchers/turso.ts +2 -2
@@ -97,7 +97,7 @@ describe.each<[string, FetcherSetup]>([
97
97
  expect(data.templates.map((r) => r.id)).toEqual([11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
98
98
  })
99
99
 
100
- it('searches the inner array', async () => {
100
+ it('searches the inner array, every typed word on its own', async () => {
101
101
  const result = await runHandler(
102
102
  setup.code,
103
103
  {
@@ -108,8 +108,9 @@ describe.each<[string, FetcherSetup]>([
108
108
  setup.fetchImpl
109
109
  )
110
110
 
111
+ // "row" and "2" each match somewhere in the name: row 2, row 12, row 20–25.
111
112
  const data = result.data as { templates: Array<{ id: number }> }
112
- expect(data.templates.map((r) => r.id)).toEqual([2, 20, 21, 22, 23, 24, 25])
113
+ expect(data.templates.map((r) => r.id)).toEqual([2, 12, 20, 21, 22, 23, 24, 25])
113
114
  })
114
115
 
115
116
  it('returns the payload untouched without the param', async () => {
@@ -31,7 +31,7 @@ var validateCSVConfig = function (config) {
31
31
  };
32
32
  exports.validateCSVConfig = validateCSVConfig;
33
33
  var generateHandlerBody = function () {
34
- return "\n try {\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset: offsetParam } = req.query\n \n const labelToIdMap = {}\n columns.forEach((col) => {\n if (col.label && col.id) {\n labelToIdMap[col.label] = col.id\n }\n })\n \n let filteredData = [...data]\n \n if (query) {\n const searchQuery = query.toLowerCase()\n \n if (queryColumns) {\n const searchColumns = safeJSONParse(queryColumns)\n filteredData = filteredData.filter((item) => {\n return searchColumns.some((col) => {\n const field = labelToIdMap[col] || col\n const value = getNestedValue(item, field)\n return value && String(value).toLowerCase().includes(searchQuery)\n })\n })\n } else {\n filteredData = filteredData.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 const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n filteredData = filteredData.filter((item) =>\n evaluateFilterTree(filterTree, (condition) => {\n const field = labelToIdMap[condition.source] || condition.source\n const value = getNestedValue(item, field)\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 }\n \n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n filteredData.sort((a, b) => {\n for (const sort of parsedSorts) {\n if (!sort.field) continue\n const field = labelToIdMap[sort.field] || sort.field\n const aVal = getNestedValue(a, field)\n const bVal = getNestedValue(b, 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 } else if (sortBy) {\n const field = labelToIdMap[sortBy] || sortBy\n filteredData.sort((a, b) => {\n const aVal = getNestedValue(a, field)\n const bVal = getNestedValue(b, field)\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 offsetValue = offsetParam !== undefined ? parseInt(offsetParam) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : 0)\n \n if (limitValue) {\n filteredData = filteredData.slice(offsetValue, offsetValue + parseInt(limitValue))\n }\n \n const safeData = JSON.parse(JSON.stringify(filteredData, 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('CSV 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";
34
+ return "\n try {\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset: offsetParam } = req.query\n \n const labelToIdMap = {}\n columns.forEach((col) => {\n if (col.label && col.id) {\n labelToIdMap[col.label] = col.id\n }\n })\n \n let filteredData = [...data]\n \n if (query) {\n const searchTerms = query.toLowerCase().split(' ').filter(Boolean)\n \n if (queryColumns) {\n const searchColumns = safeJSONParse(queryColumns)\n filteredData = filteredData.filter((item) => {\n return searchTerms.every((term) => searchColumns.some((col) => {\n const field = labelToIdMap[col] || col\n const value = getNestedValue(item, field)\n return value && String(value).toLowerCase().includes(term)\n }))\n })\n } else {\n filteredData = filteredData.filter((item) => {\n try {\n const stringified = JSON.stringify(item).toLowerCase()\n return searchTerms.every((term) => stringified.includes(term))\n } catch {\n return false\n }\n })\n }\n }\n \n if (filters) {\n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n filteredData = filteredData.filter((item) =>\n evaluateFilterTree(filterTree, (condition) => {\n const field = labelToIdMap[condition.source] || condition.source\n const value = getNestedValue(item, field)\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 }\n \n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n filteredData.sort((a, b) => {\n for (const sort of parsedSorts) {\n if (!sort.field) continue\n const field = labelToIdMap[sort.field] || sort.field\n const aVal = getNestedValue(a, field)\n const bVal = getNestedValue(b, 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 } else if (sortBy) {\n const field = labelToIdMap[sortBy] || sortBy\n filteredData.sort((a, b) => {\n const aVal = getNestedValue(a, field)\n const bVal = getNestedValue(b, field)\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 offsetValue = offsetParam !== undefined ? parseInt(offsetParam) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : 0)\n \n if (limitValue) {\n filteredData = filteredData.slice(offsetValue, offsetValue + parseInt(limitValue))\n }\n \n const safeData = JSON.parse(JSON.stringify(filteredData, 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('CSV 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";
35
35
  };
36
36
  var generateCSVFileFetcher = function (config) {
37
37
  var csvConfig = config;
@@ -1 +1 @@
1
- {"version":3,"file":"csv-file.js","sourceRoot":"","sources":["../../../src/fetchers/csv-file.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"csv-file.js","sourceRoot":"","sources":["../../../src/fetchers/csv-file.ts"],"names":[],"mappings":"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"}
@@ -29,7 +29,7 @@ exports.validateFirestoreConfig = validateFirestoreConfig;
29
29
  var generateFirestoreFetcher = function (config, tableName) {
30
30
  var firestoreConfig = config;
31
31
  var serviceAccount = firestoreConfig.serviceAccount;
32
- return "import * as admin from 'firebase-admin'\n\nlet firestore = null\n\nconst getFirestore = () => {\n if (firestore) return firestore\n \n const rawServiceAccount = ".concat((0, utils_1.replaceSecretReference)(serviceAccount), "\n let serviceAccount\n\n try {\n serviceAccount = JSON.parse(rawServiceAccount)\n } catch (error) {\n throw new Error('Invalid Firestore service account JSON: ' + error.message)\n }\n \n if (!admin.apps.length) {\n admin.initializeApp({\n credential: admin.credential.cert(serviceAccount)\n })\n }\n \n firestore = admin.firestore()\n return firestore\n}\n\n").concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, utils_1.generateDateFormatterCode)(), "\n\nexport default async function handler(req, res) {\n try {\n const firestore = getFirestore()\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n let queryRef = firestore.collection('").concat(tableName, "')\n \n if (filters) {\n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n // Chained .where() calls are ANDed, so an OR group is built with\n // Firestore's composite Filter API instead.\n const operatorMap = {\n '=': '==',\n '!=': '!=',\n '>': '>',\n '<': '<',\n '>=': '>=',\n '<=': '<=',\n }\n \n const buildCondition = (condition) => {\n const field = condition.source\n const normalizedCondition = normalizeInOperand(condition.operand, condition.destination)\n if (normalizedCondition === null) return null\n const value = normalizedCondition.value\n const operand = normalizedCondition.operand\n \n if (Array.isArray(value)) {\n if (value.length === 0) return null\n return admin.firestore.Filter.where(field, operand === '!=' ? 'not-in' : 'in', value)\n }\n \n return admin.firestore.Filter.where(field, operatorMap[operand] || '==', value)\n }\n \n const buildNode = (node) => {\n if (node.type === 'group') {\n const parts = node.children.map(buildNode).filter(Boolean)\n if (parts.length === 0) return null\n if (parts.length === 1) return parts[0]\n return node.operator === 'or'\n ? admin.firestore.Filter.or(...parts)\n : admin.firestore.Filter.and(...parts)\n }\n return buildCondition(node)\n }\n \n const filterExpression = buildNode(filterTree)\n if (filterExpression) {\n queryRef = queryRef.where(filterExpression)\n }\n }\n }\n \n let usePostFiltering = false\n \n if (query) {\n if (queryColumns) {\n const parsed = safeJSONParse(queryColumns)\n const columns = Array.isArray(parsed) ? parsed : [parsed]\n for (const column of columns) {\n queryRef = queryRef\n .where(column, '>=', query)\n .where(column, '<=', query + '\\uf8ff')\n }\n } else {\n // Firestore doesn't support full-text search without queryColumns\n // We'll fetch all data and filter in JavaScript\n usePostFiltering = true\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 parsedSorts.forEach((sort) => {\n if (!sort.field) return\n const order = (sort.order || '').toLowerCase().startsWith('desc') ? 'desc' : 'asc'\n queryRef = queryRef.orderBy(sort.field, order)\n })\n }\n } else if (sortBy) {\n const sortOrderValue = (sortOrder || '').toLowerCase().startsWith('desc') ? 'desc' : 'asc'\n queryRef = queryRef.orderBy(sortBy, sortOrderValue)\n }\n \n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage && parseInt(page) > 1 ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n \n // Only apply pagination at query level if not post-filtering\n if (!usePostFiltering) {\n if (limitValue) {\n queryRef = queryRef.limit(parseInt(limitValue))\n }\n if (offsetValue !== undefined) {\n queryRef = queryRef.offset(offsetValue)\n }\n }\n \n const snapshot = await queryRef.get()\n let documents = []\n snapshot.forEach((doc) => {\n documents.push({\n id: doc.id,\n ...doc.data()\n })\n })\n \n // Apply post-filtering if needed\n if (usePostFiltering && query) {\n const searchQuery = query.toLowerCase()\n documents = documents.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 documents = documents.slice(start, start + parseInt(limitValue))\n } else if (offsetValue) {\n documents = documents.slice(offsetValue)\n }\n }\n \n const safeData = JSON.parse(JSON.stringify(documents, 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('Firestore 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");
32
+ return "import * as admin from 'firebase-admin'\n\nlet firestore = null\n\nconst getFirestore = () => {\n if (firestore) return firestore\n \n const rawServiceAccount = ".concat((0, utils_1.replaceSecretReference)(serviceAccount), "\n let serviceAccount\n\n try {\n serviceAccount = JSON.parse(rawServiceAccount)\n } catch (error) {\n throw new Error('Invalid Firestore service account JSON: ' + error.message)\n }\n \n if (!admin.apps.length) {\n admin.initializeApp({\n credential: admin.credential.cert(serviceAccount)\n })\n }\n \n firestore = admin.firestore()\n return firestore\n}\n\n").concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, utils_1.generateDateFormatterCode)(), "\n\nexport default async function handler(req, res) {\n try {\n const firestore = getFirestore()\n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query\n \n let queryRef = firestore.collection('").concat(tableName, "')\n \n if (filters) {\n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n // Chained .where() calls are ANDed, so an OR group is built with\n // Firestore's composite Filter API instead.\n const operatorMap = {\n '=': '==',\n '!=': '!=',\n '>': '>',\n '<': '<',\n '>=': '>=',\n '<=': '<=',\n }\n \n const buildCondition = (condition) => {\n const field = condition.source\n const normalizedCondition = normalizeInOperand(condition.operand, condition.destination)\n if (normalizedCondition === null) return null\n const value = normalizedCondition.value\n const operand = normalizedCondition.operand\n \n if (Array.isArray(value)) {\n if (value.length === 0) return null\n return admin.firestore.Filter.where(field, operand === '!=' ? 'not-in' : 'in', value)\n }\n \n return admin.firestore.Filter.where(field, operatorMap[operand] || '==', value)\n }\n \n const buildNode = (node) => {\n if (node.type === 'group') {\n const parts = node.children.map(buildNode).filter(Boolean)\n if (parts.length === 0) return null\n if (parts.length === 1) return parts[0]\n return node.operator === 'or'\n ? admin.firestore.Filter.or(...parts)\n : admin.firestore.Filter.and(...parts)\n }\n return buildCondition(node)\n }\n \n const filterExpression = buildNode(filterTree)\n if (filterExpression) {\n queryRef = queryRef.where(filterExpression)\n }\n }\n }\n \n let usePostFiltering = false\n \n if (query) {\n if (queryColumns) {\n const parsed = safeJSONParse(queryColumns)\n const columns = Array.isArray(parsed) ? parsed : [parsed]\n for (const column of columns) {\n queryRef = queryRef\n .where(column, '>=', query)\n .where(column, '<=', query + '\\uf8ff')\n }\n } else {\n // Firestore doesn't support full-text search without queryColumns\n // We'll fetch all data and filter in JavaScript\n usePostFiltering = true\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 parsedSorts.forEach((sort) => {\n if (!sort.field) return\n const order = (sort.order || '').toLowerCase().startsWith('desc') ? 'desc' : 'asc'\n queryRef = queryRef.orderBy(sort.field, order)\n })\n }\n } else if (sortBy) {\n const sortOrderValue = (sortOrder || '').toLowerCase().startsWith('desc') ? 'desc' : 'asc'\n queryRef = queryRef.orderBy(sortBy, sortOrderValue)\n }\n \n const limitValue = limit || perPage\n const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage && parseInt(page) > 1 ? (parseInt(page) - 1) * parseInt(perPage) : undefined)\n \n // Only apply pagination at query level if not post-filtering\n if (!usePostFiltering) {\n if (limitValue) {\n queryRef = queryRef.limit(parseInt(limitValue))\n }\n if (offsetValue !== undefined) {\n queryRef = queryRef.offset(offsetValue)\n }\n }\n \n const snapshot = await queryRef.get()\n let documents = []\n snapshot.forEach((doc) => {\n documents.push({\n id: doc.id,\n ...doc.data()\n })\n })\n \n // Apply post-filtering if needed\n if (usePostFiltering && query) {\n const searchTerms = query.toLowerCase().split(' ').filter(Boolean)\n documents = documents.filter((item) => {\n try {\n const stringified = JSON.stringify(item).toLowerCase()\n return searchTerms.every((term) => stringified.includes(term))\n } catch {\n return false\n }\n })\n \n // Apply pagination after filtering\n if (limitValue) {\n const start = offsetValue || 0\n documents = documents.slice(start, start + parseInt(limitValue))\n } else if (offsetValue) {\n documents = documents.slice(offsetValue)\n }\n }\n \n const safeData = JSON.parse(JSON.stringify(documents, 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('Firestore 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");
33
33
  };
34
34
  exports.generateFirestoreFetcher = generateFirestoreFetcher;
35
35
  //# sourceMappingURL=firestore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"firestore.js","sourceRoot":"","sources":["../../../src/fetchers/firestore.ts"],"names":[],"mappings":";;;AAAA,kCAKiB;AAEV,IAAM,uBAAuB,GAAG,UACrC,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,cAAc,IAAI,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ,EAAE;QACvE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAA;KAC/E;IAED,IAAM,cAAc,GAAG,MAAM,CAAC,cAAwB,CAAA;IAEtD,iGAAiG;IACjG,sEAAsE;IACtE,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE;QACrD,IAAI;YACF,IAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;YACzC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;gBACrE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kDAAkD,EAAE,CAAA;aACrF;SACF;QAAC,WAAM;YACN,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAA;SACvE;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AA3BY,QAAA,uBAAuB,2BA2BnC;AAOM,IAAM,wBAAwB,GAAG,UACtC,MAA+B,EAC/B,SAAiB;IAEjB,IAAM,eAAe,GAAG,MAAyB,CAAA;IACjD,IAAM,cAAc,GAAG,eAAe,CAAC,cAAc,CAAA;IAErD,OAAO,8KAOqB,IAAA,8BAAsB,EAAC,cAAc,CAAC,+YAmBlE,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,iCAAyB,GAAE,kRAOc,SAAS,urJA+InD,CAAA;AACD,CAAC,CAAA;AA5LY,QAAA,wBAAwB,4BA4LpC"}
1
+ {"version":3,"file":"firestore.js","sourceRoot":"","sources":["../../../src/fetchers/firestore.ts"],"names":[],"mappings":";;;AAAA,kCAKiB;AAEV,IAAM,uBAAuB,GAAG,UACrC,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,cAAc,IAAI,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ,EAAE;QACvE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,4CAA4C,EAAE,CAAA;KAC/E;IAED,IAAM,cAAc,GAAG,MAAM,CAAC,cAAwB,CAAA;IAEtD,iGAAiG;IACjG,sEAAsE;IACtE,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,qBAAqB,CAAC,EAAE;QACrD,IAAI;YACF,IAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAA;YACzC,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE;gBACrE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kDAAkD,EAAE,CAAA;aACrF;SACF;QAAC,WAAM;YACN,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,oCAAoC,EAAE,CAAA;SACvE;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AA3BY,QAAA,uBAAuB,2BA2BnC;AAOM,IAAM,wBAAwB,GAAG,UACtC,MAA+B,EAC/B,SAAiB;IAEjB,IAAM,eAAe,GAAG,MAAyB,CAAA;IACjD,IAAM,cAAc,GAAG,eAAe,CAAC,cAAc,CAAA;IAErD,OAAO,8KAOqB,IAAA,8BAAsB,EAAC,cAAc,CAAC,+YAmBlE,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,iCAAyB,GAAE,kRAOc,SAAS,wuJA+InD,CAAA;AACD,CAAC,CAAA;AA5LY,QAAA,wBAAwB,4BA4LpC"}
@@ -29,7 +29,7 @@ var generateGoogleSheetsFetcher = function (config) {
29
29
  var autoDetectHeader = sheetsConfig.autoDetectHeader;
30
30
  var firstRowIsHeader = sheetsConfig.firstRowIsHeader;
31
31
  var configColumns = sheetsConfig.columns || [];
32
- return "import fetch from 'node-fetch'\n\n".concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateSortFilterHelperCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, header_detection_1.generateHeaderDetectionCode)(), "\n\nexport default async function handler(req, res) {\n try {\n const sheetUrl = ").concat(JSON.stringify(sheetsConfig.sheetUrl), "\n let sheetId = ").concat(JSON.stringify(sheetsConfig.sheetId), "\n const range = ").concat(JSON.stringify(sheetsConfig.range || 'A1:Z1000'), "\n const maxRows = ").concat(sheetsConfig.maxRows || 0, "\n const autoDetectHeader = ").concat(autoDetectHeader !== undefined ? autoDetectHeader : true, "\n const firstRowIsHeader = ").concat(firstRowIsHeader !== undefined ? firstRowIsHeader : true, "\n \n if (!sheetId && sheetUrl) {\n const match = sheetUrl.match(/\\/d\\/([a-zA-Z0-9-_]+)/)\n sheetId = match ? match[1] : undefined\n }\n \n if (!sheetId) {\n return res.status(400).json({\n success: false,\n error: 'Invalid Google Sheets URL or Sheet ID',\n timestamp: Date.now()\n })\n }\n \n let gid = undefined\n if (sheetUrl) {\n const gidMatch = sheetUrl.match(/[#&]gid=([0-9]+)/)\n gid = gidMatch ? gidMatch[1] : undefined\n }\n \n let url = `https://docs.google.com/spreadsheets/d/${sheetId}/gviz/tq?tqx=out:json&range=${range}`\n \n if (gid) {\n url += `&gid=${gid}`\n }\n \n if (maxRows && maxRows > 0) {\n url += `&tq=limit ${maxRows}`\n }\n \n const response = await fetch(url)\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 const text = await response.text()\n const jsonMatch = text.match(/google\\.visualization\\.Query\\.setResponse\\((.*)\\);/)\n \n if (!jsonMatch) {\n return res.status(500).json({\n success: false,\n error: 'Unable to parse Google Sheets response',\n timestamp: Date.now()\n })\n }\n \n const data = JSON.parse(jsonMatch[1])\n \n if (data.status === 'error') {\n return res.status(500).json({\n success: false,\n error: data.errors?.[0]?.detailed_message || 'Failed to fetch Google Sheets data',\n timestamp: Date.now()\n })\n }\n \n const formatDateValue = (date) => {\n const options = {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n }\n \n const timeOptions = {\n hour: '2-digit',\n minute: '2-digit',\n }\n \n const hasTime = date.getHours() !== 0 || date.getMinutes() !== 0 || date.getSeconds() !== 0\n \n if (hasTime) {\n return date.toLocaleString('en-US', { ...options, ...timeOptions })\n }\n \n return date.toLocaleDateString('en-US', options)\n }\n \n const parseGoogleSheetsValue = (value) => {\n if (typeof value === 'string') {\n const dateMatch = value.match(/^Date\\((\\d+),(\\d+),(\\d+)(?:,(\\d+),(\\d+),(\\d+))?\\)$/)\n if (dateMatch) {\n const year = parseInt(dateMatch[1], 10)\n const month = parseInt(dateMatch[2], 10)\n const day = parseInt(dateMatch[3], 10)\n const hour = dateMatch[4] ? parseInt(dateMatch[4], 10) : 0\n const minute = dateMatch[5] ? parseInt(dateMatch[5], 10) : 0\n const second = dateMatch[6] ? parseInt(dateMatch[6], 10) : 0\n const date = new Date(year, month, day, hour, minute, second)\n return formatDateValue(date)\n }\n }\n return value\n }\n \n const table = data.table\n const rawRows = table.rows || []\n \n if (rawRows.length === 0) {\n return res.status(200).json({\n success: true,\n data: [],\n timestamp: Date.now()\n })\n }\n \n const firstRow = rawRows[0]\n const firstRowValues = firstRow.c.map((cell) => cell?.v ?? cell?.f ?? null)\n \n const shouldAutoDetect = autoDetectHeader !== false\n let hasHeaderRow = false\n \n if (shouldAutoDetect) {\n hasHeaderRow = detectHeaderRow(firstRowValues, rawRows)\n } else {\n hasHeaderRow = firstRowIsHeader !== false\n }\n \n const configColumns = ").concat(JSON.stringify(configColumns), "\n const useConfigColumns = configColumns && configColumns.length > 0\n \n let columns\n let dataRows\n \n if (hasHeaderRow && rawRows.length > 1) {\n columns = table.cols.map((col, index) => {\n const configCol = useConfigColumns ? configColumns[index] : null\n return {\n id: configCol?.id || col.id || `col_${index}`,\n label: String(firstRowValues[index] || col.label || configCol?.label || `Column ${index + 1}`),\n type: configCol?.type || col.type || 'string'\n }\n })\n dataRows = rawRows.slice(1)\n } else {\n columns = table.cols.map((col, index) => {\n const configCol = useConfigColumns ? configColumns[index] : null\n return {\n id: configCol?.id || col.id || `col_${index}`,\n label: configCol?.label || col.label || `Column ${index + 1}`,\n type: configCol?.type || col.type || 'string'\n }\n })\n dataRows = rawRows\n }\n \n if (maxRows && dataRows.length > maxRows) {\n dataRows = dataRows.slice(0, maxRows)\n }\n \n const rows = dataRows.map((row) => {\n const rowData = {}\n row.c.forEach((cell, index) => {\n const columnId = columns[index]?.id || `col_${index}`\n const rawValue = cell?.v ?? cell?.f ?? null\n rowData[columnId] = parseGoogleSheetsValue(rawValue)\n })\n return rowData\n })\n \n const columnsWithData = columns.filter((col, index) => {\n const hasHeaderData = col.label && col.label !== `Column ${index + 1}`\n const hasDataInColumn = rows.some((row) => {\n const value = row[col.id]\n return value !== null && value !== undefined && value !== ''\n })\n return hasHeaderData || hasDataInColumn\n })\n \n const filteredRows = rows.map((row) => {\n const filteredRow = {}\n columnsWithData.forEach((col) => {\n filteredRow[col.id] = row[col.id]\n })\n return filteredRow\n })\n \n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset: offsetParam } = req.query\n \n // Create label-to-ID mapping for filters and sorts\n const labelToIdMap = {}\n columnsWithData.forEach((col) => {\n labelToIdMap[col.label] = col.id\n })\n \n let filteredData = [...filteredRows]\n \n if (query) {\n const searchQuery = query.toLowerCase()\n \n if (queryColumns) {\n const searchColumns = safeJSONParse(queryColumns)\n filteredData = filteredData.filter((item) => {\n return searchColumns.some((col) => {\n // Map label to column ID\n const field = labelToIdMap[col] || col\n const value = getNestedValue(item, field)\n return value && String(value).toLowerCase().includes(searchQuery)\n })\n })\n } else {\n filteredData = filteredData.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 const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n filteredData = filteredData.filter((item) =>\n evaluateFilterTree(filterTree, (condition) => {\n // Map label to column ID\n const field = labelToIdMap[condition.source] || condition.source\n const value = getNestedValue(item, field)\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 }\n \n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n filteredData.sort((a, b) => {\n for (const sort of parsedSorts) {\n if (!sort.field) continue\n // Map label to column ID\n const field = labelToIdMap[sort.field] || sort.field\n const aVal = getNestedValue(a, field)\n const bVal = getNestedValue(b, 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 } else if (sortBy) {\n filteredData.sort((a, b) => {\n // Map label to column ID\n const field = labelToIdMap[sortBy] || sortBy\n const aVal = getNestedValue(a, field)\n const bVal = getNestedValue(b, field)\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 offsetValue = offsetParam !== undefined ? parseInt(offsetParam) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : 0)\n \n if (limitValue) {\n filteredData = filteredData.slice(offsetValue, offsetValue + parseInt(limitValue))\n }\n \n const safeData = JSON.parse(JSON.stringify(filteredData))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Google Sheets 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");
32
+ return "import fetch from 'node-fetch'\n\n".concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateSortFilterHelperCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, header_detection_1.generateHeaderDetectionCode)(), "\n\nexport default async function handler(req, res) {\n try {\n const sheetUrl = ").concat(JSON.stringify(sheetsConfig.sheetUrl), "\n let sheetId = ").concat(JSON.stringify(sheetsConfig.sheetId), "\n const range = ").concat(JSON.stringify(sheetsConfig.range || 'A1:Z1000'), "\n const maxRows = ").concat(sheetsConfig.maxRows || 0, "\n const autoDetectHeader = ").concat(autoDetectHeader !== undefined ? autoDetectHeader : true, "\n const firstRowIsHeader = ").concat(firstRowIsHeader !== undefined ? firstRowIsHeader : true, "\n \n if (!sheetId && sheetUrl) {\n const match = sheetUrl.match(/\\/d\\/([a-zA-Z0-9-_]+)/)\n sheetId = match ? match[1] : undefined\n }\n \n if (!sheetId) {\n return res.status(400).json({\n success: false,\n error: 'Invalid Google Sheets URL or Sheet ID',\n timestamp: Date.now()\n })\n }\n \n let gid = undefined\n if (sheetUrl) {\n const gidMatch = sheetUrl.match(/[#&]gid=([0-9]+)/)\n gid = gidMatch ? gidMatch[1] : undefined\n }\n \n let url = `https://docs.google.com/spreadsheets/d/${sheetId}/gviz/tq?tqx=out:json&range=${range}`\n \n if (gid) {\n url += `&gid=${gid}`\n }\n \n if (maxRows && maxRows > 0) {\n url += `&tq=limit ${maxRows}`\n }\n \n const response = await fetch(url)\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 const text = await response.text()\n const jsonMatch = text.match(/google\\.visualization\\.Query\\.setResponse\\((.*)\\);/)\n \n if (!jsonMatch) {\n return res.status(500).json({\n success: false,\n error: 'Unable to parse Google Sheets response',\n timestamp: Date.now()\n })\n }\n \n const data = JSON.parse(jsonMatch[1])\n \n if (data.status === 'error') {\n return res.status(500).json({\n success: false,\n error: data.errors?.[0]?.detailed_message || 'Failed to fetch Google Sheets data',\n timestamp: Date.now()\n })\n }\n \n const formatDateValue = (date) => {\n const options = {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n }\n \n const timeOptions = {\n hour: '2-digit',\n minute: '2-digit',\n }\n \n const hasTime = date.getHours() !== 0 || date.getMinutes() !== 0 || date.getSeconds() !== 0\n \n if (hasTime) {\n return date.toLocaleString('en-US', { ...options, ...timeOptions })\n }\n \n return date.toLocaleDateString('en-US', options)\n }\n \n const parseGoogleSheetsValue = (value) => {\n if (typeof value === 'string') {\n const dateMatch = value.match(/^Date\\((\\d+),(\\d+),(\\d+)(?:,(\\d+),(\\d+),(\\d+))?\\)$/)\n if (dateMatch) {\n const year = parseInt(dateMatch[1], 10)\n const month = parseInt(dateMatch[2], 10)\n const day = parseInt(dateMatch[3], 10)\n const hour = dateMatch[4] ? parseInt(dateMatch[4], 10) : 0\n const minute = dateMatch[5] ? parseInt(dateMatch[5], 10) : 0\n const second = dateMatch[6] ? parseInt(dateMatch[6], 10) : 0\n const date = new Date(year, month, day, hour, minute, second)\n return formatDateValue(date)\n }\n }\n return value\n }\n \n const table = data.table\n const rawRows = table.rows || []\n \n if (rawRows.length === 0) {\n return res.status(200).json({\n success: true,\n data: [],\n timestamp: Date.now()\n })\n }\n \n const firstRow = rawRows[0]\n const firstRowValues = firstRow.c.map((cell) => cell?.v ?? cell?.f ?? null)\n \n const shouldAutoDetect = autoDetectHeader !== false\n let hasHeaderRow = false\n \n if (shouldAutoDetect) {\n hasHeaderRow = detectHeaderRow(firstRowValues, rawRows)\n } else {\n hasHeaderRow = firstRowIsHeader !== false\n }\n \n const configColumns = ").concat(JSON.stringify(configColumns), "\n const useConfigColumns = configColumns && configColumns.length > 0\n \n let columns\n let dataRows\n \n if (hasHeaderRow && rawRows.length > 1) {\n columns = table.cols.map((col, index) => {\n const configCol = useConfigColumns ? configColumns[index] : null\n return {\n id: configCol?.id || col.id || `col_${index}`,\n label: String(firstRowValues[index] || col.label || configCol?.label || `Column ${index + 1}`),\n type: configCol?.type || col.type || 'string'\n }\n })\n dataRows = rawRows.slice(1)\n } else {\n columns = table.cols.map((col, index) => {\n const configCol = useConfigColumns ? configColumns[index] : null\n return {\n id: configCol?.id || col.id || `col_${index}`,\n label: configCol?.label || col.label || `Column ${index + 1}`,\n type: configCol?.type || col.type || 'string'\n }\n })\n dataRows = rawRows\n }\n \n if (maxRows && dataRows.length > maxRows) {\n dataRows = dataRows.slice(0, maxRows)\n }\n \n const rows = dataRows.map((row) => {\n const rowData = {}\n row.c.forEach((cell, index) => {\n const columnId = columns[index]?.id || `col_${index}`\n const rawValue = cell?.v ?? cell?.f ?? null\n rowData[columnId] = parseGoogleSheetsValue(rawValue)\n })\n return rowData\n })\n \n const columnsWithData = columns.filter((col, index) => {\n const hasHeaderData = col.label && col.label !== `Column ${index + 1}`\n const hasDataInColumn = rows.some((row) => {\n const value = row[col.id]\n return value !== null && value !== undefined && value !== ''\n })\n return hasHeaderData || hasDataInColumn\n })\n \n const filteredRows = rows.map((row) => {\n const filteredRow = {}\n columnsWithData.forEach((col) => {\n filteredRow[col.id] = row[col.id]\n })\n return filteredRow\n })\n \n const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset: offsetParam } = req.query\n \n // Create label-to-ID mapping for filters and sorts\n const labelToIdMap = {}\n columnsWithData.forEach((col) => {\n labelToIdMap[col.label] = col.id\n })\n \n let filteredData = [...filteredRows]\n \n if (query) {\n const searchTerms = query.toLowerCase().split(' ').filter(Boolean)\n \n if (queryColumns) {\n const searchColumns = safeJSONParse(queryColumns)\n filteredData = filteredData.filter((item) => {\n return searchTerms.every((term) => searchColumns.some((col) => {\n // Map label to column ID\n const field = labelToIdMap[col] || col\n const value = getNestedValue(item, field)\n return value && String(value).toLowerCase().includes(term)\n }))\n })\n } else {\n filteredData = filteredData.filter((item) => {\n try {\n const stringified = JSON.stringify(item).toLowerCase()\n return searchTerms.every((term) => stringified.includes(term))\n } catch {\n return false\n }\n })\n }\n }\n \n if (filters) {\n const filterTree = normalizeFilterTree(safeJSONParse(filters))\n \n if (filterTree) {\n filteredData = filteredData.filter((item) =>\n evaluateFilterTree(filterTree, (condition) => {\n // Map label to column ID\n const field = labelToIdMap[condition.source] || condition.source\n const value = getNestedValue(item, field)\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 }\n \n if (sorts) {\n const parsedSorts = safeJSONParse(sorts)\n if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {\n filteredData.sort((a, b) => {\n for (const sort of parsedSorts) {\n if (!sort.field) continue\n // Map label to column ID\n const field = labelToIdMap[sort.field] || sort.field\n const aVal = getNestedValue(a, field)\n const bVal = getNestedValue(b, 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 } else if (sortBy) {\n filteredData.sort((a, b) => {\n // Map label to column ID\n const field = labelToIdMap[sortBy] || sortBy\n const aVal = getNestedValue(a, field)\n const bVal = getNestedValue(b, field)\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 offsetValue = offsetParam !== undefined ? parseInt(offsetParam) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : 0)\n \n if (limitValue) {\n filteredData = filteredData.slice(offsetValue, offsetValue + parseInt(limitValue))\n }\n \n const safeData = JSON.parse(JSON.stringify(filteredData))\n \n return res.status(200).json({\n success: true,\n data: safeData,\n timestamp: Date.now()\n })\n } catch (error) {\n console.error('Google Sheets 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");
33
33
  };
34
34
  exports.generateGoogleSheetsFetcher = generateGoogleSheetsFetcher;
35
35
  //# sourceMappingURL=google-sheets.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"google-sheets.js","sourceRoot":"","sources":["../../../src/fetchers/google-sheets.ts"],"names":[],"mappings":";;;AAAA,kCAIiB;AACjB,6DAAsE;AAE/D,IAAM,0BAA0B,GAAG,UACxC,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,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;QACvC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAA;KACxE;IAED,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE;QACxD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAA;KAC9D;IAED,IAAI,MAAM,CAAC,QAAQ,EAAE;QACnB,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE;YACvC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAA;SAC/D;QAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAAE;YAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAA;SACrE;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AA1BY,QAAA,0BAA0B,8BA0BtC;AAcM,IAAM,2BAA2B,GAAG,UAAC,MAA+B;IACzE,IAAM,YAAY,GAAG,MAA4B,CAAA;IACjD,IAAM,gBAAgB,GAAG,YAAY,CAAC,gBAAgB,CAAA;IACtD,IAAM,gBAAgB,GAAG,YAAY,CAAC,gBAAgB,CAAA;IACtD,IAAM,aAAa,GAAG,YAAY,CAAC,OAAO,IAAI,EAAE,CAAA;IAEhD,OAAO,4CAEP,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,oCAA4B,GAAE,iBAE9B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,8CAA2B,GAAE,kGAIR,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC,iCACxC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,iCACpC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,IAAI,UAAU,CAAC,mCAC9C,YAAY,CAAC,OAAO,IAAI,CAAC,4CAChB,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,4CACxD,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,6iHA2H3D,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,qoOA2MxD,CAAA;AACD,CAAC,CAAA;AA9VY,QAAA,2BAA2B,+BA8VvC"}
1
+ {"version":3,"file":"google-sheets.js","sourceRoot":"","sources":["../../../src/fetchers/google-sheets.ts"],"names":[],"mappings":";;;AAAA,kCAIiB;AACjB,6DAAsE;AAE/D,IAAM,0BAA0B,GAAG,UACxC,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,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;QACvC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,qCAAqC,EAAE,CAAA;KACxE;IAED,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE;QACxD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAA;KAC9D;IAED,IAAI,MAAM,CAAC,QAAQ,EAAE;QACnB,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE;YACvC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAA;SAC/D;QAED,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAAE;YAC7D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAA;SACrE;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AA1BY,QAAA,0BAA0B,8BA0BtC;AAcM,IAAM,2BAA2B,GAAG,UAAC,MAA+B;IACzE,IAAM,YAAY,GAAG,MAA4B,CAAA;IACjD,IAAM,gBAAgB,GAAG,YAAY,CAAC,gBAAgB,CAAA;IACtD,IAAM,gBAAgB,GAAG,YAAY,CAAC,gBAAgB,CAAA;IACtD,IAAM,aAAa,GAAG,YAAY,CAAC,OAAO,IAAI,EAAE,CAAA;IAEhD,OAAO,4CAEP,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,oCAA4B,GAAE,iBAE9B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,8CAA2B,GAAE,kGAIR,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAQ,CAAC,iCACxC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,OAAO,CAAC,iCACpC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,IAAI,UAAU,CAAC,mCAC9C,YAAY,CAAC,OAAO,IAAI,CAAC,4CAChB,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,4CACxD,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,6iHA2H3D,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,4sOA2MxD,CAAA;AACD,CAAC,CAAA;AA9VY,QAAA,2BAA2B,+BA8VvC"}
@@ -30,7 +30,7 @@ var validateJavaScriptConfig = function (config) {
30
30
  exports.validateJavaScriptConfig = validateJavaScriptConfig;
31
31
  var generateJavaScriptFetcher = function (config) {
32
32
  var jsConfig = config;
33
- return "".concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateDateFormatterCode)(), "\n\n").concat((0, utils_1.generateSortFilterHelperCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, utils_1.generateCollectionPathHelperCode)(), "\n\nexport default async function handler(req, res) {\n try {\n const { limit, offset, page, perPage, query, queryColumns, sortBy, sortOrder, filters, sorts, collectionPath, itemsPath } = req.query\n \n const code = ").concat(JSON.stringify(jsConfig.code), "\n const executeCode = new Function('return ' + code)\n let data = resolveCollectionPath(executeCode(), collectionPath)\n const itemsEnvelope = openItemsEnvelope(data, itemsPath)\n if (itemsEnvelope) {\n data = itemsEnvelope.items\n }\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 if (itemsEnvelope) {\n data = itemsEnvelope.close(data)\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('JavaScript execution error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to execute code',\n timestamp: Date.now()\n })\n }\n}\n");
33
+ return "".concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateDateFormatterCode)(), "\n\n").concat((0, utils_1.generateSortFilterHelperCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, utils_1.generateCollectionPathHelperCode)(), "\n\nexport default async function handler(req, res) {\n try {\n const { limit, offset, page, perPage, query, queryColumns, sortBy, sortOrder, filters, sorts, collectionPath, itemsPath } = req.query\n \n const code = ").concat(JSON.stringify(jsConfig.code), "\n const executeCode = new Function('return ' + code)\n let data = resolveCollectionPath(executeCode(), collectionPath)\n const itemsEnvelope = openItemsEnvelope(data, itemsPath)\n if (itemsEnvelope) {\n data = itemsEnvelope.items\n }\n \n if (Array.isArray(data)) {\n if (query && query.trim()) {\n const searchTerms = query.toLowerCase().split(' ').filter(Boolean)\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 searchTerms.every((term) => columns.some(col => {\n const value = getNestedValue(item, col)\n if (value === null || value === undefined) return false\n return String(value).toLowerCase().includes(term)\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 searchTerms.every((term) => stringified.includes(term))\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 if (itemsEnvelope) {\n data = itemsEnvelope.close(data)\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('JavaScript execution error:', error)\n return res.status(500).json({\n success: false,\n error: error.message || 'Failed to execute code',\n timestamp: Date.now()\n })\n }\n}\n");
34
34
  };
35
35
  exports.generateJavaScriptFetcher = generateJavaScriptFetcher;
36
36
  // tslint:disable-next-line:variable-name
@@ -1 +1 @@
1
- {"version":3,"file":"javascript.js","sourceRoot":"","sources":["../../../src/fetchers/javascript.ts"],"names":[],"mappings":";;;AAAA,kCAMiB;AAEV,IAAM,wBAAwB,GAAG,UACtC,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,IAAI,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAChF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAA;KAChE;IAED,IAAM,iBAAiB,GAAG;QACxB,eAAe;QACf,YAAY;QACZ,YAAY;QACZ,gBAAgB;QAChB,YAAY;QACZ,WAAW;QACX,cAAc;KACf,CAAA;IAED,KAAsB,UAAiB,EAAjB,uCAAiB,EAAjB,+BAAiB,EAAjB,IAAiB,EAAE;QAApC,IAAM,OAAO,0BAAA;QAChB,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;YAC7B,OAAO,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAA;YAC9F,MAAK;SACN;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AA7BY,QAAA,wBAAwB,4BA6BpC;AAMM,IAAM,yBAAyB,GAAG,UAAC,MAA+B;IACvE,IAAM,QAAQ,GAAG,MAA0B,CAAA;IAE3C,OAAO,UAAG,IAAA,iCAAyB,GAAE,iBAErC,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,oCAA4B,GAAE,iBAE9B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,wCAAgC,GAAE,+OAMjB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,6vLA8J/C,CAAA;AACD,CAAC,CAAA;AAhLY,QAAA,yBAAyB,6BAgLrC;AAED,yCAAyC;AAClC,IAAM,8BAA8B,GAAG,UAAC,OAAY;IACzD,OAAO,m2CAgDR,CAAA;AACD,CAAC,CAAA;AAlDY,QAAA,8BAA8B,kCAkD1C"}
1
+ {"version":3,"file":"javascript.js","sourceRoot":"","sources":["../../../src/fetchers/javascript.ts"],"names":[],"mappings":";;;AAAA,kCAMiB;AAEV,IAAM,wBAAwB,GAAG,UACtC,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,IAAI,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAChF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAA;KAChE;IAED,IAAM,iBAAiB,GAAG;QACxB,eAAe;QACf,YAAY;QACZ,YAAY;QACZ,gBAAgB;QAChB,YAAY;QACZ,WAAW;QACX,cAAc;KACf,CAAA;IAED,KAAsB,UAAiB,EAAjB,uCAAiB,EAAjB,+BAAiB,EAAjB,IAAiB,EAAE;QAApC,IAAM,OAAO,0BAAA;QAChB,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;YAC7B,OAAO,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAA;YAC9F,MAAK;SACN;KACF;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;AAC1B,CAAC,CAAA;AA7BY,QAAA,wBAAwB,4BA6BpC;AAMM,IAAM,yBAAyB,GAAG,UAAC,MAA+B;IACvE,IAAM,QAAQ,GAAG,MAA0B,CAAA;IAE3C,OAAO,UAAG,IAAA,iCAAyB,GAAE,iBAErC,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,oCAA4B,GAAE,iBAE9B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,wCAAgC,GAAE,+OAMjB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,o0LA8J/C,CAAA;AACD,CAAC,CAAA;AAhLY,QAAA,yBAAyB,6BAgLrC;AAED,yCAAyC;AAClC,IAAM,8BAA8B,GAAG,UAAC,OAAY;IACzD,OAAO,m2CAgDR,CAAA;AACD,CAAC,CAAA;AAlDY,QAAA,8BAA8B,kCAkD1C"}
@@ -92,7 +92,7 @@ var generateRESTAPIFetcher = function (config) {
92
92
  restConfig.body
93
93
  ? " else {\n options.body = ".concat(JSON.stringify(restConfig.body), "\n }")
94
94
  : '', "\n ")
95
- : '', "\n \n const response = await ").concat(cached ? 'fetchRestApiWithCache' : '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 = ").concat(cached ? 'JSON.parse(response.bodyText)' : 'await response.json()', "\n \n data = resolveCollectionPath(data, collectionPath)\n const itemsEnvelope = openItemsEnvelope(data, itemsPath)\n if (itemsEnvelope) {\n data = itemsEnvelope.items\n }\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 if (itemsEnvelope) {\n data = itemsEnvelope.close(data)\n }\n \n const safeData = JSON.parse(JSON.stringify(data, dateReplacer))\n \n ").concat(cached ? 'applyRestApiCacheHeaders(req, res, response.fetchedAt)\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");
95
+ : '', "\n \n const response = await ").concat(cached ? 'fetchRestApiWithCache' : '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 = ").concat(cached ? 'JSON.parse(response.bodyText)' : 'await response.json()', "\n \n data = resolveCollectionPath(data, collectionPath)\n const itemsEnvelope = openItemsEnvelope(data, itemsPath)\n if (itemsEnvelope) {\n data = itemsEnvelope.items\n }\n \n if (Array.isArray(data)) {\n if (query && query.trim()) {\n const searchTerms = query.toLowerCase().split(' ').filter(Boolean)\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 searchTerms.every((term) => columns.some((col) => {\n const value = getNestedValue(item, col)\n if (value === null || value === undefined) return false\n return String(value).toLowerCase().includes(term)\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 searchTerms.every((term) => stringified.includes(term))\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 if (itemsEnvelope) {\n data = itemsEnvelope.close(data)\n }\n \n const safeData = JSON.parse(JSON.stringify(data, dateReplacer))\n \n ").concat(cached ? 'applyRestApiCacheHeaders(req, res, response.fetchedAt)\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");
96
96
  };
97
97
  exports.generateRESTAPIFetcher = generateRESTAPIFetcher;
98
98
  //# sourceMappingURL=rest-api.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rest-api.js","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rest-api.js","sourceRoot":"","sources":["../../../src/fetchers/rest-api.ts"],"names":[],"mappings":";;;AAAA,kCAMiB;AACjB,2EAIwC;AAEjC,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;AA5BY,QAAA,qBAAqB,yBA4BjC;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,0EAA0E;YAC1E,wCAAwC;YACxC,OAAO,kCAA2B,WAAW,CAAC,MAAM,MAAG,CAAA;QACzD,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;AAaD;;;;;;;;GAQG;AACH,IAAM,eAAe,GAAG,UACtB,GAAuB,EACvB,WAAoC;IAEpC,IAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CACrD,UAAC,EAAY;YAAX,GAAG,QAAA,EAAE,KAAK,QAAA;QAAM,OAAA,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,OAAO,KAAK,KAAK,QAAQ;IAA9C,CAA8C,CACjE,CAAA;IACD,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE;QAC/B,OAAO,GAAG,CAAA;KACX;IAED,IAAM,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IAC/B,MAAM,CAAC,OAAO,CAAC,UAAC,EAAY;YAAX,GAAG,QAAA,EAAE,KAAK,QAAA;QAAM,OAAA,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC;IAA1C,CAA0C,CAAC,CAAA;IAC5E,OAAO,UAAU,CAAC,QAAQ,EAAE,CAAA;AAC9B,CAAC,CAAA;AAEM,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;IACjE,sEAAsE;IACtE,+DAA+D;IAC/D,IAAM,eAAe,GAAG,IAAA,uDAA6B,EAAC,UAAU,CAAC,KAAK,CAAC,CAAA;IACvE,IAAM,MAAM,GAAG,eAAe,KAAK,SAAS,CAAA;IAE5C,OAAO,4CAEP,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,oCAA4B,GAAE,iBAE9B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,wCAAgC,GAAE,SAChC,MAAM,CAAC,CAAC,CAAC,cAAO,IAAA,0DAAgC,EAAC,eAAe,CAAC,CAAE,CAAC,CAAC,CAAC,EAAE,8OAO1D,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,UAAU,CAAC,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,kCACpE,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;QAGhB,qEAAqE;QACrE,yEAAyE;QACzE,yEAAyE;QACzE,qEAAqE;QACrE,mDAAmD;QACnD,UAAU,CAAC,IAAI;YACb,CAAC,CAAC,wCACa,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,YAChD;YACE,CAAC,CAAC,EAAE,WAEP;QACG,CAAC,CAAC,EAAE,gDAGiB,MAAM,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,OAAO,8QAUtD,MAAM,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,uBAAuB,o7KAiJ7E,MAAM,CAAC,CAAC,CAAC,oEAAoE,CAAC,CAAC,CAAC,EAAE,4VAevF,CAAA;AACD,CAAC,CAAA;AAzOY,QAAA,sBAAsB,0BAyOlC"}
@@ -19,7 +19,7 @@ var generateTursoFetcher = function (config, tableName) {
19
19
  var tursoConfig = config;
20
20
  var databaseUrl = tursoConfig.databaseUrl;
21
21
  var token = tursoConfig.token;
22
- return "import { createClient } from '@libsql/client'\n\n".concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, utils_1.generateSearchEscapeHelpersCode)(), "\n\n").concat((0, utils_1.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((0, utils_1.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 normalizedCondition = normalizeInOperand(condition.operand, condition.destination)\n if (normalizedCondition === null) return null\n const value = normalizedCondition.value\n const operand = normalizedCondition.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");
22
+ return "import { createClient } from '@libsql/client'\n\n".concat((0, utils_1.generateSafeJSONParseCode)(), "\n\n").concat((0, utils_1.generateFilterTreeHelpersCode)(), "\n\n").concat((0, utils_1.generateSearchEscapeHelpersCode)(), "\n\n").concat((0, utils_1.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((0, utils_1.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 normalizedCondition = normalizeInOperand(condition.operand, condition.destination)\n if (normalizedCondition === null) return null\n const value = normalizedCondition.value\n const operand = normalizedCondition.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 searchTerms = searchQueryColumns.toLowerCase().split(' ').filter(Boolean)\n data = data.filter((item) => {\n try {\n const stringified = JSON.stringify(item).toLowerCase()\n return searchTerms.every((term) => stringified.includes(term))\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");
23
23
  };
24
24
  exports.generateTursoFetcher = generateTursoFetcher;
25
25
  //# sourceMappingURL=turso.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"turso.js","sourceRoot":"","sources":["../../../src/fetchers/turso.ts"],"names":[],"mappings":";;;AAAA,kCAMiB;AAEV,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;AAhBY,QAAA,mBAAmB,uBAgB/B;AASM,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,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,uCAA+B,GAAE,iBAEjC,IAAA,iCAAyB,GAAE,0IAMhB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,iCACrB,IAAA,8BAAsB,EAAC,KAAK,CAAC,gLAKhB,SAAS,kkLAyKxC,CAAA;AACD,CAAC,CAAA;AAtMY,QAAA,oBAAoB,wBAsMhC"}
1
+ {"version":3,"file":"turso.js","sourceRoot":"","sources":["../../../src/fetchers/turso.ts"],"names":[],"mappings":";;;AAAA,kCAMiB;AAEV,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;AAhBY,QAAA,mBAAmB,uBAgB/B;AASM,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,IAAA,iCAAyB,GAAE,iBAE3B,IAAA,qCAA6B,GAAE,iBAE/B,IAAA,uCAA+B,GAAE,iBAEjC,IAAA,iCAAyB,GAAE,0IAMhB,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,iCACrB,IAAA,8BAAsB,EAAC,KAAK,CAAC,gLAKhB,SAAS,mnLAyKxC,CAAA;AACD,CAAC,CAAA;AAtMY,QAAA,oBAAoB,wBAsMhC"}