@hypequery/cli 1.22.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +77 -12
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +20 -15
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +25 -5
- package/dist/commands/generate-datasets.d.ts +0 -6
- package/dist/commands/generate-datasets.d.ts.map +1 -1
- package/dist/commands/generate-datasets.js +17 -1
- package/dist/commands/generate-manifest.d.ts.map +1 -1
- package/dist/commands/generate-manifest.js +4 -0
- package/dist/commands/generate.d.ts.map +1 -1
- package/dist/commands/generate.js +14 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +80 -55
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +47 -10
- package/dist/commands/telemetry.d.ts +3 -0
- package/dist/commands/telemetry.d.ts.map +1 -0
- package/dist/commands/telemetry.js +19 -0
- package/dist/generators/chdb.d.ts +3 -0
- package/dist/generators/chdb.d.ts.map +1 -1
- package/dist/generators/chdb.js +2 -0
- package/dist/generators/clickhouse.d.ts +3 -1
- package/dist/generators/clickhouse.d.ts.map +1 -1
- package/dist/generators/clickhouse.js +2 -0
- package/dist/typegen/generate-types.d.ts +3 -0
- package/dist/typegen/generate-types.d.ts.map +1 -1
- package/dist/typegen/generate-types.js +5 -1
- package/dist/typegen/type-parsing.d.ts +1 -1
- package/dist/typegen/type-parsing.d.ts.map +1 -1
- package/dist/typegen/type-parsing.js +11 -7
- package/dist/utils/chdb-gitignore-entry.d.ts +2 -0
- package/dist/utils/chdb-gitignore-entry.d.ts.map +1 -0
- package/dist/utils/chdb-gitignore-entry.js +17 -0
- package/dist/utils/cli-version.d.ts +2 -0
- package/dist/utils/cli-version.d.ts.map +1 -0
- package/dist/utils/cli-version.js +11 -0
- package/dist/utils/cloud-credential-store.d.ts.map +1 -1
- package/dist/utils/cloud-credential-store.js +2 -13
- package/dist/utils/command-exit.d.ts +13 -0
- package/dist/utils/command-exit.d.ts.map +1 -0
- package/dist/utils/command-exit.js +31 -0
- package/dist/utils/config-directory.d.ts +3 -0
- package/dist/utils/config-directory.d.ts.map +1 -0
- package/dist/utils/config-directory.js +14 -0
- package/dist/utils/detect-database-environment.d.ts +3 -0
- package/dist/utils/detect-database-environment.d.ts.map +1 -0
- package/dist/utils/detect-database-environment.js +8 -0
- package/dist/utils/detect-database.d.ts.map +1 -1
- package/dist/utils/detect-database.js +4 -8
- package/dist/utils/init-options.d.ts +11 -0
- package/dist/utils/init-options.d.ts.map +1 -0
- package/dist/utils/init-options.js +28 -0
- package/dist/utils/load-api.d.ts +2 -0
- package/dist/utils/load-api.d.ts.map +1 -1
- package/dist/utils/load-api.js +50 -51
- package/dist/utils/load-env-files.d.ts +10 -0
- package/dist/utils/load-env-files.d.ts.map +1 -0
- package/dist/utils/load-env-files.js +27 -0
- package/dist/utils/project-root.d.ts +14 -0
- package/dist/utils/project-root.d.ts.map +1 -0
- package/dist/utils/project-root.js +41 -0
- package/dist/utils/telemetry/buckets.d.ts +5 -0
- package/dist/utils/telemetry/buckets.d.ts.map +1 -0
- package/dist/utils/telemetry/buckets.js +23 -0
- package/dist/utils/telemetry/catalog-docs.d.ts +3 -0
- package/dist/utils/telemetry/catalog-docs.d.ts.map +1 -0
- package/dist/utils/telemetry/catalog-docs.js +52 -0
- package/dist/utils/telemetry/catalog.d.ts +1124 -0
- package/dist/utils/telemetry/catalog.d.ts.map +1 -0
- package/dist/utils/telemetry/catalog.js +154 -0
- package/dist/utils/telemetry/command-context.d.ts +17 -0
- package/dist/utils/telemetry/command-context.d.ts.map +1 -0
- package/dist/utils/telemetry/command-context.js +30 -0
- package/dist/utils/telemetry/config-schema.d.ts +12 -0
- package/dist/utils/telemetry/config-schema.d.ts.map +1 -0
- package/dist/utils/telemetry/config-schema.js +33 -0
- package/dist/utils/telemetry/config-store.d.ts +35 -0
- package/dist/utils/telemetry/config-store.d.ts.map +1 -0
- package/dist/utils/telemetry/config-store.js +147 -0
- package/dist/utils/telemetry/delivery.d.ts +13 -0
- package/dist/utils/telemetry/delivery.d.ts.map +1 -0
- package/dist/utils/telemetry/delivery.js +26 -0
- package/dist/utils/telemetry/detached-dispatch.d.ts +12 -0
- package/dist/utils/telemetry/detached-dispatch.d.ts.map +1 -0
- package/dist/utils/telemetry/detached-dispatch.js +33 -0
- package/dist/utils/telemetry/detached-sender.d.ts +2 -0
- package/dist/utils/telemetry/detached-sender.d.ts.map +1 -0
- package/dist/utils/telemetry/detached-sender.js +31 -0
- package/dist/utils/telemetry/dev-session.d.ts +15 -0
- package/dist/utils/telemetry/dev-session.d.ts.map +1 -0
- package/dist/utils/telemetry/dev-session.js +25 -0
- package/dist/utils/telemetry/domains.d.ts +69 -0
- package/dist/utils/telemetry/domains.d.ts.map +1 -0
- package/dist/utils/telemetry/domains.js +64 -0
- package/dist/utils/telemetry/endpoint.d.ts +3 -0
- package/dist/utils/telemetry/endpoint.d.ts.map +1 -0
- package/dist/utils/telemetry/endpoint.js +15 -0
- package/dist/utils/telemetry/environment.d.ts +27 -0
- package/dist/utils/telemetry/environment.d.ts.map +1 -0
- package/dist/utils/telemetry/environment.js +95 -0
- package/dist/utils/telemetry/error-code.d.ts +4 -0
- package/dist/utils/telemetry/error-code.d.ts.map +1 -0
- package/dist/utils/telemetry/error-code.js +57 -0
- package/dist/utils/telemetry/flags.d.ts +5 -0
- package/dist/utils/telemetry/flags.d.ts.map +1 -0
- package/dist/utils/telemetry/flags.js +41 -0
- package/dist/utils/telemetry/generation-metrics.d.ts +15 -0
- package/dist/utils/telemetry/generation-metrics.d.ts.map +1 -0
- package/dist/utils/telemetry/generation-metrics.js +35 -0
- package/dist/utils/telemetry/identity.d.ts +12 -0
- package/dist/utils/telemetry/identity.d.ts.map +1 -0
- package/dist/utils/telemetry/identity.js +42 -0
- package/dist/utils/telemetry/init-funnel.d.ts +15 -0
- package/dist/utils/telemetry/init-funnel.d.ts.map +1 -0
- package/dist/utils/telemetry/init-funnel.js +25 -0
- package/dist/utils/telemetry/invocation.d.ts +22 -0
- package/dist/utils/telemetry/invocation.d.ts.map +1 -0
- package/dist/utils/telemetry/invocation.js +46 -0
- package/dist/utils/telemetry/lifecycle.d.ts +32 -0
- package/dist/utils/telemetry/lifecycle.d.ts.map +1 -0
- package/dist/utils/telemetry/lifecycle.js +99 -0
- package/dist/utils/telemetry/mcp-session.d.ts +10 -0
- package/dist/utils/telemetry/mcp-session.d.ts.map +1 -0
- package/dist/utils/telemetry/mcp-session.js +36 -0
- package/dist/utils/telemetry/notice.d.ts +11 -0
- package/dist/utils/telemetry/notice.d.ts.map +1 -0
- package/dist/utils/telemetry/notice.js +24 -0
- package/dist/utils/telemetry/opt-out.d.ts +16 -0
- package/dist/utils/telemetry/opt-out.d.ts.map +1 -0
- package/dist/utils/telemetry/opt-out.js +32 -0
- package/dist/utils/telemetry/post-json.d.ts +13 -0
- package/dist/utils/telemetry/post-json.d.ts.map +1 -0
- package/dist/utils/telemetry/post-json.js +32 -0
- package/dist/utils/telemetry/project-context.d.ts +15 -0
- package/dist/utils/telemetry/project-context.d.ts.map +1 -0
- package/dist/utils/telemetry/project-context.js +86 -0
- package/dist/utils/telemetry/schema.d.ts +72 -0
- package/dist/utils/telemetry/schema.d.ts.map +1 -0
- package/dist/utils/telemetry/schema.js +17 -0
- package/dist/utils/telemetry/session-config.d.ts +6 -0
- package/dist/utils/telemetry/session-config.d.ts.map +1 -0
- package/dist/utils/telemetry/session-config.js +17 -0
- package/dist/utils/telemetry/settings-lock.d.ts +36 -0
- package/dist/utils/telemetry/settings-lock.d.ts.map +1 -0
- package/dist/utils/telemetry/settings-lock.js +102 -0
- package/dist/utils/telemetry/transport.d.ts +25 -0
- package/dist/utils/telemetry/transport.d.ts.map +1 -0
- package/dist/utils/telemetry/transport.js +76 -0
- package/dist/utils/telemetry/validation.d.ts +10 -0
- package/dist/utils/telemetry/validation.d.ts.map +1 -0
- package/dist/utils/telemetry/validation.js +77 -0
- package/dist/utils/telemetry/value-formats.d.ts +30 -0
- package/dist/utils/telemetry/value-formats.d.ts.map +1 -0
- package/dist/utils/telemetry/value-formats.js +13 -0
- package/package.json +12 -8
package/dist/bin/cli.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { program } from '../cli.js';
|
|
3
|
-
import {
|
|
3
|
+
import { loadEnvFiles } from '../utils/load-env-files.js';
|
|
4
|
+
import { CommandExit, finishAndExit, installCommandExitFinalizer } from '../utils/command-exit.js';
|
|
5
|
+
import { CommandLifecycle } from '../utils/telemetry/lifecycle.js';
|
|
6
|
+
import { telemetryErrorCode } from '../utils/telemetry/error-code.js';
|
|
7
|
+
import { cleanupLoadedApiArtifacts } from '../utils/load-api.js';
|
|
8
|
+
import { withCommandTelemetry } from '../utils/telemetry/command-context.js';
|
|
9
|
+
import { settleTelemetrySettings } from '../utils/telemetry/config-store.js';
|
|
4
10
|
async function loadEnv() {
|
|
5
11
|
try {
|
|
6
12
|
const dotenvx = await import('@dotenvx/dotenvx');
|
|
@@ -14,19 +20,78 @@ async function loadEnv() {
|
|
|
14
20
|
catch {
|
|
15
21
|
// Optional dependency, ignore if missing
|
|
16
22
|
}
|
|
17
|
-
|
|
18
|
-
const { config } = await import('dotenv');
|
|
19
|
-
for (const path of envFiles(process.env.NODE_ENV)) {
|
|
20
|
-
// Missing files are a no-op.
|
|
21
|
-
config({ path });
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
// dotenv is optional; continue if not available
|
|
26
|
-
}
|
|
23
|
+
await loadEnvFiles(process.cwd());
|
|
27
24
|
}
|
|
28
25
|
async function main() {
|
|
29
26
|
await loadEnv();
|
|
30
|
-
|
|
27
|
+
const args = process.argv.slice(2);
|
|
28
|
+
const requested = args.find(arg => !arg.startsWith('-'));
|
|
29
|
+
const lifecycle = new CommandLifecycle(args, {
|
|
30
|
+
telemetry: args.includes('--no-telemetry') ? false : undefined,
|
|
31
|
+
});
|
|
32
|
+
let selected;
|
|
33
|
+
let finishing;
|
|
34
|
+
const finish = (exit) => {
|
|
35
|
+
finishing ??= (async () => {
|
|
36
|
+
// finish() never rejects; the guard keeps cleanup independent of telemetry.
|
|
37
|
+
await lifecycle.finish(exit, selected?.name() === 'help' ? selected.args[0] : undefined).catch(() => undefined);
|
|
38
|
+
// Signals end in process.exit(), which skips finally blocks: let any
|
|
39
|
+
// settings write release its lock first (bounded).
|
|
40
|
+
await settleTelemetrySettings();
|
|
41
|
+
await cleanupLoadedApiArtifacts();
|
|
42
|
+
})();
|
|
43
|
+
return finishing;
|
|
44
|
+
};
|
|
45
|
+
installCommandExitFinalizer(finish);
|
|
46
|
+
const crash = (error) => lifecycle.crash(error);
|
|
47
|
+
process.on('uncaughtExceptionMonitor', crash);
|
|
48
|
+
program.exitOverride();
|
|
49
|
+
for (const command of program.commands)
|
|
50
|
+
command.exitOverride();
|
|
51
|
+
program.hook('preAction', async (_root, command) => {
|
|
52
|
+
selected = command;
|
|
53
|
+
await lifecycle.begin(command.name(), command.opts().database);
|
|
54
|
+
});
|
|
55
|
+
const observeSignal = (signal) => {
|
|
56
|
+
lifecycle.markInterrupted();
|
|
57
|
+
// dev and mcp own asynchronous server teardown once their handlers exist.
|
|
58
|
+
// During startup, or for short commands, the executable owns shutdown.
|
|
59
|
+
if ((lifecycle.command === 'dev' || lifecycle.command === 'mcp') && process.listenerCount(signal) > 1)
|
|
60
|
+
return;
|
|
61
|
+
void finishAndExit(lifecycle.command === 'dev' || lifecycle.command === 'mcp' ? 0 : signal === 'SIGINT' ? 130 : 143, 'interrupted');
|
|
62
|
+
};
|
|
63
|
+
process.on('SIGINT', () => observeSignal('SIGINT'));
|
|
64
|
+
process.on('SIGTERM', () => observeSignal('SIGTERM'));
|
|
65
|
+
try {
|
|
66
|
+
await withCommandTelemetry(lifecycle, () => program.parseAsync(process.argv));
|
|
67
|
+
if (lifecycle.command === 'dev')
|
|
68
|
+
return; // Its shutdown handler finalizes after teardown.
|
|
69
|
+
await finish(new CommandExit(Number(process.exitCode ?? 0), process.exitCode ? 'failure' : 'success', process.exitCode ? 'unknown' : undefined));
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
const commander = error;
|
|
73
|
+
if (commander.code === 'commander.helpDisplayed' || commander.code === 'commander.help') {
|
|
74
|
+
const topic = selected?.name() === 'help' ? selected.args[0] : selected?.name()
|
|
75
|
+
?? program.commands.find(command => requested === command.name())?.name();
|
|
76
|
+
await lifecycle.begin('help');
|
|
77
|
+
const code = commander.exitCode ?? 0;
|
|
78
|
+
await lifecycle.finish(new CommandExit(code, code ? 'failure' : 'success', code ? 'validation_failed' : undefined), topic)
|
|
79
|
+
.catch(() => undefined);
|
|
80
|
+
process.exitCode = code;
|
|
81
|
+
await settleTelemetrySettings();
|
|
82
|
+
await cleanupLoadedApiArtifacts();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (commander.code === 'commander.version') {
|
|
86
|
+
await lifecycle.begin('version');
|
|
87
|
+
await finish(new CommandExit(0, 'success'));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (!selected)
|
|
91
|
+
await lifecycle.begin(['unknown_command', 'unknown_option'].includes(telemetryErrorCode(error)) ? 'unknown' : requested ?? 'unknown');
|
|
92
|
+
const exit = error instanceof CommandExit ? error
|
|
93
|
+
: new CommandExit(commander.exitCode ?? 1, 'failure', telemetryErrorCode(error));
|
|
94
|
+
await finishAndExit(exit.exitCode, exit.outcome, exit.errorCode);
|
|
95
|
+
}
|
|
31
96
|
}
|
|
32
97
|
main();
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyCpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAE9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;AA8RD,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
1
|
import { Command } from 'commander';
|
|
4
2
|
import { initCommand } from './commands/init.js';
|
|
5
3
|
import { mcpCommand } from './commands/mcp.js';
|
|
@@ -13,16 +11,11 @@ import { deploymentStatusCommand, } from './commands/deployment-status.js';
|
|
|
13
11
|
import { loginCommand, logoutCommand, } from './commands/login.js';
|
|
14
12
|
import { diffCommand, pullCommand, } from './commands/live-source.js';
|
|
15
13
|
import { isPromptCancelled } from './utils/prompts.js';
|
|
14
|
+
import { telemetryCommand } from './commands/telemetry.js';
|
|
15
|
+
import { getCliVersion } from './utils/cli-version.js';
|
|
16
|
+
import { CommandExit } from './utils/command-exit.js';
|
|
17
|
+
import { telemetryErrorCode } from './utils/telemetry/error-code.js';
|
|
16
18
|
const program = new Command();
|
|
17
|
-
function getCliVersion() {
|
|
18
|
-
try {
|
|
19
|
-
const pkg = JSON.parse(readFileSync(fileURLToPath(new URL('../package.json', import.meta.url)), 'utf8'));
|
|
20
|
-
return pkg.version ?? '0.0.0';
|
|
21
|
-
}
|
|
22
|
-
catch {
|
|
23
|
-
return '0.0.0';
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
19
|
export function normalizeInitOptions(options) {
|
|
27
20
|
return {
|
|
28
21
|
...options,
|
|
@@ -32,7 +25,14 @@ export function normalizeInitOptions(options) {
|
|
|
32
25
|
program
|
|
33
26
|
.name('hypequery')
|
|
34
27
|
.description('Type-safe analytics layer for ClickHouse')
|
|
35
|
-
.version(getCliVersion())
|
|
28
|
+
.version(getCliVersion())
|
|
29
|
+
.option('--no-telemetry', 'Disable anonymous usage telemetry for this invocation');
|
|
30
|
+
program
|
|
31
|
+
.command('telemetry [action]')
|
|
32
|
+
.description('Show or change anonymous usage telemetry settings (status|enable|disable)')
|
|
33
|
+
.action(runCommand(async (action) => {
|
|
34
|
+
await telemetryCommand(action, { telemetry: program.opts().telemetry });
|
|
35
|
+
}));
|
|
36
36
|
program
|
|
37
37
|
.command('login')
|
|
38
38
|
.description('Authorize this machine with Hypequery Cloud')
|
|
@@ -72,14 +72,16 @@ function runCommand(action) {
|
|
|
72
72
|
await action(...args);
|
|
73
73
|
}
|
|
74
74
|
catch (error) {
|
|
75
|
+
if (error instanceof CommandExit)
|
|
76
|
+
throw error;
|
|
75
77
|
// Ctrl+C at a prompt is a deliberate abort, not a failure: report it as
|
|
76
78
|
// the interrupt it is instead of dumping an error and exiting 1.
|
|
77
79
|
if (isPromptCancelled(error)) {
|
|
78
80
|
console.log('\nCancelled.');
|
|
79
|
-
|
|
81
|
+
throw new CommandExit(130, 'cancelled', 'prompt_cancelled');
|
|
80
82
|
}
|
|
81
83
|
console.error(error instanceof Error ? error.message : error);
|
|
82
|
-
|
|
84
|
+
throw new CommandExit(1, 'failure', telemetryErrorCode(error));
|
|
83
85
|
}
|
|
84
86
|
};
|
|
85
87
|
}
|
|
@@ -236,7 +238,7 @@ program
|
|
|
236
238
|
}
|
|
237
239
|
else {
|
|
238
240
|
console.error(`Unknown command: ${command}`);
|
|
239
|
-
|
|
241
|
+
throw new CommandExit(1, 'failure', 'unknown_command');
|
|
240
242
|
}
|
|
241
243
|
}
|
|
242
244
|
else {
|
|
@@ -247,6 +249,9 @@ program
|
|
|
247
249
|
program.on('--help', () => {
|
|
248
250
|
console.log('');
|
|
249
251
|
console.log('Examples:');
|
|
252
|
+
console.log(' hypequery telemetry status');
|
|
253
|
+
console.log(' hypequery telemetry disable');
|
|
254
|
+
console.log(' hypequery --no-telemetry init');
|
|
250
255
|
console.log(' hypequery login');
|
|
251
256
|
console.log(' hypequery logout');
|
|
252
257
|
console.log(' hypequery init');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/commands/dev.ts"],"names":[],"mappings":"AAkCA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,iBA2OvE"}
|
package/dist/commands/dev.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { exitWith, finishAndExit } from '../utils/command-exit.js';
|
|
2
|
+
import { telemetryErrorCode } from '../utils/telemetry/error-code.js';
|
|
3
|
+
import { DevSession } from '../utils/telemetry/dev-session.js';
|
|
4
|
+
import { setCommandTelemetryError } from '../utils/telemetry/command-context.js';
|
|
1
5
|
import { watch } from 'node:fs';
|
|
2
6
|
import path from 'node:path';
|
|
3
7
|
import ora from 'ora';
|
|
@@ -27,6 +31,7 @@ function displayQueriesFileNotFoundError(commandName) {
|
|
|
27
31
|
logger.newline();
|
|
28
32
|
}
|
|
29
33
|
export async function devCommand(file, options = {}) {
|
|
34
|
+
const telemetry = new DevSession();
|
|
30
35
|
// Step 1: Find queries file
|
|
31
36
|
const queriesFile = file
|
|
32
37
|
? await findQueriesFile(file)
|
|
@@ -35,10 +40,11 @@ export async function devCommand(file, options = {}) {
|
|
|
35
40
|
: await findQueriesFile();
|
|
36
41
|
if (!queriesFile) {
|
|
37
42
|
displayQueriesFileNotFoundError('dev');
|
|
38
|
-
|
|
43
|
+
exitWith(1, 'failure', 'entrypoint_not_found');
|
|
39
44
|
}
|
|
40
45
|
logger.info(`Found: ${path.relative(process.cwd(), queriesFile)}`);
|
|
41
46
|
logger.newline();
|
|
47
|
+
telemetry.start(queriesFile, file, options);
|
|
42
48
|
let currentServer = null;
|
|
43
49
|
let lifecycleOperation = Promise.resolve();
|
|
44
50
|
let shutdownRequested = false;
|
|
@@ -61,9 +67,11 @@ export async function devCommand(file, options = {}) {
|
|
|
61
67
|
// Loading spinners for slow operations
|
|
62
68
|
const compileSpinner = ora('Compiling queries...').start();
|
|
63
69
|
const dbSpinner = ora('Connecting to ClickHouse...').start();
|
|
70
|
+
let loading = true;
|
|
64
71
|
try {
|
|
65
72
|
// Load the API module
|
|
66
73
|
const api = await loadApiModule(queriesFile);
|
|
74
|
+
loading = false;
|
|
67
75
|
compileSpinner.succeed('Compiled queries');
|
|
68
76
|
// Get table count for display
|
|
69
77
|
let tableCount = 0;
|
|
@@ -125,8 +133,10 @@ export async function devCommand(file, options = {}) {
|
|
|
125
133
|
logger.indent(`Visit: ${baseUrl}`);
|
|
126
134
|
}
|
|
127
135
|
}
|
|
136
|
+
return true;
|
|
128
137
|
}
|
|
129
138
|
catch (error) {
|
|
139
|
+
const code = loading ? telemetry.loadFailed(error) : telemetryErrorCode(error);
|
|
130
140
|
// If server startup or later setup fails, tear down any resources
|
|
131
141
|
// acquired by this attempt before retrying or exiting.
|
|
132
142
|
try {
|
|
@@ -158,21 +168,31 @@ export async function devCommand(file, options = {}) {
|
|
|
158
168
|
}
|
|
159
169
|
logger.newline();
|
|
160
170
|
if (!shouldWatch) {
|
|
161
|
-
|
|
171
|
+
setCommandTelemetryError(code);
|
|
172
|
+
exitWith(1, 'failure', code);
|
|
162
173
|
}
|
|
174
|
+
return false;
|
|
163
175
|
}
|
|
164
176
|
};
|
|
165
177
|
const restartServer = () => queueLifecycleOperation(async () => {
|
|
166
178
|
if (shutdownRequested)
|
|
167
179
|
return;
|
|
180
|
+
telemetry.reload();
|
|
168
181
|
if (currentServer) {
|
|
169
182
|
logger.newline();
|
|
170
183
|
logger.reload('File changed, restarting...');
|
|
171
184
|
logger.newline();
|
|
172
|
-
|
|
185
|
+
try {
|
|
186
|
+
await stopCurrentRuntime();
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
telemetry.reloadFailed();
|
|
190
|
+
throw error;
|
|
191
|
+
}
|
|
173
192
|
}
|
|
174
193
|
if (!shutdownRequested) {
|
|
175
|
-
await startServer()
|
|
194
|
+
if (!await startServer())
|
|
195
|
+
telemetry.reloadFailed();
|
|
176
196
|
}
|
|
177
197
|
});
|
|
178
198
|
const shutdown = () => {
|
|
@@ -183,7 +203,7 @@ export async function devCommand(file, options = {}) {
|
|
|
183
203
|
logger.info('Shutting down dev server...');
|
|
184
204
|
return queueLifecycleOperation(async () => {
|
|
185
205
|
await stopCurrentRuntime();
|
|
186
|
-
|
|
206
|
+
await finishAndExit(0, 'interrupted');
|
|
187
207
|
});
|
|
188
208
|
};
|
|
189
209
|
// Start initial server
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-datasets.d.ts","sourceRoot":"","sources":["../../src/commands/generate-datasets.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate-datasets.d.ts","sourceRoot":"","sources":["../../src/commands/generate-datasets.ts"],"names":[],"mappings":"AAsBA,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AA2BD,wBAAsB,uBAAuB,CAAC,OAAO,GAAE,uBAA4B,iBA+KlF"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { exitWith } from '../utils/command-exit.js';
|
|
2
|
+
import { telemetryErrorCode } from '../utils/telemetry/error-code.js';
|
|
1
3
|
/**
|
|
2
4
|
* Generate Datasets Command
|
|
3
5
|
*
|
|
@@ -13,6 +15,9 @@ import { redactConnectionUrl } from '../utils/redact-connection-url.js';
|
|
|
13
15
|
import { logDatasetGenerationWarnings } from '../utils/dataset-generation-warnings.js';
|
|
14
16
|
import { formatGeneratedFileDiff } from '../utils/generated-file-diff.js';
|
|
15
17
|
import { readGeneratedFile, writeGeneratedFileAtomically } from '../utils/generated-file.js';
|
|
18
|
+
import { updateCommandTelemetry, setCommandTelemetryError } from '../utils/telemetry/command-context.js';
|
|
19
|
+
import { countBucket } from '../utils/telemetry/buckets.js';
|
|
20
|
+
import { warningBuckets } from '../utils/telemetry/generation-metrics.js';
|
|
16
21
|
/**
|
|
17
22
|
* Turns the written path into something pasteable into an import statement:
|
|
18
23
|
* strips the `.ts` extension and makes it explicitly relative.
|
|
@@ -35,6 +40,8 @@ function parseTableList(value) {
|
|
|
35
40
|
return parsed && parsed.length > 0 ? parsed : undefined;
|
|
36
41
|
}
|
|
37
42
|
export async function generateDatasetsCommand(options = {}) {
|
|
43
|
+
updateCommandTelemetry('generate:datasets', { mode: options.check ? 'check' : options.diff ? 'diff' : 'write', force: !!options.force,
|
|
44
|
+
tenant_column_used: !!options.tenantColumn, tables_filter_used: !!options.tables, exclude_filter_used: !!options.excludeTables });
|
|
38
45
|
// Determine output path
|
|
39
46
|
let outputPath;
|
|
40
47
|
if (options.output) {
|
|
@@ -52,6 +59,7 @@ export async function generateDatasetsCommand(options = {}) {
|
|
|
52
59
|
const excludedTables = parseTableList(options.excludeTables);
|
|
53
60
|
if (options.force && (options.check || options.diff)) {
|
|
54
61
|
logger.error('--force cannot be combined with --check or --diff.');
|
|
62
|
+
setCommandTelemetryError('validation_failed');
|
|
55
63
|
process.exitCode = 1;
|
|
56
64
|
return;
|
|
57
65
|
}
|
|
@@ -80,9 +88,16 @@ export async function generateDatasetsCommand(options = {}) {
|
|
|
80
88
|
const generatedCount = generatedTables.length || tableCount;
|
|
81
89
|
datasetSpinner.succeed(`Generated dataset definitions for ${generatedCount} ${generatedCount === 1 ? 'table' : 'tables'}`);
|
|
82
90
|
logDatasetGenerationWarnings(generated?.warnings);
|
|
91
|
+
updateCommandTelemetry('generate:datasets', { datasets_generated_bucket: countBucket(generated.tables.length), warning_counts: warningBuckets(generated.warnings) });
|
|
83
92
|
const relativeOutput = path.relative(process.cwd(), outputPath);
|
|
84
93
|
const currentContents = await readGeneratedFile(outputPath);
|
|
85
94
|
const contentsMatch = currentContents === generated.contents;
|
|
95
|
+
if (options.check) {
|
|
96
|
+
const result = contentsMatch ? 'up_to_date' : currentContents === undefined ? 'missing' : 'out_of_date';
|
|
97
|
+
updateCommandTelemetry('generate:datasets', { check_result: result });
|
|
98
|
+
if (!contentsMatch)
|
|
99
|
+
setCommandTelemetryError(currentContents === undefined ? 'output_missing' : 'output_out_of_date');
|
|
100
|
+
}
|
|
86
101
|
if (contentsMatch) {
|
|
87
102
|
logger.success(options.check || options.diff
|
|
88
103
|
? `Dataset definitions are up to date: ${relativeOutput}`
|
|
@@ -92,6 +107,7 @@ export async function generateDatasetsCommand(options = {}) {
|
|
|
92
107
|
}
|
|
93
108
|
}
|
|
94
109
|
else if (options.diff) {
|
|
110
|
+
setCommandTelemetryError('output_out_of_date');
|
|
95
111
|
logger.raw(formatGeneratedFileDiff(currentContents ?? '', generated.contents, relativeOutput));
|
|
96
112
|
logger.error(`Generated dataset definitions differ: ${relativeOutput}`);
|
|
97
113
|
process.exitCode = 1;
|
|
@@ -173,6 +189,6 @@ export async function generateDatasetsCommand(options = {}) {
|
|
|
173
189
|
logger.error(String(error));
|
|
174
190
|
}
|
|
175
191
|
logger.newline();
|
|
176
|
-
|
|
192
|
+
exitWith(1, 'failure', telemetryErrorCode(error));
|
|
177
193
|
}
|
|
178
194
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-manifest.d.ts","sourceRoot":"","sources":["../../src/commands/generate-manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate-manifest.d.ts","sourceRoot":"","sources":["../../src/commands/generate-manifest.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,uBAA4B,iBA2BtC"}
|
|
@@ -2,7 +2,10 @@ import { mkdir, writeFile } from 'node:fs/promises';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { loadApiModule } from '../utils/load-api.js';
|
|
4
4
|
import { logger } from '../utils/logger.js';
|
|
5
|
+
import { updateCommandTelemetry } from '../utils/telemetry/command-context.js';
|
|
6
|
+
import { manifestMetrics } from '../utils/telemetry/generation-metrics.js';
|
|
5
7
|
export async function generateManifestCommand(apiPath, options = {}) {
|
|
8
|
+
updateCommandTelemetry('generate:manifest', { custom_output: options.output !== undefined });
|
|
6
9
|
if (!apiPath) {
|
|
7
10
|
throw new Error('Missing API module path.\n\n' +
|
|
8
11
|
'Usage: hypequery generate:manifest analytics/api.ts --output analytics/hypequery-manifest.json');
|
|
@@ -15,6 +18,7 @@ export async function generateManifestCommand(apiPath, options = {}) {
|
|
|
15
18
|
`Export the value returned by createAPI() or initServe(...).serve(...).`);
|
|
16
19
|
}
|
|
17
20
|
const manifest = api.manifest();
|
|
21
|
+
updateCommandTelemetry('generate:manifest', manifestMetrics(api, manifest));
|
|
18
22
|
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
19
23
|
await writeFile(outputPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
|
|
20
24
|
logger.success(`Manifest written to ${outputPath}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/commands/generate.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiC,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAQ/F,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,eAAe,CAAC,OAAO,GAAE,eAAoB,iBAqKlE"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { exitWith } from '../utils/command-exit.js';
|
|
2
|
+
import { telemetryErrorCode } from '../utils/telemetry/error-code.js';
|
|
1
3
|
import path from 'node:path';
|
|
2
4
|
import ora from 'ora';
|
|
3
5
|
import { logger } from '../utils/logger.js';
|
|
@@ -6,7 +8,13 @@ import { detectDatabase, getTableCount } from '../utils/detect-database.js';
|
|
|
6
8
|
import { ensureChdbInstalled } from '../utils/chdb-client.js';
|
|
7
9
|
import { getTypeGenerator } from '../generators/index.js';
|
|
8
10
|
import { redactConnectionUrl } from '../utils/redact-connection-url.js';
|
|
11
|
+
import { updateCommandTelemetry } from '../utils/telemetry/command-context.js';
|
|
12
|
+
import { countBucket } from '../utils/telemetry/buckets.js';
|
|
13
|
+
import { TypeGenerationMetrics } from '../utils/telemetry/generation-metrics.js';
|
|
9
14
|
export async function generateCommand(options = {}) {
|
|
15
|
+
const command = options.commandName === 'hypequery generate:types' ? 'generate:types' : 'generate';
|
|
16
|
+
const metrics = new TypeGenerationMetrics();
|
|
17
|
+
updateCommandTelemetry(command, { custom_output: !!(options.output || options.path), tables_filter_used: !!options.tables, chdb_path_given: !!options.chdbPath });
|
|
10
18
|
// Determine output path
|
|
11
19
|
let outputPath;
|
|
12
20
|
if (options.output) {
|
|
@@ -35,6 +43,7 @@ export async function generateCommand(options = {}) {
|
|
|
35
43
|
const requestedDbType = options.database;
|
|
36
44
|
const dbType = requestedDbType ?? (await detectDatabase());
|
|
37
45
|
const chdbPath = dbType === 'chdb' ? options.chdbPath : undefined;
|
|
46
|
+
updateCommandTelemetry(command, { database: dbType === 'clickhouse' || dbType === 'chdb' || dbType === 'bigquery' ? dbType : 'unknown', chdb_path_given: !!chdbPath });
|
|
38
47
|
if (dbType === 'chdb' && !requestedDbType) {
|
|
39
48
|
throw new Error('chDB generation must be explicit. Re-run with --database chdb and add --chdb-path <dir> for persistent storage.');
|
|
40
49
|
}
|
|
@@ -68,10 +77,13 @@ export async function generateCommand(options = {}) {
|
|
|
68
77
|
outputPath,
|
|
69
78
|
includeTables: parsedTables,
|
|
70
79
|
chdbPath,
|
|
80
|
+
onColumn: () => metrics.column(),
|
|
81
|
+
onUnsupportedType: type => metrics.fallback(type),
|
|
71
82
|
});
|
|
72
83
|
// The generator returns what it actually wrote after applying filters.
|
|
73
84
|
// Requested names may contain duplicates or tables that do not exist.
|
|
74
85
|
const generatedCount = generatedTables.length;
|
|
86
|
+
updateCommandTelemetry(command, { ...metrics.snapshot(), table_count_bucket: countBucket(generatedCount) });
|
|
75
87
|
typeSpinner.succeed(`Generated types for ${generatedCount} ${generatedCount === 1 ? 'table' : 'tables'}`);
|
|
76
88
|
logger.success(`Updated ${path.relative(process.cwd(), outputPath)}`);
|
|
77
89
|
logger.newline();
|
|
@@ -79,6 +91,7 @@ export async function generateCommand(options = {}) {
|
|
|
79
91
|
logger.newline();
|
|
80
92
|
}
|
|
81
93
|
catch (error) {
|
|
94
|
+
updateCommandTelemetry(command, metrics.snapshot());
|
|
82
95
|
activeSpinner.fail(failureMessage);
|
|
83
96
|
logger.newline();
|
|
84
97
|
if (error instanceof Error) {
|
|
@@ -140,6 +153,6 @@ export async function generateCommand(options = {}) {
|
|
|
140
153
|
logger.error(String(error));
|
|
141
154
|
}
|
|
142
155
|
logger.newline();
|
|
143
|
-
|
|
156
|
+
exitWith(1, 'failure', telemetryErrorCode(error));
|
|
144
157
|
}
|
|
145
158
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAUA,OAAO,EAcL,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAc7B,OAAO,EAA2B,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAYzF,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,gBAAgB,CAAC;CACzB;AA6GD,wBAAsB,WAAW,CAAC,OAAO,GAAE,WAAgB,iBAY1D"}
|