@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,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema loader using esbuild
|
|
3
|
+
* Bundles and executes TypeScript schema files at runtime
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as esbuild from "esbuild";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import { watch as chokidarWatch, type FSWatcher } from "chokidar";
|
|
10
|
+
import { isProjectDefinition, type ProjectDefinition, type DatasourcesDefinition, type PipesDefinition } from "../schema/project.js";
|
|
11
|
+
import { isDatasourceDefinition, type DatasourceDefinition } from "../schema/datasource.js";
|
|
12
|
+
import { isPipeDefinition, type PipeDefinition } from "../schema/pipe.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Result of loading a schema file
|
|
16
|
+
*/
|
|
17
|
+
export interface LoadedSchema {
|
|
18
|
+
/** The loaded project definition */
|
|
19
|
+
project: ProjectDefinition;
|
|
20
|
+
/** The resolved path to the schema file */
|
|
21
|
+
schemaPath: string;
|
|
22
|
+
/** The directory containing the schema */
|
|
23
|
+
schemaDir: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Options for the schema loader
|
|
28
|
+
*/
|
|
29
|
+
export interface LoaderOptions {
|
|
30
|
+
/** The path to the schema file (can be relative or absolute) */
|
|
31
|
+
schemaPath: string;
|
|
32
|
+
/** The working directory for resolution (defaults to cwd) */
|
|
33
|
+
cwd?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Load and execute a TypeScript schema file
|
|
38
|
+
*
|
|
39
|
+
* Uses esbuild to bundle the schema and its dependencies,
|
|
40
|
+
* then dynamically imports the bundle to get the ProjectDefinition.
|
|
41
|
+
*
|
|
42
|
+
* @param options - Loader options
|
|
43
|
+
* @returns The loaded project definition
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const { project } = await loadSchema({
|
|
48
|
+
* schemaPath: 'src/tinybird/schema.ts',
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* console.log(project.datasources);
|
|
52
|
+
* console.log(project.pipes);
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export async function loadSchema(options: LoaderOptions): Promise<LoadedSchema> {
|
|
56
|
+
const cwd = options.cwd ?? process.cwd();
|
|
57
|
+
const schemaPath = path.isAbsolute(options.schemaPath)
|
|
58
|
+
? options.schemaPath
|
|
59
|
+
: path.resolve(cwd, options.schemaPath);
|
|
60
|
+
|
|
61
|
+
// Verify the file exists
|
|
62
|
+
if (!fs.existsSync(schemaPath)) {
|
|
63
|
+
throw new Error(`Schema file not found: ${schemaPath}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const schemaDir = path.dirname(schemaPath);
|
|
67
|
+
|
|
68
|
+
// Create a temporary output file for the bundle
|
|
69
|
+
const outfile = path.join(
|
|
70
|
+
schemaDir,
|
|
71
|
+
`.tinybird-schema-${Date.now()}.mjs`
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
// Bundle the schema with esbuild
|
|
76
|
+
await esbuild.build({
|
|
77
|
+
entryPoints: [schemaPath],
|
|
78
|
+
outfile,
|
|
79
|
+
bundle: true,
|
|
80
|
+
platform: "node",
|
|
81
|
+
format: "esm",
|
|
82
|
+
target: "node18",
|
|
83
|
+
// Mark @tinybirdco/sdk as external - it should already be installed
|
|
84
|
+
external: ["@tinybirdco/sdk"],
|
|
85
|
+
// Enable source maps for better error messages
|
|
86
|
+
sourcemap: "inline",
|
|
87
|
+
// Minify is off for debugging
|
|
88
|
+
minify: false,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Import the bundled module
|
|
92
|
+
const moduleUrl = `file://${outfile}`;
|
|
93
|
+
const module = await import(moduleUrl);
|
|
94
|
+
|
|
95
|
+
// Look for the project definition
|
|
96
|
+
// It can be the default export or a named 'project' export
|
|
97
|
+
let project: ProjectDefinition | undefined;
|
|
98
|
+
|
|
99
|
+
if (module.default && isProjectDefinition(module.default)) {
|
|
100
|
+
project = module.default;
|
|
101
|
+
} else if (module.project && isProjectDefinition(module.project)) {
|
|
102
|
+
project = module.project;
|
|
103
|
+
} else {
|
|
104
|
+
// Check all exports for a project definition
|
|
105
|
+
for (const key of Object.keys(module)) {
|
|
106
|
+
if (isProjectDefinition(module[key])) {
|
|
107
|
+
project = module[key];
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!project) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`No ProjectDefinition found in ${schemaPath}. ` +
|
|
116
|
+
`Make sure to export a project created with defineProject().`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
project,
|
|
122
|
+
schemaPath,
|
|
123
|
+
schemaDir,
|
|
124
|
+
};
|
|
125
|
+
} finally {
|
|
126
|
+
// Clean up the temporary bundle file
|
|
127
|
+
try {
|
|
128
|
+
if (fs.existsSync(outfile)) {
|
|
129
|
+
fs.unlinkSync(outfile);
|
|
130
|
+
}
|
|
131
|
+
// Also clean up the source map if it was created separately
|
|
132
|
+
const sourcemapFile = outfile + ".map";
|
|
133
|
+
if (fs.existsSync(sourcemapFile)) {
|
|
134
|
+
fs.unlinkSync(sourcemapFile);
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
// Ignore cleanup errors
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Information about an entity discovered from a source file
|
|
144
|
+
*/
|
|
145
|
+
export interface EntityInfo {
|
|
146
|
+
/** The export name used in the source file */
|
|
147
|
+
exportName: string;
|
|
148
|
+
/** The source file path (relative to cwd) */
|
|
149
|
+
sourceFile: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Result of loading entities from multiple files
|
|
154
|
+
*/
|
|
155
|
+
export interface LoadedEntities {
|
|
156
|
+
/** Discovered datasources with their metadata */
|
|
157
|
+
datasources: Record<string, { definition: DatasourceDefinition; info: EntityInfo }>;
|
|
158
|
+
/** Discovered pipes with their metadata */
|
|
159
|
+
pipes: Record<string, { definition: PipeDefinition; info: EntityInfo }>;
|
|
160
|
+
/** All source files that were scanned */
|
|
161
|
+
sourceFiles: string[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Options for loading entities
|
|
166
|
+
*/
|
|
167
|
+
export interface LoadEntitiesOptions {
|
|
168
|
+
/** Array of file paths to scan (can be relative or absolute) */
|
|
169
|
+
includePaths: string[];
|
|
170
|
+
/** The working directory for resolution (defaults to cwd) */
|
|
171
|
+
cwd?: string;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Load datasources and pipes from multiple TypeScript files
|
|
176
|
+
*
|
|
177
|
+
* Uses esbuild to bundle each file and scans exports for datasource
|
|
178
|
+
* and pipe definitions.
|
|
179
|
+
*
|
|
180
|
+
* @param options - Loader options
|
|
181
|
+
* @returns Discovered entities with metadata
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```ts
|
|
185
|
+
* const entities = await loadEntities({
|
|
186
|
+
* includePaths: ['src/datasources.ts', 'src/pipes.ts'],
|
|
187
|
+
* });
|
|
188
|
+
*
|
|
189
|
+
* console.log(Object.keys(entities.datasources)); // ['pageViews', 'events']
|
|
190
|
+
* console.log(Object.keys(entities.pipes)); // ['topPages', 'topEvents']
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export async function loadEntities(options: LoadEntitiesOptions): Promise<LoadedEntities> {
|
|
194
|
+
const cwd = options.cwd ?? process.cwd();
|
|
195
|
+
const result: LoadedEntities = {
|
|
196
|
+
datasources: {},
|
|
197
|
+
pipes: {},
|
|
198
|
+
sourceFiles: [],
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
for (const includePath of options.includePaths) {
|
|
202
|
+
const absolutePath = path.isAbsolute(includePath)
|
|
203
|
+
? includePath
|
|
204
|
+
: path.resolve(cwd, includePath);
|
|
205
|
+
|
|
206
|
+
// Verify the file exists
|
|
207
|
+
if (!fs.existsSync(absolutePath)) {
|
|
208
|
+
throw new Error(`Include file not found: ${absolutePath}`);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
result.sourceFiles.push(includePath);
|
|
212
|
+
const fileDir = path.dirname(absolutePath);
|
|
213
|
+
|
|
214
|
+
// Create a temporary output file for the bundle
|
|
215
|
+
const outfile = path.join(
|
|
216
|
+
fileDir,
|
|
217
|
+
`.tinybird-entities-${Date.now()}.mjs`
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
// Bundle the file with esbuild
|
|
222
|
+
await esbuild.build({
|
|
223
|
+
entryPoints: [absolutePath],
|
|
224
|
+
outfile,
|
|
225
|
+
bundle: true,
|
|
226
|
+
platform: "node",
|
|
227
|
+
format: "esm",
|
|
228
|
+
target: "node18",
|
|
229
|
+
// Mark @tinybirdco/sdk as external - it should already be installed
|
|
230
|
+
external: ["@tinybirdco/sdk"],
|
|
231
|
+
// Enable source maps for better error messages
|
|
232
|
+
sourcemap: "inline",
|
|
233
|
+
minify: false,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Import the bundled module
|
|
237
|
+
const moduleUrl = `file://${outfile}`;
|
|
238
|
+
const module = await import(moduleUrl);
|
|
239
|
+
|
|
240
|
+
// Scan all exports for datasources and pipes
|
|
241
|
+
for (const [exportName, value] of Object.entries(module)) {
|
|
242
|
+
if (isDatasourceDefinition(value)) {
|
|
243
|
+
result.datasources[exportName] = {
|
|
244
|
+
definition: value,
|
|
245
|
+
info: {
|
|
246
|
+
exportName,
|
|
247
|
+
sourceFile: includePath,
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
} else if (isPipeDefinition(value)) {
|
|
251
|
+
result.pipes[exportName] = {
|
|
252
|
+
definition: value,
|
|
253
|
+
info: {
|
|
254
|
+
exportName,
|
|
255
|
+
sourceFile: includePath,
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
} finally {
|
|
261
|
+
// Clean up the temporary bundle file
|
|
262
|
+
try {
|
|
263
|
+
if (fs.existsSync(outfile)) {
|
|
264
|
+
fs.unlinkSync(outfile);
|
|
265
|
+
}
|
|
266
|
+
const sourcemapFile = outfile + ".map";
|
|
267
|
+
if (fs.existsSync(sourcemapFile)) {
|
|
268
|
+
fs.unlinkSync(sourcemapFile);
|
|
269
|
+
}
|
|
270
|
+
} catch {
|
|
271
|
+
// Ignore cleanup errors
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Convert loaded entities to a format compatible with generators
|
|
281
|
+
*/
|
|
282
|
+
export function entitiesToProject(entities: LoadedEntities): {
|
|
283
|
+
datasources: DatasourcesDefinition;
|
|
284
|
+
pipes: PipesDefinition;
|
|
285
|
+
} {
|
|
286
|
+
const datasources: DatasourcesDefinition = {};
|
|
287
|
+
const pipes: PipesDefinition = {};
|
|
288
|
+
|
|
289
|
+
for (const [name, { definition }] of Object.entries(entities.datasources)) {
|
|
290
|
+
datasources[name] = definition;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
for (const [name, { definition }] of Object.entries(entities.pipes)) {
|
|
294
|
+
pipes[name] = definition;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return { datasources, pipes };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Watch options for the schema loader
|
|
302
|
+
*/
|
|
303
|
+
export interface WatchOptions extends LoaderOptions {
|
|
304
|
+
/** Callback when the schema changes */
|
|
305
|
+
onChange: (result: LoadedSchema) => void | Promise<void>;
|
|
306
|
+
/** Callback when there's an error loading the schema */
|
|
307
|
+
onError?: (error: Error) => void;
|
|
308
|
+
/** Debounce delay in milliseconds (default: 100) */
|
|
309
|
+
debounce?: number;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Schema watcher controller
|
|
314
|
+
*/
|
|
315
|
+
export interface SchemaWatcher {
|
|
316
|
+
/** Stop watching for changes */
|
|
317
|
+
close: () => Promise<void>;
|
|
318
|
+
/** The initial loaded schema */
|
|
319
|
+
initialSchema: LoadedSchema;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Watch a TypeScript schema file for changes
|
|
324
|
+
*
|
|
325
|
+
* Performs an initial load, then watches for file changes and reloads.
|
|
326
|
+
* Uses debouncing to coalesce rapid file system events.
|
|
327
|
+
*
|
|
328
|
+
* @param options - Watch options
|
|
329
|
+
* @returns A controller to stop watching
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```ts
|
|
333
|
+
* const watcher = await watchSchema({
|
|
334
|
+
* schemaPath: 'src/tinybird/schema.ts',
|
|
335
|
+
* onChange: (schema) => {
|
|
336
|
+
* console.log('Schema updated:', schema.project);
|
|
337
|
+
* },
|
|
338
|
+
* onError: (err) => {
|
|
339
|
+
* console.error('Load error:', err.message);
|
|
340
|
+
* },
|
|
341
|
+
* });
|
|
342
|
+
*
|
|
343
|
+
* // Later, stop watching
|
|
344
|
+
* await watcher.close();
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
export async function watchSchema(options: WatchOptions): Promise<SchemaWatcher> {
|
|
348
|
+
const debounceMs = options.debounce ?? 100;
|
|
349
|
+
|
|
350
|
+
// Perform initial load
|
|
351
|
+
const initialSchema = await loadSchema(options);
|
|
352
|
+
|
|
353
|
+
const schemaPath = initialSchema.schemaPath;
|
|
354
|
+
const schemaDir = initialSchema.schemaDir;
|
|
355
|
+
|
|
356
|
+
// Set up debounced reload
|
|
357
|
+
let debounceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
358
|
+
|
|
359
|
+
const reload = async () => {
|
|
360
|
+
try {
|
|
361
|
+
const result = await loadSchema(options);
|
|
362
|
+
await options.onChange(result);
|
|
363
|
+
} catch (error) {
|
|
364
|
+
if (options.onError) {
|
|
365
|
+
options.onError(error as Error);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
const debouncedReload = () => {
|
|
371
|
+
if (debounceTimer) {
|
|
372
|
+
clearTimeout(debounceTimer);
|
|
373
|
+
}
|
|
374
|
+
debounceTimer = setTimeout(() => {
|
|
375
|
+
debounceTimer = null;
|
|
376
|
+
reload().catch((error) => {
|
|
377
|
+
if (options.onError) {
|
|
378
|
+
options.onError(error as Error);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}, debounceMs);
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// Watch the schema file and its directory for TypeScript files
|
|
385
|
+
const watcher: FSWatcher = chokidarWatch([schemaPath, path.join(schemaDir, "**/*.ts")], {
|
|
386
|
+
ignoreInitial: true,
|
|
387
|
+
ignored: [
|
|
388
|
+
/node_modules/,
|
|
389
|
+
/\.tinybird-schema-.*\.mjs$/,
|
|
390
|
+
],
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
watcher.on("change", debouncedReload);
|
|
394
|
+
watcher.on("add", debouncedReload);
|
|
395
|
+
watcher.on("unlink", debouncedReload);
|
|
396
|
+
|
|
397
|
+
return {
|
|
398
|
+
close: async () => {
|
|
399
|
+
if (debounceTimer) {
|
|
400
|
+
clearTimeout(debounceTimer);
|
|
401
|
+
}
|
|
402
|
+
await watcher.close();
|
|
403
|
+
},
|
|
404
|
+
initialSchema,
|
|
405
|
+
};
|
|
406
|
+
}
|