@tinybirdco/sdk 0.0.37 → 0.0.38

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 (48) hide show
  1. package/README.md +50 -1
  2. package/dist/api/api.d.ts +49 -0
  3. package/dist/api/api.d.ts.map +1 -1
  4. package/dist/api/api.js +23 -0
  5. package/dist/api/api.js.map +1 -1
  6. package/dist/api/api.test.js +32 -0
  7. package/dist/api/api.test.js.map +1 -1
  8. package/dist/api/tokens.d.ts +79 -0
  9. package/dist/api/tokens.d.ts.map +1 -0
  10. package/dist/api/tokens.js +80 -0
  11. package/dist/api/tokens.js.map +1 -0
  12. package/dist/api/tokens.test.d.ts +2 -0
  13. package/dist/api/tokens.test.d.ts.map +1 -0
  14. package/dist/api/tokens.test.js +209 -0
  15. package/dist/api/tokens.test.js.map +1 -0
  16. package/dist/client/base.d.ts +3 -0
  17. package/dist/client/base.d.ts.map +1 -1
  18. package/dist/client/base.js +5 -0
  19. package/dist/client/base.js.map +1 -1
  20. package/dist/client/tokens.d.ts +42 -0
  21. package/dist/client/tokens.d.ts.map +1 -0
  22. package/dist/client/tokens.js +67 -0
  23. package/dist/client/tokens.js.map +1 -0
  24. package/dist/client/tokens.test.d.ts +2 -0
  25. package/dist/client/tokens.test.d.ts.map +1 -0
  26. package/dist/client/tokens.test.js +79 -0
  27. package/dist/client/tokens.test.js.map +1 -0
  28. package/dist/index.d.ts +3 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/schema/project.d.ts +21 -12
  33. package/dist/schema/project.d.ts.map +1 -1
  34. package/dist/schema/project.js +55 -13
  35. package/dist/schema/project.js.map +1 -1
  36. package/dist/schema/project.test.js +11 -10
  37. package/dist/schema/project.test.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/api/api.test.ts +43 -0
  40. package/src/api/api.ts +79 -0
  41. package/src/api/tokens.test.ts +253 -0
  42. package/src/api/tokens.ts +169 -0
  43. package/src/client/base.ts +12 -0
  44. package/src/client/tokens.test.ts +103 -0
  45. package/src/client/tokens.ts +69 -0
  46. package/src/index.ts +15 -0
  47. package/src/schema/project.test.ts +11 -10
  48. package/src/schema/project.ts +95 -27
@@ -70,7 +70,7 @@ describe("Project Schema", () => {
70
70
  expect(project.pipes.topEvents).toBe(topEvents);
71
71
  });
72
72
 
