@teleporthq/teleport-plugin-next-data-source 0.42.7 → 0.42.9

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 (125) hide show
  1. package/__tests__/fetchers.test.ts +2 -2
  2. package/dist/cjs/fetchers/airtable.d.ts.map +1 -1
  3. package/dist/cjs/fetchers/airtable.js +2 -2
  4. package/dist/cjs/fetchers/airtable.js.map +1 -1
  5. package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -1
  6. package/dist/cjs/fetchers/clickhouse.js +1 -1
  7. package/dist/cjs/fetchers/clickhouse.js.map +1 -1
  8. package/dist/cjs/fetchers/csv-file.d.ts.map +1 -1
  9. package/dist/cjs/fetchers/csv-file.js +2 -1
  10. package/dist/cjs/fetchers/csv-file.js.map +1 -1
  11. package/dist/cjs/fetchers/firestore.d.ts.map +1 -1
  12. package/dist/cjs/fetchers/firestore.js +1 -1
  13. package/dist/cjs/fetchers/firestore.js.map +1 -1
  14. package/dist/cjs/fetchers/google-sheets.d.ts.map +1 -1
  15. package/dist/cjs/fetchers/google-sheets.js +1 -1
  16. package/dist/cjs/fetchers/google-sheets.js.map +1 -1
  17. package/dist/cjs/fetchers/javascript.d.ts.map +1 -1
  18. package/dist/cjs/fetchers/javascript.js +2 -1
  19. package/dist/cjs/fetchers/javascript.js.map +1 -1
  20. package/dist/cjs/fetchers/mariadb.d.ts.map +1 -1
  21. package/dist/cjs/fetchers/mariadb.js +9 -3
  22. package/dist/cjs/fetchers/mariadb.js.map +1 -1
  23. package/dist/cjs/fetchers/mongodb.d.ts.map +1 -1
  24. package/dist/cjs/fetchers/mongodb.js +1 -1
  25. package/dist/cjs/fetchers/mongodb.js.map +1 -1
  26. package/dist/cjs/fetchers/mysql.d.ts.map +1 -1
  27. package/dist/cjs/fetchers/mysql.js +2 -2
  28. package/dist/cjs/fetchers/mysql.js.map +1 -1
  29. package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
  30. package/dist/cjs/fetchers/postgresql.js +4 -4
  31. package/dist/cjs/fetchers/postgresql.js.map +1 -1
  32. package/dist/cjs/fetchers/redis.d.ts.map +1 -1
  33. package/dist/cjs/fetchers/redis.js +1 -1
  34. package/dist/cjs/fetchers/redis.js.map +1 -1
  35. package/dist/cjs/fetchers/redshift.d.ts.map +1 -1
  36. package/dist/cjs/fetchers/redshift.js +3 -3
  37. package/dist/cjs/fetchers/redshift.js.map +1 -1
  38. package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
  39. package/dist/cjs/fetchers/rest-api.js +3 -2
  40. package/dist/cjs/fetchers/rest-api.js.map +1 -1
  41. package/dist/cjs/fetchers/static-collection.d.ts.map +1 -1
  42. package/dist/cjs/fetchers/static-collection.js +2 -1
  43. package/dist/cjs/fetchers/static-collection.js.map +1 -1
  44. package/dist/cjs/fetchers/supabase.d.ts.map +1 -1
  45. package/dist/cjs/fetchers/supabase.js +1 -1
  46. package/dist/cjs/fetchers/supabase.js.map +1 -1
  47. package/dist/cjs/fetchers/turso.d.ts.map +1 -1
  48. package/dist/cjs/fetchers/turso.js +1 -1
  49. package/dist/cjs/fetchers/turso.js.map +1 -1
  50. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  51. package/dist/cjs/utils.d.ts +1 -0
  52. package/dist/cjs/utils.d.ts.map +1 -1
  53. package/dist/cjs/utils.js +5 -1
  54. package/dist/cjs/utils.js.map +1 -1
  55. package/dist/esm/fetchers/airtable.d.ts.map +1 -1
  56. package/dist/esm/fetchers/airtable.js +3 -3
  57. package/dist/esm/fetchers/airtable.js.map +1 -1
  58. package/dist/esm/fetchers/clickhouse.d.ts.map +1 -1
  59. package/dist/esm/fetchers/clickhouse.js +2 -2
  60. package/dist/esm/fetchers/clickhouse.js.map +1 -1
  61. package/dist/esm/fetchers/csv-file.d.ts.map +1 -1
  62. package/dist/esm/fetchers/csv-file.js +2 -1
  63. package/dist/esm/fetchers/csv-file.js.map +1 -1
  64. package/dist/esm/fetchers/firestore.d.ts.map +1 -1
  65. package/dist/esm/fetchers/firestore.js +2 -2
  66. package/dist/esm/fetchers/firestore.js.map +1 -1
  67. package/dist/esm/fetchers/google-sheets.d.ts.map +1 -1
  68. package/dist/esm/fetchers/google-sheets.js +1 -1
  69. package/dist/esm/fetchers/google-sheets.js.map +1 -1
  70. package/dist/esm/fetchers/javascript.d.ts.map +1 -1
  71. package/dist/esm/fetchers/javascript.js +2 -1
  72. package/dist/esm/fetchers/javascript.js.map +1 -1
  73. package/dist/esm/fetchers/mariadb.d.ts.map +1 -1
  74. package/dist/esm/fetchers/mariadb.js +10 -4
  75. package/dist/esm/fetchers/mariadb.js.map +1 -1
  76. package/dist/esm/fetchers/mongodb.d.ts.map +1 -1
  77. package/dist/esm/fetchers/mongodb.js +2 -2
  78. package/dist/esm/fetchers/mongodb.js.map +1 -1
  79. package/dist/esm/fetchers/mysql.d.ts.map +1 -1
  80. package/dist/esm/fetchers/mysql.js +3 -3
  81. package/dist/esm/fetchers/mysql.js.map +1 -1
  82. package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
  83. package/dist/esm/fetchers/postgresql.js +5 -5
  84. package/dist/esm/fetchers/postgresql.js.map +1 -1
  85. package/dist/esm/fetchers/redis.d.ts.map +1 -1
  86. package/dist/esm/fetchers/redis.js +2 -2
  87. package/dist/esm/fetchers/redis.js.map +1 -1
  88. package/dist/esm/fetchers/redshift.d.ts.map +1 -1
  89. package/dist/esm/fetchers/redshift.js +4 -4
  90. package/dist/esm/fetchers/redshift.js.map +1 -1
  91. package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
  92. package/dist/esm/fetchers/rest-api.js +3 -2
  93. package/dist/esm/fetchers/rest-api.js.map +1 -1
  94. package/dist/esm/fetchers/static-collection.d.ts.map +1 -1
  95. package/dist/esm/fetchers/static-collection.js +2 -1
  96. package/dist/esm/fetchers/static-collection.js.map +1 -1
  97. package/dist/esm/fetchers/supabase.d.ts.map +1 -1
  98. package/dist/esm/fetchers/supabase.js +2 -2
  99. package/dist/esm/fetchers/supabase.js.map +1 -1
  100. package/dist/esm/fetchers/turso.d.ts.map +1 -1
  101. package/dist/esm/fetchers/turso.js +2 -2
  102. package/dist/esm/fetchers/turso.js.map +1 -1
  103. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  104. package/dist/esm/utils.d.ts +1 -0
  105. package/dist/esm/utils.d.ts.map +1 -1
  106. package/dist/esm/utils.js +3 -0
  107. package/dist/esm/utils.js.map +1 -1
  108. package/package.json +2 -2
  109. package/src/fetchers/airtable.ts +4 -2
  110. package/src/fetchers/clickhouse.ts +4 -2
  111. package/src/fetchers/csv-file.ts +5 -1
  112. package/src/fetchers/firestore.ts +4 -2
  113. package/src/fetchers/google-sheets.ts +109 -9
  114. package/src/fetchers/javascript.ts +6 -2
  115. package/src/fetchers/mariadb.ts +51 -10
  116. package/src/fetchers/mongodb.ts +9 -3
  117. package/src/fetchers/mysql.ts +28 -15
  118. package/src/fetchers/postgresql.ts +33 -18
  119. package/src/fetchers/redis.ts +4 -2
  120. package/src/fetchers/redshift.ts +21 -15
  121. package/src/fetchers/rest-api.ts +5 -1
  122. package/src/fetchers/static-collection.ts +5 -1
  123. package/src/fetchers/supabase.ts +4 -2
  124. package/src/fetchers/turso.ts +9 -3
  125. package/src/utils.ts +30 -0
