@tinybirdco/sdk 0.0.1
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 +518 -0
- package/bin/tinybird.js +7 -0
- package/dist/api/branches.d.ts +98 -0
- package/dist/api/branches.d.ts.map +1 -0
- package/dist/api/branches.js +203 -0
- package/dist/api/branches.js.map +1 -0
- package/dist/api/branches.test.d.ts +2 -0
- package/dist/api/branches.test.d.ts.map +1 -0
- package/dist/api/branches.test.js +286 -0
- package/dist/api/branches.test.js.map +1 -0
- package/dist/api/build.d.ts +130 -0
- package/dist/api/build.d.ts.map +1 -0
- package/dist/api/build.js +143 -0
- package/dist/api/build.js.map +1 -0
- package/dist/api/build.test.d.ts +2 -0
- package/dist/api/build.test.d.ts.map +1 -0
- package/dist/api/build.test.js +138 -0
- package/dist/api/build.test.js.map +1 -0
- package/dist/api/deploy.d.ts +39 -0
- package/dist/api/deploy.d.ts.map +1 -0
- package/dist/api/deploy.js +135 -0
- package/dist/api/deploy.js.map +1 -0
- package/dist/api/deploy.test.d.ts +2 -0
- package/dist/api/deploy.test.d.ts.map +1 -0
- package/dist/api/deploy.test.js +118 -0
- package/dist/api/deploy.test.js.map +1 -0
- package/dist/api/workspaces.d.ts +46 -0
- package/dist/api/workspaces.d.ts.map +1 -0
- package/dist/api/workspaces.js +39 -0
- package/dist/api/workspaces.js.map +1 -0
- package/dist/api/workspaces.test.d.ts +2 -0
- package/dist/api/workspaces.test.d.ts.map +1 -0
- package/dist/api/workspaces.test.js +65 -0
- package/dist/api/workspaces.test.js.map +1 -0
- package/dist/cli/auth.d.ts +86 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +284 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/branch-store.d.ts +53 -0
- package/dist/cli/branch-store.d.ts.map +1 -0
- package/dist/cli/branch-store.js +91 -0
- package/dist/cli/branch-store.js.map +1 -0
- package/dist/cli/branch-store.test.d.ts +2 -0
- package/dist/cli/branch-store.test.d.ts.map +1 -0
- package/dist/cli/branch-store.test.js +115 -0
- package/dist/cli/branch-store.test.js.map +1 -0
- package/dist/cli/commands/branch.d.ts +82 -0
- package/dist/cli/commands/branch.d.ts.map +1 -0
- package/dist/cli/commands/branch.js +215 -0
- package/dist/cli/commands/branch.js.map +1 -0
- package/dist/cli/commands/build.d.ts +43 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +138 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/dev.d.ts +78 -0
- package/dist/cli/commands/dev.d.ts.map +1 -0
- package/dist/cli/commands/dev.js +226 -0
- package/dist/cli/commands/dev.js.map +1 -0
- package/dist/cli/commands/init.d.ts +45 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +277 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/init.test.d.ts +2 -0
- package/dist/cli/commands/init.test.d.ts.map +1 -0
- package/dist/cli/commands/init.test.js +158 -0
- package/dist/cli/commands/init.test.js.map +1 -0
- package/dist/cli/commands/login.d.ts +37 -0
- package/dist/cli/commands/login.d.ts.map +1 -0
- package/dist/cli/commands/login.js +64 -0
- package/dist/cli/commands/login.js.map +1 -0
- package/dist/cli/config.d.ts +114 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +258 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/config.test.d.ts +2 -0
- package/dist/cli/config.test.d.ts.map +1 -0
- package/dist/cli/config.test.js +243 -0
- package/dist/cli/config.test.js.map +1 -0
- package/dist/cli/env.d.ts +29 -0
- package/dist/cli/env.d.ts.map +1 -0
- package/dist/cli/env.js +66 -0
- package/dist/cli/env.js.map +1 -0
- package/dist/cli/git.d.ts +29 -0
- package/dist/cli/git.d.ts.map +1 -0
- package/dist/cli/git.js +114 -0
- package/dist/cli/git.js.map +1 -0
- package/dist/cli/git.test.d.ts +2 -0
- package/dist/cli/git.test.d.ts.map +1 -0
- package/dist/cli/git.test.js +125 -0
- package/dist/cli/git.test.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +337 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/schema-validation.d.ts +95 -0
- package/dist/cli/utils/schema-validation.d.ts.map +1 -0
- package/dist/cli/utils/schema-validation.js +175 -0
- package/dist/cli/utils/schema-validation.js.map +1 -0
- package/dist/cli/utils/schema-validation.test.d.ts +5 -0
- package/dist/cli/utils/schema-validation.test.d.ts.map +1 -0
- package/dist/cli/utils/schema-validation.test.js +173 -0
- package/dist/cli/utils/schema-validation.test.js.map +1 -0
- package/dist/client/base.d.ts +116 -0
- package/dist/client/base.d.ts.map +1 -0
- package/dist/client/base.js +328 -0
- package/dist/client/base.js.map +1 -0
- package/dist/client/types.d.ts +137 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +43 -0
- package/dist/client/types.js.map +1 -0
- package/dist/generator/client.d.ts +44 -0
- package/dist/generator/client.d.ts.map +1 -0
- package/dist/generator/client.js +144 -0
- package/dist/generator/client.js.map +1 -0
- package/dist/generator/datasource.d.ts +57 -0
- package/dist/generator/datasource.d.ts.map +1 -0
- package/dist/generator/datasource.js +169 -0
- package/dist/generator/datasource.js.map +1 -0
- package/dist/generator/datasource.test.d.ts +2 -0
- package/dist/generator/datasource.test.d.ts.map +1 -0
- package/dist/generator/datasource.test.js +254 -0
- package/dist/generator/datasource.test.js.map +1 -0
- package/dist/generator/index.d.ts +131 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +121 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/index.test.d.ts +2 -0
- package/dist/generator/index.test.d.ts.map +1 -0
- package/dist/generator/index.test.js +175 -0
- package/dist/generator/index.test.js.map +1 -0
- package/dist/generator/loader.d.ts +156 -0
- package/dist/generator/loader.d.ts.map +1 -0
- package/dist/generator/loader.js +295 -0
- package/dist/generator/loader.js.map +1 -0
- package/dist/generator/pipe.d.ts +72 -0
- package/dist/generator/pipe.d.ts.map +1 -0
- package/dist/generator/pipe.js +174 -0
- package/dist/generator/pipe.js.map +1 -0
- package/dist/generator/pipe.test.d.ts +2 -0
- package/dist/generator/pipe.test.d.ts.map +1 -0
- package/dist/generator/pipe.test.js +393 -0
- package/dist/generator/pipe.test.js.map +1 -0
- package/dist/index.d.ts +74 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/infer/index.d.ts +202 -0
- package/dist/infer/index.d.ts.map +1 -0
- package/dist/infer/index.js +5 -0
- package/dist/infer/index.js.map +1 -0
- package/dist/schema/datasource.d.ts +135 -0
- package/dist/schema/datasource.d.ts.map +1 -0
- package/dist/schema/datasource.js +105 -0
- package/dist/schema/datasource.js.map +1 -0
- package/dist/schema/datasource.test.d.ts +2 -0
- package/dist/schema/datasource.test.d.ts.map +1 -0
- package/dist/schema/datasource.test.js +142 -0
- package/dist/schema/datasource.test.js.map +1 -0
- package/dist/schema/engines.d.ts +157 -0
- package/dist/schema/engines.d.ts.map +1 -0
- package/dist/schema/engines.js +155 -0
- package/dist/schema/engines.js.map +1 -0
- package/dist/schema/engines.test.d.ts +2 -0
- package/dist/schema/engines.test.d.ts.map +1 -0
- package/dist/schema/engines.test.js +221 -0
- package/dist/schema/engines.test.js.map +1 -0
- package/dist/schema/params.d.ts +106 -0
- package/dist/schema/params.d.ts.map +1 -0
- package/dist/schema/params.js +138 -0
- package/dist/schema/params.js.map +1 -0
- package/dist/schema/params.test.d.ts +2 -0
- package/dist/schema/params.test.d.ts.map +1 -0
- package/dist/schema/params.test.js +175 -0
- package/dist/schema/params.test.js.map +1 -0
- package/dist/schema/pipe.d.ts +436 -0
- package/dist/schema/pipe.d.ts.map +1 -0
- package/dist/schema/pipe.js +484 -0
- package/dist/schema/pipe.js.map +1 -0
- package/dist/schema/pipe.test.d.ts +2 -0
- package/dist/schema/pipe.test.d.ts.map +1 -0
- package/dist/schema/pipe.test.js +488 -0
- package/dist/schema/pipe.test.js.map +1 -0
- package/dist/schema/project.d.ts +202 -0
- package/dist/schema/project.d.ts.map +1 -0
- package/dist/schema/project.js +188 -0
- package/dist/schema/project.js.map +1 -0
- package/dist/schema/project.test.d.ts +2 -0
- package/dist/schema/project.test.d.ts.map +1 -0
- package/dist/schema/project.test.js +180 -0
- package/dist/schema/project.test.js.map +1 -0
- package/dist/schema/types.d.ts +140 -0
- package/dist/schema/types.d.ts.map +1 -0
- package/dist/schema/types.js +174 -0
- package/dist/schema/types.js.map +1 -0
- package/dist/schema/types.test.d.ts +2 -0
- package/dist/schema/types.test.d.ts.map +1 -0
- package/dist/schema/types.test.js +176 -0
- package/dist/schema/types.test.js.map +1 -0
- package/dist/test/handlers.d.ts +58 -0
- package/dist/test/handlers.d.ts.map +1 -0
- package/dist/test/handlers.js +62 -0
- package/dist/test/handlers.js.map +1 -0
- package/dist/test/setup.d.ts +5 -0
- package/dist/test/setup.d.ts.map +1 -0
- package/dist/test/setup.js +11 -0
- package/dist/test/setup.js.map +1 -0
- package/package.json +57 -0
- package/src/api/branches.test.ts +377 -0
- package/src/api/branches.ts +334 -0
- package/src/api/build.test.ts +216 -0
- package/src/api/build.ts +266 -0
- package/src/api/deploy.test.ts +193 -0
- package/src/api/deploy.ts +163 -0
- package/src/api/workspaces.test.ts +81 -0
- package/src/api/workspaces.ts +77 -0
- package/src/cli/auth.ts +358 -0
- package/src/cli/branch-store.test.ts +139 -0
- package/src/cli/branch-store.ts +137 -0
- package/src/cli/commands/branch.ts +306 -0
- package/src/cli/commands/build.ts +183 -0
- package/src/cli/commands/dev.ts +334 -0
- package/src/cli/commands/init.test.ts +249 -0
- package/src/cli/commands/init.ts +323 -0
- package/src/cli/commands/login.ts +98 -0
- package/src/cli/config.test.ts +359 -0
- package/src/cli/config.ts +335 -0
- package/src/cli/env.ts +86 -0
- package/src/cli/git.test.ts +147 -0
- package/src/cli/git.ts +125 -0
- package/src/cli/index.ts +382 -0
- package/src/cli/utils/schema-validation.test.ts +222 -0
- package/src/cli/utils/schema-validation.ts +272 -0
- package/src/client/base.ts +414 -0
- package/src/client/types.ts +165 -0
- package/src/generator/client.ts +194 -0
- package/src/generator/datasource.test.ts +297 -0
- package/src/generator/datasource.ts +217 -0
- package/src/generator/index.test.ts +209 -0
- package/src/generator/index.ts +203 -0
- package/src/generator/loader.ts +406 -0
- package/src/generator/pipe.test.ts +441 -0
- package/src/generator/pipe.ts +220 -0
- package/src/index.ts +191 -0
- package/src/infer/index.ts +247 -0
- package/src/schema/datasource.test.ts +187 -0
- package/src/schema/datasource.ts +195 -0
- package/src/schema/engines.test.ts +247 -0
- package/src/schema/engines.ts +271 -0
- package/src/schema/params.test.ts +208 -0
- package/src/schema/params.ts +249 -0
- package/src/schema/pipe.test.ts +588 -0
- package/src/schema/pipe.ts +832 -0
- package/src/schema/project.test.ts +236 -0
- package/src/schema/project.ts +394 -0
- package/src/schema/types.test.ts +212 -0
- package/src/schema/types.ts +366 -0
- package/src/test/handlers.ts +79 -0
- package/src/test/setup.ts +13 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
defineProject,
|
|
4
|
+
isProjectDefinition,
|
|
5
|
+
getDatasourceNames,
|
|
6
|
+
getPipeNames,
|
|
7
|
+
getDatasource,
|
|
8
|
+
getPipe,
|
|
9
|
+
} from "./project.js";
|
|
10
|
+
import { defineDatasource } from "./datasource.js";
|
|
11
|
+
import { definePipe, node } from "./pipe.js";
|
|
12
|
+
import { t } from "./types.js";
|
|
13
|
+
|
|
14
|
+
describe("Project Schema", () => {
|
|
15
|
+
describe("defineProject", () => {
|
|
16
|
+
it("creates a project with empty config", () => {
|
|
17
|
+
const project = defineProject({});
|
|
18
|
+
|
|
19
|
+
expect(project._type).toBe("project");
|
|
20
|
+
expect(project.datasources).toEqual({});
|
|
21
|
+
expect(project.pipes).toEqual({});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("creates a project with datasources", () => {
|
|
25
|
+
const events = defineDatasource("events", {
|
|
26
|
+
schema: { id: t.string(), timestamp: t.dateTime() },
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const project = defineProject({
|
|
30
|
+
datasources: { events },
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(project.datasources.events).toBe(events);
|
|
34
|
+
expect(project.pipes).toEqual({});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("creates a project with pipes", () => {
|
|
38
|
+
const topEvents = definePipe("top_events", {
|
|
39
|
+
nodes: [node({ name: "endpoint", sql: "SELECT 1" })],
|
|
40
|
+
output: { count: t.int64() },
|
|
41
|
+
endpoint: true,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const project = defineProject({
|
|
45
|
+
pipes: { topEvents },
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(project.pipes.topEvents).toBe(topEvents);
|
|
49
|
+
expect(project.datasources).toEqual({});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("creates a project with both datasources and pipes", () => {
|
|
53
|
+
const events = defineDatasource("events", {
|
|
54
|
+
schema: { id: t.string() },
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const topEvents = definePipe("top_events", {
|
|
58
|
+
nodes: [node({ name: "endpoint", sql: "SELECT 1" })],
|
|
59
|
+
output: { count: t.int64() },
|
|
60
|
+
endpoint: true,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const project = defineProject({
|
|
64
|
+
datasources: { events },
|
|
65
|
+
pipes: { topEvents },
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
expect(project.datasources.events).toBe(events);
|
|
69
|
+
expect(project.pipes.topEvents).toBe(topEvents);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("creates tinybird client with query and ingest methods", () => {
|
|
73
|
+
const events = defineDatasource("events", {
|
|
74
|
+
schema: { id: t.string() },
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const topEvents = definePipe("top_events", {
|
|
78
|
+
nodes: [node({ name: "endpoint", sql: "SELECT 1" })],
|
|
79
|
+
output: { count: t.int64() },
|
|
80
|
+
endpoint: true,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const project = defineProject({
|
|
84
|
+
datasources: { events },
|
|
85
|
+
pipes: { topEvents },
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(project.tinybird.query).toBeDefined();
|
|
89
|
+
expect(project.tinybird.ingest).toBeDefined();
|
|
90
|
+
expect(typeof project.tinybird.query.topEvents).toBe("function");
|
|
91
|
+
expect(typeof project.tinybird.ingest.events).toBe("function");
|
|
92
|
+
expect(typeof project.tinybird.ingest.eventsBatch).toBe("function");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("throws error when accessing client before initialization", () => {
|
|
96
|
+
const project = defineProject({});
|
|
97
|
+
|
|
98
|
+
expect(() => project.tinybird.client).toThrow(
|
|
99
|
+
"Client not initialized"
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("creates stub for non-endpoint pipes that throws clear error", async () => {
|
|
104
|
+
const internalPipe = definePipe("internal_pipe", {
|
|
105
|
+
nodes: [node({ name: "endpoint", sql: "SELECT 1" })],
|
|
106
|
+
output: { count: t.int64() },
|
|
107
|
+
endpoint: false,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const project = defineProject({
|
|
111
|
+
pipes: { internalPipe },
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Cast to any since the type system expects params but stub throws regardless
|
|
115
|
+
const queryFn = project.tinybird.query.internalPipe as () => Promise<unknown>;
|
|
116
|
+
await expect(queryFn()).rejects.toThrow(
|
|
117
|
+
'Pipe "internalPipe" is not exposed as an endpoint'
|
|
118
|
+
);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("isProjectDefinition", () => {
|
|
123
|
+
it("returns true for valid project", () => {
|
|
124
|
+
const project = defineProject({});
|
|
125
|
+
|
|
126
|
+
expect(isProjectDefinition(project)).toBe(true);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("returns false for non-project objects", () => {
|
|
130
|
+
expect(isProjectDefinition({})).toBe(false);
|
|
131
|
+
expect(isProjectDefinition(null)).toBe(false);
|
|
132
|
+
expect(isProjectDefinition(undefined)).toBe(false);
|
|
133
|
+
expect(isProjectDefinition("string")).toBe(false);
|
|
134
|
+
expect(isProjectDefinition(123)).toBe(false);
|
|
135
|
+
expect(isProjectDefinition({ _type: "project" })).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
describe("getDatasourceNames", () => {
|
|
140
|
+
it("returns all datasource names", () => {
|
|
141
|
+
const events = defineDatasource("events", {
|
|
142
|
+
schema: { id: t.string() },
|
|
143
|
+
});
|
|
144
|
+
const users = defineDatasource("users", {
|
|
145
|
+
schema: { id: t.string() },
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const project = defineProject({
|
|
149
|
+
datasources: { events, users },
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const names = getDatasourceNames(project);
|
|
153
|
+
|
|
154
|
+
expect(names).toHaveLength(2);
|
|
155
|
+
expect(names).toContain("events");
|
|
156
|
+
expect(names).toContain("users");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("returns empty array for project with no datasources", () => {
|
|
160
|
+
const project = defineProject({});
|
|
161
|
+
|
|
162
|
+
const names = getDatasourceNames(project);
|
|
163
|
+
|
|
164
|
+
expect(names).toHaveLength(0);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe("getPipeNames", () => {
|
|
169
|
+
it("returns all pipe names", () => {
|
|
170
|
+
const topEvents = definePipe("top_events", {
|
|
171
|
+
nodes: [node({ name: "endpoint", sql: "SELECT 1" })],
|
|
172
|
+
output: { count: t.int64() },
|
|
173
|
+
endpoint: true,
|
|
174
|
+
});
|
|
175
|
+
const userActivity = definePipe("user_activity", {
|
|
176
|
+
nodes: [node({ name: "endpoint", sql: "SELECT 2" })],
|
|
177
|
+
output: { count: t.int64() },
|
|
178
|
+
endpoint: true,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const project = defineProject({
|
|
182
|
+
pipes: { topEvents, userActivity },
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const names = getPipeNames(project);
|
|
186
|
+
|
|
187
|
+
expect(names).toHaveLength(2);
|
|
188
|
+
expect(names).toContain("topEvents");
|
|
189
|
+
expect(names).toContain("userActivity");
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("returns empty array for project with no pipes", () => {
|
|
193
|
+
const project = defineProject({});
|
|
194
|
+
|
|
195
|
+
const names = getPipeNames(project);
|
|
196
|
+
|
|
197
|
+
expect(names).toHaveLength(0);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe("getDatasource", () => {
|
|
202
|
+
it("returns datasource by name", () => {
|
|
203
|
+
const events = defineDatasource("events", {
|
|
204
|
+
schema: { id: t.string() },
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const project = defineProject({
|
|
208
|
+
datasources: { events },
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const retrieved = getDatasource(project, "events");
|
|
212
|
+
|
|
213
|
+
expect(retrieved).toBe(events);
|
|
214
|
+
expect(retrieved._name).toBe("events");
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
describe("getPipe", () => {
|
|
219
|
+
it("returns pipe by name", () => {
|
|
220
|
+
const topEvents = definePipe("top_events", {
|
|
221
|
+
nodes: [node({ name: "endpoint", sql: "SELECT 1" })],
|
|
222
|
+
output: { count: t.int64() },
|
|
223
|
+
endpoint: true,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
const project = defineProject({
|
|
227
|
+
pipes: { topEvents },
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const retrieved = getPipe(project, "topEvents");
|
|
231
|
+
|
|
232
|
+
expect(retrieved).toBe(topEvents);
|
|
233
|
+
expect(retrieved._name).toBe("top_events");
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
});
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project definition for Tinybird
|
|
3
|
+
* Aggregates all datasources and pipes into a single schema
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { DatasourceDefinition, SchemaDefinition } from "./datasource.js";
|
|
7
|
+
import type { PipeDefinition, ParamsDefinition, OutputDefinition } from "./pipe.js";
|
|
8
|
+
import { getEndpointConfig } from "./pipe.js";
|
|
9
|
+
import type { TinybirdClient } from "../client/base.js";
|
|
10
|
+
import type { QueryResult } from "../client/types.js";
|
|
11
|
+
import type { InferRow, InferParams, InferOutputRow } from "../infer/index.js";
|
|
12
|
+
|
|
13
|
+
// Symbol for brand typing
|
|
14
|
+
const PROJECT_BRAND = Symbol("tinybird.project");
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Collection of datasource definitions
|
|
18
|
+
*/
|
|
19
|
+
export type DatasourcesDefinition = Record<string, DatasourceDefinition<SchemaDefinition>>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Collection of pipe definitions
|
|
23
|
+
*/
|
|
24
|
+
export type PipesDefinition = Record<string, PipeDefinition<ParamsDefinition, OutputDefinition>>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Type for a single query method
|
|
28
|
+
*/
|
|
29
|
+
type QueryMethod<T extends PipeDefinition<ParamsDefinition, OutputDefinition>> =
|
|
30
|
+
T extends PipeDefinition<infer P, OutputDefinition>
|
|
31
|
+
? keyof P extends never
|
|
32
|
+
? () => Promise<QueryResult<InferOutputRow<T>>>
|
|
33
|
+
: (params: InferParams<T>) => Promise<QueryResult<InferOutputRow<T>>>
|
|
34
|
+
: never;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Type for query methods object
|
|
38
|
+
* Note: At runtime, only pipes with endpoint: true are included
|
|
39
|
+
*/
|
|
40
|
+
type QueryMethods<T extends PipesDefinition> = {
|
|
41
|
+
[K in keyof T]: QueryMethod<T[K]>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Type for a single ingest method
|
|
46
|
+
*/
|
|
47
|
+
type IngestMethod<T extends DatasourceDefinition<SchemaDefinition>> = (
|
|
48
|
+
event: InferRow<T>
|
|
49
|
+
) => Promise<void>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Type for a batch ingest method
|
|
53
|
+
*/
|
|
54
|
+
type IngestBatchMethod<T extends DatasourceDefinition<SchemaDefinition>> = (
|
|
55
|
+
events: InferRow<T>[]
|
|
56
|
+
) => Promise<void>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Type for ingest methods object
|
|
60
|
+
*/
|
|
61
|
+
type IngestMethods<T extends DatasourcesDefinition> = {
|
|
62
|
+
[K in keyof T]: IngestMethod<T[K]>;
|
|
63
|
+
} & {
|
|
64
|
+
[K in keyof T as `${K & string}Batch`]: IngestBatchMethod<T[K]>;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Typed client interface for a project
|
|
69
|
+
*/
|
|
70
|
+
export interface ProjectClient<
|
|
71
|
+
TDatasources extends DatasourcesDefinition,
|
|
72
|
+
TPipes extends PipesDefinition
|
|
73
|
+
> {
|
|
74
|
+
/** Query endpoint pipes */
|
|
75
|
+
query: QueryMethods<TPipes>;
|
|
76
|
+
/** Ingest events to datasources */
|
|
77
|
+
ingest: IngestMethods<TDatasources>;
|
|
78
|
+
/** Raw client for advanced usage */
|
|
79
|
+
readonly client: TinybirdClient;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Configuration for createTinybirdClient
|
|
84
|
+
*/
|
|
85
|
+
export interface TinybirdClientConfig<
|
|
86
|
+
TDatasources extends DatasourcesDefinition = DatasourcesDefinition,
|
|
87
|
+
TPipes extends PipesDefinition = PipesDefinition
|
|
88
|
+
> {
|
|
89
|
+
/** All datasources */
|
|
90
|
+
datasources: TDatasources;
|
|
91
|
+
/** All pipes */
|
|
92
|
+
pipes: TPipes;
|
|
93
|
+
/** Tinybird API base URL (defaults to TINYBIRD_URL env var or https://api.tinybird.co) */
|
|
94
|
+
baseUrl?: string;
|
|
95
|
+
/** Tinybird API token (defaults to TINYBIRD_TOKEN env var) */
|
|
96
|
+
token?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Project configuration
|
|
101
|
+
*/
|
|
102
|
+
export interface ProjectConfig<
|
|
103
|
+
TDatasources extends DatasourcesDefinition = DatasourcesDefinition,
|
|
104
|
+
TPipes extends PipesDefinition = PipesDefinition
|
|
105
|
+
> {
|
|
106
|
+
/** All datasources in this project */
|
|
107
|
+
datasources?: TDatasources;
|
|
108
|
+
/** All pipes in this project */
|
|
109
|
+
pipes?: TPipes;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* A project definition with full type information
|
|
114
|
+
*/
|
|
115
|
+
export interface ProjectDefinition<
|
|
116
|
+
TDatasources extends DatasourcesDefinition = DatasourcesDefinition,
|
|
117
|
+
TPipes extends PipesDefinition = PipesDefinition
|
|
118
|
+
> {
|
|
119
|
+
readonly [PROJECT_BRAND]: true;
|
|
120
|
+
/** Type marker for inference */
|
|
121
|
+
readonly _type: "project";
|
|
122
|
+
/** All datasources */
|
|
123
|
+
readonly datasources: TDatasources;
|
|
124
|
+
/** All pipes */
|
|
125
|
+
readonly pipes: TPipes;
|
|
126
|
+
/** Typed Tinybird client */
|
|
127
|
+
readonly tinybird: ProjectClient<TDatasources, TPipes>;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Define a Tinybird project
|
|
132
|
+
*
|
|
133
|
+
* This aggregates all datasources and pipes into a single schema definition
|
|
134
|
+
* that can be used for code generation and type inference.
|
|
135
|
+
*
|
|
136
|
+
* @param config - Project configuration with datasources and pipes
|
|
137
|
+
* @returns A project definition
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```ts
|
|
141
|
+
* // tinybird/schema.ts
|
|
142
|
+
* import { defineProject } from '@tinybirdco/sdk';
|
|
143
|
+
* import { events, users } from './datasources';
|
|
144
|
+
* import { topEvents, userActivity } from './pipes';
|
|
145
|
+
*
|
|
146
|
+
* export default defineProject({
|
|
147
|
+
* datasources: {
|
|
148
|
+
* events,
|
|
149
|
+
* users,
|
|
150
|
+
* },
|
|
151
|
+
* pipes: {
|
|
152
|
+
* topEvents,
|
|
153
|
+
* userActivity,
|
|
154
|
+
* },
|
|
155
|
+
* });
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export function defineProject<
|
|
159
|
+
TDatasources extends DatasourcesDefinition,
|
|
160
|
+
TPipes extends PipesDefinition
|
|
161
|
+
>(
|
|
162
|
+
config: ProjectConfig<TDatasources, TPipes>
|
|
163
|
+
): ProjectDefinition<TDatasources, TPipes> {
|
|
164
|
+
const datasources = (config.datasources ?? {}) as TDatasources;
|
|
165
|
+
const pipes = (config.pipes ?? {}) as TPipes;
|
|
166
|
+
|
|
167
|
+
// Use the shared client builder
|
|
168
|
+
const tinybird = buildProjectClient(datasources, pipes);
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
[PROJECT_BRAND]: true,
|
|
172
|
+
_type: "project",
|
|
173
|
+
datasources,
|
|
174
|
+
pipes,
|
|
175
|
+
tinybird,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Check if a value is a project definition
|
|
181
|
+
*/
|
|
182
|
+
export function isProjectDefinition(value: unknown): value is ProjectDefinition {
|
|
183
|
+
return (
|
|
184
|
+
typeof value === "object" &&
|
|
185
|
+
value !== null &&
|
|
186
|
+
PROJECT_BRAND in value &&
|
|
187
|
+
(value as Record<symbol, unknown>)[PROJECT_BRAND] === true
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Build a typed Tinybird client from datasources and pipes
|
|
193
|
+
*
|
|
194
|
+
* This is an internal helper that builds query/ingest methods.
|
|
195
|
+
*/
|
|
196
|
+
function buildProjectClient<
|
|
197
|
+
TDatasources extends DatasourcesDefinition,
|
|
198
|
+
TPipes extends PipesDefinition
|
|
199
|
+
>(
|
|
200
|
+
datasources: TDatasources,
|
|
201
|
+
pipes: TPipes,
|
|
202
|
+
options?: { baseUrl?: string; token?: string }
|
|
203
|
+
): ProjectClient<TDatasources, TPipes> {
|
|
204
|
+
// Lazy client initialization
|
|
205
|
+
let _client: TinybirdClient | null = null;
|
|
206
|
+
|
|
207
|
+
const getClient = async (): Promise<TinybirdClient> => {
|
|
208
|
+
if (!_client) {
|
|
209
|
+
// Dynamic import to avoid circular dependencies
|
|
210
|
+
const { createClient } = await import("../client/base.js");
|
|
211
|
+
_client = createClient({
|
|
212
|
+
baseUrl: options?.baseUrl ?? process.env.TINYBIRD_URL ?? "https://api.tinybird.co",
|
|
213
|
+
token: options?.token ?? process.env.TINYBIRD_TOKEN!,
|
|
214
|
+
devMode: process.env.NODE_ENV === "development",
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
return _client;
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
// Build query methods for pipes
|
|
221
|
+
const queryMethods: Record<string, (params?: unknown) => Promise<unknown>> = {};
|
|
222
|
+
for (const [name, pipe] of Object.entries(pipes)) {
|
|
223
|
+
const endpointConfig = getEndpointConfig(pipe);
|
|
224
|
+
|
|
225
|
+
if (!endpointConfig) {
|
|
226
|
+
// Non-endpoint pipes get a stub that throws a clear error
|
|
227
|
+
queryMethods[name] = async () => {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Pipe "${name}" is not exposed as an endpoint. ` +
|
|
230
|
+
`Set "endpoint: true" in the pipe definition to enable querying.`
|
|
231
|
+
);
|
|
232
|
+
};
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Use the Tinybird pipe name (snake_case)
|
|
237
|
+
const tinybirdName = pipe._name;
|
|
238
|
+
queryMethods[name] = async (params?: unknown) => {
|
|
239
|
+
const client = await getClient();
|
|
240
|
+
return client.query(tinybirdName, (params ?? {}) as Record<string, unknown>);
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Build ingest methods for datasources
|
|
245
|
+
const ingestMethods: Record<string, (data: unknown) => Promise<void>> = {};
|
|
246
|
+
for (const [name, datasource] of Object.entries(datasources)) {
|
|
247
|
+
// Use the Tinybird datasource name (snake_case)
|
|
248
|
+
const tinybirdName = datasource._name;
|
|
249
|
+
|
|
250
|
+
// Single event ingest
|
|
251
|
+
ingestMethods[name] = async (event: unknown) => {
|
|
252
|
+
const client = await getClient();
|
|
253
|
+
await client.ingest(tinybirdName, event as Record<string, unknown>);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// Batch ingest
|
|
257
|
+
ingestMethods[`${name}Batch`] = async (events: unknown) => {
|
|
258
|
+
const client = await getClient();
|
|
259
|
+
await client.ingestBatch(tinybirdName, events as Record<string, unknown>[]);
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Create the typed client object
|
|
264
|
+
return {
|
|
265
|
+
query: queryMethods,
|
|
266
|
+
ingest: ingestMethods,
|
|
267
|
+
get client(): TinybirdClient {
|
|
268
|
+
// Synchronous client access - will throw if not initialized
|
|
269
|
+
if (!_client) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
"Client not initialized. Call a query or ingest method first, or access client asynchronously."
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
return _client;
|
|
275
|
+
},
|
|
276
|
+
} as ProjectClient<TDatasources, TPipes>;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Create a typed Tinybird client
|
|
281
|
+
*
|
|
282
|
+
* Creates a client with typed query and ingest methods based on the provided
|
|
283
|
+
* datasources and pipes. This is the recommended way to create a Tinybird client
|
|
284
|
+
* when using the SDK's auto-generated client file.
|
|
285
|
+
*
|
|
286
|
+
* @param config - Client configuration with datasources and pipes
|
|
287
|
+
* @returns A typed client with query and ingest methods
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* import { createTinybirdClient } from '@tinybirdco/sdk';
|
|
292
|
+
* import { pageViews, events } from './datasources';
|
|
293
|
+
* import { topPages } from './pipes';
|
|
294
|
+
*
|
|
295
|
+
* export const tinybird = createTinybirdClient({
|
|
296
|
+
* datasources: { pageViews, events },
|
|
297
|
+
* pipes: { topPages },
|
|
298
|
+
* });
|
|
299
|
+
*
|
|
300
|
+
* // Query a pipe (fully typed)
|
|
301
|
+
* const result = await tinybird.query.topPages({
|
|
302
|
+
* start_date: new Date('2024-01-01'),
|
|
303
|
+
* end_date: new Date('2024-01-31'),
|
|
304
|
+
* });
|
|
305
|
+
*
|
|
306
|
+
* // Ingest an event (fully typed)
|
|
307
|
+
* await tinybird.ingest.pageViews({
|
|
308
|
+
* timestamp: new Date(),
|
|
309
|
+
* pathname: '/home',
|
|
310
|
+
* session_id: 'abc123',
|
|
311
|
+
* });
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
export function createTinybirdClient<
|
|
315
|
+
TDatasources extends DatasourcesDefinition,
|
|
316
|
+
TPipes extends PipesDefinition
|
|
317
|
+
>(
|
|
318
|
+
config: TinybirdClientConfig<TDatasources, TPipes>
|
|
319
|
+
): ProjectClient<TDatasources, TPipes> {
|
|
320
|
+
return buildProjectClient(
|
|
321
|
+
config.datasources,
|
|
322
|
+
config.pipes,
|
|
323
|
+
{ baseUrl: config.baseUrl, token: config.token }
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Get all datasource names from a project
|
|
329
|
+
*/
|
|
330
|
+
export function getDatasourceNames<T extends ProjectDefinition>(
|
|
331
|
+
project: T
|
|
332
|
+
): (keyof T["datasources"])[] {
|
|
333
|
+
return Object.keys(project.datasources) as (keyof T["datasources"])[];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Get all pipe names from a project
|
|
338
|
+
*/
|
|
339
|
+
export function getPipeNames<T extends ProjectDefinition>(project: T): (keyof T["pipes"])[] {
|
|
340
|
+
return Object.keys(project.pipes) as (keyof T["pipes"])[];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Get a datasource by name from a project
|
|
345
|
+
*/
|
|
346
|
+
export function getDatasource<
|
|
347
|
+
TDatasources extends DatasourcesDefinition,
|
|
348
|
+
TPipes extends PipesDefinition,
|
|
349
|
+
K extends keyof TDatasources
|
|
350
|
+
>(project: ProjectDefinition<TDatasources, TPipes>, name: K): TDatasources[K] {
|
|
351
|
+
return project.datasources[name];
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Get a pipe by name from a project
|
|
356
|
+
*/
|
|
357
|
+
export function getPipe<
|
|
358
|
+
TDatasources extends DatasourcesDefinition,
|
|
359
|
+
TPipes extends PipesDefinition,
|
|
360
|
+
K extends keyof TPipes
|
|
361
|
+
>(project: ProjectDefinition<TDatasources, TPipes>, name: K): TPipes[K] {
|
|
362
|
+
return project.pipes[name];
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Helper type to extract datasources from a project
|
|
367
|
+
*/
|
|
368
|
+
export type ExtractDatasources<T> = T extends ProjectDefinition<infer D, PipesDefinition>
|
|
369
|
+
? D
|
|
370
|
+
: never;
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Helper type to extract pipes from a project
|
|
374
|
+
*/
|
|
375
|
+
export type ExtractPipes<T> = T extends ProjectDefinition<DatasourcesDefinition, infer P>
|
|
376
|
+
? P
|
|
377
|
+
: never;
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Data model type derived from a project
|
|
381
|
+
* Useful for generating typed clients
|
|
382
|
+
*/
|
|
383
|
+
export type DataModel<T extends ProjectDefinition> = {
|
|
384
|
+
datasources: {
|
|
385
|
+
[K in keyof T["datasources"]]: T["datasources"][K] extends DatasourceDefinition<infer S>
|
|
386
|
+
? S
|
|
387
|
+
: never;
|
|
388
|
+
};
|
|
389
|
+
pipes: {
|
|
390
|
+
[K in keyof T["pipes"]]: T["pipes"][K] extends PipeDefinition<infer P, infer O>
|
|
391
|
+
? { params: P; output: O }
|
|
392
|
+
: never;
|
|
393
|
+
};
|
|
394
|
+
};
|