@teleporthq/teleport-plugin-next-data-source 0.40.15

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 (240) hide show
  1. package/ARRAY_MAPPER_PAGINATION.md +1128 -0
  2. package/LICENSE +21 -0
  3. package/README.md +40 -0
  4. package/SEARCH_IMPLEMENTATION_SUMMARY.md +983 -0
  5. package/__tests__/fetchers.test.ts +545 -0
  6. package/__tests__/integration.test.ts +561 -0
  7. package/__tests__/mocks.ts +241 -0
  8. package/__tests__/pagination.test.ts +31 -0
  9. package/__tests__/plugin.test.ts +577 -0
  10. package/__tests__/utils.test.ts +430 -0
  11. package/__tests__/validation.test.ts +348 -0
  12. package/dist/cjs/array-mapper-pagination.d.ts +32 -0
  13. package/dist/cjs/array-mapper-pagination.d.ts.map +1 -0
  14. package/dist/cjs/array-mapper-pagination.js +77 -0
  15. package/dist/cjs/array-mapper-pagination.js.map +1 -0
  16. package/dist/cjs/count-fetchers.d.ts +12 -0
  17. package/dist/cjs/count-fetchers.d.ts.map +1 -0
  18. package/dist/cjs/count-fetchers.js +46 -0
  19. package/dist/cjs/count-fetchers.js.map +1 -0
  20. package/dist/cjs/data-source-fetchers.d.ts +14 -0
  21. package/dist/cjs/data-source-fetchers.d.ts.map +1 -0
  22. package/dist/cjs/data-source-fetchers.js +185 -0
  23. package/dist/cjs/data-source-fetchers.js.map +1 -0
  24. package/dist/cjs/fetchers/airtable.d.ts +6 -0
  25. package/dist/cjs/fetchers/airtable.d.ts.map +1 -0
  26. package/dist/cjs/fetchers/airtable.js +27 -0
  27. package/dist/cjs/fetchers/airtable.js.map +1 -0
  28. package/dist/cjs/fetchers/clickhouse.d.ts +6 -0
  29. package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -0
  30. package/dist/cjs/fetchers/clickhouse.js +29 -0
  31. package/dist/cjs/fetchers/clickhouse.js.map +1 -0
  32. package/dist/cjs/fetchers/csv-file.d.ts +7 -0
  33. package/dist/cjs/fetchers/csv-file.d.ts.map +1 -0
  34. package/dist/cjs/fetchers/csv-file.js +36 -0
  35. package/dist/cjs/fetchers/csv-file.js.map +1 -0
  36. package/dist/cjs/fetchers/firestore.d.ts +6 -0
  37. package/dist/cjs/fetchers/firestore.d.ts.map +1 -0
  38. package/dist/cjs/fetchers/firestore.js +35 -0
  39. package/dist/cjs/fetchers/firestore.js.map +1 -0
  40. package/dist/cjs/fetchers/google-sheets.d.ts +6 -0
  41. package/dist/cjs/fetchers/google-sheets.d.ts.map +1 -0
  42. package/dist/cjs/fetchers/google-sheets.js +30 -0
  43. package/dist/cjs/fetchers/google-sheets.js.map +1 -0
  44. package/dist/cjs/fetchers/index.d.ts +17 -0
  45. package/dist/cjs/fetchers/index.d.ts.map +1 -0
  46. package/dist/cjs/fetchers/index.js +56 -0
  47. package/dist/cjs/fetchers/index.js.map +1 -0
  48. package/dist/cjs/fetchers/javascript.d.ts +7 -0
  49. package/dist/cjs/fetchers/javascript.d.ts.map +1 -0
  50. package/dist/cjs/fetchers/javascript.js +40 -0
  51. package/dist/cjs/fetchers/javascript.js.map +1 -0
  52. package/dist/cjs/fetchers/mariadb.d.ts +3 -0
  53. package/dist/cjs/fetchers/mariadb.d.ts.map +1 -0
  54. package/dist/cjs/fetchers/mariadb.js +23 -0
  55. package/dist/cjs/fetchers/mariadb.js.map +1 -0
  56. package/dist/cjs/fetchers/mongodb.d.ts +7 -0
  57. package/dist/cjs/fetchers/mongodb.d.ts.map +1 -0
  58. package/dist/cjs/fetchers/mongodb.js +52 -0
  59. package/dist/cjs/fetchers/mongodb.js.map +1 -0
  60. package/dist/cjs/fetchers/mysql.d.ts +3 -0
  61. package/dist/cjs/fetchers/mysql.d.ts.map +1 -0
  62. package/dist/cjs/fetchers/mysql.js +30 -0
  63. package/dist/cjs/fetchers/mysql.js.map +1 -0
  64. package/dist/cjs/fetchers/postgresql.d.ts +3 -0
  65. package/dist/cjs/fetchers/postgresql.d.ts.map +1 -0
  66. package/dist/cjs/fetchers/postgresql.js +25 -0
  67. package/dist/cjs/fetchers/postgresql.js.map +1 -0
  68. package/dist/cjs/fetchers/redis.d.ts +6 -0
  69. package/dist/cjs/fetchers/redis.d.ts.map +1 -0
  70. package/dist/cjs/fetchers/redis.js +46 -0
  71. package/dist/cjs/fetchers/redis.js.map +1 -0
  72. package/dist/cjs/fetchers/redshift.d.ts +2 -0
  73. package/dist/cjs/fetchers/redshift.d.ts.map +1 -0
  74. package/dist/cjs/fetchers/redshift.js +24 -0
  75. package/dist/cjs/fetchers/redshift.js.map +1 -0
  76. package/dist/cjs/fetchers/rest-api.d.ts +6 -0
  77. package/dist/cjs/fetchers/rest-api.d.ts.map +1 -0
  78. package/dist/cjs/fetchers/rest-api.js +58 -0
  79. package/dist/cjs/fetchers/rest-api.js.map +1 -0
  80. package/dist/cjs/fetchers/static-collection.d.ts +7 -0
  81. package/dist/cjs/fetchers/static-collection.d.ts.map +1 -0
  82. package/dist/cjs/fetchers/static-collection.js +24 -0
  83. package/dist/cjs/fetchers/static-collection.js.map +1 -0
  84. package/dist/cjs/fetchers/supabase.d.ts +7 -0
  85. package/dist/cjs/fetchers/supabase.d.ts.map +1 -0
  86. package/dist/cjs/fetchers/supabase.js +42 -0
  87. package/dist/cjs/fetchers/supabase.js.map +1 -0
  88. package/dist/cjs/fetchers/turso.d.ts +6 -0
  89. package/dist/cjs/fetchers/turso.d.ts.map +1 -0
  90. package/dist/cjs/fetchers/turso.js +25 -0
  91. package/dist/cjs/fetchers/turso.js.map +1 -0
  92. package/dist/cjs/index.d.ts +9 -0
  93. package/dist/cjs/index.d.ts.map +1 -0
  94. package/dist/cjs/index.js +325 -0
  95. package/dist/cjs/index.js.map +1 -0
  96. package/dist/cjs/pagination-plugin.d.ts +5 -0
  97. package/dist/cjs/pagination-plugin.d.ts.map +1 -0
  98. package/dist/cjs/pagination-plugin.js +1484 -0
  99. package/dist/cjs/pagination-plugin.js.map +1 -0
  100. package/dist/cjs/pagination-with-count.d.ts +6 -0
  101. package/dist/cjs/pagination-with-count.d.ts.map +1 -0
  102. package/dist/cjs/pagination-with-count.js +63 -0
  103. package/dist/cjs/pagination-with-count.js.map +1 -0
  104. package/dist/cjs/tsconfig.tsbuildinfo +1 -0
  105. package/dist/cjs/utils.d.ts +31 -0
  106. package/dist/cjs/utils.d.ts.map +1 -0
  107. package/dist/cjs/utils.js +763 -0
  108. package/dist/cjs/utils.js.map +1 -0
  109. package/dist/cjs/validation.d.ts +5 -0
  110. package/dist/cjs/validation.d.ts.map +1 -0
  111. package/dist/cjs/validation.js +29 -0
  112. package/dist/cjs/validation.js.map +1 -0
  113. package/dist/esm/array-mapper-pagination.d.ts +32 -0
  114. package/dist/esm/array-mapper-pagination.d.ts.map +1 -0
  115. package/dist/esm/array-mapper-pagination.js +72 -0
  116. package/dist/esm/array-mapper-pagination.js.map +1 -0
  117. package/dist/esm/count-fetchers.d.ts +12 -0
  118. package/dist/esm/count-fetchers.d.ts.map +1 -0
  119. package/dist/esm/count-fetchers.js +35 -0
  120. package/dist/esm/count-fetchers.js.map +1 -0
  121. package/dist/esm/data-source-fetchers.d.ts +14 -0
  122. package/dist/esm/data-source-fetchers.d.ts.map +1 -0
  123. package/dist/esm/data-source-fetchers.js +179 -0
  124. package/dist/esm/data-source-fetchers.js.map +1 -0
  125. package/dist/esm/fetchers/airtable.d.ts +6 -0
  126. package/dist/esm/fetchers/airtable.d.ts.map +1 -0
  127. package/dist/esm/fetchers/airtable.js +22 -0
  128. package/dist/esm/fetchers/airtable.js.map +1 -0
  129. package/dist/esm/fetchers/clickhouse.d.ts +6 -0
  130. package/dist/esm/fetchers/clickhouse.d.ts.map +1 -0
  131. package/dist/esm/fetchers/clickhouse.js +24 -0
  132. package/dist/esm/fetchers/clickhouse.js.map +1 -0
  133. package/dist/esm/fetchers/csv-file.d.ts +7 -0
  134. package/dist/esm/fetchers/csv-file.d.ts.map +1 -0
  135. package/dist/esm/fetchers/csv-file.js +30 -0
  136. package/dist/esm/fetchers/csv-file.js.map +1 -0
  137. package/dist/esm/fetchers/firestore.d.ts +6 -0
  138. package/dist/esm/fetchers/firestore.d.ts.map +1 -0
  139. package/dist/esm/fetchers/firestore.js +30 -0
  140. package/dist/esm/fetchers/firestore.js.map +1 -0
  141. package/dist/esm/fetchers/google-sheets.d.ts +6 -0
  142. package/dist/esm/fetchers/google-sheets.d.ts.map +1 -0
  143. package/dist/esm/fetchers/google-sheets.js +25 -0
  144. package/dist/esm/fetchers/google-sheets.js.map +1 -0
  145. package/dist/esm/fetchers/index.d.ts +17 -0
  146. package/dist/esm/fetchers/index.d.ts.map +1 -0
  147. package/dist/esm/fetchers/index.js +17 -0
  148. package/dist/esm/fetchers/index.js.map +1 -0
  149. package/dist/esm/fetchers/javascript.d.ts +7 -0
  150. package/dist/esm/fetchers/javascript.d.ts.map +1 -0
  151. package/dist/esm/fetchers/javascript.js +34 -0
  152. package/dist/esm/fetchers/javascript.js.map +1 -0
  153. package/dist/esm/fetchers/mariadb.d.ts +3 -0
  154. package/dist/esm/fetchers/mariadb.d.ts.map +1 -0
  155. package/dist/esm/fetchers/mariadb.js +18 -0
  156. package/dist/esm/fetchers/mariadb.js.map +1 -0
  157. package/dist/esm/fetchers/mongodb.d.ts +7 -0
  158. package/dist/esm/fetchers/mongodb.d.ts.map +1 -0
  159. package/dist/esm/fetchers/mongodb.js +46 -0
  160. package/dist/esm/fetchers/mongodb.js.map +1 -0
  161. package/dist/esm/fetchers/mysql.d.ts +3 -0
  162. package/dist/esm/fetchers/mysql.d.ts.map +1 -0
  163. package/dist/esm/fetchers/mysql.js +25 -0
  164. package/dist/esm/fetchers/mysql.js.map +1 -0
  165. package/dist/esm/fetchers/postgresql.d.ts +3 -0
  166. package/dist/esm/fetchers/postgresql.d.ts.map +1 -0
  167. package/dist/esm/fetchers/postgresql.js +20 -0
  168. package/dist/esm/fetchers/postgresql.js.map +1 -0
  169. package/dist/esm/fetchers/redis.d.ts +6 -0
  170. package/dist/esm/fetchers/redis.d.ts.map +1 -0
  171. package/dist/esm/fetchers/redis.js +41 -0
  172. package/dist/esm/fetchers/redis.js.map +1 -0
  173. package/dist/esm/fetchers/redshift.d.ts +2 -0
  174. package/dist/esm/fetchers/redshift.d.ts.map +1 -0
  175. package/dist/esm/fetchers/redshift.js +20 -0
  176. package/dist/esm/fetchers/redshift.js.map +1 -0
  177. package/dist/esm/fetchers/rest-api.d.ts +6 -0
  178. package/dist/esm/fetchers/rest-api.d.ts.map +1 -0
  179. package/dist/esm/fetchers/rest-api.js +53 -0
  180. package/dist/esm/fetchers/rest-api.js.map +1 -0
  181. package/dist/esm/fetchers/static-collection.d.ts +7 -0
  182. package/dist/esm/fetchers/static-collection.d.ts.map +1 -0
  183. package/dist/esm/fetchers/static-collection.js +18 -0
  184. package/dist/esm/fetchers/static-collection.js.map +1 -0
  185. package/dist/esm/fetchers/supabase.d.ts +7 -0
  186. package/dist/esm/fetchers/supabase.d.ts.map +1 -0
  187. package/dist/esm/fetchers/supabase.js +36 -0
  188. package/dist/esm/fetchers/supabase.js.map +1 -0
  189. package/dist/esm/fetchers/turso.d.ts +6 -0
  190. package/dist/esm/fetchers/turso.d.ts.map +1 -0
  191. package/dist/esm/fetchers/turso.js +20 -0
  192. package/dist/esm/fetchers/turso.js.map +1 -0
  193. package/dist/esm/index.d.ts +9 -0
  194. package/dist/esm/index.d.ts.map +1 -0
  195. package/dist/esm/index.js +306 -0
  196. package/dist/esm/index.js.map +1 -0
  197. package/dist/esm/pagination-plugin.d.ts +5 -0
  198. package/dist/esm/pagination-plugin.d.ts.map +1 -0
  199. package/dist/esm/pagination-plugin.js +1457 -0
  200. package/dist/esm/pagination-plugin.js.map +1 -0
  201. package/dist/esm/pagination-with-count.d.ts +6 -0
  202. package/dist/esm/pagination-with-count.d.ts.map +1 -0
  203. package/dist/esm/pagination-with-count.js +34 -0
  204. package/dist/esm/pagination-with-count.js.map +1 -0
  205. package/dist/esm/tsconfig.tsbuildinfo +1 -0
  206. package/dist/esm/utils.d.ts +31 -0
  207. package/dist/esm/utils.d.ts.map +1 -0
  208. package/dist/esm/utils.js +722 -0
  209. package/dist/esm/utils.js.map +1 -0
  210. package/dist/esm/validation.d.ts +5 -0
  211. package/dist/esm/validation.d.ts.map +1 -0
  212. package/dist/esm/validation.js +25 -0
  213. package/dist/esm/validation.js.map +1 -0
  214. package/package.json +33 -0
  215. package/src/array-mapper-pagination.ts +113 -0
  216. package/src/count-fetchers.ts +99 -0
  217. package/src/data-source-fetchers.ts +313 -0
  218. package/src/fetchers/airtable.ts +153 -0
  219. package/src/fetchers/clickhouse.ts +127 -0
  220. package/src/fetchers/csv-file.ts +163 -0
  221. package/src/fetchers/firestore.ts +138 -0
  222. package/src/fetchers/google-sheets.ts +189 -0
  223. package/src/fetchers/index.ts +32 -0
  224. package/src/fetchers/javascript.ts +150 -0
  225. package/src/fetchers/mariadb.ts +230 -0
  226. package/src/fetchers/mongodb.ts +239 -0
  227. package/src/fetchers/mysql.ts +237 -0
  228. package/src/fetchers/postgresql.ts +247 -0
  229. package/src/fetchers/redis.ts +152 -0
  230. package/src/fetchers/redshift.ts +138 -0
  231. package/src/fetchers/rest-api.ts +148 -0
  232. package/src/fetchers/static-collection.ts +149 -0
  233. package/src/fetchers/supabase.ts +246 -0
  234. package/src/fetchers/turso.ts +131 -0
  235. package/src/index.ts +352 -0
  236. package/src/pagination-plugin.ts +2335 -0
  237. package/src/pagination-with-count.ts +89 -0
  238. package/src/utils.ts +1013 -0
  239. package/src/validation.ts +32 -0
  240. package/tsconfig.json +9 -0
