@tinybirdco/sdk 0.0.4 → 0.0.7

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 (165) hide show
  1. package/README.md +52 -13
  2. package/dist/api/branches.d.ts.map +1 -1
  3. package/dist/api/branches.js +6 -5
  4. package/dist/api/branches.js.map +1 -1
  5. package/dist/api/branches.test.js +32 -6
  6. package/dist/api/branches.test.js.map +1 -1
  7. package/dist/api/build.d.ts.map +1 -1
  8. package/dist/api/build.js +2 -1
  9. package/dist/api/build.js.map +1 -1
  10. package/dist/api/deploy.d.ts +42 -3
  11. package/dist/api/deploy.d.ts.map +1 -1
  12. package/dist/api/deploy.js +162 -19
  13. package/dist/api/deploy.js.map +1 -1
  14. package/dist/api/deploy.test.js +83 -31
  15. package/dist/api/deploy.test.js.map +1 -1
  16. package/dist/api/fetcher.d.ts +6 -0
  17. package/dist/api/fetcher.d.ts.map +1 -0
  18. package/dist/api/fetcher.js +13 -0
  19. package/dist/api/fetcher.js.map +1 -0
  20. package/dist/api/local.d.ts.map +1 -1
  21. package/dist/api/local.js +5 -4
  22. package/dist/api/local.js.map +1 -1
  23. package/dist/api/local.test.js.map +1 -1
  24. package/dist/api/resources.d.ts +178 -0
  25. package/dist/api/resources.d.ts.map +1 -0
  26. package/dist/api/resources.js +245 -0
  27. package/dist/api/resources.js.map +1 -0
  28. package/dist/api/resources.test.d.ts +2 -0
  29. package/dist/api/resources.test.d.ts.map +1 -0
  30. package/dist/api/resources.test.js +255 -0
  31. package/dist/api/resources.test.js.map +1 -0
  32. package/dist/api/workspaces.d.ts.map +1 -1
  33. package/dist/api/workspaces.js +2 -1
  34. package/dist/api/workspaces.js.map +1 -1
  35. package/dist/api/workspaces.test.js +9 -1
  36. package/dist/api/workspaces.test.js.map +1 -1
  37. package/dist/cli/auth.d.ts.map +1 -1
  38. package/dist/cli/auth.js +2 -1
  39. package/dist/cli/auth.js.map +1 -1
  40. package/dist/cli/commands/build.d.ts +3 -4
  41. package/dist/cli/commands/build.d.ts.map +1 -1
  42. package/dist/cli/commands/build.js +23 -25
  43. package/dist/cli/commands/build.js.map +1 -1
  44. package/dist/cli/commands/deploy.d.ts +41 -0
  45. package/dist/cli/commands/deploy.d.ts.map +1 -0
  46. package/dist/cli/commands/deploy.js +92 -0
  47. package/dist/cli/commands/deploy.js.map +1 -0
  48. package/dist/cli/commands/dev.d.ts.map +1 -1
  49. package/dist/cli/commands/dev.js +7 -3
  50. package/dist/cli/commands/dev.js.map +1 -1
  51. package/dist/cli/commands/init.d.ts +38 -1
  52. package/dist/cli/commands/init.d.ts.map +1 -1
  53. package/dist/cli/commands/init.js +434 -23
  54. package/dist/cli/commands/init.js.map +1 -1
  55. package/dist/cli/commands/init.test.js +190 -30
  56. package/dist/cli/commands/init.test.js.map +1 -1
  57. package/dist/cli/index.js +80 -15
  58. package/dist/cli/index.js.map +1 -1
  59. package/dist/cli/utils/package-manager.d.ts +8 -0
  60. package/dist/cli/utils/package-manager.d.ts.map +1 -0
  61. package/dist/cli/utils/package-manager.js +45 -0
  62. package/dist/cli/utils/package-manager.js.map +1 -0
  63. package/dist/cli/utils/package-manager.test.d.ts +2 -0
  64. package/dist/cli/utils/package-manager.test.d.ts.map +1 -0
  65. package/dist/cli/utils/package-manager.test.js +85 -0
  66. package/dist/cli/utils/package-manager.test.js.map +1 -0
  67. package/dist/client/base.d.ts.map +1 -1
  68. package/dist/client/base.js +2 -1
  69. package/dist/client/base.js.map +1 -1
  70. package/dist/codegen/index.d.ts +39 -0
  71. package/dist/codegen/index.d.ts.map +1 -0
  72. package/dist/codegen/index.js +300 -0
  73. package/dist/codegen/index.js.map +1 -0
  74. package/dist/codegen/index.test.d.ts +2 -0
  75. package/dist/codegen/index.test.d.ts.map +1 -0
  76. package/dist/codegen/index.test.js +310 -0
  77. package/dist/codegen/index.test.js.map +1 -0
  78. package/dist/codegen/type-mapper.d.ts +20 -0
  79. package/dist/codegen/type-mapper.d.ts.map +1 -0
  80. package/dist/codegen/type-mapper.js +238 -0
  81. package/dist/codegen/type-mapper.js.map +1 -0
  82. package/dist/codegen/type-mapper.test.d.ts +2 -0
  83. package/dist/codegen/type-mapper.test.d.ts.map +1 -0
  84. package/dist/codegen/type-mapper.test.js +167 -0
  85. package/dist/codegen/type-mapper.test.js.map +1 -0
  86. package/dist/codegen/utils.d.ts +46 -0
  87. package/dist/codegen/utils.d.ts.map +1 -0
  88. package/dist/codegen/utils.js +141 -0
  89. package/dist/codegen/utils.js.map +1 -0
  90. package/dist/codegen/utils.test.d.ts +2 -0
  91. package/dist/codegen/utils.test.d.ts.map +1 -0
  92. package/dist/codegen/utils.test.js +178 -0
  93. package/dist/codegen/utils.test.js.map +1 -0
  94. package/dist/generator/index.d.ts +3 -0
  95. package/dist/generator/index.d.ts.map +1 -1
  96. package/dist/generator/index.js +17 -1
  97. package/dist/generator/index.js.map +1 -1
  98. package/dist/generator/index.test.js +104 -1
  99. package/dist/generator/index.test.js.map +1 -1
  100. package/dist/generator/loader.d.ts +15 -0
  101. package/dist/generator/loader.d.ts.map +1 -1
  102. package/dist/generator/loader.js +24 -0
  103. package/dist/generator/loader.js.map +1 -1
  104. package/dist/schema/connection.d.ts.map +1 -1
  105. package/dist/schema/connection.js +3 -2
  106. package/dist/schema/connection.js.map +1 -1
  107. package/dist/schema/datasource.d.ts.map +1 -1
  108. package/dist/schema/datasource.js +3 -2
  109. package/dist/schema/datasource.js.map +1 -1
  110. package/dist/schema/params.d.ts.map +1 -1
  111. package/dist/schema/params.js +3 -2
  112. package/dist/schema/params.js.map +1 -1
  113. package/dist/schema/pipe.d.ts +2 -2
  114. package/dist/schema/pipe.d.ts.map +1 -1
  115. package/dist/schema/pipe.js +4 -4
  116. package/dist/schema/pipe.js.map +1 -1
  117. package/dist/schema/project.d.ts.map +1 -1
  118. package/dist/schema/project.js +3 -2
  119. package/dist/schema/project.js.map +1 -1
  120. package/dist/schema/types.d.ts.map +1 -1
  121. package/dist/schema/types.js +3 -2
  122. package/dist/schema/types.js.map +1 -1
  123. package/dist/test/handlers.d.ts +49 -0
  124. package/dist/test/handlers.d.ts.map +1 -1
  125. package/dist/test/handlers.js +45 -0
  126. package/dist/test/handlers.js.map +1 -1
  127. package/package.json +4 -2
  128. package/src/api/branches.test.ts +65 -57
  129. package/src/api/branches.ts +7 -5
  130. package/src/api/build.ts +2 -1
  131. package/src/api/deploy.test.ts +141 -36
  132. package/src/api/deploy.ts +231 -23
  133. package/src/api/fetcher.ts +17 -0
  134. package/src/api/local.test.ts +43 -31
  135. package/src/api/local.ts +5 -4
  136. package/src/api/resources.test.ts +332 -0
  137. package/src/api/resources.ts +555 -0
  138. package/src/api/workspaces.test.ts +15 -9
  139. package/src/api/workspaces.ts +3 -1
  140. package/src/cli/auth.ts +2 -1
  141. package/src/cli/commands/build.ts +29 -33
  142. package/src/cli/commands/deploy.ts +131 -0
  143. package/src/cli/commands/dev.ts +10 -3
  144. package/src/cli/commands/init.test.ts +239 -30
  145. package/src/cli/commands/init.ts +548 -26
  146. package/src/cli/index.ts +117 -20
  147. package/src/cli/utils/package-manager.test.ts +118 -0
  148. package/src/cli/utils/package-manager.ts +44 -0
  149. package/src/client/base.ts +3 -2
  150. package/src/codegen/index.test.ts +367 -0
  151. package/src/codegen/index.ts +379 -0
  152. package/src/codegen/type-mapper.test.ts +224 -0
  153. package/src/codegen/type-mapper.ts +265 -0
  154. package/src/codegen/utils.test.ts +221 -0
  155. package/src/codegen/utils.ts +174 -0
  156. package/src/generator/index.test.ts +121 -1
  157. package/src/generator/index.ts +19 -1
  158. package/src/generator/loader.ts +43 -0
  159. package/src/schema/connection.ts +3 -2
  160. package/src/schema/datasource.ts +3 -2
  161. package/src/schema/params.ts +3 -2
  162. package/src/schema/pipe.ts +4 -4
  163. package/src/schema/project.ts +3 -2
  164. package/src/schema/types.ts +3 -2
  165. package/src/test/handlers.ts +58 -0
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
2
  import * as fs from "fs";
