@tinybirdco/sdk 0.0.20 → 0.0.22

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 (52) hide show
  1. package/dist/api/dashboard.d.ts +74 -0
  2. package/dist/api/dashboard.d.ts.map +1 -0
  3. package/dist/api/dashboard.js +102 -0
  4. package/dist/api/dashboard.js.map +1 -0
  5. package/dist/api/dashboard.test.d.ts +2 -0
  6. package/dist/api/dashboard.test.d.ts.map +1 -0
  7. package/dist/api/dashboard.test.js +91 -0
  8. package/dist/api/dashboard.test.js.map +1 -0
  9. package/dist/cli/commands/branch.d.ts +2 -0
  10. package/dist/cli/commands/branch.d.ts.map +1 -1
  11. package/dist/cli/commands/branch.js +12 -1
  12. package/dist/cli/commands/branch.js.map +1 -1
  13. package/dist/cli/commands/build.d.ts +17 -0
  14. package/dist/cli/commands/build.d.ts.map +1 -1
  15. package/dist/cli/commands/build.js +25 -0
  16. package/dist/cli/commands/build.js.map +1 -1
  17. package/dist/cli/commands/dev.d.ts +2 -0
  18. package/dist/cli/commands/dev.d.ts.map +1 -1
  19. package/dist/cli/commands/dev.js +19 -3
  20. package/dist/cli/commands/dev.js.map +1 -1
  21. package/dist/cli/index.js +23 -24
  22. package/dist/cli/index.js.map +1 -1
  23. package/dist/cli/output.d.ts +20 -0
  24. package/dist/cli/output.d.ts.map +1 -1
  25. package/dist/cli/output.js +37 -0
  26. package/dist/cli/output.js.map +1 -1
  27. package/dist/client/base.d.ts +36 -5
  28. package/dist/client/base.d.ts.map +1 -1
  29. package/dist/client/base.js +64 -18
  30. package/dist/client/base.js.map +1 -1
  31. package/dist/client/base.test.d.ts +2 -0
  32. package/dist/client/base.test.d.ts.map +1 -0
  33. package/dist/client/base.test.js +104 -0
  34. package/dist/client/base.test.js.map +1 -0
  35. package/dist/client/types.d.ts +16 -0
  36. package/dist/client/types.d.ts.map +1 -1
  37. package/dist/index.d.ts +3 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +2 -0
  40. package/dist/index.js.map +1 -1
  41. package/package.json +1 -1
  42. package/src/api/dashboard.test.ts +115 -0
  43. package/src/api/dashboard.ts +121 -0
  44. package/src/cli/commands/branch.ts +15 -1
  45. package/src/cli/commands/build.ts +46 -0
  46. package/src/cli/commands/dev.ts +47 -7
  47. package/src/cli/index.ts +25 -27
  48. package/src/cli/output.ts +54 -0
  49. package/src/client/base.test.ts +129 -0
  50. package/src/client/base.ts +68 -18
  51. package/src/client/types.ts +17 -0
  52. package/src/index.ts +10 -0
@@ -4,7 +4,16 @@
4
4
 
5
5
  import * as path from "path";
6
6
  import { watch } from "chokidar";
7
- import { loadConfig, configExists, findConfigFile, hasValidToken, updateConfig, LOCAL_BASE_URL, type ResolvedConfig, type DevMode } from "../config.js";
7
+ import {
8
+ loadConfig,
9
+ configExists,
10
+ findConfigFile,
11
+ hasValidToken,
12
+ updateConfig,
13
+ LOCAL_BASE_URL,
14
+ type ResolvedConfig,
15
+ type DevMode,
16
+ } from "../config.js";
8
17
  import { runBuild, type BuildCommandResult } from "./build.js";
9
18
  import { getOrCreateBranch, type TinybirdBranch } from "../../api/branches.js";
10
19
  import { browserLogin } from "../auth.js";
@@ -19,6 +28,8 @@ import {
19
28
  getLocalWorkspaceName,
20
29
  type LocalWorkspace,
21
30
  } from "../../api/local.js";
31
+ import { getWorkspace } from "../../api/workspaces.js";
32
+ import { getBranchDashboardUrl, getLocalDashboardUrl } from "../../api/dashboard.js";
22
33
 
23
34
  /**
24
35
  * Login result info
@@ -70,6 +81,8 @@ export interface BranchReadyInfo {
70
81
  isLocal?: boolean;
71
82
  /** Local workspace info (only in local mode) */
