@tinybirdco/sdk 0.0.6 → 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/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 +1 -0
- package/dist/api/deploy.d.ts.map +1 -1
- package/dist/api/deploy.js +27 -6
- package/dist/api/deploy.js.map +1 -1
- package/dist/api/deploy.test.js +6 -2
- 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.map +1 -1
- package/dist/api/resources.js +5 -4
- package/dist/api/resources.js.map +1 -1
- 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/deploy.d.ts +2 -0
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/deploy.js +3 -1
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/init.d.ts +14 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +264 -4
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/index.js +8 -3
- package/dist/cli/index.js.map +1 -1
- 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/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/package.json +1 -1
- 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 +6 -2
- package/src/api/deploy.ts +35 -7
- 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.ts +5 -4
- 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/deploy.ts +6 -1
- package/src/cli/commands/init.ts +311 -6
- package/src/cli/index.ts +35 -11
- package/src/client/base.ts +3 -2
- 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/cli/commands/init.ts
CHANGED
|
@@ -114,6 +114,64 @@ export type { PageViewsRow, TopPagesParams, TopPagesOutput };
|
|
|
114
114
|
export { pageViews, topPages };
|
|
115
115
|
`;
|
|
116
116
|
|
|
117
|
+
const TINYBIRD_CI_WORKFLOW = `name: Tinybird CI
|
|
118
|
+
|
|
119
|
+
on:
|
|
120
|
+
pull_request:
|
|
121
|
+
paths:
|
|
122
|
+
- "tinybird.json"
|
|
123
|
+
- "src/tinybird/**"
|
|
124
|
+
- "tinybird/**"
|
|
125
|
+
- "**/*.datasource"
|
|
126
|
+
- "**/*.pipe"
|
|
127
|
+
|
|
128
|
+
jobs:
|
|
129
|
+
tinybird:
|
|
130
|
+
runs-on: ubuntu-latest
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/checkout@v4
|
|
133
|
+
- uses: pnpm/action-setup@v4
|
|
134
|
+
- uses: actions/setup-node@v4
|
|
135
|
+
with:
|
|
136
|
+
node-version: "20"
|
|
137
|
+
cache: "pnpm"
|
|
138
|
+
- run: pnpm install --frozen-lockfile
|
|
139
|
+
- run: pnpm run tinybird:deploy -- --check
|
|
140
|
+
env:
|
|
141
|
+
TINYBIRD_TOKEN: \${{ secrets.TINYBIRD_TOKEN }}
|
|
142
|
+
`;
|
|
143
|
+
|
|
144
|
+
const TINYBIRD_CD_WORKFLOW = `name: Tinybird CD
|
|
145
|
+
|
|
146
|
+
on:
|
|
147
|
+
push:
|
|
148
|
+
branches:
|
|
149
|
+
- main
|
|
150
|
+
paths:
|
|
151
|
+
- "tinybird.json"
|
|
152
|
+
- "src/tinybird/**"
|
|
153
|
+
- "tinybird/**"
|
|
154
|
+
- "**/*.datasource"
|
|
155
|
+
- "**/*.pipe"
|
|
156
|
+
|
|
157
|
+
jobs:
|
|
158
|
+
tinybird:
|
|
159
|
+
runs-on: ubuntu-latest
|
|
160
|
+
steps:
|
|
161
|
+
- uses: actions/checkout@v4
|
|
162
|
+
- uses: pnpm/action-setup@v4
|
|
163
|
+
- uses: actions/setup-node@v4
|
|
164
|
+
with:
|
|
165
|
+
node-version: "20"
|
|
166
|
+
cache: "pnpm"
|
|
167
|
+
- run: pnpm install --frozen-lockfile
|
|
168
|
+
- run: pnpm run tinybird:deploy
|
|
169
|
+
env:
|
|
170
|
+
TINYBIRD_TOKEN: \${{ secrets.TINYBIRD_TOKEN }}
|
|
171
|
+
`;
|
|
172
|
+
|
|
173
|
+
const TINYBIRD_GITLAB_CI = `stages:\n - tinybird\n\ntinybird_ci:\n stage: tinybird\n image: node:20\n rules:\n - changes:\n - tinybird.json\n - src/tinybird/**\n - tinybird/**\n - **/*.datasource\n - **/*.pipe\n script:\n - corepack enable\n - pnpm install --frozen-lockfile\n - pnpm run tinybird:deploy -- --check\n variables:\n TINYBIRD_TOKEN: \${TINYBIRD_TOKEN}\n\ntinybird_cd:\n stage: tinybird\n image: node:20\n rules:\n - if: '$CI_COMMIT_BRANCH == \"main\"'\n changes:\n - tinybird.json\n - src/tinybird/**\n - tinybird/**\n - **/*.datasource\n - **/*.pipe\n script:\n - corepack enable\n - pnpm install --frozen-lockfile\n - pnpm run tinybird:deploy\n variables:\n TINYBIRD_TOKEN: \${TINYBIRD_TOKEN}\n`;
|
|
174
|
+
|
|
117
175
|
/**
|
|
118
176
|
* Default config content generator
|
|
119
177
|
*/
|
|
@@ -153,6 +211,14 @@ export interface InitOptions {
|
|
|
153
211
|
skipDatafilePrompt?: boolean;
|
|
154
212
|
/** Auto-include existing datafiles without prompting - for testing */
|
|
155
213
|
includeExistingDatafiles?: boolean;
|
|
214
|
+
/** Skip GitHub Actions workflow prompts */
|
|
215
|
+
skipWorkflowPrompt?: boolean;
|
|
216
|
+
/** Include Tinybird CI workflow */
|
|
217
|
+
includeCiWorkflow?: boolean;
|
|
218
|
+
/** Include Tinybird CD workflow */
|
|
219
|
+
includeCdWorkflow?: boolean;
|
|
220
|
+
/** Git provider for workflow templates */
|
|
221
|
+
workflowProvider?: "github" | "gitlab";
|
|
156
222
|
}
|
|
157
223
|
|
|
158
224
|
/**
|
|
@@ -179,6 +245,12 @@ export interface InitResult {
|
|
|
179
245
|
clientPath?: string;
|
|
180
246
|
/** Existing datafiles that were added to config */
|
|
181
247
|
existingDatafiles?: string[];
|
|
248
|
+
/** Whether a Tinybird CI workflow was created */
|
|
249
|
+
ciWorkflowCreated?: boolean;
|
|
250
|
+
/** Whether a Tinybird CD workflow was created */
|
|
251
|
+
cdWorkflowCreated?: boolean;
|
|
252
|
+
/** Git provider used for workflow templates */
|
|
253
|
+
workflowProvider?: "github" | "gitlab";
|
|
182
254
|
}
|
|
183
255
|
|
|
184
256
|
/**
|
|
@@ -252,7 +324,11 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
252
324
|
|
|
253
325
|
const created: string[] = [];
|
|
254
326
|
const skipped: string[] = [];
|
|
327
|
+
let didPrompt = false;
|
|
255
328
|
let existingDatafiles: string[] = [];
|
|
329
|
+
let ciWorkflowCreated = false;
|
|
330
|
+
let cdWorkflowCreated = false;
|
|
331
|
+
let workflowProvider = options.workflowProvider;
|
|
256
332
|
|
|
257
333
|
// Check for existing .datasource and .pipe files
|
|
258
334
|
const foundDatafiles = findExistingDatafiles(cwd);
|
|
@@ -281,7 +357,7 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
281
357
|
});
|
|
282
358
|
|
|
283
359
|
if (p.isCancel(workflowChoice)) {
|
|
284
|
-
p.cancel("
|
|
360
|
+
p.cancel("Operation cancelled");
|
|
285
361
|
return {
|
|
286
362
|
success: false,
|
|
287
363
|
created: [],
|
|
@@ -290,6 +366,7 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
290
366
|
};
|
|
291
367
|
}
|
|
292
368
|
|
|
369
|
+
didPrompt = true;
|
|
293
370
|
devMode = workflowChoice as DevMode;
|
|
294
371
|
}
|
|
295
372
|
|
|
@@ -300,13 +377,13 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
300
377
|
if (!options.clientPath && !options.devMode) {
|
|
301
378
|
// Ask user to confirm or change the client path
|
|
302
379
|
const clientPathChoice = await p.text({
|
|
303
|
-
message: "Where should we
|
|
380
|
+
message: "Where should we create Tinybird definitions?",
|
|
304
381
|
placeholder: defaultRelativePath,
|
|
305
382
|
defaultValue: defaultRelativePath,
|
|
306
383
|
});
|
|
307
384
|
|
|
308
385
|
if (p.isCancel(clientPathChoice)) {
|
|
309
|
-
p.cancel("
|
|
386
|
+
p.cancel("Operation cancelled");
|
|
310
387
|
return {
|
|
311
388
|
success: false,
|
|
312
389
|
created: [],
|
|
@@ -315,14 +392,97 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
315
392
|
};
|
|
316
393
|
}
|
|
317
394
|
|
|
395
|
+
didPrompt = true;
|
|
318
396
|
relativeTinybirdDir = clientPathChoice || defaultRelativePath;
|
|
319
397
|
}
|
|
320
398
|
|
|
399
|
+
const skipWorkflowPrompt =
|
|
400
|
+
options.skipWorkflowPrompt ??
|
|
401
|
+
(options.devMode !== undefined || options.clientPath !== undefined);
|
|
402
|
+
let includeCiWorkflow = options.includeCiWorkflow ?? false;
|
|
403
|
+
let includeCdWorkflow = options.includeCdWorkflow ?? false;
|
|
404
|
+
const shouldPromptWorkflows =
|
|
405
|
+
!skipWorkflowPrompt && options.includeCiWorkflow === undefined;
|
|
406
|
+
const shouldPromptProvider = !skipWorkflowPrompt && !workflowProvider;
|
|
407
|
+
|
|
408
|
+
if (shouldPromptProvider && shouldPromptWorkflows) {
|
|
409
|
+
const providerChoice = await p.select({
|
|
410
|
+
message: "Which git provider are you using?",
|
|
411
|
+
options: [
|
|
412
|
+
{ value: "github", label: "GitHub" },
|
|
413
|
+
{ value: "gitlab", label: "GitLab" },
|
|
414
|
+
],
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
if (p.isCancel(providerChoice)) {
|
|
418
|
+
p.cancel("Operation cancelled");
|
|
419
|
+
return {
|
|
420
|
+
success: false,
|
|
421
|
+
created: [],
|
|
422
|
+
skipped: [],
|
|
423
|
+
error: "Cancelled by user",
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
didPrompt = true;
|
|
428
|
+
workflowProvider = providerChoice as "github" | "gitlab";
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (shouldPromptWorkflows) {
|
|
432
|
+
const confirmWorkflows = await p.confirm({
|
|
433
|
+
message: "Create CI/CD workflows for Tinybird?",
|
|
434
|
+
initialValue: true,
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
if (p.isCancel(confirmWorkflows)) {
|
|
438
|
+
p.cancel("Operation cancelled");
|
|
439
|
+
return {
|
|
440
|
+
success: false,
|
|
441
|
+
created: [],
|
|
442
|
+
skipped: [],
|
|
443
|
+
error: "Cancelled by user",
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
didPrompt = true;
|
|
448
|
+
includeCiWorkflow = confirmWorkflows;
|
|
449
|
+
includeCdWorkflow = confirmWorkflows;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (shouldPromptProvider && !shouldPromptWorkflows && !workflowProvider) {
|
|
453
|
+
const providerChoice = await p.select({
|
|
454
|
+
message: "Which git provider are you using?",
|
|
455
|
+
options: [
|
|
456
|
+
{ value: "github", label: "GitHub" },
|
|
457
|
+
{ value: "gitlab", label: "GitLab" },
|
|
458
|
+
],
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
if (p.isCancel(providerChoice)) {
|
|
462
|
+
p.cancel("Operation cancelled");
|
|
463
|
+
return {
|
|
464
|
+
success: false,
|
|
465
|
+
created: [],
|
|
466
|
+
skipped: [],
|
|
467
|
+
error: "Cancelled by user",
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
didPrompt = true;
|
|
472
|
+
workflowProvider = providerChoice as "github" | "gitlab";
|
|
473
|
+
}
|
|
474
|
+
if ((includeCiWorkflow || includeCdWorkflow) && !workflowProvider) {
|
|
475
|
+
workflowProvider = "github";
|
|
476
|
+
}
|
|
477
|
+
|
|
321
478
|
// Ask about existing datafiles if found
|
|
322
479
|
if (foundDatafiles.length > 0 && !options.skipDatafilePrompt) {
|
|
323
480
|
const includeDatafiles =
|
|
324
481
|
options.includeExistingDatafiles ??
|
|
325
|
-
(await
|
|
482
|
+
(await (async () => {
|
|
483
|
+
didPrompt = true;
|
|
484
|
+
return promptForExistingDatafiles(foundDatafiles);
|
|
485
|
+
})());
|
|
326
486
|
|
|
327
487
|
if (includeDatafiles) {
|
|
328
488
|
existingDatafiles = foundDatafiles;
|
|
@@ -331,6 +491,47 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
331
491
|
existingDatafiles = foundDatafiles;
|
|
332
492
|
}
|
|
333
493
|
|
|
494
|
+
if (didPrompt) {
|
|
495
|
+
const devModeLabel = devMode === "local" ? "Tinybird Local" : "Branches";
|
|
496
|
+
const datafileSummary =
|
|
497
|
+
foundDatafiles.length > 0
|
|
498
|
+
? existingDatafiles.length > 0
|
|
499
|
+
? `${existingDatafiles.length} included`
|
|
500
|
+
: "none included"
|
|
501
|
+
: "none found";
|
|
502
|
+
let workflowSummary = "none";
|
|
503
|
+
if (includeCiWorkflow || includeCdWorkflow) {
|
|
504
|
+
workflowSummary =
|
|
505
|
+
workflowProvider === "gitlab"
|
|
506
|
+
? "GitLab (.gitlab-ci.yml)"
|
|
507
|
+
: "GitHub Actions (tinybird-ci.yaml, tinybird-cd.yaml)";
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const summaryLines = [
|
|
511
|
+
`Mode: ${devModeLabel}`,
|
|
512
|
+
`Definitions: ${relativeTinybirdDir}/`,
|
|
513
|
+
`Existing datafiles: ${datafileSummary}`,
|
|
514
|
+
`Workflows: ${workflowSummary}`,
|
|
515
|
+
];
|
|
516
|
+
|
|
517
|
+
p.note(summaryLines.join("\n"), "Installation Summary");
|
|
518
|
+
|
|
519
|
+
const confirmInit = await p.confirm({
|
|
520
|
+
message: "Proceed with initialization?",
|
|
521
|
+
initialValue: true,
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
if (p.isCancel(confirmInit) || !confirmInit) {
|
|
525
|
+
p.cancel("Init cancelled.");
|
|
526
|
+
return {
|
|
527
|
+
success: false,
|
|
528
|
+
created: [],
|
|
529
|
+
skipped: [],
|
|
530
|
+
error: "Cancelled by user",
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
334
535
|
const tinybirdDir = path.join(cwd, relativeTinybirdDir);
|
|
335
536
|
|
|
336
537
|
// File paths
|
|
@@ -464,6 +665,94 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
464
665
|
}
|
|
465
666
|
}
|
|
466
667
|
|
|
668
|
+
const workflowsDir = path.join(cwd, ".github", "workflows");
|
|
669
|
+
const ciWorkflowPath = path.join(workflowsDir, "tinybird-ci.yaml");
|
|
670
|
+
const cdWorkflowPath = path.join(workflowsDir, "tinybird-cd.yaml");
|
|
671
|
+
const gitlabWorkflowPath = path.join(cwd, ".gitlab-ci.yml");
|
|
672
|
+
|
|
673
|
+
if (includeCiWorkflow || includeCdWorkflow) {
|
|
674
|
+
if (workflowProvider === "github") {
|
|
675
|
+
try {
|
|
676
|
+
fs.mkdirSync(workflowsDir, { recursive: true });
|
|
677
|
+
} catch (error) {
|
|
678
|
+
return {
|
|
679
|
+
success: false,
|
|
680
|
+
created,
|
|
681
|
+
skipped,
|
|
682
|
+
error: `Failed to create .github/workflows folder: ${
|
|
683
|
+
(error as Error).message
|
|
684
|
+
}`,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
if (workflowProvider === "gitlab") {
|
|
690
|
+
if (fs.existsSync(gitlabWorkflowPath) && !force) {
|
|
691
|
+
skipped.push(".gitlab-ci.yml");
|
|
692
|
+
} else {
|
|
693
|
+
try {
|
|
694
|
+
fs.writeFileSync(gitlabWorkflowPath, TINYBIRD_GITLAB_CI);
|
|
695
|
+
created.push(".gitlab-ci.yml");
|
|
696
|
+
ciWorkflowCreated = includeCiWorkflow;
|
|
697
|
+
cdWorkflowCreated = includeCdWorkflow;
|
|
698
|
+
} catch (error) {
|
|
699
|
+
return {
|
|
700
|
+
success: false,
|
|
701
|
+
created,
|
|
702
|
+
skipped,
|
|
703
|
+
error: `Failed to create .gitlab-ci.yml: ${
|
|
704
|
+
(error as Error).message
|
|
705
|
+
}`,
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
if (workflowProvider === "github") {
|
|
713
|
+
if (includeCiWorkflow) {
|
|
714
|
+
if (fs.existsSync(ciWorkflowPath) && !force) {
|
|
715
|
+
skipped.push(".github/workflows/tinybird-ci.yaml");
|
|
716
|
+
} else {
|
|
717
|
+
try {
|
|
718
|
+
fs.writeFileSync(ciWorkflowPath, TINYBIRD_CI_WORKFLOW);
|
|
719
|
+
created.push(".github/workflows/tinybird-ci.yaml");
|
|
720
|
+
ciWorkflowCreated = true;
|
|
721
|
+
} catch (error) {
|
|
722
|
+
return {
|
|
723
|
+
success: false,
|
|
724
|
+
created,
|
|
725
|
+
skipped,
|
|
726
|
+
error: `Failed to create tinybird-ci.yaml: ${
|
|
727
|
+
(error as Error).message
|
|
728
|
+
}`,
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (includeCdWorkflow) {
|
|
735
|
+
if (fs.existsSync(cdWorkflowPath) && !force) {
|
|
736
|
+
skipped.push(".github/workflows/tinybird-cd.yaml");
|
|
737
|
+
} else {
|
|
738
|
+
try {
|
|
739
|
+
fs.writeFileSync(cdWorkflowPath, TINYBIRD_CD_WORKFLOW);
|
|
740
|
+
created.push(".github/workflows/tinybird-cd.yaml");
|
|
741
|
+
cdWorkflowCreated = true;
|
|
742
|
+
} catch (error) {
|
|
743
|
+
return {
|
|
744
|
+
success: false,
|
|
745
|
+
created,
|
|
746
|
+
skipped,
|
|
747
|
+
error: `Failed to create tinybird-cd.yaml: ${
|
|
748
|
+
(error as Error).message
|
|
749
|
+
}`,
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
467
756
|
// Check if login is needed
|
|
468
757
|
if (!skipLogin && !hasValidToken(cwd)) {
|
|
469
758
|
console.log("\nNo authentication found. Starting login flow...\n");
|
|
@@ -495,6 +784,9 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
495
784
|
clientPath: relativeTinybirdDir,
|
|
496
785
|
existingDatafiles:
|
|
497
786
|
existingDatafiles.length > 0 ? existingDatafiles : undefined,
|
|
787
|
+
ciWorkflowCreated,
|
|
788
|
+
cdWorkflowCreated,
|
|
789
|
+
workflowProvider,
|
|
498
790
|
};
|
|
499
791
|
} catch (error) {
|
|
500
792
|
// Login succeeded but saving credentials failed
|
|
@@ -510,6 +802,9 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
510
802
|
clientPath: relativeTinybirdDir,
|
|
511
803
|
existingDatafiles:
|
|
512
804
|
existingDatafiles.length > 0 ? existingDatafiles : undefined,
|
|
805
|
+
ciWorkflowCreated,
|
|
806
|
+
cdWorkflowCreated,
|
|
807
|
+
workflowProvider,
|
|
513
808
|
};
|
|
514
809
|
}
|
|
515
810
|
} else {
|
|
@@ -523,6 +818,9 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
523
818
|
clientPath: relativeTinybirdDir,
|
|
524
819
|
existingDatafiles:
|
|
525
820
|
existingDatafiles.length > 0 ? existingDatafiles : undefined,
|
|
821
|
+
ciWorkflowCreated,
|
|
822
|
+
cdWorkflowCreated,
|
|
823
|
+
workflowProvider,
|
|
526
824
|
};
|
|
527
825
|
}
|
|
528
826
|
}
|
|
@@ -535,6 +833,9 @@ export async function runInit(options: InitOptions = {}): Promise<InitResult> {
|
|
|
535
833
|
clientPath: relativeTinybirdDir,
|
|
536
834
|
existingDatafiles:
|
|
537
835
|
existingDatafiles.length > 0 ? existingDatafiles : undefined,
|
|
836
|
+
ciWorkflowCreated,
|
|
837
|
+
cdWorkflowCreated,
|
|
838
|
+
workflowProvider,
|
|
538
839
|
};
|
|
539
840
|
}
|
|
540
841
|
|
|
@@ -551,14 +852,18 @@ async function promptForExistingDatafiles(
|
|
|
551
852
|
|
|
552
853
|
const parts: string[] = [];
|
|
553
854
|
if (datasourceCount > 0) {
|
|
554
|
-
parts.push(
|
|
855
|
+
parts.push(
|
|
856
|
+
`${datasourceCount} .datasource file${datasourceCount > 1 ? "s" : ""}`
|
|
857
|
+
);
|
|
555
858
|
}
|
|
556
859
|
if (pipeCount > 0) {
|
|
557
860
|
parts.push(`${pipeCount} .pipe file${pipeCount > 1 ? "s" : ""}`);
|
|
558
861
|
}
|
|
559
862
|
|
|
560
863
|
const confirmInclude = await p.confirm({
|
|
561
|
-
message: `Found ${parts.join(
|
|
864
|
+
message: `Found ${parts.join(
|
|
865
|
+
" and "
|
|
866
|
+
)} in your project. Include them in tinybird.json?`,
|
|
562
867
|
initialValue: true,
|
|
563
868
|
});
|
|
564
869
|
|
package/src/cli/index.ts
CHANGED
|
@@ -62,7 +62,9 @@ function createCli(): Command {
|
|
|
62
62
|
.action(async (options) => {
|
|
63
63
|
// Validate mode if provided
|
|
64
64
|
if (options.mode && !["branch", "local"].includes(options.mode)) {
|
|
65
|
-
console.error(
|
|
65
|
+
console.error(
|
|
66
|
+
`Error: Invalid mode '${options.mode}'. Use 'branch' or 'local'.`
|
|
67
|
+
);
|
|
66
68
|
process.exit(1);
|
|
67
69
|
}
|
|
68
70
|
|
|
@@ -186,7 +188,9 @@ function createCli(): Command {
|
|
|
186
188
|
const { build, deploy } = result;
|
|
187
189
|
|
|
188
190
|
if (build) {
|
|
189
|
-
console.log(
|
|
191
|
+
console.log(
|
|
192
|
+
`Generated ${build.stats.datasourceCount} datasource(s), ${build.stats.pipeCount} pipe(s)`
|
|
193
|
+
);
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
if (options.dryRun) {
|
|
@@ -222,6 +226,7 @@ function createCli(): Command {
|
|
|
222
226
|
.command("deploy")
|
|
223
227
|
.description("Deploy resources to main Tinybird workspace (production)")
|
|
224
228
|
.option("--dry-run", "Generate without pushing to API")
|
|
229
|
+
.option("--check", "Validate deploy with Tinybird API without applying")
|
|
225
230
|
.option("--debug", "Show debug output including API requests/responses")
|
|
226
231
|
.action(async (options) => {
|
|
227
232
|
if (options.debug) {
|
|
@@ -232,6 +237,7 @@ function createCli(): Command {
|
|
|
232
237
|
|
|
233
238
|
const result = await runDeploy({
|
|
234
239
|
dryRun: options.dryRun,
|
|
240
|
+
check: options.check,
|
|
235
241
|
});
|
|
236
242
|
|
|
237
243
|
if (!result.success) {
|
|
@@ -242,7 +248,9 @@ function createCli(): Command {
|
|
|
242
248
|
const { build, deploy } = result;
|
|
243
249
|
|
|
244
250
|
if (build) {
|
|
245
|
-
console.log(
|
|
251
|
+
console.log(
|
|
252
|
+
`Generated ${build.stats.datasourceCount} datasource(s), ${build.stats.pipeCount} pipe(s)`
|
|
253
|
+
);
|
|
246
254
|
}
|
|
247
255
|
|
|
248
256
|
if (options.dryRun) {
|
|
@@ -262,6 +270,8 @@ function createCli(): Command {
|
|
|
262
270
|
console.log(pipe.content);
|
|
263
271
|
});
|
|
264
272
|
}
|
|
273
|
+
} else if (options.check) {
|
|
274
|
+
console.log("\n[Check] Resources validated with Tinybird API");
|
|
265
275
|
} else if (deploy) {
|
|
266
276
|
if (deploy.result === "no_changes") {
|
|
267
277
|
console.log("No changes detected - already up to date");
|
|
@@ -314,7 +324,9 @@ function createCli(): Command {
|
|
|
314
324
|
console.log("Workspace created.\n");
|
|
315
325
|
} else {
|
|
316
326
|
console.log(`Using local Tinybird container`);
|
|
317
|
-
console.log(
|
|
327
|
+
console.log(
|
|
328
|
+
`Using existing local workspace '${workspaceName}'\n`
|
|
329
|
+
);
|
|
318
330
|
}
|
|
319
331
|
} else if (info.isMainBranch) {
|
|
320
332
|
console.log("On main branch - deploying to workspace\n");
|
|
@@ -326,7 +338,9 @@ function createCli(): Command {
|
|
|
326
338
|
console.log("Branch created and token cached.\n");
|
|
327
339
|
} else {
|
|
328
340
|
console.log(`Detected git branch: ${info.gitBranch}`);
|
|
329
|
-
console.log(
|
|
341
|
+
console.log(
|
|
342
|
+
`Using existing Tinybird branch '${tinybirdName}'\n`
|
|
343
|
+
);
|
|
330
344
|
}
|
|
331
345
|
} else {
|
|
332
346
|
console.log("Not in a git repository - deploying to workspace\n");
|
|
@@ -347,7 +361,9 @@ function createCli(): Command {
|
|
|
347
361
|
if (deploy.result === "no_changes") {
|
|
348
362
|
console.log(`[${formatTime()}] No changes detected`);
|
|
349
363
|
} else {
|
|
350
|
-
console.log(
|
|
364
|
+
console.log(
|
|
365
|
+
`[${formatTime()}] Built in ${result.durationMs}ms`
|
|
366
|
+
);
|
|
351
367
|
|
|
352
368
|
// Show datasource changes
|
|
353
369
|
if (deploy.datasources) {
|
|
@@ -382,7 +398,9 @@ function createCli(): Command {
|
|
|
382
398
|
console.log(`[${formatTime()}] Schema validation:`);
|
|
383
399
|
for (const issue of validation.issues) {
|
|
384
400
|
if (issue.type === "error") {
|
|
385
|
-
console.error(
|
|
401
|
+
console.error(
|
|
402
|
+
` ERROR [${issue.pipeName}]: ${issue.message}`
|
|
403
|
+
);
|
|
386
404
|
} else {
|
|
387
405
|
console.warn(` WARN [${issue.pipeName}]: ${issue.message}`);
|
|
388
406
|
}
|
|
@@ -415,8 +433,9 @@ function createCli(): Command {
|
|
|
415
433
|
});
|
|
416
434
|
|
|
417
435
|
// Branch command
|
|
418
|
-
const branchCommand = new Command("branch")
|
|
419
|
-
|
|
436
|
+
const branchCommand = new Command("branch").description(
|
|
437
|
+
"Manage Tinybird branches"
|
|
438
|
+
);
|
|
420
439
|
|
|
421
440
|
branchCommand
|
|
422
441
|
.command("list")
|
|
@@ -453,8 +472,13 @@ function createCli(): Command {
|
|
|
453
472
|
|
|
454
473
|
console.log("Branch Status:");
|
|
455
474
|
console.log(` Git branch: ${result.gitBranch ?? "(not in git repo)"}`);
|
|
456
|
-
if (
|
|
457
|
-
|
|
475
|
+
if (
|
|
476
|
+
result.tinybirdBranchName &&
|
|
477
|
+
result.tinybirdBranchName !== result.gitBranch
|
|
478
|
+
) {
|
|
479
|
+
console.log(
|
|
480
|
+
` Tinybird branch name: ${result.tinybirdBranchName} (sanitized)`
|
|
481
|
+
);
|
|
458
482
|
}
|
|
459
483
|
console.log(` Main branch: ${result.isMainBranch ? "yes" : "no"}`);
|
|
460
484
|
|
package/src/client/base.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
TinybirdErrorResponse,
|
|
12
12
|
} from "./types.js";
|
|
13
13
|
import { TinybirdError } from "./types.js";
|
|
14
|
+
import { createTinybirdFetcher, type TinybirdFetch } from "../api/fetcher.js";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Default timeout for requests (30 seconds)
|
|
@@ -56,7 +57,7 @@ interface ResolvedTokenInfo {
|
|
|
56
57
|
*/
|
|
57
58
|
export class TinybirdClient {
|
|
58
59
|
private readonly config: ClientConfig;
|
|
59
|
-
private readonly fetchFn:
|
|
60
|
+
private readonly fetchFn: TinybirdFetch;
|
|
60
61
|
private tokenPromise: Promise<ResolvedTokenInfo> | null = null;
|
|
61
62
|
private resolvedToken: string | null = null;
|
|
62
63
|
|
|
@@ -75,7 +76,7 @@ export class TinybirdClient {
|
|
|
75
76
|
baseUrl: config.baseUrl.replace(/\/$/, ""),
|
|
76
77
|
};
|
|
77
78
|
|
|
78
|
-
this.fetchFn = config.fetch ?? globalThis.fetch;
|
|
79
|
+
this.fetchFn = createTinybirdFetcher(config.fetch ?? globalThis.fetch);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
/**
|
package/src/schema/connection.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* Define external connections (Kafka, etc.) as TypeScript with full type safety
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
// Symbol for brand typing
|
|
7
|
-
|
|
6
|
+
// Symbol for brand typing - use Symbol.for() for global registry
|
|
7
|
+
// This ensures the same symbol is used across module instances
|
|
8
|
+
const CONNECTION_BRAND = Symbol.for("tinybird.connection");
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Kafka security protocol options
|
package/src/schema/datasource.ts
CHANGED
|
@@ -7,8 +7,9 @@ import type { AnyTypeValidator } from "./types.js";
|
|
|
7
7
|
import type { EngineConfig } from "./engines.js";
|
|
8
8
|
import type { KafkaConnectionDefinition } from "./connection.js";
|
|
9
9
|
|
|
10
|
-
// Symbol for brand typing
|
|
11
|
-
|
|
10
|
+
// Symbol for brand typing - use Symbol.for() for global registry
|
|
11
|
+
// This ensures the same symbol is used across module instances
|
|
12
|
+
const DATASOURCE_BRAND = Symbol.for("tinybird.datasource");
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* A column can be defined as just a type validator,
|
package/src/schema/params.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* Similar to the column type validators but for query parameters
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
// Symbol for brand typing
|
|
7
|
-
|
|
6
|
+
// Symbol for brand typing - use Symbol.for() for global registry
|
|
7
|
+
// This ensures the same symbol is used across module instances
|
|
8
|
+
const PARAM_BRAND = Symbol.for("tinybird.param");
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Base interface for parameter validators
|
package/src/schema/pipe.ts
CHANGED
|
@@ -9,10 +9,10 @@ import type { DatasourceDefinition, SchemaDefinition, ColumnDefinition } from ".
|
|
|
9
9
|
import { getColumnType } from "./datasource.js";
|
|
10
10
|
import { getTinybirdType } from "./types.js";
|
|
11
11
|
|
|
12
|
-
/** Symbol for brand typing pipes */
|
|
13
|
-
export const PIPE_BRAND
|
|
14
|
-
/** Symbol for brand typing nodes */
|
|
15
|
-
export const NODE_BRAND
|
|
12
|
+
/** Symbol for brand typing pipes - use Symbol.for() for global registry */
|
|
13
|
+
export const PIPE_BRAND = Symbol.for("tinybird.pipe");
|
|
14
|
+
/** Symbol for brand typing nodes - use Symbol.for() for global registry */
|
|
15
|
+
export const NODE_BRAND = Symbol.for("tinybird.node");
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Parameter definition for a pipe
|
package/src/schema/project.ts
CHANGED
|
@@ -11,8 +11,9 @@ import type { TinybirdClient } from "../client/base.js";
|
|
|
11
11
|
import type { QueryResult } from "../client/types.js";
|
|
12
12
|
import type { InferRow, InferParams, InferOutputRow } from "../infer/index.js";
|
|
13
13
|
|
|
14
|
-
// Symbol for brand typing
|
|
15
|
-
|
|
14
|
+
// Symbol for brand typing - use Symbol.for() for global registry
|
|
15
|
+
// This ensures the same symbol is used across module instances
|
|
16
|
+
const PROJECT_BRAND = Symbol.for("tinybird.project");
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Collection of datasource definitions
|
package/src/schema/types.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* Similar to Convex's `v.*` pattern, but for ClickHouse types
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
// Symbol for brand typing
|
|
7
|
-
|
|
6
|
+
// Symbol for brand typing - use Symbol.for() for global registry
|
|
7
|
+
// This ensures the same symbol is used across module instances
|
|
8
|
+
const VALIDATOR_BRAND = Symbol.for("tinybird.validator");
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Base interface for all type validators
|