3
3
  import * as path from "path";
4
4
  import * as os from "os";
5
- import { runInit } from "./init.js";
5
+ import { runInit, findExistingDatafiles } from "./init.js";
6
6
 
7
7
  // Mock the auth module to avoid browser login
8
8
  vi.mock("../auth.js", () => ({
@@ -25,15 +25,15 @@ describe("Init Command", () => {
25
25
  });
26
26
 
27
27
  describe("folder structure creation", () => {
28
- it("creates tinybird folder with datasources.ts, pipes.ts, client.ts when project has no src folder", async () => {
29
- const result = await runInit({ cwd: tempDir, skipLogin: true });
28
+ it("creates tinybird folder with datasources.ts, endpoints.ts, client.ts when project has no src folder", async () => {
29
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
30
30
 
31
31
  expect(result.success).toBe(true);
32
32
  expect(result.created).toContain("tinybird/datasources.ts");
33
- expect(result.created).toContain("tinybird/pipes.ts");
33
+ expect(result.created).toContain("tinybird/endpoints.ts");
34
34
  expect(result.created).toContain("tinybird/client.ts");
35
35
  expect(fs.existsSync(path.join(tempDir, "tinybird", "datasources.ts"))).toBe(true);
36
- expect(fs.existsSync(path.join(tempDir, "tinybird", "pipes.ts"))).toBe(true);
36
+ expect(fs.existsSync(path.join(tempDir, "tinybird", "endpoints.ts"))).toBe(true);
37
37
  expect(fs.existsSync(path.join(tempDir, "tinybird", "client.ts"))).toBe(true);
38
38
  });
39
39
 
@@ -41,17 +41,17 @@ describe("Init Command", () => {
41
41
  // Create src folder to simulate existing project
42
42
  fs.mkdirSync(path.join(tempDir, "src"));
43
43
 
44
- const result = await runInit({ cwd: tempDir, skipLogin: true });
44
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "src/tinybird" });
45
45
 
46
46
  expect(result.success).toBe(true);
47
47
  expect(result.created).toContain("src/tinybird/datasources.ts");
48
- expect(result.created).toContain("src/tinybird/pipes.ts");
48
+ expect(result.created).toContain("src/tinybird/endpoints.ts");
49
49
  expect(result.created).toContain("src/tinybird/client.ts");
50
50
  expect(
51
51
  fs.existsSync(path.join(tempDir, "src", "tinybird", "datasources.ts"))
52
52
  ).toBe(true);
53
53
  expect(
54
- fs.existsSync(path.join(tempDir, "src", "tinybird", "pipes.ts"))
54
+ fs.existsSync(path.join(tempDir, "src", "tinybird", "endpoints.ts"))
55
55
  ).toBe(true);
56
56
  expect(
57
57
  fs.existsSync(path.join(tempDir, "src", "tinybird", "client.ts"))
@@ -59,7 +59,7 @@ describe("Init Command", () => {
59
59
  });
60
60
 
61
61
  it("creates tinybird.json with correct include paths for tinybird folder", async () => {
62
- const result = await runInit({ cwd: tempDir, skipLogin: true });
62
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
63
63
 
64
64
  expect(result.success).toBe(true);
65
65
  expect(result.created).toContain("tinybird.json");
@@ -69,14 +69,14 @@ describe("Init Command", () => {
69
69
  );
70
70
  expect(config.include).toEqual([
71
71
  "tinybird/datasources.ts",
72
- "tinybird/pipes.ts",
72
+ "tinybird/endpoints.ts",
73
73
  ]);
74
74
  });
75
75
 
76
76
  it("creates tinybird.json with correct include paths for src/tinybird", async () => {
77
77
  fs.mkdirSync(path.join(tempDir, "src"));
78
78
 
79
- const result = await runInit({ cwd: tempDir, skipLogin: true });
79
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "src/tinybird" });
80
80
 
81
81
  expect(result.success).toBe(true);
82
82
 
@@ -85,14 +85,14 @@ describe("Init Command", () => {
85
85
  );
86
86
  expect(config.include).toEqual([
87
87
  "src/tinybird/datasources.ts",
88
- "src/tinybird/pipes.ts",
88
+ "src/tinybird/endpoints.ts",
89
89
  ]);
90
90
  });
91
91
  });
92
92
 
93
93
  describe("config file creation", () => {
94
94
  it("creates tinybird.json with default values", async () => {
95
- await runInit({ cwd: tempDir, skipLogin: true });
95
+ await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
96
96
 
97
97
  const config = JSON.parse(
98
98
  fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
@@ -109,7 +109,7 @@ describe("Init Command", () => {
109
109
  JSON.stringify(existingConfig)
110
110
  );
111
111
 
112
- const result = await runInit({ cwd: tempDir, skipLogin: true });
112
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
113
113
 
114
114
  expect(result.success).toBe(true);
115
115
  expect(result.skipped).toContain("tinybird.json");
@@ -128,7 +128,7 @@ describe("Init Command", () => {
128
128
  JSON.stringify(existingConfig)
129
129
  );
130
130
 
131
- const result = await runInit({ cwd: tempDir, skipLogin: true, force: true });
131
+ const result = await runInit({ cwd: tempDir, skipLogin: true, force: true, devMode: "branch", clientPath: "tinybird" });
132
132
 
133
133
  expect(result.success).toBe(true);
134
134
  expect(result.created).toContain("tinybird.json");
@@ -138,14 +138,14 @@ describe("Init Command", () => {
138
138
  );
139
139
  expect(config.include).toEqual([
140
140
  "tinybird/datasources.ts",
141
- "tinybird/pipes.ts",
141
+ "tinybird/endpoints.ts",
142
142
  ]);
143
143
  });
144
144
  });
145
145
 
146
146
  describe("file content creation", () => {
147
147
  it("creates datasources.ts with example datasource and InferRow type", async () => {
148
- await runInit({ cwd: tempDir, skipLogin: true });
148
+ await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
149
149
 
150
150
  const content = fs.readFileSync(
151
151
  path.join(tempDir, "tinybird", "datasources.ts"),
@@ -158,11 +158,11 @@ describe("Init Command", () => {
158
158
  expect(content).toContain("PageViewsRow");
159
159
  });
160
160
 
161
- it("creates pipes.ts with example endpoint and types", async () => {
162
- await runInit({ cwd: tempDir, skipLogin: true });
161
+ it("creates endpoints.ts with example endpoint and types", async () => {
162
+ await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
163
163
 
164
164
  const content = fs.readFileSync(
165
- path.join(tempDir, "tinybird", "pipes.ts"),
165
+ path.join(tempDir, "tinybird", "endpoints.ts"),
166
166
  "utf-8"
167
167
  );
168
168
 
@@ -175,7 +175,7 @@ describe("Init Command", () => {
175
175
  });
176
176
 
177
177
  it("creates client.ts with createTinybirdClient", async () => {
178
- await runInit({ cwd: tempDir, skipLogin: true });
178
+ await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
179
179
 
180
180
  const content = fs.readFileSync(
181
181
  path.join(tempDir, "tinybird", "client.ts"),
@@ -195,7 +195,7 @@ describe("Init Command", () => {
195
195
  "// existing content"
196
196
  );
197
197
 
198
- const result = await runInit({ cwd: tempDir, skipLogin: true });
198
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
199
199
 
200
200
  expect(result.success).toBe(true);
201
201
  expect(result.skipped).toContain("tinybird/datasources.ts");
@@ -215,7 +215,7 @@ describe("Init Command", () => {
215
215
  "// existing content"
216
216
  );
217
217
 
218
- const result = await runInit({ cwd: tempDir, skipLogin: true, force: true });
218
+ const result = await runInit({ cwd: tempDir, skipLogin: true, force: true, devMode: "branch", clientPath: "tinybird" });
219
219
 
220
220
  expect(result.success).toBe(true);
221
221
  expect(result.created).toContain("tinybird/datasources.ts");
@@ -229,14 +229,14 @@ describe("Init Command", () => {
229
229
  });
230
230
 
231
231
  describe("package.json scripts", () => {
232
- it("adds tinybird:dev and tinybird:build scripts to existing package.json", async () => {
232
+ it("adds tinybird:dev, tinybird:build, and tinybird:deploy scripts to existing package.json", async () => {
233
233
  const packageJson = { name: "test-project", scripts: { dev: "next dev" } };
234
234
  fs.writeFileSync(
235
235
  path.join(tempDir, "package.json"),
236
236
  JSON.stringify(packageJson, null, 2)
237
237
  );
238
238
 
239
- const result = await runInit({ cwd: tempDir, skipLogin: true });
239
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
240
240
 
241
241
  expect(result.success).toBe(true);
242
242
  expect(result.created).toContain("package.json (added tinybird scripts)");
@@ -246,6 +246,7 @@ describe("Init Command", () => {
246
246
  );
247
247
  expect(updatedPackageJson.scripts["tinybird:dev"]).toBe("tinybird dev");
248
248
  expect(updatedPackageJson.scripts["tinybird:build"]).toBe("tinybird build");
249
+ expect(updatedPackageJson.scripts["tinybird:deploy"]).toBe("tinybird deploy");
249
250
  expect(updatedPackageJson.scripts.dev).toBe("next dev"); // preserved
250
251
  });
251
252
 
@@ -255,6 +256,7 @@ describe("Init Command", () => {
255
256
  scripts: {
256
257
  "tinybird:dev": "custom dev command",
257
258
  "tinybird:build": "custom build command",
259
+ "tinybird:deploy": "custom deploy command",
258
260
  },
259
261
  };
260
262
  fs.writeFileSync(
@@ -262,7 +264,7 @@ describe("Init Command", () => {
262
264
  JSON.stringify(packageJson, null, 2)
263
265
  );
264
266
 
265
- const result = await runInit({ cwd: tempDir, skipLogin: true });
267
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
266
268
 
267
269
  expect(result.success).toBe(true);
268
270
  expect(result.created).not.toContain("package.json (added tinybird scripts)");
@@ -272,6 +274,7 @@ describe("Init Command", () => {
272
274
  );
273
275
  expect(updatedPackageJson.scripts["tinybird:dev"]).toBe("custom dev command");
274
276
  expect(updatedPackageJson.scripts["tinybird:build"]).toBe("custom build command");
277
+ expect(updatedPackageJson.scripts["tinybird:deploy"]).toBe("custom deploy command");
275
278
  });
276
279
 
277
280
  it("creates scripts object if package.json has no scripts", async () => {
@@ -281,7 +284,7 @@ describe("Init Command", () => {
281
284
  JSON.stringify(packageJson, null, 2)
282
285
  );
283
286
 
284
- const result = await runInit({ cwd: tempDir, skipLogin: true });
287
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
285
288
 
286
289
  expect(result.success).toBe(true);
287
290
 
@@ -293,7 +296,7 @@ describe("Init Command", () => {
293
296
  });
294
297
 
295
298
  it("does not fail if no package.json exists", async () => {
296
- const result = await runInit({ cwd: tempDir, skipLogin: true });
299
+ const result = await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
297
300
 
298
301
  expect(result.success).toBe(true);
299
302
  expect(result.created).not.toContain("package.json (added tinybird scripts)");
@@ -304,7 +307,7 @@ describe("Init Command", () => {
304
307
  it("creates tinybird directory if it does not exist", async () => {
305
308
  expect(fs.existsSync(path.join(tempDir, "tinybird"))).toBe(false);
306
309
 
307
- await runInit({ cwd: tempDir, skipLogin: true });
310
+ await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "tinybird" });
308
311
 
309
312
  expect(fs.existsSync(path.join(tempDir, "tinybird"))).toBe(true);
310
313
  });
@@ -313,9 +316,215 @@ describe("Init Command", () => {
313
316
  fs.mkdirSync(path.join(tempDir, "src"));
314
317
  expect(fs.existsSync(path.join(tempDir, "src", "tinybird"))).toBe(false);
315
318
 
316
- await runInit({ cwd: tempDir, skipLogin: true });
319
+ await runInit({ cwd: tempDir, skipLogin: true, devMode: "branch", clientPath: "src/tinybird" });
317
320
 
318
321
  expect(fs.existsSync(path.join(tempDir, "src", "tinybird"))).toBe(true);
319
322
  });
320
323
  });
324
+
325
+ describe("findExistingDatafiles", () => {
326
+ it("finds .datasource files in the project", () => {
327
+ fs.mkdirSync(path.join(tempDir, "datasources"), { recursive: true });
328
+ fs.writeFileSync(path.join(tempDir, "datasources", "events.datasource"), "");
329
+ fs.writeFileSync(path.join(tempDir, "datasources", "users.datasource"), "");
330
+
331
+ const files = findExistingDatafiles(tempDir);
332
+
333
+ expect(files).toContain("datasources/events.datasource");
334
+ expect(files).toContain("datasources/users.datasource");
335
+ });
336
+
337
+ it("finds .pipe files in the project", () => {
338
+ fs.mkdirSync(path.join(tempDir, "pipes"), { recursive: true });
339
+ fs.writeFileSync(path.join(tempDir, "pipes", "top_events.pipe"), "");
340
+ fs.writeFileSync(path.join(tempDir, "pipes", "analytics.pipe"), "");
341
+
342
+ const files = findExistingDatafiles(tempDir);
343
+
344
+ expect(files).toContain("pipes/analytics.pipe");
345
+ expect(files).toContain("pipes/top_events.pipe");
346
+ });
347
+
348
+ it("finds both .datasource and .pipe files", () => {
349
+ fs.mkdirSync(path.join(tempDir, "tinybird"), { recursive: true });
350
+ fs.writeFileSync(path.join(tempDir, "tinybird", "events.datasource"), "");
351
+ fs.writeFileSync(path.join(tempDir, "tinybird", "top_events.pipe"), "");
352
+
353
+ const files = findExistingDatafiles(tempDir);
354
+
355
+ expect(files).toHaveLength(2);
356
+ expect(files).toContain("tinybird/events.datasource");
357
+ expect(files).toContain("tinybird/top_events.pipe");
358
+ });
359
+
360
+ it("skips node_modules directory", () => {
361
+ fs.mkdirSync(path.join(tempDir, "node_modules", "some-package"), { recursive: true });
362
+ fs.writeFileSync(path.join(tempDir, "node_modules", "some-package", "test.datasource"), "");
363
+
364
+ const files = findExistingDatafiles(tempDir);
365
+
366
+ expect(files).not.toContain("node_modules/some-package/test.datasource");
367
+ expect(files).toHaveLength(0);
368
+ });
369
+
370
+ it("skips hidden directories", () => {
371
+ fs.mkdirSync(path.join(tempDir, ".git", "hooks"), { recursive: true });
372
+ fs.writeFileSync(path.join(tempDir, ".git", "hooks", "test.datasource"), "");
373
+
374
+ const files = findExistingDatafiles(tempDir);
375
+
376
+ expect(files).not.toContain(".git/hooks/test.datasource");
377
+ expect(files).toHaveLength(0);
378
+ });
379
+
380
+ it("skips dist and build directories", () => {
381
+ fs.mkdirSync(path.join(tempDir, "dist"), { recursive: true });
382
+ fs.mkdirSync(path.join(tempDir, "build"), { recursive: true });
383
+ fs.writeFileSync(path.join(tempDir, "dist", "test.datasource"), "");
384
+ fs.writeFileSync(path.join(tempDir, "build", "test.pipe"), "");
385
+
386
+ const files = findExistingDatafiles(tempDir);
387
+
388
+ expect(files).toHaveLength(0);
389
+ });
390
+
391
+ it("returns empty array when no datafiles exist", () => {
392
+ const files = findExistingDatafiles(tempDir);
393
+
394
+ expect(files).toEqual([]);
395
+ });
396
+
397
+ it("respects maxDepth parameter", () => {
398
+ // Create a deeply nested file
399
+ fs.mkdirSync(path.join(tempDir, "a", "b", "c", "d", "e", "f"), { recursive: true });
400
+ fs.writeFileSync(path.join(tempDir, "a", "b", "c", "d", "e", "f", "deep.datasource"), "");
401
+ // Create a shallow file
402
+ fs.writeFileSync(path.join(tempDir, "a", "shallow.datasource"), "");
403
+
404
+ const filesDefault = findExistingDatafiles(tempDir, 5);
405
+ expect(filesDefault).toContain("a/shallow.datasource");
406
+ expect(filesDefault).not.toContain("a/b/c/d/e/f/deep.datasource");
407
+
408
+ const filesDeep = findExistingDatafiles(tempDir, 10);
409
+ expect(filesDeep).toContain("a/b/c/d/e/f/deep.datasource");
410
+ });
411
+
412
+ it("returns files in sorted order", () => {
413
+ fs.mkdirSync(path.join(tempDir, "datasources"), { recursive: true });
414
+ fs.writeFileSync(path.join(tempDir, "datasources", "zebra.datasource"), "");
415
+ fs.writeFileSync(path.join(tempDir, "datasources", "alpha.datasource"), "");
416
+ fs.writeFileSync(path.join(tempDir, "datasources", "beta.datasource"), "");
417
+
418
+ const files = findExistingDatafiles(tempDir);
419
+
420
+ expect(files).toEqual([
421
+ "datasources/alpha.datasource",
422
+ "datasources/beta.datasource",
423
+ "datasources/zebra.datasource",
424
+ ]);
425
+ });
426
+ });
427
+
428
+ describe("existing datafiles detection", () => {
429
+ it("includes existing datafiles in config when user opts in", async () => {
430
+ // Create existing datafiles
431
+ fs.mkdirSync(path.join(tempDir, "datasources"), { recursive: true });
432
+ fs.writeFileSync(path.join(tempDir, "datasources", "events.datasource"), "");
433
+ fs.mkdirSync(path.join(tempDir, "pipes"), { recursive: true });
434
+ fs.writeFileSync(path.join(tempDir, "pipes", "top_events.pipe"), "");
435
+
436
+ const result = await runInit({
437
+ cwd: tempDir,
438
+ skipLogin: true,
439
+ devMode: "branch",
440
+ clientPath: "tinybird",
441
+ skipDatafilePrompt: true,
442
+ includeExistingDatafiles: true,
443
+ });
444
+
445
+ expect(result.success).toBe(true);
446
+ expect(result.existingDatafiles).toContain("datasources/events.datasource");
447
+ expect(result.existingDatafiles).toContain("pipes/top_events.pipe");
448
+
449
+ const config = JSON.parse(
450
+ fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
451
+ );
452
+ expect(config.include).toContain("datasources/events.datasource");
453
+ expect(config.include).toContain("pipes/top_events.pipe");
454
+ });
455
+
456
+ it("does not include existing datafiles when user opts out", async () => {
457
+ // Create existing datafiles
458
+ fs.mkdirSync(path.join(tempDir, "datasources"), { recursive: true });
459
+ fs.writeFileSync(path.join(tempDir, "datasources", "events.datasource"), "");
460
+
461
+ const result = await runInit({
462
+ cwd: tempDir,
463
+ skipLogin: true,
464
+ devMode: "branch",
465
+ clientPath: "tinybird",
466
+ skipDatafilePrompt: true,
467
+ includeExistingDatafiles: false,
468
+ });
469
+
470
+ expect(result.success).toBe(true);
471
+ expect(result.existingDatafiles).toBeUndefined();
472
+
473
+ const config = JSON.parse(
474
+ fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
475
+ );
476
+ expect(config.include).not.toContain("datasources/events.datasource");
477
+ expect(config.include).toEqual([
478
+ "tinybird/datasources.ts",
479
+ "tinybird/endpoints.ts",
480
+ ]);
481
+ });
482
+
483
+ it("preserves TypeScript include paths alongside datafiles", async () => {
484
+ // Create existing datafiles
485
+ fs.mkdirSync(path.join(tempDir, "datasources"), { recursive: true });
486
+ fs.writeFileSync(path.join(tempDir, "datasources", "events.datasource"), "");
487
+
488
+ const result = await runInit({
489
+ cwd: tempDir,
490
+ skipLogin: true,
491
+ devMode: "branch",
492
+ clientPath: "tinybird",
493
+ skipDatafilePrompt: true,
494
+ includeExistingDatafiles: true,
495
+ });
496
+
497
+ expect(result.success).toBe(true);
498
+
499
+ const config = JSON.parse(
500
+ fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
501
+ );
502
+ // Should have both TypeScript files AND datafiles
503
+ expect(config.include).toContain("tinybird/datasources.ts");
504
+ expect(config.include).toContain("tinybird/endpoints.ts");
505
+ expect(config.include).toContain("datasources/events.datasource");
506
+ });
507
+
508
+ it("handles projects with no existing datafiles", async () => {
509
+ const result = await runInit({
510
+ cwd: tempDir,
511
+ skipLogin: true,
512
+ devMode: "branch",
513
+ clientPath: "tinybird",
514
+ skipDatafilePrompt: true,
515
+ includeExistingDatafiles: true,
516
+ });
517
+
518
+ expect(result.success).toBe(true);
519
+ expect(result.existingDatafiles).toBeUndefined();
520
+
521
+ const config = JSON.parse(
522
+ fs.readFileSync(path.join(tempDir, "tinybird.json"), "utf-8")
523
+ );
524
+ expect(config.include).toEqual([
525
+ "tinybird/datasources.ts",
526
+ "tinybird/endpoints.ts",
527
+ ]);
528
+ });
529
+ });
321
530
  });