@@ -0,0 +1,545 @@
1
+ import {
2
+ generateDataSourceFetcher,
3
+ generateDataSourceFetcherWithCore,
4
+ getDataSourceDependencies,
5
+ } from '../src/data-source-fetchers'
6
+ import { validateDatabaseConfig } from '../src/validation'
7
+ import {
8
+ validateMongoDBConfig,
9
+ validateRedisConfig,
10
+ validateRESTAPIConfig,
11
+ validateJavaScriptConfig,
12
+ validateStaticCollectionConfig,
13
+ } from '../src/fetchers'
14
+ import {
15
+ createPostgreSQLDataSource,
16
+ createMySQLDataSource,
17
+ createMongoDBDataSource,
18
+ createRESTAPIDataSource,
19
+ createJavaScriptDataSource,
20
+ createStaticCollectionDataSource,
21
+ createRedisDataSource,
22
+ } from './mocks'
23
+
24
+ describe('getDataSourceDependencies', () => {
25
+ it('returns correct dependencies for REST API', () => {
26
+ const deps = getDataSourceDependencies('rest-api')
27
+ expect(deps.packages).toContain('node-fetch')
28
+ expect(deps.isDefaultImport).toBe(true)
29
+ })
30
+
31
+ it('returns correct dependencies for PostgreSQL', () => {
32
+ const deps = getDataSourceDependencies('postgresql')
33
+ expect(deps.packages).toContain('pg')
34
+ expect(deps.isDefaultImport).toBe(false)
35
+ })
36
+
37
+ it('returns correct dependencies for MySQL', () => {
38
+ const deps = getDataSourceDependencies('mysql')
39
+ expect(deps.packages).toContain('mysql2')
40
+ })
41
+
42
+ it('returns correct dependencies for MongoDB', () => {
43
+ const deps = getDataSourceDependencies('mongodb')
44
+ expect(deps.packages).toContain('mongodb')
45
+ })
46
+
47
+ it('returns correct dependencies for Redis', () => {
48
+ const deps = getDataSourceDependencies('redis')
49
+ expect(deps.packages).toContain('redis')
50
+ })
51
+
52
+ it('returns empty dependencies for embedded sources', () => {
53
+ expect(getDataSourceDependencies('javascript').packages).toEqual([])
54
+ expect(getDataSourceDependencies('csv-file').packages).toEqual([])
55
+ expect(getDataSourceDependencies('static-collection').packages).toEqual([])
56
+ })
57
+
58
+ it('handles all supported data source types', () => {
59
+ const types = [
60
+ 'rest-api',
61
+ 'postgresql',
62
+ 'mysql',
63
+ 'mariadb',
64
+ 'amazon-redshift',
65
+ 'mongodb',
66
+ 'cockroachdb',
67
+ 'tidb',
68
+ 'redis',
69
+ 'firestore',
70
+ 'clickhouse',
71
+ 'airtable',
72
+ 'supabase',
73
+ 'turso',
74
+ 'javascript',
75
+ 'google-sheets',
76
+ 'csv-file',
77
+ 'static-collection',
78
+ ]
79
+
80
+ types.forEach((type) => {
81
+ const deps = getDataSourceDependencies(type as any)
82
+ expect(deps).toBeDefined()
83
+ expect(Array.isArray(deps.packages)).toBe(true)
84
+ })
85
+ })
86
+ })
87
+
88
+ describe('validateDatabaseConfig', () => {
89
+ it('validates correct database config', () => {
90
+ const result = validateDatabaseConfig({
91
+ host: 'localhost',
92
+ port: 5432,
93
+ user: 'testuser',
94
+ password: 'testpass',
95
+ database: 'testdb',
96
+ })
97
+ expect(result.isValid).toBe(true)
98
+ })
99
+
100
+ it('accepts username instead of user', () => {
101
+ const result = validateDatabaseConfig({
102
+ host: 'localhost',
103
+ username: 'testuser',
104
+ password: 'testpass',
105
+ database: 'testdb',
106
+ })
107
+ expect(result.isValid).toBe(true)
108
+ })
109
+
110
+ it('rejects missing host', () => {
111
+ const result = validateDatabaseConfig({
112
+ port: 5432,
113
+ user: 'testuser',
114
+ password: 'testpass',
115
+ database: 'testdb',
116
+ })
117
+ expect(result.isValid).toBe(false)
118
+ expect(result.error).toContain('Host')
119
+ })
120
+
121
+ it('rejects invalid port', () => {
122
+ const result = validateDatabaseConfig({
123
+ host: 'localhost',
124
+ port: 99999,
125
+ user: 'testuser',
126
+ password: 'testpass',
127
+ database: 'testdb',
128
+ })
129
+ expect(result.isValid).toBe(false)
130
+ expect(result.error).toContain('Port')
131
+ })
132
+
133
+ it('rejects missing password', () => {
134
+ const result = validateDatabaseConfig({
135
+ host: 'localhost',
136
+ user: 'testuser',
137
+ database: 'testdb',
138
+ })
139
+ expect(result.isValid).toBe(false)
140
+ expect(result.error).toContain('Password')
141
+ })
142
+
143
+ it('rejects missing database', () => {
144
+ const result = validateDatabaseConfig({
145
+ host: 'localhost',
146
+ user: 'testuser',
147
+ password: 'testpass',
148
+ })
149
+ expect(result.isValid).toBe(false)
150
+ expect(result.error).toContain('Database')
151
+ })
152
+
153
+ it('allows optional port', () => {
154
+ const result = validateDatabaseConfig({
155
+ host: 'localhost',
156
+ user: 'testuser',
157
+ password: 'testpass',
158
+ database: 'testdb',
159
+ })
160
+ expect(result.isValid).toBe(true)
161
+ })
162
+ })
163
+
164
+ describe('validateMongoDBConfig', () => {
165
+ it('validates with connection string', () => {
166
+ const result = validateMongoDBConfig({
167
+ connectionString: 'mongodb://localhost:27017/testdb',
168
+ database: 'testdb',
169
+ })
170
+ expect(result.isValid).toBe(true)
171
+ })
172
+
173
+ it('validates mongodb+srv protocol', () => {
174
+ const result = validateMongoDBConfig({
175
+ connectionString: 'mongodb+srv://cluster.mongodb.net/testdb',
176
+ database: 'testdb',
177
+ })
178
+ expect(result.isValid).toBe(true)
179
+ })
180
+
181
+ it('validates with host/port', () => {
182
+ const result = validateMongoDBConfig({
183
+ host: 'localhost',
184
+ port: 27017,
185
+ database: 'testdb',
186
+ })
187
+ expect(result.isValid).toBe(true)
188
+ })
189
+
190
+ it('rejects invalid connection string', () => {
191
+ const result = validateMongoDBConfig({
192
+ connectionString: 'invalid://connection',
193
+ database: 'testdb',
194
+ })
195
+ expect(result.isValid).toBe(false)
196
+ })
197
+
198
+ it('requires database field even with connection string', () => {
199
+ const result = validateMongoDBConfig({
200
+ connectionString: 'mongodb://localhost:27017/testdb',
201
+ database: 'testdb',
202
+ })
203
+ expect(result.isValid).toBe(true)
204
+ })
205
+
206
+ it('accepts secret references in connection string', () => {
207
+ const result = validateMongoDBConfig({
208
+ connectionString: 'teleporthq.secrets.MONGO_CONNECTION',
209
+ database: 'testdb',
210
+ })
211
+ expect(result.isValid).toBe(true)
212
+ })
213
+ })
214
+
215
+ describe('validateRedisConfig', () => {
216
+ it('validates with host', () => {
217
+ const result = validateRedisConfig({
218
+ host: 'localhost',
219
+ })
220
+ expect(result.isValid).toBe(true)
221
+ })
222
+
223
+ it('validates with connection string', () => {
224
+ const result = validateRedisConfig({
225
+ connectionString: 'redis://localhost:6379',
226
+ })
227
+ expect(result.isValid).toBe(true)
228
+ })
229
+
230
+ it('validates with rediss protocol', () => {
231
+ const result = validateRedisConfig({
232
+ connectionString: 'rediss://localhost:6379',
233
+ })
234
+ expect(result.isValid).toBe(true)
235
+ })
236
+
237
+ it('validates with secret reference', () => {
238
+ const result = validateRedisConfig({
239
+ connectionString: 'teleporthq.secrets.REDIS_CONNECTION',
240
+ })
241
+ expect(result.isValid).toBe(true)
242
+ })
243
+
244
+ it('rejects invalid connection string', () => {
245
+ const result = validateRedisConfig({
246
+ connectionString: 'invalid://localhost',
247
+ })
248
+ expect(result.isValid).toBe(false)
249
+ })
250
+
251
+ it('requires either host or connectionString', () => {
252
+ const result = validateRedisConfig({
253
+ port: 6379,
254
+ })
255
+ expect(result.isValid).toBe(false)
256
+ })
257
+ })
258
+
259
+ describe('validateRESTAPIConfig', () => {
260
+ it('validates correct REST API config', () => {
261
+ const result = validateRESTAPIConfig({
262
+ url: 'https://api.example.com/data',
263
+ method: 'GET',
264
+ })
265
+ expect(result.isValid).toBe(true)
266
+ })
267
+
268
+ it('accepts all valid HTTP methods', () => {
269
+ const methods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']
270
+ methods.forEach((method) => {
271
+ const result = validateRESTAPIConfig({
272
+ url: 'https://api.example.com',
273
+ method,
274
+ })
275
+ expect(result.isValid).toBe(true)
276
+ })
277
+ })
278
+
279
+ it('rejects invalid URL', () => {
280
+ const result = validateRESTAPIConfig({
281
+ url: 'not-a-url',
282
+ })
283
+ expect(result.isValid).toBe(false)
284
+ })
285
+
286
+ it('rejects non-HTTP protocols', () => {
287
+ const result = validateRESTAPIConfig({
288
+ url: 'ftp://example.com',
289
+ })
290
+ expect(result.isValid).toBe(false)
291
+ })
292
+
293
+ it('rejects invalid HTTP method', () => {
294
+ const result = validateRESTAPIConfig({
295
+ url: 'https://api.example.com',
296
+ method: 'INVALID',
297
+ })
298
+ expect(result.isValid).toBe(false)
299
+ })
300
+ })
301
+
302
+ describe('validateJavaScriptConfig', () => {
303
+ it('validates correct JavaScript config', () => {
304
+ const result = validateJavaScriptConfig({
305
+ code: '[{id: 1, name: "Item 1"}]',
306
+ })
307
+ expect(result.isValid).toBe(true)
308
+ })
309
+
310
+ it('rejects missing code', () => {
311
+ const result = validateJavaScriptConfig({})
312
+ expect(result.isValid).toBe(false)
313
+ expect(result.error).toContain('code')
314
+ })
315
+
316
+ it('rejects empty code', () => {
317
+ const result = validateJavaScriptConfig({
318
+ code: '',
319
+ })
320
+ expect(result.isValid).toBe(false)
321
+ })
322
+
323
+ it('warns about dangerous patterns but still validates', () => {
324
+ const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
325
+
326
+ const result = validateJavaScriptConfig({
327
+ code: 'require("fs")',
328
+ })
329
+
330
+ expect(result.isValid).toBe(true)
331
+ expect(consoleSpy).toHaveBeenCalled()
332
+
333
+ consoleSpy.mockRestore()
334
+ })
335
+ })
336
+
337
+ describe('validateStaticCollectionConfig', () => {
338
+ it('validates correct static collection', () => {
339
+ const result = validateStaticCollectionConfig({
340
+ data: [{ id: 1 }, { id: 2 }],
341
+ })
342
+ expect(result.isValid).toBe(true)
343
+ })
344
+
345
+ it('rejects non-array data', () => {
346
+ const result = validateStaticCollectionConfig({
347
+ data: 'not an array',
348
+ })
349
+ expect(result.isValid).toBe(false)
350
+ })
351
+
352
+ it('rejects missing data', () => {
353
+ const result = validateStaticCollectionConfig({})
354
+ expect(result.isValid).toBe(false)
355
+ })
356
+
357
+ it('accepts empty array', () => {
358
+ const result = validateStaticCollectionConfig({
359
+ data: [],
360
+ })
361
+ expect(result.isValid).toBe(true)
362
+ })
363
+ })
364
+
365
+ describe('generateDataSourceFetcher', () => {
366
+ it('generates PostgreSQL fetcher', () => {
367
+ const dataSource = createPostgreSQLDataSource('ds-1')
368
+ const code = generateDataSourceFetcher(dataSource, 'users')
369
+
370
+ expect(code).toContain('import { Pool } from')
371
+ expect(code).toContain('export default async function handler')
372
+ expect(code).toContain('SELECT * FROM users')
373
+ expect(code).toContain('localhost')
374
+ })
375
+
376
+ it('generates MySQL fetcher', () => {
377
+ const dataSource = createMySQLDataSource('ds-1')
378
+ const code = generateDataSourceFetcher(dataSource, 'products')
379
+
380
+ expect(code).toContain('mysql')
381
+ expect(code).toContain('products')
382
+ expect(code).toContain('FROM')
383
+ })
384
+
385
+ it('generates MongoDB fetcher', () => {
386
+ const dataSource = createMongoDBDataSource('ds-1')
387
+ const code = generateDataSourceFetcher(dataSource, 'orders')
388
+
389
+ expect(code).toContain('MongoClient')
390
+ expect(code).toContain("collection('orders')")
391
+ })
392
+
393
+ it('generates REST API fetcher', () => {
394
+ const dataSource = createRESTAPIDataSource('ds-1')
395
+ const code = generateDataSourceFetcher(dataSource, '')
396
+
397
+ expect(code).toContain('fetch')
398
+ expect(code).toContain('https://api.example.com/data')
399
+ })
400
+
401
+ it('generates JavaScript fetcher', () => {
402
+ const dataSource = createJavaScriptDataSource('ds-1')
403
+ const code = generateDataSourceFetcher(dataSource, '')
404
+
405
+ expect(code).toContain('executeCode')
406
+ expect(code).toContain('new Function')
407
+ })
408
+
409
+ it('generates Static Collection fetcher', () => {
410
+ const dataSource = createStaticCollectionDataSource('ds-1')
411
+ const code = generateDataSourceFetcher(dataSource, '')
412
+
413
+ expect(code).toContain('const data = ')
414
+ expect(code).toContain('"Item 1"')
415
+ expect(code).toContain('"Item 2"')
416
+ })
417
+
418
+ it('generates Redis fetcher', () => {
419
+ const dataSource = createRedisDataSource('ds-1')
420
+ const code = generateDataSourceFetcher(dataSource, '')
421
+
422
+ expect(code).toContain('redis')
423
+ expect(code).toContain('createClient')
424
+ })
425
+
426
+ it('handles CockroachDB as PostgreSQL', () => {
427
+ const dataSource = {
428
+ id: 'ds-1',
429
+ name: 'CockroachDB',
430
+ type: 'cockroachdb' as const,
431
+ config: {
432
+ host: 'localhost',
433
+ port: 26257,
434
+ user: 'root',
435
+ password: 'password',
436
+ database: 'testdb',
437
+ },
438
+ }
439
+ const code = generateDataSourceFetcher(dataSource, 'users')
440
+
441
+ expect(code).toContain('Pool')
442
+ })
443
+
444
+ it('handles TiDB as MySQL', () => {
445
+ const dataSource = {
446
+ id: 'ds-1',
447
+ name: 'TiDB',
448
+ type: 'tidb' as const,
449
+ config: {
450
+ host: 'localhost',
451
+ port: 4000,
452
+ user: 'root',
453
+ password: 'password',
454
+ database: 'testdb',
455
+ },
456
+ }
457
+ const code = generateDataSourceFetcher(dataSource, 'users')
458
+
459
+ expect(code).toContain('mysql')
460
+ })
461
+
462
+ it('throws error for invalid data source', () => {
463
+ expect(() => {
464
+ generateDataSourceFetcher(null as any, 'users')
465
+ }).toThrow('Invalid data source')
466
+ })
467
+
468
+ it('throws error for missing type', () => {
469
+ expect(() => {
470
+ generateDataSourceFetcher({ config: {} } as any, 'users')
471
+ }).toThrow('type is required')
472
+ })
473
+
474
+ it('throws error for missing config', () => {
475
+ expect(() => {
476
+ generateDataSourceFetcher({ type: 'postgresql' } as any, 'users')
477
+ }).toThrow('config is required')
478
+ })
479
+
480
+ it('throws error for unsupported type', () => {
481
+ expect(() => {
482
+ generateDataSourceFetcher({ type: 'unsupported', config: {} } as any, 'users')
483
+ }).toThrow('Unsupported data source type')
484
+ })
485
+
486
+ it('handles validation errors', () => {
487
+ expect(() => {
488
+ generateDataSourceFetcher(
489
+ {
490
+ type: 'postgresql',
491
+ config: { host: '' },
492
+ } as any,
493
+ 'users'
494
+ )
495
+ }).toThrow('validation failed')
496
+ })
497
+ })
498
+
499
+ describe('generateDataSourceFetcherWithCore', () => {
500
+ it('generates both fetchData and handler functions', () => {
501
+ const dataSource = createPostgreSQLDataSource('ds-1')
502
+ const code = generateDataSourceFetcherWithCore(dataSource, 'users')
503
+
504
+ expect(code).toContain('async function fetchData')
505
+ expect(code).toContain('async function handler')
506
+ expect(code).toContain('export { fetchData, fetchCount, handler, getCount }')
507
+ expect(code).toContain('export default { fetchData, fetchCount, handler, getCount }')
508
+ })
509
+
510
+ it('includes simulation of req/res for fetchData', () => {
511
+ const dataSource = createPostgreSQLDataSource('ds-1')
512
+ const code = generateDataSourceFetcherWithCore(dataSource, 'users')
513
+
514
+ expect(code).toContain('const req = {')
515
+ expect(code).toContain('query: params')
516
+ expect(code).toContain('const res = {')
517
+ expect(code).toContain('status: (code)')
518
+ expect(code).toContain('json: (data)')
519
+ })
520
+
521
+ it('includes error handling in fetchData', () => {
522
+ const dataSource = createPostgreSQLDataSource('ds-1')
523
+ const code = generateDataSourceFetcherWithCore(dataSource, 'users')
524
+
525
+ expect(code).toContain('if (statusCode !== 200')
526
+ expect(code).toContain('throw new Error')
527
+ })
528
+
529
+ it('works with all data source types', () => {
530
+ const dataSources = [
531
+ createPostgreSQLDataSource('ds-1'),
532
+ createMySQLDataSource('ds-2'),
533
+ createMongoDBDataSource('ds-3'),
534
+ createRESTAPIDataSource('ds-4'),
535
+ createJavaScriptDataSource('ds-5'),
536
+ createStaticCollectionDataSource('ds-6'),
537
+ ]
538
+
539
+ dataSources.forEach((dataSource) => {
540
+ const code = generateDataSourceFetcherWithCore(dataSource, 'test')
541
+ expect(code).toContain('async function fetchData')
542
+ expect(code).toContain('async function handler')
543
+ })
544
+ })
545
+ })