73
- it("creates tinybird client with query and ingest methods", () => {
73
+ it("creates tinybird client with pipe accessors and ingest methods", () => {
74
74
  const events = defineDatasource("events", {
75
75
  schema: { id: t.string() },
76
76
  });
@@ -86,11 +86,12 @@ describe("Project Schema", () => {
86
86
  pipes: { topEvents },
87
87
  });
88
88
 
89
- expect(project.tinybird.query).toBeDefined();
90
89
  expect(project.tinybird.ingest).toBeDefined();
91
- expect(typeof project.tinybird.query.topEvents).toBe("function");
90
+ expect(typeof project.tinybird.topEvents.query).toBe("function");
92
91
  expect(typeof project.tinybird.ingest.events).toBe("function");
93
92
  expect(typeof project.tinybird.ingest.eventsBatch).toBe("function");
93
+ expect((project.tinybird as unknown as Record<string, unknown>).query).toBeUndefined();
94
+ expect((project.tinybird as unknown as Record<string, unknown>).pipes).toBeUndefined();
94
95
  });
95
96
 
96
97
  it("creates datasource accessors with append method", () => {
@@ -144,7 +145,7 @@ describe("Project Schema", () => {
144
145
  });
145
146
 
146
147
  // Cast to any since the type system expects params but stub throws regardless
147
- const queryFn = project.tinybird.query.internalPipe as () => Promise<unknown>;
148
+ const queryFn = project.tinybird.internalPipe.query as () => Promise<unknown>;
148
149
  await expect(queryFn()).rejects.toThrow(
149
150
  'Pipe "internalPipe" is not exposed as an endpoint'
150
151
  );
@@ -277,7 +278,7 @@ describe("Project Schema", () => {
277
278
  process.env.NODE_ENV = originalNodeEnv;
278
279
  });
279
280
 
280
- it("creates a client with query and ingest methods", () => {
281
+ it("creates a client with pipe accessors and ingest methods", () => {
281
282
  const events = defineDatasource("events", {
282
283
  schema: { id: t.string() },
283
284
  });
@@ -293,11 +294,14 @@ describe("Project Schema", () => {
293
294
  pipes: { topEvents },
294
295
  });
295
296
 
296
- expect(client.query).toBeDefined();
297
297
  expect(client.ingest).toBeDefined();
298
- expect(typeof client.query.topEvents).toBe("function");
298
+ expect(client.sql).toBeDefined();
299
+ expect(typeof client.topEvents.query).toBe("function");
299
300
  expect(typeof client.ingest.events).toBe("function");
300
301
  expect(typeof client.ingest.eventsBatch).toBe("function");
302
+ expect(typeof client.sql).toBe("function");
303
+ expect((client as unknown as Record<string, unknown>).query).toBeUndefined();
304
+ expect((client as unknown as Record<string, unknown>).pipes).toBeUndefined();
301
305
  });
302
306
 
303
307
  it("creates datasource accessors with append method", () => {
@@ -345,7 +349,6 @@ describe("Project Schema", () => {
345
349
  devMode: true,
346
350
  });
347
351
 
348
- expect(clientWithDevMode.query).toBeDefined();
349
352
  expect(clientWithDevMode.ingest).toBeDefined();
350
353
 
351
354
  const clientWithoutDevMode = createTinybirdClient({
@@ -354,7 +357,6 @@ describe("Project Schema", () => {
354
357
  devMode: false,
355
358
  });
356
359
 
357
- expect(clientWithoutDevMode.query).toBeDefined();
358
360
  expect(clientWithoutDevMode.ingest).toBeDefined();
359
361
  });
360
362
 
@@ -373,7 +375,6 @@ describe("Project Schema", () => {
373
375
  devMode: true,
374
376
  });
375
377
 
376
- expect(client.query).toBeDefined();
377
378
  expect(client.ingest).toBeDefined();
378
379
  });
379
380
 
@@ -8,8 +8,15 @@ import type { PipeDefinition, ParamsDefinition, OutputDefinition } from "./pipe.
8
8
  import type { ConnectionDefinition } from "./connection.js";
9
9
  import { getEndpointConfig } from "./pipe.js";
10
10
  import type { TinybirdClient } from "../client/base.js";
11
- import type { AppendOptions, AppendResult, QueryResult } from "../client/types.js";
11
+ import type {
12
+ AppendOptions,
13
+ AppendResult,
14
+ DatasourcesNamespace,
15
+ QueryOptions,
16
+ QueryResult,
17
+ } from "../client/types.js";
12
18
  import type { InferRow, InferParams, InferOutputRow } from "../infer/index.js";
19
+ import type { TokensNamespace } from "../client/tokens.js";
13
20
 
14
21
  // Symbol for brand typing - use Symbol.for() for global registry
15
22
  // This ensures the same symbol is used across module instances
@@ -41,11 +48,14 @@ type QueryMethod<T extends PipeDefinition<ParamsDefinition, OutputDefinition>> =
41
48
  : never;
42
49
 
43
50
  /**
44
- * Type for query methods object
45
- * Note: At runtime, only pipes with endpoint: true are included
51
+ * Type for pipe entity accessors object
52
+ * Note: At runtime, all declared pipes are included. Non-endpoint pipes throw
53
+ * when queried with a clear error message.
46
54
  */
47
- type QueryMethods<T extends PipesDefinition> = {
48
- [K in keyof T]: QueryMethod<T[K]>;
55
+ type PipeEntityAccessors<T extends PipesDefinition> = {
56
+ [K in keyof T]: {
57
+ query: QueryMethod<T[K]>;
58
+ };
49
59
  };
50
60
 
51
61
  /**
@@ -90,14 +100,15 @@ type DatasourceAccessors<T extends DatasourcesDefinition> = {
90
100
  /**
91
101
  * Base project client interface
92
102
  */
93
- interface ProjectClientBase<
94
- TDatasources extends DatasourcesDefinition,
95
- TPipes extends PipesDefinition
96
- > {
97
- /** Query endpoint pipes */
98
- query: QueryMethods<TPipes>;
103
+ interface ProjectClientBase<TDatasources extends DatasourcesDefinition> {
99
104
  /** Ingest events to datasources */
100
105
  ingest: IngestMethods<TDatasources>;
106
+ /** Token operations (JWT creation, etc.) */
107
+ readonly tokens: TokensNamespace;
108
+ /** Datasource operations (append from URL/file) */
109
+ readonly datasources: DatasourcesNamespace;
110
+ /** Execute raw SQL queries */
111
+ sql<T = unknown>(sql: string, options?: QueryOptions): Promise<QueryResult<T>>;
101
112
  /** Raw client for advanced usage */
102
113
  readonly client: TinybirdClient;
103
114
  }
@@ -109,7 +120,9 @@ interface ProjectClientBase<
109
120
  export type ProjectClient<
110
121
  TDatasources extends DatasourcesDefinition,
111
122
  TPipes extends PipesDefinition
112
- > = ProjectClientBase<TDatasources, TPipes> & DatasourceAccessors<TDatasources>;
123
+ > = ProjectClientBase<TDatasources> &
124
+ DatasourceAccessors<TDatasources> &
125
+ PipeEntityAccessors<TPipes>;
113
126
 
114
127
  /**
115
128
  * Configuration for createTinybirdClient
@@ -243,7 +256,7 @@ export function isProjectDefinition(value: unknown): value is ProjectDefinition
243
256
  /**
244
257
  * Build a typed Tinybird client from datasources and pipes
245
258
  *
246
- * This is an internal helper that builds query/ingest methods.
259
+ * This is an internal helper that builds pipe query and datasource ingest methods.
247
260
  */
248
261
  function buildProjectClient<
249
262
  TDatasources extends DatasourcesDefinition,
@@ -253,6 +266,14 @@ function buildProjectClient<
253
266
  pipes: TPipes,
254
267
  options?: { baseUrl?: string; token?: string; configDir?: string; devMode?: boolean }
255
268
  ): ProjectClient<TDatasources, TPipes> {
269
+ const RESERVED_CLIENT_NAMES = new Set([
270
+ "ingest",
271
+ "tokens",
272
+ "datasources",
273
+ "sql",
274
+ "client",
275
+ ]);
276
+
256
277
  // Lazy client initialization
257
278
  let _client: TinybirdClient | null = null;
258
279
 
@@ -276,33 +297,57 @@ function buildProjectClient<
276
297
  return _client;
277
298
  };
278
299
 
279
- // Build query methods for pipes
280
- const queryMethods: Record<string, (params?: unknown) => Promise<unknown>> = {};
300
+ // Build pipe accessors with query methods
301
+ const pipeAccessors: Record<string, { query: (params?: unknown) => Promise<unknown> }> = {};
281
302
  for (const [name, pipe] of Object.entries(pipes)) {
303
+ if (name in datasources) {
304
+ throw new Error(
305
+ `Name conflict in createTinybirdClient(): "${name}" is defined as both datasource and pipe. ` +
306
+ `Rename one of them to expose both as top-level client properties.`
307
+ );
308
+ }
309
+ if (RESERVED_CLIENT_NAMES.has(name)) {
310
+ throw new Error(
311
+ `Name conflict in createTinybirdClient(): "${name}" is reserved by the client API. ` +
312
+ `Rename this pipe to expose it as a top-level client property.`
313
+ );
314
+ }
315
+
282
316
  const endpointConfig = getEndpointConfig(pipe);
283
317
 
284
318
  if (!endpointConfig) {
285
319
  // Non-endpoint pipes get a stub that throws a clear error
286
- queryMethods[name] = async () => {
287
- throw new Error(
288
- `Pipe "${name}" is not exposed as an endpoint. ` +
289
- `Set "endpoint: true" in the pipe definition to enable querying.`
290
- );
320
+ pipeAccessors[name] = {
321
+ query: async () => {
322
+ throw new Error(
323
+ `Pipe "${name}" is not exposed as an endpoint. ` +
324
+ `Set "endpoint: true" in the pipe definition to enable querying.`
325
+ );
326
+ },
291
327
  };
292
328
  continue;
293
329
  }
294
330
 
295
331
  // Use the Tinybird pipe name (snake_case)
296
332
  const tinybirdName = pipe._name;
297
- queryMethods[name] = async (params?: unknown) => {
298
- const client = await getClient();
299
- return client.query(tinybirdName, (params ?? {}) as Record<string, unknown>);
333
+ pipeAccessors[name] = {
334
+ query: async (params?: unknown) => {
335
+ const client = await getClient();
336
+ return client.query(tinybirdName, (params ?? {}) as Record<string, unknown>);
337
+ },
300
338
  };
301
339
  }
302
340
 
303
341
  // Build ingest methods for datasources
304
342
  const ingestMethods: Record<string, (data: unknown) => Promise<void>> = {};
305
343
  for (const [name, datasource] of Object.entries(datasources)) {
344
+ if (RESERVED_CLIENT_NAMES.has(name)) {
345
+ throw new Error(
346
+ `Name conflict in createTinybirdClient(): "${name}" is reserved by the client API. ` +
347
+ `Rename this datasource to expose it as a top-level client property.`
348
+ );
349
+ }
350
+
306
351
  // Use the Tinybird datasource name (snake_case)
307
352
  const tinybirdName = datasource._name;
308
353
 
@@ -335,8 +380,30 @@ function buildProjectClient<
335
380
  // Create the typed client object
336
381
  return {
337
382
  ...datasourceAccessors,
338
- query: queryMethods,
383
+ ...pipeAccessors,
339
384
  ingest: ingestMethods,
385
+ sql: async <T = unknown>(sql: string, options: QueryOptions = {}) => {
386
+ const client = await getClient();
387
+ return client.sql<T>(sql, options);
388
+ },
389
+ get tokens(): TokensNamespace {
390
+ // Synchronous access - will throw if not initialized
391
+ if (!_client) {
392
+ throw new Error(
393
+ "Client not initialized. Call a query or ingest method first, or access client asynchronously."
394
+ );
395
+ }
396
+ return _client.tokens;
397
+ },
398
+ get datasources(): DatasourcesNamespace {
399
+ // Synchronous access - will throw if not initialized
400
+ if (!_client) {
401
+ throw new Error(
402
+ "Client not initialized. Call a query or ingest method first, or access client asynchronously."
403
+ );
404
+ }
405
+ return _client.datasources;
406
+ },
340
407
  get client(): TinybirdClient {
341
408
  // Synchronous client access - will throw if not initialized
342
409
  if (!_client) {
@@ -352,12 +419,13 @@ function buildProjectClient<
352
419
  /**
353
420
  * Create a typed Tinybird client
354
421
  *
355
- * Creates a client with typed query and ingest methods based on the provided
422
+ * Creates a client with typed pipe query and datasource ingest methods based on
423
+ * the provided
356
424
  * datasources and pipes. This is the recommended way to create a Tinybird client
357
425
  * when using the SDK's auto-generated client file.
358
426
  *
359
427
  * @param config - Client configuration with datasources and pipes
360
- * @returns A typed client with query and ingest methods
428
+ * @returns A typed client with pipe query and datasource ingest methods
361
429
  *
362
430
  * @example
363
431
  * ```ts
@@ -371,7 +439,7 @@ function buildProjectClient<
371
439
  * });
372
440
  *
373
441
  * // Query a pipe (fully typed)
374
- * const result = await tinybird.query.topPages({
442
+ * const result = await tinybird.topPages.query({
375
443
  * start_date: new Date('2024-01-01'),
376
444
  * end_date: new Date('2024-01-31'),
377
445
  * });