@tinybirdco/sdk 0.0.11 → 0.0.13

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 (40) hide show
  1. package/dist/api/branches.d.ts +12 -1
  2. package/dist/api/branches.d.ts.map +1 -1
  3. package/dist/api/branches.js +21 -2
  4. package/dist/api/branches.js.map +1 -1
  5. package/dist/api/branches.test.js +95 -5
  6. package/dist/api/branches.test.js.map +1 -1
  7. package/dist/api/build.d.ts +3 -1
  8. package/dist/api/build.d.ts.map +1 -1
  9. package/dist/api/build.js +2 -0
  10. package/dist/api/build.js.map +1 -1
  11. package/dist/api/local.d.ts +15 -0
  12. package/dist/api/local.d.ts.map +1 -1
  13. package/dist/api/local.js +52 -0
  14. package/dist/api/local.js.map +1 -1
  15. package/dist/api/local.test.js +80 -1
  16. package/dist/api/local.test.js.map +1 -1
  17. package/dist/cli/commands/clear.d.ts +37 -0
  18. package/dist/cli/commands/clear.d.ts.map +1 -0
  19. package/dist/cli/commands/clear.js +141 -0
  20. package/dist/cli/commands/clear.js.map +1 -0
  21. package/dist/cli/index.js +144 -41
  22. package/dist/cli/index.js.map +1 -1
  23. package/dist/cli/output.d.ts +88 -0
  24. package/dist/cli/output.d.ts.map +1 -0
  25. package/dist/cli/output.js +150 -0
  26. package/dist/cli/output.js.map +1 -0
  27. package/dist/cli/output.test.d.ts +5 -0
  28. package/dist/cli/output.test.d.ts.map +1 -0
  29. package/dist/cli/output.test.js +119 -0
  30. package/dist/cli/output.test.js.map +1 -0
  31. package/package.json +1 -1
  32. package/src/api/branches.test.ts +116 -4
  33. package/src/api/branches.ts +28 -2
  34. package/src/api/build.ts +5 -1
  35. package/src/api/local.test.ts +106 -0
  36. package/src/api/local.ts +77 -0
  37. package/src/cli/commands/clear.ts +194 -0
  38. package/src/cli/index.ts +159 -58
  39. package/src/cli/output.test.ts +144 -0
  40. package/src/cli/output.ts +173 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Console output utilities with color support