72
83
  localWorkspace?: LocalWorkspace;
84
+ /** Dashboard URL for the branch (only in branch mode) */
85
+ dashboardUrl?: string;
73
86
  }
74
87
 
75
88
  /**
@@ -99,7 +112,9 @@ export interface DevController {
99
112
  * @param options - Dev options
100
113
  * @returns Dev controller
101
114
  */
102
- export async function runDev(options: DevCommandOptions = {}): Promise<DevController> {
115
+ export async function runDev(
116
+ options: DevCommandOptions = {}
117
+ ): Promise<DevController> {
103
118
  const cwd = options.cwd ?? process.cwd();
104
119
  const debounceMs = options.debounce ?? 100;
105
120
 
@@ -129,7 +144,8 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
129
144
 
130
145
  if (!authResult.success || !authResult.token) {
131
146
  throw new Error(
132
- authResult.error ?? "Login failed. Run 'npx tinybird login' to authenticate."
147
+ authResult.error ??
148
+ "Login failed. Run 'npx tinybird login' to authenticate."
133
149
  );
134
150
  }
135
151
 
@@ -173,8 +189,14 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
173
189
  if (devMode === "local") {
174
190
  // Local mode: get tokens from local container and set up workspace
175
191
  const localTokens = await getLocalTokens();
176
- const workspaceName = getLocalWorkspaceName(config.tinybirdBranch, config.cwd);
177
- const { workspace, wasCreated } = await getOrCreateLocalWorkspace(localTokens, workspaceName);
192
+ const workspaceName = getLocalWorkspaceName(
193
+ config.tinybirdBranch,
194
+ config.cwd
195
+ );
196
+ const { workspace, wasCreated } = await getOrCreateLocalWorkspace(
197
+ localTokens,
198
+ workspaceName
199
+ );
178
200
 
179
201
  effectiveToken = workspace.token;
180
202
  effectiveBaseUrl = LOCAL_BASE_URL;
@@ -184,6 +206,7 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
184
206
  isLocal: true,
185
207
  localWorkspace: workspace,
186
208
  wasCreated,
209
+ dashboardUrl: getLocalDashboardUrl(workspace.name),
187
210
  };
188
211
  } else {
189
212
  // Branch mode: use Tinybird cloud with branches
@@ -216,11 +239,22 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
216
239
  }
217
240
 
218
241
  effectiveToken = tinybirdBranch.token;
242
+
243
+ // Get workspace name for dashboard URL
244
+ const workspace = await getWorkspace({
245
+ baseUrl: config.baseUrl,
246
+ token: config.token,
247
+ });
248
+ const dashboardUrl =
249
+ getBranchDashboardUrl(config.baseUrl, workspace.name, branchName) ??
250
+ undefined;
251
+
219
252
  branchInfo = {
220
253
  gitBranch: config.gitBranch, // Original git branch name for display
221
254
  isMainBranch: false,
222
255
  tinybirdBranch,
223
256
  wasCreated: tinybirdBranch.wasCreated ?? false,
257
+ dashboardUrl,
224
258
  };
225
259
  }
226
260
  }
@@ -246,7 +280,11 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
246
280
  async function doBuild(): Promise<BuildCommandResult> {
247
281
  if (isBuilding) {
248
282
  pendingBuild = true;
249
- return { success: false, error: "Build already in progress", durationMs: 0 };
283
+ return {
284
+ success: false,
285
+ error: "Build already in progress",
286
+ durationMs: 0,
287
+ };
250
288
  }
251
289
 
252
290
  isBuilding = true;
@@ -357,7 +395,9 @@ export async function runDev(options: DevCommandOptions = {}): Promise<DevContro
357
395
  });
358
396
 
359
397
  watcher.on("error", (error: unknown) => {
360
- options.onError?.(error instanceof Error ? error : new Error(String(error)));
398
+ options.onError?.(
399
+ error instanceof Error ? error : new Error(String(error))
400
+ );
361
401
  });
362
402
 
363
403
  // Do initial build
package/src/cli/index.ts CHANGED
@@ -188,15 +188,19 @@ function createCli(): Command {
188
188
  devModeOverride = "local";
189
189
  }
190
190
 
191
- const modeLabel = devModeOverride === "local" ? " (local)" : "";
192
- output.highlight(`Building${modeLabel}...`);
193
-
194
191
  const result = await runBuild({
195
192
  dryRun: options.dryRun,
196
193
  devModeOverride,
197
194
  });