@@ -1,3 +1,5 @@
1
+ import { generateDateFormatterCode } from '../utils'
2
+
1
3
  export const validateJavaScriptConfig = (
2
4
  config: Record<string, unknown>
3
5
  ): { isValid: boolean; error?: string } => {
@@ -35,7 +37,9 @@ interface JavaScriptConfig {
35
37
 
36
38
  export const generateJavaScriptFetcher = (config: Record<string, unknown>): string => {
37
39
  const jsConfig = config as JavaScriptConfig
38
- return `export default async function handler(req, res) {
40
+ return `${generateDateFormatterCode()}
41
+
42
+ export default async function handler(req, res) {
39
43
  try {
40
44
  const { limit, offset, page, perPage, query, queryColumns, sortBy, sortOrder, filters } = req.query
41
45
 
@@ -115,7 +119,7 @@ export const generateJavaScriptFetcher = (config: Record<string, unknown>): stri
115
119
  }
116
120
  }
117
121
 
118
- const safeData = JSON.parse(JSON.stringify(data))
122
+ const safeData = JSON.parse(JSON.stringify(data, dateReplacer))
119
123
 
120
124
  return res.status(200).json({
121
125
  success: true,
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference } from '../utils'
1
+ import { replaceSecretReference, generateDateFormatterCode } from '../utils'
2
2
 
3
3
  interface MariaDBConfig {
4
4
  host?: string
@@ -20,10 +20,12 @@ export const generateMariaDBFetcher = (
20
20
 
21
21
  return `import mariadb from 'mariadb'
22
22
 
23
+ ${generateDateFormatterCode()}
24
+
23
25
  export default async function handler(req, res) {
24
- let pool = null
26
+ let connection = null
25
27
  try {
26
- pool = mariadb.createPool({
28
+ connection = await mariadb.createConnection({
27
29
  host: ${JSON.stringify(mariaConfig.host)},
28
30
  port: ${mariaConfig.port || 3306},
29
31
  user: ${JSON.stringify(mariaConfig.user)},
@@ -52,7 +54,6 @@ export default async function handler(req, res) {
52
54
  }
53
55
  })
54
56
 
55
- const connection = await pool.getConnection()
56
57
  const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
57
58
 
58
59
  const conditions = []
@@ -127,8 +128,7 @@ export default async function handler(req, res) {
127
128
  const plainRows = rowArray.map((row) =>
128
129
  row && typeof row.toJSON === 'function' ? row.toJSON() : row
129
130
  )
130
- const safeData = JSON.parse(JSON.stringify(plainRows))
131
- connection.release()
131
+ const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))
132
132
 
133
133
  return res.status(200).json({
134
134
  success: true,
@@ -143,8 +143,12 @@ export default async function handler(req, res) {
143
143
  timestamp: Date.now()
144
144
  })
145
145
  } finally {
146
- if (pool) {
147
- await pool.end()
146
+ if (connection) {
147
+ try {
148
+ await connection.end()
149
+ } catch (error) {
150
+ console.error('Error closing MariaDB connection:', error)
151
+ }
148
152
  }
149
153
  }
150
154
  }
@@ -160,9 +164,38 @@ export const generateMariaDBCountFetcher = (
160
164
 
161
165
  return `
162
166
  async function getCount(req, res) {
163
- const connection = getConnection()
167
+ let connection = null
164
168
 
165
169
  try {
170
+ connection = await mariadb.createConnection({
171
+ host: ${JSON.stringify(mariaConfig.host)},
172
+ port: ${mariaConfig.port || 3306},
173
+ user: ${JSON.stringify(mariaConfig.user)},
174
+ password: ${replaceSecretReference(mariaConfig.password)},
175
+ database: ${JSON.stringify(mariaConfig.database)},
176
+ ssl: ${mariaConfig.ssl || false}${
177
+ mariaConfig.sslConfig
178
+ ? `,
179
+ sslConfig: {
180
+ ${
181
+ mariaConfig.sslConfig.ca ? `ca: ${replaceSecretReference(mariaConfig.sslConfig.ca)},` : ''
182
+ }
183
+ ${
184
+ mariaConfig.sslConfig.cert
185
+ ? `cert: ${replaceSecretReference(mariaConfig.sslConfig.cert)},`
186
+ : ''
187
+ }
188
+ ${
189
+ mariaConfig.sslConfig.key
190
+ ? `key: ${replaceSecretReference(mariaConfig.sslConfig.key)},`
191
+ : ''
192
+ }
193
+ rejectUnauthorized: ${mariaConfig.sslConfig.rejectUnauthorized !== false}
194
+ }`
195
+ : ''
196
+ }
197
+ })
198
+
166
199
  const { query, queryColumns, filters } = req.query
167
200
  const conditions = []
168
201
  const queryParams = []
@@ -209,7 +242,7 @@ async function getCount(req, res) {
209
242
  countSql += \` WHERE \${conditions.join(' AND ')}\`
210
243
  }
211
244
 
212
- const [rows] = await connection.execute(countSql, queryParams)
245
+ const rows = await connection.query(countSql, queryParams)
213
246
  const count = rows[0].count
214
247
 
215
248
  return res.status(200).json({
@@ -224,6 +257,14 @@ async function getCount(req, res) {
224
257
  error: error.message || 'Failed to get count',
225
258
  timestamp: Date.now()
226
259
  })
260
+ } finally {
261
+ if (connection) {
262
+ try {
263
+ await connection.end()
264
+ } catch (error) {
265
+ console.error('Error closing MariaDB connection:', error)
266
+ }
267
+ }
227
268
  }
228
269
  }
229
270
  `
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference } from '../utils'
1
+ import { replaceSecretReference, generateDateFormatterCode } from '../utils'
2
2
 
3
3
  export const validateMongoDBConfig = (
4
4
  config: Record<string, unknown>
@@ -67,6 +67,8 @@ export const generateMongoDBFetcher = (
67
67
 
68
68
  return `import { MongoClient, ObjectId } from 'mongodb'
69
69
 
70
+ ${generateDateFormatterCode()}
71
+
70
72
  export default async function handler(req, res) {
71
73
  let client = null
72
74
  try {
@@ -151,7 +153,7 @@ export default async function handler(req, res) {
151
153
  }
152
154
 
153
155
  const documents = await cursor.toArray()
154
- const safeData = JSON.parse(JSON.stringify(documents))
156
+ const safeData = JSON.parse(JSON.stringify(documents, dateReplacer))
155
157
 
156
158
  return res.status(200).json({
157
159
  success: true,
@@ -167,7 +169,11 @@ export default async function handler(req, res) {
167
169
  })
168
170
  } finally {
169
171
  if (client) {
170
- await client.close()
172
+ try {
173
+ await client.close()
174
+ } catch (error) {
175
+ console.error('Error closing MongoDB client:', error)
176
+ }
171
177
  }
172
178
  }
173
179
  }
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference } from '../utils'
1
+ import { replaceSecretReference, generateDateFormatterCode } from '../utils'
2
2
 
3
3
  interface MySQLConfig {
4
4
  host?: string
@@ -46,12 +46,8 @@ export const generateMySQLFetcher = (
46
46
 
47
47
  return `import mysql from 'mysql2/promise'
48
48
 
49
- let pool = null
50
-
51
- const getPool = () => {
52
- if (pool) return pool
53
-
54
- pool = mysql.createPool({
49
+ const getConnection = () => {
50
+ return mysql.createConnection({
55
51
  host: ${JSON.stringify(mysqlConfig.host)},
56
52
  port: ${mysqlConfig.port || 3306},
57
53
  user: ${resolvedUser !== null ? JSON.stringify(resolvedUser) : 'undefined'},
@@ -59,13 +55,14 @@ const getPool = () => {
59
55
  database: ${JSON.stringify(mysqlConfig.database)},
60
56
  ssl: ${sslConfigString}
61
57
  })
62
-
63
- return pool
64
58
  }
65
59
 
60
+ ${generateDateFormatterCode()}
61
+
66
62
  export default async function handler(req, res) {
63
+ const connection = await getConnection()
64
+
67
65
  try {
68
- const pool = getPool()
69
66
  const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
70
67
 
71
68
  const conditions = []
@@ -80,7 +77,7 @@ export default async function handler(req, res) {
80
77
  } else {
81
78
  // Fallback: Get all columns from information_schema
82
79
  try {
83
- const [schemaRows] = await pool.promise().query(
80
+ const [schemaRows] = await connection.query(
84
81
  \`SELECT COLUMN_NAME FROM information_schema.COLUMNS
85
82
  WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?
86
83
  ORDER BY ORDINAL_POSITION\`,
@@ -135,12 +132,12 @@ export default async function handler(req, res) {
135
132
  sql += \` OFFSET \${offsetValue}\`
136
133
  }
137
134
 
138
- const [rows] = await pool.query(sql, queryParams)
135
+ const [rows] = await connection.query(sql, queryParams)
139
136
  const rowArray = Array.isArray(rows) ? rows : []
140
137
  const plainRows = rowArray.map((row) =>
141
138
  row && typeof row.toJSON === 'function' ? row.toJSON() : row
142
139
  )
143
- const safeData = JSON.parse(JSON.stringify(plainRows))
140
+ const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))
144
141
 
145
142
  return res.status(200).json({
146
143
  success: true,
@@ -154,6 +151,14 @@ export default async function handler(req, res) {
154
151
  error: error.message || 'Failed to fetch data',
155
152
  timestamp: Date.now()
156
153
  })
154
+ } finally {
155
+ if (connection) {
156
+ try {
157
+ await connection.end()
158
+ } catch (error) {
159
+ console.error('Error closing MySQL connection:', error)
160
+ }
161
+ }
157
162
  }
158
163
  }
159
164
  `
@@ -167,7 +172,7 @@ export const generateMySQLCountFetcher = (
167
172
 
168
173
  return `
169
174
  async function getCount(req, res) {
170
- const connection = getConnection()
175
+ const connection = await getConnection()
171
176
 
172
177
  try {
173
178
  const { query, queryColumns, filters } = req.query
@@ -216,7 +221,7 @@ async function getCount(req, res) {
216
221
  countSql += \` WHERE \${conditions.join(' AND ')}\`
217
222
  }
218
223
 
219
- const [rows] = await connection.execute(countSql, queryParams)
224
+ const [rows] = await connection.query(countSql, queryParams)
220
225
  const count = rows[0].count
221
226
 
222
227
  return res.status(200).json({
@@ -231,6 +236,14 @@ async function getCount(req, res) {
231
236
  error: error.message || 'Failed to get count',
232
237
  timestamp: Date.now()
233
238
  })
239
+ } finally {
240
+ if (connection) {
241
+ try {
242
+ await connection.end()
243
+ } catch (error) {
244
+ console.error('Error closing MySQL connection:', error)
245
+ }
246
+ }
234
247
  }
235
248
  }
236
249
  `
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference } from '../utils'
1
+ import { replaceSecretReference, generateDateFormatterCode } from '../utils'
2
2
 
3
3
  interface PostgreSQLConfig {
4
4
  host?: string
@@ -19,14 +19,10 @@ export const generatePostgreSQLFetcher = (
19
19
  const pgConfig = config as PostgreSQLConfig
20
20
  const schema = pgConfig.options?.schema
21
21
 
22
- return `import { Pool } from 'pg'
22
+ return `import { Client } from 'pg'
23
23
 
24
- let pool = null
25
-
26
- const getPool = () => {
27
- if (pool) return pool
28
-
29
- pool = new Pool({
24
+ const getClient = () => {
25
+ return new Client({
30
26
  host: ${JSON.stringify(pgConfig.host)},
31
27
  port: ${pgConfig.port || 5432},
32
28
  user: ${JSON.stringify(pgConfig.user || pgConfig.username)},
@@ -45,14 +41,16 @@ const getPool = () => {
45
41
  : '{ rejectUnauthorized: false }'
46
42
  }
47
43
  })
48
-
49
- return pool
50
44
  }
51
45
 
46
+ ${generateDateFormatterCode()}
47
+
52
48
  export default async function handler(req, res) {
49
+ const client = getClient()
50
+
53
51
  try {
54
- const pool = getPool()
55
- ${schema ? `await pool.query('SET search_path TO ${schema}')` : ''}
52
+ await client.connect()
53
+ ${schema ? `await client.query('SET search_path TO ${schema}')` : ''}
56
54
 
57
55
  const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
58
56
 
@@ -80,7 +78,7 @@ export default async function handler(req, res) {
80
78
  ? [${JSON.stringify(tableName)}, ${JSON.stringify(schema)}]
81
79
  : [${JSON.stringify(tableName)}]
82
80
 
83
- const schemaResult = await pool.query(schemaQuery, schemaParams)
81
+ const schemaResult = await client.query(schemaQuery, schemaParams)
84
82
  columns = schemaResult.rows.map(row => row.column_name)
85
83
  } catch (schemaError) {
86
84
  console.warn('Failed to fetch column names from information_schema:', schemaError.message)
@@ -135,12 +133,12 @@ export default async function handler(req, res) {
135
133
  sql += \` OFFSET \${offsetValue}\`
136
134
  }
137
135
 
138
- const result = await pool.query(sql, queryParams)
136
+ const result = await client.query(sql, queryParams)
139
137
  const rows = Array.isArray(result?.rows) ? result.rows : []
140
138
  const plainRows = rows.map((row) =>
141
139
  row && typeof row.toJSON === 'function' ? row.toJSON() : row
142
140
  )
143
- const safeData = JSON.parse(JSON.stringify(plainRows))
141
+ const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))
144
142
 
145
143
  return res.status(200).json({
146
144
  success: true,
@@ -154,6 +152,14 @@ export default async function handler(req, res) {
154
152
  error: error.message || 'Failed to fetch data',
155
153
  timestamp: Date.now()
156
154
  })
155
+ } finally {
156
+ if (client) {
157
+ try {
158
+ await client.end()
159
+ } catch (error) {
160
+ console.error('Error closing PostgreSQL client:', error)
161
+ }
162
+ }
157
163
  }
158
164
  }
159
165
  `
@@ -168,9 +174,10 @@ export const generatePostgreSQLCountFetcher = (
168
174
 
169
175
  return `
170
176
  async function getCount(req, res) {
171
- const pool = getPool()
177
+ const client = getClient()
172
178
 
173
179
  try {
180
+ await client.connect()
174
181
  const { query, queryColumns, filters } = req.query
175
182
  const conditions = []
176
183
  const queryParams = []
@@ -198,7 +205,7 @@ async function getCount(req, res) {
198
205
  : `[${JSON.stringify(tableName)}]`
199
206
  }
200
207
 
201
- const schemaResult = await pool.query(schemaQuery, schemaParams)
208
+ const schemaResult = await client.query(schemaQuery, schemaParams)
202
209
  columns = schemaResult.rows.map(row => row.column_name)
203
210
  } catch (schemaError) {
204
211
  console.warn('Failed to fetch column names from information_schema:', schemaError.message)
@@ -226,7 +233,7 @@ async function getCount(req, res) {
226
233
  countSql += \` WHERE \${conditions.join(' AND ')}\`
227
234
  }
228
235
 
229
- const result = await pool.query(countSql, queryParams)
236
+ const result = await client.query(countSql, queryParams)
230
237
  const count = parseInt(result.rows[0].count, 10)
231
238
 
232
239
  return res.status(200).json({
@@ -241,6 +248,14 @@ async function getCount(req, res) {
241
248
  error: error.message || 'Failed to get count',
242
249
  timestamp: Date.now()
243
250
  })
251
+ } finally {
252
+ if (client) {
253
+ try {
254
+ await client.end()
255
+ } catch (error) {
256
+ console.error('Error closing PostgreSQL client:', error)
257
+ }
258
+ }
244
259
  }
245
260
  }
246
261
  `
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference } from '../utils'
1
+ import { replaceSecretReference, generateDateFormatterCode } from '../utils'
2
2
 
3
3
  export const validateRedisConfig = (
4
4
  config: Record<string, unknown>
@@ -63,6 +63,8 @@ export const generateRedisFetcher = (config: Record<string, unknown>): string =>
63
63
 
64
64
  return `import { createClient } from 'redis'
65
65
 
66
+ ${generateDateFormatterCode()}
67
+
66
68
  export default async function handler(req, res) {
67
69
  let client = null
68
70
  try {
@@ -128,7 +130,7 @@ export default async function handler(req, res) {
128
130
  })
129
131
  }
130
132
 
131
- const safeData = JSON.parse(JSON.stringify(results))
133
+ const safeData = JSON.parse(JSON.stringify(results, dateReplacer))
132
134
 
133
135
  return res.status(200).json({
134
136
  success: true,
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference } from '../utils'
1
+ import { replaceSecretReference, generateDateFormatterCode } from '../utils'
2
2
 
3
3
  interface RedshiftConfig {
4
4
  host?: string
@@ -25,14 +25,10 @@ export const generateRedshiftFetcher = (
25
25
  const sslConfig = redshiftConfig.sslConfig
26
26
  const schema = redshiftConfig.options?.schema
27
27
 
28
- return `import { Pool } from 'pg'
28
+ return `import { Client } from 'pg'
29
29
 
30
- let pool = null
31
-
32
- const getPool = () => {
33
- if (pool) return pool
34
-
35
- pool = new Pool({
30
+ const getClient = () => {
31
+ return new Client({
36
32
  host: ${JSON.stringify(host)},
37
33
  port: ${port || 5439},
38
34
  user: ${JSON.stringify(user)},
@@ -51,14 +47,16 @@ const getPool = () => {
51
47
  : '{ rejectUnauthorized: false }' // Default to SSL with no cert verification for Redshift
52
48
  }
53
49
  })
54
-
55
- return pool
56
50
  }
57
51
 
52
+ ${generateDateFormatterCode()}
53
+
58
54
  export default async function handler(req, res) {
55
+ const client = getClient()
56
+
59
57
  try {
60
- const pool = getPool()
61
- ${schema ? `await pool.query('SET search_path TO ${schema}')` : ''}
58
+ await client.connect()
59
+ ${schema ? `await client.query('SET search_path TO ${schema}')` : ''}
62
60
 
63
61
  const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
64
62
 
@@ -82,7 +80,7 @@ export default async function handler(req, res) {
82
80
  ? `[${JSON.stringify(tableName)}, ${JSON.stringify(schema)}]`
83
81
  : `[${JSON.stringify(tableName)}]`
84
82
  }
85
- const schemaResult = await pool.query(schemaQuery, schemaParams)
83
+ const schemaResult = await client.query(schemaQuery, schemaParams)
86
84
  columns = schemaResult.rows.map(row => row.column_name)
87
85
  } catch (schemaError) {
88
86
  console.warn('Failed to fetch column names from information_schema:', schemaError.message)
@@ -136,12 +134,12 @@ export default async function handler(req, res) {
136
134
  sql += \` OFFSET \${offsetValue}\`
137
135
  }
138
136
 
139
- const result = await pool.query(sql, queryParams)
137
+ const result = await client.query(sql, queryParams)
140
138
  const rows = Array.isArray(result?.rows) ? result.rows : []
141
139
  const plainRows = rows.map((row) =>
142
140
  row && typeof row.toJSON === 'function' ? row.toJSON() : row
143
141
  )
144
- const safeData = JSON.parse(JSON.stringify(plainRows))
142
+ const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))
145
143
 
146
144
  return res.status(200).json({
147
145
  success: true,
@@ -155,6 +153,14 @@ export default async function handler(req, res) {
155
153
  error: error.message || 'Failed to fetch data',
156
154
  timestamp: Date.now()
157
155
  })
156
+ } finally {
157
+ if (client) {
158
+ try {
159
+ await client.end()
160
+ } catch (error) {
161
+ console.error('Error closing Redshift client:', error)
162
+ }
163
+ }
158
164
  }
159
165
  }
160
166
  `
@@ -1,3 +1,5 @@
1
+ import { generateDateFormatterCode } from '../utils'
2
+
1
3
  export const validateRESTAPIConfig = (
2
4
  config: Record<string, unknown>
3
5
  ): { isValid: boolean; error?: string } => {
@@ -75,6 +77,8 @@ export const generateRESTAPIFetcher = (config: Record<string, unknown>): string
75
77
 
76
78
  return `import fetch from 'node-fetch'
77
79
 
80
+ ${generateDateFormatterCode()}
81
+
78
82
  export default async function handler(req, res) {
79
83
  try {
80
84
  const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
@@ -190,7 +194,7 @@ export default async function handler(req, res) {
190
194
  }
191
195
  }
192
196
 
193
- const safeData = JSON.parse(JSON.stringify(data))
197
+ const safeData = JSON.parse(JSON.stringify(data, dateReplacer))
194
198
 
195
199
  return res.status(200).json({
196
200
  success: true,
@@ -1,3 +1,5 @@
1
+ import { generateDateFormatterCode } from '../utils'
2
+
1
3
  export const validateStaticCollectionConfig = (
2
4
  config: Record<string, unknown>
3
5
  ): { isValid: boolean; error?: string } => {
@@ -20,6 +22,8 @@ export const generateStaticCollectionFetcher = (config: Record<string, unknown>)
20
22
  const staticConfig = config as StaticCollectionConfig
21
23
  return `const data = ${JSON.stringify(staticConfig.data || [])}
22
24
 
25
+ ${generateDateFormatterCode()}
26
+
23
27
  export default async function handler(req, res) {
24
28
  try {
25
29
  const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset: offsetParam } = req.query
@@ -79,7 +83,7 @@ export default async function handler(req, res) {
79
83
  filteredData = filteredData.slice(offsetValue, offsetValue + parseInt(limitValue))
80
84
  }
81
85
 
82
- const safeData = JSON.parse(JSON.stringify(filteredData))
86
+ const safeData = JSON.parse(JSON.stringify(filteredData, dateReplacer))
83
87
 
84
88
  return res.status(200).json({
85
89
  success: true,
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference } from '../utils'
1
+ import { replaceSecretReference, generateDateFormatterCode } from '../utils'
2
2
 
3
3
  export const validateSupabaseConfig = (
4
4
  config: Record<string, unknown>
@@ -61,6 +61,8 @@ const getClient = () => {
61
61
  return client
62
62
  }
63
63
 
64
+ ${generateDateFormatterCode()}
65
+
64
66
  export default async function handler(req, res) {
65
67
  try {
66
68
  const client = getClient()
@@ -159,7 +161,7 @@ export default async function handler(req, res) {
159
161
  })
160
162
  }
161
163
 
162
- const safeData = JSON.parse(JSON.stringify(data))
164
+ const safeData = JSON.parse(JSON.stringify(data, dateReplacer))
163
165
 
164
166
  return res.status(200).json({
165
167
  success: true,
@@ -1,4 +1,4 @@
1
- import { replaceSecretReference } from '../utils'
1
+ import { replaceSecretReference, generateDateFormatterCode } from '../utils'
2
2
 
3
3
  export const validateTursoConfig = (
4
4
  config: Record<string, unknown>
@@ -35,6 +35,8 @@ export const generateTursoFetcher = (
35
35
 
36
36
  return `import { createClient } from '@libsql/client'
37
37
 
38
+ ${generateDateFormatterCode()}
39
+
38
40
  export default async function handler(req, res) {
39
41
  let client = null
40
42
  try {
@@ -137,7 +139,7 @@ export default async function handler(req, res) {
137
139
  }
138
140
  }
139
141
 
140
- const safeData = JSON.parse(JSON.stringify(data))
142
+ const safeData = JSON.parse(JSON.stringify(data, dateReplacer))
141
143
 
142
144
  return res.status(200).json({
143
145
  success: true,
@@ -153,7 +155,11 @@ export default async function handler(req, res) {
153
155
  })
154
156
  } finally {
155
157
  if (client) {
156
- client.close()
158
+ try {
159
+ await client.close()
160
+ } catch (error) {
161
+ console.error('Error closing Turso client:', error)
162
+ }
157
163
  }
158
164
  }
159
165
  }
package/src/utils.ts CHANGED
@@ -510,6 +510,36 @@ export const replaceSecretReference = (
510
510
  }
511
511
  }
512
512
 
513
+ export const generateDateFormatterCode = (): string => {
514
+ return `const formatDateValue = (date) => {
515
+ const options = {
516
+ year: 'numeric',
517
+ month: 'short',
518
+ day: 'numeric',
519
+ }
520
+
521
+ const timeOptions = {
522
+ hour: '2-digit',
523
+ minute: '2-digit',
524
+ }
525
+
526
+ const hasTime = date.getHours() !== 0 || date.getMinutes() !== 0 || date.getSeconds() !== 0
527
+
528
+ if (hasTime) {
529
+ return date.toLocaleString('en-US', { ...options, ...timeOptions })
530
+ }
531
+
532
+ return date.toLocaleDateString('en-US', options)
533
+ }
534
+
535
+ const dateReplacer = (key, value) => {
536
+ if (value instanceof Date) {
537
+ return formatDateValue(value)
538
+ }
539
+ return value
540
+ }`
541
+ }
542
+
513
543
  export const sanitizeNumericParam = (value: unknown, defaultValue: number = 0): number => {
514
544
  if (typeof value === 'number' && !isNaN(value) && isFinite(value)) {
515
545
  return Math.max(0, Math.floor(value))