3
+ * Provides consistent formatting similar to the Python CLI
4
+ */
5
+ /**
6
+ * Output a success message (green)
7
+ */
8
+ export declare function success(message: string): void;
9
+ /**
10
+ * Output an error message (red)
11
+ */
12
+ export declare function error(message: string): void;
13
+ /**
14
+ * Output a warning message (yellow/orange)
15
+ */
16
+ export declare function warning(message: string): void;
17
+ /**
18
+ * Output an info message (default color)
19
+ */
20
+ export declare function info(message: string): void;
21
+ /**
22
+ * Output a highlighted message (blue)
23
+ */
24
+ export declare function highlight(message: string): void;
25
+ /**
26
+ * Output a gray message (dimmed)
27
+ */
28
+ export declare function gray(message: string): void;
29
+ /**
30
+ * Output a bold message
31
+ */
32
+ export declare function bold(message: string): void;
33
+ /**
34
+ * Format a timestamp for console output
35
+ */
36
+ export declare function formatTime(): string;
37
+ /**
38
+ * Format duration in human-readable format
39
+ */
40
+ export declare function formatDuration(ms: number): string;
41
+ /**
42
+ * Show a resource change (checkmark + path + status)
43
+ */
44
+ export declare function showResourceChange(path: string, status: "created" | "changed" | "deleted"): void;
45
+ /**
46
+ * Show a warning for a resource
47
+ */
48
+ export declare function showResourceWarning(level: string, resource: string, message: string): void;
49
+ /**
50
+ * Show build errors in formatted style
51
+ */
52
+ export declare function showBuildErrors(errors: Array<{
53
+ filename?: string;
54
+ error: string;
55
+ }>): void;
56
+ /**
57
+ * Show final build success message
58
+ */
59
+ export declare function showBuildSuccess(durationMs: number, isRebuild?: boolean): void;
60
+ /**
61
+ * Show final build failure message
62
+ */
63
+ export declare function showBuildFailure(isRebuild?: boolean): void;
64
+ /**
65
+ * Show no changes message
66
+ */
67
+ export declare function showNoChanges(): void;
68
+ /**
69
+ * Output object containing all output functions
70
+ */
71
+ export declare const output: {
72
+ success: typeof success;
73
+ error: typeof error;
74
+ warning: typeof warning;
75
+ info: typeof info;
76
+ highlight: typeof highlight;
77
+ gray: typeof gray;
78
+ bold: typeof bold;
79
+ formatTime: typeof formatTime;
80
+ formatDuration: typeof formatDuration;
81
+ showResourceChange: typeof showResourceChange;
82
+ showResourceWarning: typeof showResourceWarning;
83
+ showBuildErrors: typeof showBuildErrors;
84
+ showBuildSuccess: typeof showBuildSuccess;
85
+ showBuildFailure: typeof showBuildFailure;
86
+ showNoChanges: typeof showNoChanges;
87
+ };
88
+ //# sourceMappingURL=output.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqBH;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE7C;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,GACxC,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAczF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,UAAQ,GAAG,IAAI,CAG5E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,UAAQ,GAAG,IAAI,CAGxD;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED;;GAEG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;CAgBlB,CAAC"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Console output utilities with color support
3
+ * Provides consistent formatting similar to the Python CLI
4
+ */
5
+ // ANSI color codes
6
+ const colors = {
7
+ reset: "\x1b[0m",
8
+ bold: "\x1b[1m",
9
+ red: "\x1b[91m",
10
+ green: "\x1b[92m",
11
+ yellow: "\x1b[38;5;208m",
12
+ blue: "\x1b[94m",
13
+ gray: "\x1b[90m",
14
+ };
15
+ // Check if colors should be disabled
16
+ const noColor = process.env.NO_COLOR !== undefined || !process.stdout.isTTY;
17
+ function colorize(text, color) {
18
+ if (noColor)
19
+ return text;
20
+ return `${colors[color]}${text}${colors.reset}`;
21
+ }
22
+ /**
23
+ * Output a success message (green)
24
+ */
25
+ export function success(message) {
26
+ console.log(colorize(message, "green"));
27
+ }
28
+ /**
29
+ * Output an error message (red)
30
+ */
31
+ export function error(message) {
32
+ console.error(colorize(message, "red"));
33
+ }
34
+ /**
35
+ * Output a warning message (yellow/orange)
36
+ */
37
+ export function warning(message) {
38
+ console.log(colorize(message, "yellow"));
39
+ }
40
+ /**
41
+ * Output an info message (default color)
42
+ */
43
+ export function info(message) {
44
+ console.log(message);
45
+ }
46
+ /**
47
+ * Output a highlighted message (blue)
48
+ */
49
+ export function highlight(message) {
50
+ console.log(colorize(message, "blue"));
51
+ }
52
+ /**
53
+ * Output a gray message (dimmed)
54
+ */
55
+ export function gray(message) {
56
+ console.log(colorize(message, "gray"));
57
+ }
58
+ /**
59
+ * Output a bold message
60
+ */
61
+ export function bold(message) {
62
+ console.log(colorize(message, "bold"));
63
+ }
64
+ /**
65
+ * Format a timestamp for console output
66
+ */
67
+ export function formatTime() {
68
+ return new Date().toLocaleTimeString("en-US", { hour12: false });
69
+ }
70
+ /**
71
+ * Format duration in human-readable format
72
+ */
73
+ export function formatDuration(ms) {
74
+ if (ms < 1000) {
75
+ return `${ms}ms`;
76
+ }
77
+ return `${(ms / 1000).toFixed(1)}s`;
78
+ }
79
+ /**
80
+ * Show a resource change (checkmark + path + status)
81
+ */
82
+ export function showResourceChange(path, status) {
83
+ console.log(`✓ ${path} ${status}`);
84
+ }
85
+ /**
86
+ * Show a warning for a resource
87
+ */
88
+ export function showResourceWarning(level, resource, message) {
89
+ warning(`△ ${level}: ${resource}: ${message}`);
90
+ }
91
+ /**
92
+ * Show build errors in formatted style
93
+ */
94
+ export function showBuildErrors(errors) {
95
+ for (const err of errors) {
96
+ if (err.filename) {
97
+ error(`${err.filename}`);
98
+ // Indent the error message
99
+ const lines = err.error.split("\n");
100
+ for (const line of lines) {
101
+ error(` ${line}`);
102
+ }
103
+ }
104
+ else {
105
+ error(err.error);
106
+ }
107
+ console.log(); // Empty line between errors
108
+ }
109
+ }
110
+ /**
111
+ * Show final build success message
112
+ */
113
+ export function showBuildSuccess(durationMs, isRebuild = false) {
114
+ const prefix = isRebuild ? "Rebuild" : "Build";
115
+ success(`\n✓ ${prefix} completed in ${formatDuration(durationMs)}`);
116
+ }
117
+ /**
118
+ * Show final build failure message
119
+ */
120
+ export function showBuildFailure(isRebuild = false) {
121
+ const prefix = isRebuild ? "Rebuild" : "Build";
122
+ error(`\n✗ ${prefix} failed`);
123
+ }
124
+ /**
125
+ * Show no changes message
126
+ */
127
+ export function showNoChanges() {
128
+ info("No changes. Build skipped.");
129
+ }
130
+ /**
131
+ * Output object containing all output functions
132
+ */
133
+ export const output = {
134
+ success,
135
+ error,
136
+ warning,
137
+ info,
138
+ highlight,
139
+ gray,
140
+ bold,
141
+ formatTime,
142
+ formatDuration,
143
+ showResourceChange,
144
+ showResourceWarning,
145
+ showBuildErrors,
146
+ showBuildSuccess,
147
+ showBuildFailure,
148
+ showNoChanges,
149
+ };
150
+ //# sourceMappingURL=output.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/cli/output.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for CLI output utilities
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=output.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.test.d.ts","sourceRoot":"","sources":["../../src/cli/output.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Tests for CLI output utilities
3
+ */
4
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
5
+ import { formatDuration, showResourceChange, showBuildErrors, showBuildSuccess, showBuildFailure, showNoChanges, } from "./output.js";
6
+ describe("output utilities", () => {
7
+ let consoleLogSpy;
8
+ let consoleErrorSpy;
9
+ beforeEach(() => {
10
+ consoleLogSpy = vi.spyOn(console, "log").mockImplementation(() => { });
11
+ consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => { });
12
+ });
13
+ afterEach(() => {
14
+ consoleLogSpy.mockRestore();
15
+ consoleErrorSpy.mockRestore();
16
+ });
17
+ describe("formatDuration", () => {
18
+ it("formats milliseconds for durations under 1 second", () => {
19
+ expect(formatDuration(500)).toBe("500ms");
20
+ expect(formatDuration(0)).toBe("0ms");
21
+ expect(formatDuration(999)).toBe("999ms");
22
+ });
23
+ it("formats seconds for durations 1 second or more", () => {
24
+ expect(formatDuration(1000)).toBe("1.0s");
25
+ expect(formatDuration(1500)).toBe("1.5s");
26
+ expect(formatDuration(2345)).toBe("2.3s");
27
+ expect(formatDuration(10000)).toBe("10.0s");
28
+ });
29
+ });
30
+ describe("showResourceChange", () => {
31
+ it("shows created resource", () => {
32
+ showResourceChange("events.datasource", "created");
33
+ expect(consoleLogSpy).toHaveBeenCalledWith("✓ events.datasource created");
34
+ });
35
+ it("shows changed resource", () => {
36
+ showResourceChange("top_pages.pipe", "changed");
37
+ expect(consoleLogSpy).toHaveBeenCalledWith("✓ top_pages.pipe changed");
38
+ });
39
+ it("shows deleted resource", () => {
40
+ showResourceChange("old_data.datasource", "deleted");
41
+ expect(consoleLogSpy).toHaveBeenCalledWith("✓ old_data.datasource deleted");
42
+ });
43
+ });
44
+ describe("showBuildErrors", () => {
45
+ it("shows errors with filename", () => {
46
+ showBuildErrors([
47
+ { filename: "events.datasource", error: "Invalid column type" },
48
+ ]);
49
+ expect(consoleErrorSpy).toHaveBeenCalledWith("events.datasource");
50
+ expect(consoleErrorSpy).toHaveBeenCalledWith(" Invalid column type");
51
+ });
52
+ it("shows errors without filename", () => {
53
+ showBuildErrors([{ error: "General build error" }]);
54
+ expect(consoleErrorSpy).toHaveBeenCalledWith("General build error");
55
+ });
56
+ it("shows multiple errors", () => {
57
+ showBuildErrors([
58
+ { filename: "a.datasource", error: "Error A" },
59
+ { filename: "b.pipe", error: "Error B" },
60
+ ]);
61
+ expect(consoleErrorSpy).toHaveBeenCalledWith("a.datasource");
62
+ expect(consoleErrorSpy).toHaveBeenCalledWith(" Error A");
63
+ expect(consoleErrorSpy).toHaveBeenCalledWith("b.pipe");
64
+ expect(consoleErrorSpy).toHaveBeenCalledWith(" Error B");
65
+ });
66
+ it("handles multi-line errors", () => {
67
+ showBuildErrors([
68
+ { filename: "test.pipe", error: "Line 1\nLine 2\nLine 3" },
69
+ ]);
70
+ expect(consoleErrorSpy).toHaveBeenCalledWith("test.pipe");
71
+ expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 1");
72
+ expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 2");
73
+ expect(consoleErrorSpy).toHaveBeenCalledWith(" Line 3");
74
+ });
75
+ });
76
+ describe("showBuildSuccess", () => {
77
+ it("shows build success with duration in ms", () => {
78
+ showBuildSuccess(500);
79
+ expect(consoleLogSpy).toHaveBeenCalled();
80
+ const call = consoleLogSpy.mock.calls[0][0];
81
+ expect(call).toContain("✓");
82
+ expect(call).toContain("Build completed in 500ms");
83
+ });
84
+ it("shows build success with duration in seconds", () => {
85
+ showBuildSuccess(2500);
86
+ expect(consoleLogSpy).toHaveBeenCalled();
87
+ const call = consoleLogSpy.mock.calls[0][0];
88
+ expect(call).toContain("Build completed in 2.5s");
89
+ });
90
+ it("shows rebuild success when isRebuild is true", () => {
91
+ showBuildSuccess(1000, true);
92
+ expect(consoleLogSpy).toHaveBeenCalled();
93
+ const call = consoleLogSpy.mock.calls[0][0];
94
+ expect(call).toContain("Rebuild completed in 1.0s");
95
+ });
96
+ });
97
+ describe("showBuildFailure", () => {
98
+ it("shows build failure", () => {
99
+ showBuildFailure();
100
+ expect(consoleErrorSpy).toHaveBeenCalled();
101
+ const call = consoleErrorSpy.mock.calls[0][0];
102
+ expect(call).toContain("✗");
103
+ expect(call).toContain("Build failed");
104
+ });
105
+ it("shows rebuild failure when isRebuild is true", () => {
106
+ showBuildFailure(true);
107
+ expect(consoleErrorSpy).toHaveBeenCalled();
108
+ const call = consoleErrorSpy.mock.calls[0][0];
109
+ expect(call).toContain("Rebuild failed");
110
+ });
111
+ });
112
+ describe("showNoChanges", () => {
113
+ it("shows no changes message", () => {
114
+ showNoChanges();
115
+ expect(consoleLogSpy).toHaveBeenCalledWith("No changes. Build skipped.");
116
+ });
117
+ });
118
+ });
119
+ //# sourceMappingURL=output.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.test.js","sourceRoot":"","sources":["../../src/cli/output.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinybirdco/sdk",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "TypeScript SDK for Tinybird Forward - define datasources and pipes as TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -7,6 +7,7 @@ import {
7
7
  deleteBranch,
