@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.
- package/README.md +52 -13
- package/dist/api/branches.d.ts.map +1 -1
- package/dist/api/branches.js +6 -5
- package/dist/api/branches.js.map +1 -1
- package/dist/api/branches.test.js +32 -6
- package/dist/api/branches.test.js.map +1 -1
- package/dist/api/build.d.ts.map +1 -1
- package/dist/api/build.js +2 -1
- package/dist/api/build.js.map +1 -1
- package/dist/api/deploy.d.ts +42 -3
- package/dist/api/deploy.d.ts.map +1 -1
- package/dist/api/deploy.js +162 -19
- package/dist/api/deploy.js.map +1 -1
- package/dist/api/deploy.test.js +83 -31
- package/dist/api/deploy.test.js.map +1 -1
- package/dist/api/fetcher.d.ts +6 -0
- package/dist/api/fetcher.d.ts.map +1 -0
- package/dist/api/fetcher.js +13 -0
- package/dist/api/fetcher.js.map +1 -0
- package/dist/api/local.d.ts.map +1 -1
- package/dist/api/local.js +5 -4
- package/dist/api/local.js.map +1 -1
- package/dist/api/local.test.js.map +1 -1
- package/dist/api/resources.d.ts +178 -0
- package/dist/api/resources.d.ts.map +1 -0
- package/dist/api/resources.js +245 -0
- package/dist/api/resources.js.map +1 -0
- package/dist/api/resources.test.d.ts +2 -0
- package/dist/api/resources.test.d.ts.map +1 -0
- package/dist/api/resources.test.js +255 -0
- package/dist/api/resources.test.js.map +1 -0
- package/dist/api/workspaces.d.ts.map +1 -1
- package/dist/api/workspaces.js +2 -1
- package/dist/api/workspaces.js.map +1 -1
- package/dist/api/workspaces.test.js +9 -1
- package/dist/api/workspaces.test.js.map +1 -1
- package/dist/cli/auth.d.ts.map +1 -1
- package/dist/cli/auth.js +2 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/commands/build.d.ts +3 -4
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +23 -25
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/deploy.d.ts +41 -0
- package/dist/cli/commands/deploy.d.ts.map +1 -0
- package/dist/cli/commands/deploy.js +92 -0
- package/dist/cli/commands/deploy.js.map +1 -0
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/dev.js +7 -3
- package/dist/cli/commands/dev.js.map +1 -1
- package/dist/cli/commands/init.d.ts +38 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +434 -23
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/init.test.js +190 -30
- package/dist/cli/commands/init.test.js.map +1 -1
- package/dist/cli/index.js +80 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/package-manager.d.ts +8 -0
- package/dist/cli/utils/package-manager.d.ts.map +1 -0
- package/dist/cli/utils/package-manager.js +45 -0
- package/dist/cli/utils/package-manager.js.map +1 -0
- package/dist/cli/utils/package-manager.test.d.ts +2 -0
- package/dist/cli/utils/package-manager.test.d.ts.map +1 -0
- package/dist/cli/utils/package-manager.test.js +85 -0
- package/dist/cli/utils/package-manager.test.js.map +1 -0
- package/dist/client/base.d.ts.map +1 -1
- package/dist/client/base.js +2 -1
- package/dist/client/base.js.map +1 -1
- package/dist/codegen/index.d.ts +39 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +300 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/codegen/index.test.d.ts +2 -0
- package/dist/codegen/index.test.d.ts.map +1 -0
- package/dist/codegen/index.test.js +310 -0
- package/dist/codegen/index.test.js.map +1 -0
- package/dist/codegen/type-mapper.d.ts +20 -0
- package/dist/codegen/type-mapper.d.ts.map +1 -0
- package/dist/codegen/type-mapper.js +238 -0
- package/dist/codegen/type-mapper.js.map +1 -0
- package/dist/codegen/type-mapper.test.d.ts +2 -0
- package/dist/codegen/type-mapper.test.d.ts.map +1 -0
- package/dist/codegen/type-mapper.test.js +167 -0
- package/dist/codegen/type-mapper.test.js.map +1 -0
- package/dist/codegen/utils.d.ts +46 -0
- package/dist/codegen/utils.d.ts.map +1 -0
- package/dist/codegen/utils.js +141 -0
- package/dist/codegen/utils.js.map +1 -0
- package/dist/codegen/utils.test.d.ts +2 -0
- package/dist/codegen/utils.test.d.ts.map +1 -0
- package/dist/codegen/utils.test.js +178 -0
- package/dist/codegen/utils.test.js.map +1 -0
- package/dist/generator/index.d.ts +3 -0
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/index.js +17 -1
- package/dist/generator/index.js.map +1 -1
- package/dist/generator/index.test.js +104 -1
- package/dist/generator/index.test.js.map +1 -1
- package/dist/generator/loader.d.ts +15 -0
- package/dist/generator/loader.d.ts.map +1 -1
- package/dist/generator/loader.js +24 -0
- package/dist/generator/loader.js.map +1 -1
- package/dist/schema/connection.d.ts.map +1 -1
- package/dist/schema/connection.js +3 -2
- package/dist/schema/connection.js.map +1 -1
- package/dist/schema/datasource.d.ts.map +1 -1
- package/dist/schema/datasource.js +3 -2
- package/dist/schema/datasource.js.map +1 -1
- package/dist/schema/params.d.ts.map +1 -1
- package/dist/schema/params.js +3 -2
- package/dist/schema/params.js.map +1 -1
- package/dist/schema/pipe.d.ts +2 -2
- package/dist/schema/pipe.d.ts.map +1 -1
- package/dist/schema/pipe.js +4 -4
- package/dist/schema/pipe.js.map +1 -1
- package/dist/schema/project.d.ts.map +1 -1
- package/dist/schema/project.js +3 -2
- package/dist/schema/project.js.map +1 -1
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +3 -2
- package/dist/schema/types.js.map +1 -1
- package/dist/test/handlers.d.ts +49 -0
- package/dist/test/handlers.d.ts.map +1 -1
- package/dist/test/handlers.js +45 -0
- package/dist/test/handlers.js.map +1 -1
- package/package.json +4 -2
- package/src/api/branches.test.ts +65 -57
- package/src/api/branches.ts +7 -5
- package/src/api/build.ts +2 -1
- package/src/api/deploy.test.ts +141 -36
- package/src/api/deploy.ts +231 -23
- package/src/api/fetcher.ts +17 -0
- package/src/api/local.test.ts +43 -31
- package/src/api/local.ts +5 -4
- package/src/api/resources.test.ts +332 -0
- package/src/api/resources.ts +555 -0
- package/src/api/workspaces.test.ts +15 -9
- package/src/api/workspaces.ts +3 -1
- package/src/cli/auth.ts +2 -1
- package/src/cli/commands/build.ts +29 -33
- package/src/cli/commands/deploy.ts +131 -0
- package/src/cli/commands/dev.ts +10 -3
- package/src/cli/commands/init.test.ts +239 -30
- package/src/cli/commands/init.ts +548 -26
- package/src/cli/index.ts +117 -20
- package/src/cli/utils/package-manager.test.ts +118 -0
- package/src/cli/utils/package-manager.ts +44 -0
- package/src/client/base.ts +3 -2
- package/src/codegen/index.test.ts +367 -0
- package/src/codegen/index.ts +379 -0
- package/src/codegen/type-mapper.test.ts +224 -0
- package/src/codegen/type-mapper.ts +265 -0
- package/src/codegen/utils.test.ts +221 -0
- package/src/codegen/utils.ts +174 -0
- package/src/generator/index.test.ts +121 -1
- package/src/generator/index.ts +19 -1
- package/src/generator/loader.ts +43 -0
- package/src/schema/connection.ts +3 -2
- package/src/schema/datasource.ts +3 -2
- package/src/schema/params.ts +3 -2
- package/src/schema/pipe.ts +4 -4
- package/src/schema/project.ts +3 -2
- package/src/schema/types.ts +3 -2
- package/src/test/handlers.ts +58 -0
package/src/api/deploy.ts
CHANGED
|
@@ -1,17 +1,55 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Deploy resources to Tinybird main workspace
|
|
3
|
-
* Uses the /v1/deploy endpoint
|
|
3
|
+
* Uses the /v1/deploy endpoint to create a deployment, then sets it live
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { GeneratedResources } from "../generator/index.js";
|
|
7
|
-
import type { BuildConfig, BuildApiResult
|
|
7
|
+
import type { BuildConfig, BuildApiResult } from "./build.js";
|
|
8
|
+
import { tinybirdFetch } from "./fetcher.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Deployment object returned by the /v1/deploy endpoint
|
|
12
|
+
*/
|
|
13
|
+
export interface Deployment {
|
|
14
|
+
id: string;
|
|
15
|
+
status: string;
|
|
16
|
+
live?: boolean;
|
|
17
|
+
created_at?: string;
|
|
18
|
+
updated_at?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Response from /v1/deployments list endpoint
|
|
23
|
+
*/
|
|
24
|
+
export interface DeploymentsListResponse {
|
|
25
|
+
deployments: Deployment[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Response from /v1/deploy endpoint
|
|
30
|
+
*/
|
|
31
|
+
export interface DeployResponse {
|
|
32
|
+
result: "success" | "failed";
|
|
33
|
+
deployment?: Deployment;
|
|
34
|
+
error?: string;
|
|
35
|
+
errors?: Array<{ filename?: string; error: string }>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Response from /v1/deployments/{id} endpoint
|
|
40
|
+
*/
|
|
41
|
+
export interface DeploymentStatusResponse {
|
|
42
|
+
result: string;
|
|
43
|
+
deployment: Deployment;
|
|
44
|
+
}
|
|
8
45
|
|
|
9
46
|
/**
|
|
10
47
|
* Deploy generated resources to Tinybird main workspace
|
|
11
48
|
*
|
|
12
49
|
* Uses the /v1/deploy endpoint which accepts all resources in a single
|
|
13
|
-
* multipart form request.
|
|
14
|
-
* (
|
|
50
|
+
* multipart form request. After creating the deployment, this function:
|
|
51
|
+
* 1. Polls until the deployment is ready (status === 'data_ready')
|
|
52
|
+
* 2. Sets the deployment as live via /v1/deployments/{id}/set-live
|
|
15
53
|
*
|
|
16
54
|
* @param config - Build configuration with API URL and token
|
|
17
55
|
* @param resources - Generated resources to deploy
|
|
@@ -38,9 +76,18 @@ import type { BuildConfig, BuildApiResult, BuildResponse } from "./build.js";
|
|
|
38
76
|
export async function deployToMain(
|
|
39
77
|
config: BuildConfig,
|
|
40
78
|
resources: GeneratedResources,
|
|
41
|
-
options?: {
|
|
79
|
+
options?: {
|
|
80
|
+
debug?: boolean;
|
|
81
|
+
pollIntervalMs?: number;
|
|
82
|
+
maxPollAttempts?: number;
|
|
83
|
+
check?: boolean;
|
|
84
|
+
}
|
|
42
85
|
): Promise<BuildApiResult> {
|
|
43
86
|
const debug = options?.debug ?? !!process.env.TINYBIRD_DEBUG;
|
|
87
|
+
const pollIntervalMs = options?.pollIntervalMs ?? 1000;
|
|
88
|
+
const maxPollAttempts = options?.maxPollAttempts ?? 120; // 2 minutes max
|
|
89
|
+
const baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
90
|
+
|
|
44
91
|
const formData = new FormData();
|
|
45
92
|
|
|
46
93
|
// Add datasources
|
|
@@ -73,14 +120,49 @@ export async function deployToMain(
|
|
|
73
120
|
);
|
|
74
121
|
}
|
|
75
122
|
|
|
76
|
-
//
|
|
77
|
-
|
|
123
|
+
// Step 0: Clean up any stale non-live deployments that might block the new deployment
|
|
124
|
+
try {
|
|
125
|
+
const deploymentsUrl = `${baseUrl}/v1/deployments`;
|
|
126
|
+
const deploymentsResponse = await tinybirdFetch(deploymentsUrl, {
|
|
127
|
+
headers: {
|
|
128
|
+
Authorization: `Bearer ${config.token}`,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (deploymentsResponse.ok) {
|
|
133
|
+
const deploymentsBody = (await deploymentsResponse.json()) as DeploymentsListResponse;
|
|
134
|
+
const staleDeployments = deploymentsBody.deployments.filter(
|
|
135
|
+
(d) => !d.live && d.status !== "live"
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
for (const stale of staleDeployments) {
|
|
139
|
+
if (debug) {
|
|
140
|
+
console.log(`[debug] Cleaning up stale deployment: ${stale.id} (status: ${stale.status})`);
|
|
141
|
+
}
|
|
142
|
+
await tinybirdFetch(`${baseUrl}/v1/deployments/${stale.id}`, {
|
|
143
|
+
method: "DELETE",
|
|
144
|
+
headers: {
|
|
145
|
+
Authorization: `Bearer ${config.token}`,
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
} catch (e) {
|
|
151
|
+
// Ignore errors during cleanup - we'll try to deploy anyway
|
|
152
|
+
if (debug) {
|
|
153
|
+
console.log(`[debug] Failed to clean up stale deployments: ${e}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Step 1: Create deployment via /v1/deploy
|
|
158
|
+
const deployUrlBase = `${baseUrl}/v1/deploy`;
|
|
159
|
+
const deployUrl = options?.check ? `${deployUrlBase}?check=true` : deployUrlBase;
|
|
78
160
|
|
|
79
161
|
if (debug) {
|
|
80
|
-
console.log(`[debug] POST ${
|
|
162
|
+
console.log(`[debug] POST ${deployUrl}`);
|
|
81
163
|
}
|
|
82
164
|
|
|
83
|
-
const response = await
|
|
165
|
+
const response = await tinybirdFetch(deployUrl, {
|
|
84
166
|
method: "POST",
|
|
85
167
|
headers: {
|
|
86
168
|
Authorization: `Bearer ${config.token}`,
|
|
@@ -89,7 +171,7 @@ export async function deployToMain(
|
|
|
89
171
|
});
|
|
90
172
|
|
|
91
173
|
// Parse response
|
|
92
|
-
let body:
|
|
174
|
+
let body: DeployResponse;
|
|
93
175
|
const rawBody = await response.text();
|
|
94
176
|
|
|
95
177
|
if (debug) {
|
|
@@ -98,7 +180,7 @@ export async function deployToMain(
|
|
|
98
180
|
}
|
|
99
181
|
|
|
100
182
|
try {
|
|
101
|
-
body = JSON.parse(rawBody) as
|
|
183
|
+
body = JSON.parse(rawBody) as DeployResponse;
|
|
102
184
|
} catch {
|
|
103
185
|
throw new Error(
|
|
104
186
|
`Failed to parse response from Tinybird API: ${response.status} ${response.statusText}\nBody: ${rawBody}`
|
|
@@ -130,8 +212,29 @@ export async function deployToMain(
|
|
|
130
212
|
};
|
|
131
213
|
}
|
|
132
214
|
|
|
215
|
+
if (options?.check) {
|
|
216
|
+
if (body.result === "failed") {
|
|
217
|
+
return {
|
|
218
|
+
success: false,
|
|
219
|
+
result: "failed",
|
|
220
|
+
error: formatErrors(),
|
|
221
|
+
datasourceCount: resources.datasources.length,
|
|
222
|
+
pipeCount: resources.pipes.length,
|
|
223
|
+
connectionCount: resources.connections?.length ?? 0,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
success: true,
|
|
229
|
+
result: body.result ?? "success",
|
|
230
|
+
datasourceCount: resources.datasources.length,
|
|
231
|
+
pipeCount: resources.pipes.length,
|
|
232
|
+
connectionCount: resources.connections?.length ?? 0,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
|
|
133
236
|
// Handle API result
|
|
134
|
-
if (body.result === "failed") {
|
|
237
|
+
if (body.result === "failed" || !body.deployment) {
|
|
135
238
|
return {
|
|
136
239
|
success: false,
|
|
137
240
|
result: "failed",
|
|
@@ -142,25 +245,130 @@ export async function deployToMain(
|
|
|
142
245
|
};
|
|
143
246
|
}
|
|
144
247
|
|
|
248
|
+
const deploymentId = body.deployment.id;
|
|
249
|
+
|
|
250
|
+
if (debug) {
|
|
251
|
+
console.log(`[debug] Deployment created with ID: ${deploymentId}`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Step 2: Poll until deployment is ready
|
|
255
|
+
let deployment = body.deployment;
|
|
256
|
+
let attempts = 0;
|
|
257
|
+
|
|
258
|
+
while (deployment.status !== "data_ready" && attempts < maxPollAttempts) {
|
|
259
|
+
await sleep(pollIntervalMs);
|
|
260
|
+
attempts++;
|
|
261
|
+
|
|
262
|
+
if (debug) {
|
|
263
|
+
console.log(`[debug] Polling deployment status (attempt ${attempts})...`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const statusUrl = `${baseUrl}/v1/deployments/${deploymentId}`;
|
|
267
|
+
const statusResponse = await tinybirdFetch(statusUrl, {
|
|
268
|
+
headers: {
|
|
269
|
+
Authorization: `Bearer ${config.token}`,
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
if (!statusResponse.ok) {
|
|
274
|
+
return {
|
|
275
|
+
success: false,
|
|
276
|
+
result: "failed",
|
|
277
|
+
error: `Failed to check deployment status: ${statusResponse.status} ${statusResponse.statusText}`,
|
|
278
|
+
datasourceCount: resources.datasources.length,
|
|
279
|
+
pipeCount: resources.pipes.length,
|
|
280
|
+
connectionCount: resources.connections?.length ?? 0,
|
|
281
|
+
buildId: deploymentId,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const statusBody = (await statusResponse.json()) as DeploymentStatusResponse;
|
|
286
|
+
deployment = statusBody.deployment;
|
|
287
|
+
|
|
288
|
+
if (debug) {
|
|
289
|
+
console.log(`[debug] Deployment status: ${deployment.status}`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Check for failed status
|
|
293
|
+
if (deployment.status === "failed" || deployment.status === "error") {
|
|
294
|
+
return {
|
|
295
|
+
success: false,
|
|
296
|
+
result: "failed",
|
|
297
|
+
error: `Deployment failed with status: ${deployment.status}`,
|
|
298
|
+
datasourceCount: resources.datasources.length,
|
|
299
|
+
pipeCount: resources.pipes.length,
|
|
300
|
+
connectionCount: resources.connections?.length ?? 0,
|
|
301
|
+
buildId: deploymentId,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (deployment.status !== "data_ready") {
|
|
307
|
+
return {
|
|
308
|
+
success: false,
|
|
309
|
+
result: "failed",
|
|
310
|
+
error: `Deployment timed out after ${maxPollAttempts} attempts. Last status: ${deployment.status}`,
|
|
311
|
+
datasourceCount: resources.datasources.length,
|
|
312
|
+
pipeCount: resources.pipes.length,
|
|
313
|
+
connectionCount: resources.connections?.length ?? 0,
|
|
314
|
+
buildId: deploymentId,
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Step 3: Set the deployment as live
|
|
319
|
+
const setLiveUrl = `${baseUrl}/v1/deployments/${deploymentId}/set-live`;
|
|
320
|
+
|
|
321
|
+
if (debug) {
|
|
322
|
+
console.log(`[debug] POST ${setLiveUrl}`);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const setLiveResponse = await tinybirdFetch(setLiveUrl, {
|
|
326
|
+
method: "POST",
|
|
327
|
+
headers: {
|
|
328
|
+
Authorization: `Bearer ${config.token}`,
|
|
329
|
+
},
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
if (!setLiveResponse.ok) {
|
|
333
|
+
const setLiveBody = await setLiveResponse.text();
|
|
334
|
+
return {
|
|
335
|
+
success: false,
|
|
336
|
+
result: "failed",
|
|
337
|
+
error: `Failed to set deployment as live: ${setLiveResponse.status} ${setLiveResponse.statusText}\n${setLiveBody}`,
|
|
338
|
+
datasourceCount: resources.datasources.length,
|
|
339
|
+
pipeCount: resources.pipes.length,
|
|
340
|
+
connectionCount: resources.connections?.length ?? 0,
|
|
341
|
+
buildId: deploymentId,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (debug) {
|
|
346
|
+
console.log(`[debug] Deployment ${deploymentId} is now live`);
|
|
347
|
+
}
|
|
348
|
+
|
|
145
349
|
return {
|
|
146
350
|
success: true,
|
|
147
|
-
result:
|
|
351
|
+
result: "success",
|
|
148
352
|
datasourceCount: resources.datasources.length,
|
|
149
353
|
pipeCount: resources.pipes.length,
|
|
150
354
|
connectionCount: resources.connections?.length ?? 0,
|
|
151
|
-
buildId:
|
|
355
|
+
buildId: deploymentId,
|
|
152
356
|
pipes: {
|
|
153
|
-
changed:
|
|
154
|
-
created:
|
|
155
|
-
deleted:
|
|
357
|
+
changed: [],
|
|
358
|
+
created: [],
|
|
359
|
+
deleted: [],
|
|
156
360
|
},
|
|
157
361
|
datasources: {
|
|
158
|
-
changed:
|
|
159
|
-
created:
|
|
160
|
-
deleted:
|
|
362
|
+
changed: [],
|
|
363
|
+
created: [],
|
|
364
|
+
deleted: [],
|
|
161
365
|
},
|
|
162
|
-
// Keep deprecated fields for backwards compatibility
|
|
163
|
-
changedPipeNames: body.build?.changed_pipe_names ?? [],
|
|
164
|
-
newPipeNames: body.build?.new_pipe_names ?? [],
|
|
165
366
|
};
|
|
166
367
|
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Helper function to sleep for a given number of milliseconds
|
|
371
|
+
*/
|
|
372
|
+
function sleep(ms: number): Promise<void> {
|
|
373
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
374
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export const TINYBIRD_FROM_PARAM = "ts-sdk";
|
|
2
|
+
|
|
3
|
+
export type TinybirdFetch = (url: string, init?: RequestInit) => Promise<Response>;
|
|
4
|
+
|
|
5
|
+
export function withTinybirdFromParam(url: string): string {
|
|
6
|
+
const parsedUrl = new URL(url);
|
|
7
|
+
parsedUrl.searchParams.set("from", TINYBIRD_FROM_PARAM);
|
|
8
|
+
return parsedUrl.toString();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createTinybirdFetcher(fetchFn: typeof fetch): TinybirdFetch {
|
|
12
|
+
return (url, init) => fetchFn(withTinybirdFromParam(url), init);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function tinybirdFetch(url: string, init?: RequestInit): Promise<Response> {
|
|
16
|
+
return fetch(withTinybirdFromParam(url), init);
|
|
17
|
+
}
|
package/src/api/local.test.ts
CHANGED
|
@@ -94,15 +94,18 @@ describe("Local API", () => {
|
|
|
94
94
|
describe("listLocalWorkspaces", () => {
|
|
95
95
|
it("returns list of workspaces", async () => {
|
|
96
96
|
server.use(
|
|
97
|
-
http.get(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
97
|
+
http.get(
|
|
98
|
+
`${LOCAL_BASE_URL}/v1/user/workspaces`,
|
|
99
|
+
() => {
|
|
100
|
+
return HttpResponse.json({
|
|
101
|
+
organization_id: "org-123",
|
|
102
|
+
workspaces: [
|
|
103
|
+
{ id: "ws-1", name: "Workspace1", token: "token-1" },
|
|
104
|
+
{ id: "ws-2", name: "Workspace2", token: "token-2" },
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
)
|
|
106
109
|
);
|
|
107
110
|
|
|
108
111
|
const result = await listLocalWorkspaces("admin-token");
|
|
@@ -118,9 +121,12 @@ describe("Local API", () => {
|
|
|
118
121
|
|
|
119
122
|
it("throws LocalApiError on failure", async () => {
|
|
120
123
|
server.use(
|
|
121
|
-
http.get(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
http.get(
|
|
125
|
+
`${LOCAL_BASE_URL}/v1/user/workspaces`,
|
|
126
|
+
() => {
|
|
127
|
+
return new HttpResponse("Not found", { status: 404 });
|
|
128
|
+
}
|
|
129
|
+
)
|
|
124
130
|
);
|
|
125
131
|
|
|
126
132
|
await expect(listLocalWorkspaces("admin-token")).rejects.toThrow(LocalApiError);
|
|
@@ -170,14 +176,17 @@ describe("Local API", () => {
|
|
|
170
176
|
|
|
171
177
|
it("returns existing workspace if found", async () => {
|
|
172
178
|
server.use(
|
|
173
|
-
http.get(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
http.get(
|
|
180
|
+
`${LOCAL_BASE_URL}/v1/user/workspaces`,
|
|
181
|
+
() => {
|
|
182
|
+
return HttpResponse.json({
|
|
183
|
+
organization_id: "org-123",
|
|
184
|
+
workspaces: [
|
|
185
|
+
{ id: "existing-ws", name: "MyWorkspace", token: "existing-token" },
|
|
186
|
+
],
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
)
|
|
181
190
|
);
|
|
182
191
|
|
|
183
192
|
const result = await getOrCreateLocalWorkspace(tokens, "MyWorkspace");
|
|
@@ -191,21 +200,24 @@ describe("Local API", () => {
|
|
|
191
200
|
let createCalled = false;
|
|
192
201
|
|
|
193
202
|
server.use(
|
|
194
|
-
http.get(
|
|
195
|
-
|
|
196
|
-
|
|
203
|
+
http.get(
|
|
204
|
+
`${LOCAL_BASE_URL}/v1/user/workspaces`,
|
|
205
|
+
() => {
|
|
206
|
+
// Return different response based on whether create was called
|
|
207
|
+
if (createCalled) {
|
|
208
|
+
return HttpResponse.json({
|
|
209
|
+
organization_id: "org-123",
|
|
210
|
+
workspaces: [
|
|
211
|
+
{ id: "new-ws", name: "NewWorkspace", token: "new-token" },
|
|
212
|
+
],
|
|
213
|
+
});
|
|
214
|
+
}
|
|
197
215
|
return HttpResponse.json({
|
|
198
216
|
organization_id: "org-123",
|
|
199
|
-
workspaces: [
|
|
200
|
-
{ id: "new-ws", name: "NewWorkspace", token: "new-token" },
|
|
201
|
-
],
|
|
217
|
+
workspaces: [], // Empty initially
|
|
202
218
|
});
|
|
203
219
|
}
|
|
204
|
-
|
|
205
|
-
organization_id: "org-123",
|
|
206
|
-
workspaces: [], // Empty initially
|
|
207
|
-
});
|
|
208
|
-
}),
|
|
220
|
+
),
|
|
209
221
|
http.post(`${LOCAL_BASE_URL}/v1/workspaces`, () => {
|
|
210
222
|
createCalled = true;
|
|
211
223
|
return HttpResponse.json({
|
package/src/api/local.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import * as crypto from "crypto";
|
|
7
7
|
import { LOCAL_BASE_URL } from "../cli/config.js";
|
|
8
|
+
import { tinybirdFetch } from "./fetcher.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Tokens returned by the local /tokens endpoint
|
|
@@ -76,7 +77,7 @@ export class LocalApiError extends Error {
|
|
|
76
77
|
*/
|
|
77
78
|
export async function isLocalRunning(): Promise<boolean> {
|
|
78
79
|
try {
|
|
79
|
-
const response = await
|
|
80
|
+
const response = await tinybirdFetch(`${LOCAL_BASE_URL}/tokens`, {
|
|
80
81
|
method: "GET",
|
|
81
82
|
signal: AbortSignal.timeout(5000),
|
|
82
83
|
});
|
|
@@ -94,7 +95,7 @@ export async function isLocalRunning(): Promise<boolean> {
|
|
|
94
95
|
*/
|
|
95
96
|
export async function getLocalTokens(): Promise<LocalTokens> {
|
|
96
97
|
try {
|
|
97
|
-
const response = await
|
|
98
|
+
const response = await tinybirdFetch(`${LOCAL_BASE_URL}/tokens`, {
|
|
98
99
|
method: "GET",
|
|
99
100
|
signal: AbortSignal.timeout(5000),
|
|
100
101
|
});
|
|
@@ -136,7 +137,7 @@ export async function listLocalWorkspaces(
|
|
|
136
137
|
): Promise<{ workspaces: LocalWorkspace[]; organizationId?: string }> {
|
|
137
138
|
const url = `${LOCAL_BASE_URL}/v1/user/workspaces?with_organization=true&token=${adminToken}`;
|
|
138
139
|
|
|
139
|
-
const response = await
|
|
140
|
+
const response = await tinybirdFetch(url, {
|
|
140
141
|
method: "GET",
|
|
141
142
|
});
|
|
142
143
|
|
|
@@ -182,7 +183,7 @@ export async function createLocalWorkspace(
|
|
|
182
183
|
formData.append("assign_to_organization_id", organizationId);
|
|
183
184
|
}
|
|
184
185
|
|
|
185
|
-
const response = await
|
|
186
|
+
const response = await tinybirdFetch(url, {
|
|
186
187
|
method: "POST",
|
|
187
188
|
headers: {
|
|
188
189
|
Authorization: `Bearer ${userToken}`,
|