198
195
 
199
- const { build, deploy } = result;
196
+ const { build, deploy, branchInfo } = result;
197
+
198
+ // Show branch info
199
+ if (branchInfo) {
200
+ output.showBranchInfo(branchInfo);
201
+ }
202
+
203
+ output.highlight("Building...");
200
204
 
201
205
  if (!result.success) {
202
206
  // Show detailed errors if available
@@ -486,32 +490,23 @@ function createCli(): Command {
486
490
  },
487
491
  onBranchReady: (info) => {
488
492
  if (info.isLocal) {
489
- // Local mode
490
- const workspaceName = info.localWorkspace?.name ?? "unknown";
491
- if (info.wasCreated) {
492
- console.log(`Using local Tinybird container`);
493
- console.log(`Creating local workspace '${workspaceName}'...`);
494
- console.log("Workspace created.\n");
495
- } else {
496
- console.log(`Using local Tinybird container`);
497
- console.log(
498
- `Using existing local workspace '${workspaceName}'\n`
499
- );
500
- }
493
+ output.showBranchInfo({
494
+ gitBranch: info.gitBranch,
495
+ tinybirdBranch: info.localWorkspace?.name ?? null,
496
+ wasCreated: info.wasCreated ?? false,
497
+ dashboardUrl: info.dashboardUrl,
498
+ isLocal: true,
499
+ });
501
500
  } else if (info.isMainBranch) {
502
501
  console.log("On main branch - deploying to workspace\n");
503
502
  } else if (info.gitBranch) {
504
- const tinybirdName = info.tinybirdBranch?.name ?? info.gitBranch;
505
- if (info.wasCreated) {
506
- console.log(`Detected git branch: ${info.gitBranch}`);
507
- console.log(`Creating Tinybird branch '${tinybirdName}'...`);
508
- console.log("Branch created and token cached.\n");
509
- } else {
510
- console.log(`Detected git branch: ${info.gitBranch}`);
511
- console.log(
512
- `Using existing Tinybird branch '${tinybirdName}'\n`
513
- );
514
- }
503
+ output.showBranchInfo({
504
+ gitBranch: info.gitBranch,
505
+ tinybirdBranch: info.tinybirdBranch?.name ?? null,
506
+ wasCreated: info.wasCreated ?? false,
507
+ dashboardUrl: info.dashboardUrl,
508
+ isLocal: false,
509
+ });
515
510
  } else {
516
511
  console.log("Not in a git repository - deploying to workspace\n");
517
512
  }
@@ -659,6 +654,9 @@ function createCli(): Command {
659
654
  console.log(` Tinybird branch: ${result.tinybirdBranch.name}`);
660
655
  console.log(` Branch ID: ${result.tinybirdBranch.id}`);
661
656
  console.log(` Created: ${result.tinybirdBranch.created_at}`);
657
+ if (result.dashboardUrl) {
658
+ console.log(` Dashboard: ${result.dashboardUrl}`);
659
+ }
662
660
  } else if (!result.isMainBranch && result.tinybirdBranchName) {
663
661
  console.log(" Tinybird branch: not created yet");
664
662
  console.log(" (Run 'npx tinybird dev' to create it)");
package/src/cli/output.ts CHANGED
@@ -239,6 +239,59 @@ export function showDeployFailure(): void {
239
239
  error(`\n✗ Deploy failed`);
240
240
  }
241
241
 
242
+ /**
243
+ * Branch info for display
244
+ */
245
+ export interface BranchDisplayInfo {
246
+ /** Git branch name */
247
+ gitBranch: string | null;
248
+ /** Tinybird branch name */
249
+ tinybirdBranch: string | null;
250
+ /** Whether the branch was newly created */
251
+ wasCreated: boolean;
252
+ /** Dashboard URL for the branch */
253
+ dashboardUrl?: string;
254
+ /** Whether using local mode */
255
+ isLocal?: boolean;
256
+ }
257
+
258
+ /**
259
+ * Show branch information in a compact, styled format
260
+ */
261
+ export function showBranchInfo(info: BranchDisplayInfo): void {
262
+ const status = info.wasCreated
263
+ ? colorize("✓ created", "green")
264
+ : colorize("existing", "gray");
265
+
266
+ if (info.isLocal) {
267
+ // Show git branch
268
+ if (info.gitBranch) {
269
+ console.log(`» Git branch: ${info.gitBranch}`);
270
+ }
271
+ // Show local workspace
272
+ const name = info.tinybirdBranch ?? "unknown";
273
+ console.log(`» Local workspace: ${name} ${status}`);
274
+ // Show dashboard URL
275
+ if (info.dashboardUrl) {
276
+ console.log(colorize(` ↳ ${info.dashboardUrl}`, "gray"));
277
+ }
278
+ } else {
279
+ // Show git branch
280
+ if (info.gitBranch) {
281
+ console.log(`» Git branch: ${info.gitBranch}`);
282
+ }
283
+ // Show Tinybird branch
284
+ if (info.tinybirdBranch) {
285
+ console.log(`» Tinybird branch: ${info.tinybirdBranch} ${status}`);
286
+ }
287
+ // Show dashboard URL
288
+ if (info.dashboardUrl) {
289
+ console.log(colorize(` ↳ ${info.dashboardUrl}`, "gray"));
290
+ }
291
+ }
292
+ console.log("");
293
+ }
294
+
242
295
  /**
243
296
  * Output object containing all output functions
244
297
  */
@@ -265,4 +318,5 @@ export const output = {
265
318
  showValidatingDeployment,
266
319
  showDeploySuccess,
267
320
  showDeployFailure,
321
+ showBranchInfo,
268
322
  };
@@ -0,0 +1,129 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { TinybirdClient, createClient } from "./base.js";
3
+
4
+ describe("TinybirdClient", () => {
5
+ describe("constructor", () => {
6
+ it("throws error when baseUrl is missing", () => {
7
+ expect(() => new TinybirdClient({ baseUrl: "", token: "test-token" })).toThrow(
8
+ "baseUrl is required"
9
+ );
10
+ });
11
+
12
+ it("throws error when token is missing", () => {
13
+ expect(
14
+ () => new TinybirdClient({ baseUrl: "https://api.tinybird.co", token: "" })
15
+ ).toThrow("token is required");
16
+ });
17
+
18
+ it("creates client with valid config", () => {
19
+ const client = new TinybirdClient({
20
+ baseUrl: "https://api.tinybird.co",
21
+ token: "test-token",
22
+ });
23
+ expect(client).toBeInstanceOf(TinybirdClient);
24
+ });
25
+
26
+ it("normalizes baseUrl by removing trailing slash", async () => {
27
+ const client = new TinybirdClient({
28
+ baseUrl: "https://api.tinybird.co/",
29
+ token: "test-token",
30
+ });
31
+ const context = await client.getContext();
32
+ expect(context.baseUrl).toBe("https://api.tinybird.co");
33
+ });
34
+ });
35
+
36
+ describe("getContext", () => {
37
+ it("returns correct context in non-devMode", async () => {
38
+ const client = new TinybirdClient({
39
+ baseUrl: "https://api.tinybird.co",
40
+ token: "test-token",
41
+ });
42
+
43
+ const context = await client.getContext();
44
+
45
+ expect(context).toEqual({
46
+ token: "test-token",
47
+ baseUrl: "https://api.tinybird.co",
48
+ devMode: false,
49
+ isBranchToken: false,
50
+ branchName: null,
51
+ });
52
+ });
53
+
54
+ it("returns devMode: false when devMode is not set", async () => {
55
+ const client = new TinybirdClient({
56
+ baseUrl: "https://api.tinybird.co",
57
+ token: "test-token",
58
+ });
59
+
60
+ const context = await client.getContext();
61
+ expect(context.devMode).toBe(false);
62
+ });
63
+
64
+ it("returns isBranchToken: false when not in devMode", async () => {
65
+ const client = new TinybirdClient({
66
+ baseUrl: "https://api.tinybird.co",
67
+ token: "test-token",
68
+ });
69
+
70
+ const context = await client.getContext();
71
+ expect(context.isBranchToken).toBe(false);
72
+ });
73
+
74
+ it("returns branchName: null when not in devMode", async () => {
75
+ const client = new TinybirdClient({
76
+ baseUrl: "https://api.tinybird.co",
77
+ token: "test-token",
78
+ });
79
+
80
+ const context = await client.getContext();
81
+ expect(context.branchName).toBeNull();
82
+ });
83
+
84
+ it("caches the resolved context", async () => {
85
+ const client = new TinybirdClient({
86
+ baseUrl: "https://api.tinybird.co",
87
+ token: "test-token",
88
+ });
89
+
90
+ const context1 = await client.getContext();
91
+ const context2 = await client.getContext();
92
+
93
+ expect(context1).toBe(context2);
94
+ });
95
+
96
+ it("works with different baseUrl regions", async () => {
97
+ const client = new TinybirdClient({
98
+ baseUrl: "https://api.us-east.tinybird.co",
99
+ token: "us-token",
100
+ });
101
+
102
+ const context = await client.getContext();
103
+ expect(context.baseUrl).toBe("https://api.us-east.tinybird.co");
104
+ expect(context.token).toBe("us-token");
105
+ });
106
+ });
107
+
108
+ describe("createClient", () => {
109
+ it("creates a TinybirdClient instance", () => {
110
+ const client = createClient({
111
+ baseUrl: "https://api.tinybird.co",
112
+ token: "test-token",
113
+ });
114
+
115
+ expect(client).toBeInstanceOf(TinybirdClient);
116
+ });
117
+
118
+ it("passes config to the client correctly", async () => {
119
+ const client = createClient({
120
+ baseUrl: "https://api.tinybird.co",
121
+ token: "my-token",
122
+ });
123
+
124
+ const context = await client.getContext();
125
+ expect(context.token).toBe("my-token");
126
+ expect(context.baseUrl).toBe("https://api.tinybird.co");
127
+ });
128
+ });
129
+ });
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type {
6
6
  ClientConfig,
7
+ ClientContext,
7
8
  QueryResult,
8
9
  IngestResult,
9
10
  QueryOptions,
@@ -52,8 +53,8 @@ interface ResolvedTokenInfo {
52
53
  export class TinybirdClient {
53
54
  private readonly config: ClientConfig;
54
55
  private readonly apisByToken = new Map<string, TinybirdApi>();
55
- private tokenPromise: Promise<ResolvedTokenInfo> | null = null;
56
- private resolvedToken: string | null = null;
56
+ private contextPromise: Promise<ClientContext> | null = null;
57
+ private resolvedContext: ClientContext | null = null;
57
58
 
58
59
  constructor(config: ClientConfig) {
59
60
  // Validate required config
@@ -75,31 +76,55 @@ export class TinybirdClient {
75
76
  * Get the effective token, resolving branch token in dev mode if needed
76
77
  */
77
78
  private async getToken(): Promise<string> {
79
+ const context = await this.resolveContext();
80
+ return context.token;
81
+ }
82
+
83
+ /**
84
+ * Resolve the client context, including branch token resolution in dev mode
85
+ * This is the single source of truth for all context data
86
+ */
87
+ private async resolveContext(): Promise<ClientContext> {
78
88
  // If already resolved, return it
79
- if (this.resolvedToken) {
80
- return this.resolvedToken;
89
+ if (this.resolvedContext) {
90
+ return this.resolvedContext;
81
91
  }
82
92
 
83
93
  // If not in dev mode, use the configured token
84
94
  if (!this.config.devMode) {
85
- this.resolvedToken = this.config.token;
86
- return this.resolvedToken;
95
+ this.resolvedContext = this.buildContext({
96
+ token: this.config.token,
97
+ isBranchToken: false,
98
+ });
99
+ return this.resolvedContext;
87
100
  }
88
101
 
89
102
  // In dev mode, lazily resolve the branch token
90
- if (!this.tokenPromise) {
91
- this.tokenPromise = this.resolveBranchToken();
103
+ if (!this.contextPromise) {
104
+ this.contextPromise = this.resolveBranchContext();
92
105
  }
93
106
 
94
- const resolved = await this.tokenPromise;
95
- this.resolvedToken = resolved.token;
96
- return this.resolvedToken;
107
+ this.resolvedContext = await this.contextPromise;
108
+ return this.resolvedContext;
109
+ }
110
+
111
+ /**
112
+ * Build the client context from resolved token info
113
+ */
114
+ private buildContext(tokenInfo: ResolvedTokenInfo): ClientContext {
115
+ return {
116
+ token: tokenInfo.token,
117
+ baseUrl: this.config.baseUrl,
118
+ devMode: this.config.devMode ?? false,
119
+ isBranchToken: tokenInfo.isBranchToken,
120
+ branchName: tokenInfo.branchName ?? null,
121
+ };
97
122
  }
98
123
 
99
124
  /**
100
- * Resolve the branch token in dev mode
125
+ * Resolve the branch context in dev mode
101
126
  */
102
- private async resolveBranchToken(): Promise<ResolvedTokenInfo> {
127
+ private async resolveBranchContext(): Promise<ClientContext> {
103
128
  try {
104
129
  // Dynamic import to avoid circular dependencies and to keep CLI code
105
130
  // out of the client bundle when not using dev mode
@@ -110,7 +135,7 @@ export class TinybirdClient {
110
135
 
111
136
  // If on main branch, use the workspace token
112
137
  if (config.isMainBranch || !config.tinybirdBranch) {
113
- return { token: this.config.token, isBranchToken: false };
138
+ return this.buildContext({ token: this.config.token, isBranchToken: false });
114
139
  }
115
140
 
116
141
  const branchName = config.tinybirdBranch;
@@ -123,17 +148,17 @@ export class TinybirdClient {
123
148
 
124
149
  if (!branch.token) {
125
150
  // Fall back to workspace token if no branch token
126
- return { token: this.config.token, isBranchToken: false };
151
+ return this.buildContext({ token: this.config.token, isBranchToken: false });
127
152
  }
128
153
 
129
- return {
154
+ return this.buildContext({
130
155
  token: branch.token,
131
156
  isBranchToken: true,
132
157
  branchName,
133
- };
158
+ });
134
159
  } catch {
135
160
  // If anything fails, fall back to the workspace token
136
- return { token: this.config.token, isBranchToken: false };
161
+ return this.buildContext({ token: this.config.token, isBranchToken: false });
137
162
  }
138
163
  }
139
164
 
@@ -217,6 +242,31 @@ export class TinybirdClient {
217
242
  }
218
243
  }
219
244
 
245
+ /**
246
+ * Get the current client context
247
+ *
248
+ * Returns information about the resolved configuration including the token being used,
249
+ * API URL, dev mode status, and branch information.
250
+ *
251
+ * @returns Client context with resolved configuration
252
+ *
253
+ * @example
254
+ * ```ts
255
+ * const client = createClient({
256
+ * baseUrl: 'https://api.tinybird.co',
257
+ * token: process.env.TINYBIRD_TOKEN,
258
+ * devMode: true,
259
+ * });
260
+ *
261
+ * const context = await client.getContext();
262
+ * console.log(context.branchName); // 'feature_my_branch'
263
+ * console.log(context.isBranchToken); // true
264
+ * ```
265
+ */
266
+ async getContext(): Promise<ClientContext> {
267
+ return this.resolveContext();
268
+ }
269
+
220
270
  private getApi(token: string): TinybirdApi {
221
271
  const existing = this.apisByToken.get(token);
222
272
  if (existing) {
@@ -147,6 +147,23 @@ export interface IngestOptions {
147
147
  wait?: boolean;
148
148
  }
149
149
 
150
+ /**
151
+ * Client context information
152
+ * Contains the resolved configuration and state of the client
153
+ */
154
+ export interface ClientContext {
155
+ /** The resolved token being used for requests (workspace or branch token) */
156
+ token: string;
157
+ /** Tinybird API base URL */
158
+ baseUrl: string;
159
+ /** Whether dev mode is enabled */
160
+ devMode: boolean;
161
+ /** Whether the resolved token is a branch token (vs workspace token) */
162
+ isBranchToken: boolean;
163
+ /** The branch name if using a branch token */
164
+ branchName: string | null;
165
+ }
166
+
150
167
  /**
151
168
  * Base interface for typed pipe endpoints
152
169
  */
package/src/index.ts CHANGED
@@ -203,6 +203,7 @@ export { TinybirdClient, createClient } from "./client/base.js";
203
203
  export { TinybirdError } from "./client/types.js";
204
204
  export type {
205
205
  ClientConfig,
206
+ ClientContext,
206
207
  QueryResult,
207
208
  IngestResult,
208
209
  QueryOptions,
@@ -235,3 +236,12 @@ export {
235
236
  resolveToken,
236
237
  clearTokenCache,
237
238
  } from "./client/preview.js";
239
+
240
+ // ============ Dashboard URL Utilities ============
241
+ export {
242
+ parseApiUrl,
243
+ getDashboardUrl,
244
+ getBranchDashboardUrl,
245
+ getLocalDashboardUrl,
246
+ } from "./api/dashboard.js";
247
+ export type { RegionInfo } from "./api/dashboard.js";