8
8
  branchExists,
9
9
  getOrCreateBranch,
10
+ clearBranch,
10
11
  type BranchApiConfig,
11
12
  } from "./branches.js";
12
13
 
@@ -271,16 +272,39 @@ describe("Branch API client", () => {
271
272
 
272
273
  describe("deleteBranch", () => {
273
274
  it("deletes a branch successfully", async () => {
275
+ const mockBranch = {
276
+ id: "branch-123",
277
+ name: "my-feature",
278
+ token: "p.branch-token",
279
+ created_at: "2024-01-01T00:00:00Z",
280
+ };
281
+
282
+ // 1. getBranch to get the ID
283
+ mockFetch.mockResolvedValueOnce({
284
+ ok: true,
285
+ json: () => Promise.resolve(mockBranch),
286
+ });
287
+
288
+ // 2. DELETE the branch by ID
274
289
  mockFetch.mockResolvedValueOnce({
275
290
  ok: true,
276
291
  });
277
292
 
278
293
  await deleteBranch(config, "my-feature");
279
294
 
280
- const [url, init] = mockFetch.mock.calls[0];
281
- const parsed = expectFromParam(url);
282
- expect(parsed.pathname).toBe("/v1/environments/my-feature");
283
- expect(init).toEqual({
295
+ expect(mockFetch).toHaveBeenCalledTimes(2);
296
+
297
+ // First call: get branch
298
+ const [getUrl, getInit] = mockFetch.mock.calls[0];
299
+ const getParsed = expectFromParam(getUrl);
300
+ expect(getParsed.pathname).toBe("/v0/environments/my-feature");
301
+ expect(getInit.method).toBe("GET");
302
+
303
+ // Second call: delete branch by ID
304
+ const [deleteUrl, deleteInit] = mockFetch.mock.calls[1];
305
+ const deleteParsed = expectFromParam(deleteUrl);
306
+ expect(deleteParsed.pathname).toBe("/v0/environments/branch-123");
307
+ expect(deleteInit).toEqual({
284
308
  method: "DELETE",
285
309
  headers: {
286
310
  Authorization: "Bearer p.test-token",
@@ -382,4 +406,92 @@ describe("Branch API client", () => {
382
406
  expect(mockFetch).toHaveBeenCalledTimes(4);
383
407
  });
384
408
  });
409
+
410
+ describe("clearBranch", () => {
411
+ it("clears a branch by deleting and recreating it", async () => {
412
+ const existingBranch = {
413
+ id: "branch-old",
414
+ name: "my-feature",
415
+ token: "p.old-token",
416
+ created_at: "2024-01-01T00:00:00Z",
417
+ };
418
+
419
+ const newBranch = {
420
+ id: "branch-new",
421
+ name: "my-feature",
422
+ token: "p.new-token",
423
+ created_at: "2024-01-02T00:00:00Z",
424
+ };
425
+
426
+ // 1. GET branch to get ID (for delete)
427
+ mockFetch.mockResolvedValueOnce({
428
+ ok: true,
429
+ json: () => Promise.resolve(existingBranch),
430
+ });
431
+
432
+ // 2. DELETE branch by ID
433
+ mockFetch.mockResolvedValueOnce({
434
+ ok: true,
435
+ });
436
+
437
+ // 3. POST to /v1/environments returns a job
438
+ mockFetch.mockResolvedValueOnce({
439
+ ok: true,
440
+ json: () => Promise.resolve({
441
+ job: { id: "job-789", status: "waiting" },
442
+ workspace: { id: "ws-789" },
443
+ }),
444
+ });
445
+
446
+ // 4. Poll job - done
447
+ mockFetch.mockResolvedValueOnce({
448
+ ok: true,
449
+ json: () => Promise.resolve({ id: "job-789", status: "done" }),
450
+ });
451
+
452
+ // 5. Get branch with token (after create)
453
+ mockFetch.mockResolvedValueOnce({
454
+ ok: true,
455
+ json: () => Promise.resolve(newBranch),
456
+ });
457
+
458
+ const result = await clearBranch(config, "my-feature");
459
+
460
+ expect(mockFetch).toHaveBeenCalledTimes(5);
461
+
462
+ // Verify get was called first
463
+ const [getUrl, getInit] = mockFetch.mock.calls[0];
464
+ const getParsed = expectFromParam(getUrl);
465
+ expect(getParsed.pathname).toBe("/v0/environments/my-feature");
466
+ expect(getInit.method).toBe("GET");
467
+
468
+ // Verify delete was called with ID
469
+ const [deleteUrl, deleteInit] = mockFetch.mock.calls[1];
470
+ const deleteParsed = expectFromParam(deleteUrl);
471
+ expect(deleteParsed.pathname).toBe("/v0/environments/branch-old");
472
+ expect(deleteInit.method).toBe("DELETE");
473
+
474
+ // Verify create was called
475
+ const [createUrl, createInit] = mockFetch.mock.calls[2];
476
+ const createParsed = expectFromParam(createUrl);
477
+ expect(createParsed.pathname).toBe("/v1/environments");
478
+ expect(createParsed.searchParams.get("name")).toBe("my-feature");
479
+ expect(createInit.method).toBe("POST");
480
+
481
+ expect(result).toEqual(newBranch);
482
+ });
483
+
484
+ it("throws BranchApiError when branch does not exist", async () => {
485
+ mockFetch.mockResolvedValueOnce({
486
+ ok: false,
487
+ status: 404,
488
+ statusText: "Not Found",
489
+ text: () => Promise.resolve("Branch not found"),
490
+ });
491
+
492
+ await expect(clearBranch(config, "nonexistent")).rejects.toThrow(
493
+ BranchApiError
494
+ );
495
+ });
496
+ });
385
497
  });
@@ -264,7 +264,10 @@ export async function getBranch(
264
264
 
265
265
  /**
266
266
  * Delete a branch
267
- * DELETE /v1/environments/{name}
267
+ * DELETE /v0/environments/{id}
268
+ *
269
+ * Note: The API requires the branch ID, not name. This function first
270
+ * fetches the branch to get its ID, then deletes it.
268
271
  *
269
272
  * @param config - API configuration
270
273
  * @param name - Branch name to delete
@@ -273,7 +276,10 @@ export async function deleteBranch(
273
276
  config: BranchApiConfig,
274
277
  name: string
275
278
  ): Promise<void> {
276
- const url = new URL(`/v1/environments/${encodeURIComponent(name)}`, config.baseUrl);
279
+ // First get the branch to find its ID
280
+ const branch = await getBranch(config, name);
281
+
282
+ const url = new URL(`/v0/environments/${branch.id}`, config.baseUrl);
277
283
 
278
284
  const response = await tinybirdFetch(url.toString(), {
279
285
  method: "DELETE",
@@ -334,3 +340,23 @@ export async function getOrCreateBranch(
334
340
  throw error;
335
341
  }
336
342
  }
343
+
344
+ /**
345
+ * Clear a branch by deleting and recreating it
346
+ *
347
+ * @param config - API configuration
348
+ * @param name - Branch name to clear
349
+ * @returns The recreated branch with token
350
+ */
351
+ export async function clearBranch(
352
+ config: BranchApiConfig,
353
+ name: string
354
+ ): Promise<TinybirdBranch> {
355
+ // Delete the branch
356
+ await deleteBranch(config, name);
357
+
358
+ // Recreate the branch
359
+ const branch = await createBranch(config, name);
360
+
361
+ return branch;
362
+ }
package/src/api/build.ts CHANGED
@@ -83,8 +83,10 @@ export interface BuildApiResult {
83
83
  success: boolean;
84
84
  /** Result status from API */
85
85
  result: "success" | "failed" | "no_changes";
86
- /** Error message if failed */
86
+ /** Error message if failed (formatted for display) */
87
87
  error?: string;
88
+ /** Detailed errors array from the API */
89
+ errors?: BuildError[];
88
90
  /** Number of datasources deployed */
89
91
  datasourceCount: number;
90
92
  /** Number of pipes deployed */
@@ -233,6 +235,7 @@ export async function buildToTinybird(
233
235
  success: false,
234
236
  result: "failed",
235
237
  error: formatErrors(),
238
+ errors: body.errors,
236
239
  datasourceCount: resources.datasources.length,
237
240
  pipeCount: resources.pipes.length,
238
241
  connectionCount: resources.connections?.length ?? 0,
@@ -245,6 +248,7 @@ export async function buildToTinybird(
245
248
  success: false,
246
249
  result: "failed",
247
250
  error: formatErrors(),
251
+ errors: body.errors,
248
252
  datasourceCount: resources.datasources.length,
249
253
  pipeCount: resources.pipes.length,
250
254
  connectionCount: resources.connections?.length ?? 0,