@hypequery/cli 1.13.0 → 1.13.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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +7 -0
- package/dist/utils/dependency-installer.d.ts +1 -0
- package/dist/utils/dependency-installer.d.ts.map +1 -1
- package/dist/utils/dependency-installer.js +29 -10
- package/dist/utils/prompts.d.ts +7 -0
- package/dist/utils/prompts.d.ts.map +1 -1
- package/dist/utils/prompts.js +50 -19
- package/package.json +3 -3
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA0BpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAa9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;AA4ND,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ import { generateManifestCommand } from './commands/generate-manifest.js';
|
|
|
9
9
|
import { buildDeploymentCommand, prepareDeploymentReleaseCommand, validateDeploymentCommand, } from './commands/deployment.js';
|
|
10
10
|
import { deployCommand, submitDeploymentCommand, } from './commands/deploy.js';
|
|
11
11
|
import { loginCommand, logoutCommand, } from './commands/login.js';
|
|
12
|
+
import { isPromptCancelled } from './utils/prompts.js';
|
|
12
13
|
const program = new Command();
|
|
13
14
|
function getCliVersion() {
|
|
14
15
|
try {
|
|
@@ -48,6 +49,12 @@ function runCommand(action) {
|
|
|
48
49
|
await action(...args);
|
|
49
50
|
}
|
|
50
51
|
catch (error) {
|
|
52
|
+
// Ctrl+C at a prompt is a deliberate abort, not a failure: report it as
|
|
53
|
+
// the interrupt it is instead of dumping an error and exiting 1.
|
|
54
|
+
if (isPromptCancelled(error)) {
|
|
55
|
+
console.log('\nCancelled.');
|
|
56
|
+
process.exit(130);
|
|
57
|
+
}
|
|
51
58
|
console.error(error instanceof Error ? error.message : error);
|
|
52
59
|
process.exit(1);
|
|
53
60
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
type ScaffoldStyle = 'queries' | 'datasets';
|
|
2
2
|
type ScaffoldDatabase = 'clickhouse' | 'chdb';
|
|
3
|
+
export declare function isCanaryVersion(version: string | undefined): boolean;
|
|
3
4
|
export declare function resolveScaffoldPackages(cliVersion: string | undefined, style?: ScaffoldStyle, database?: ScaffoldDatabase): string[];
|
|
4
5
|
export declare function installScaffoldDependencies(style?: ScaffoldStyle, database?: ScaffoldDatabase): Promise<void>;
|
|
5
6
|
export declare const installServeDependencies: typeof installScaffoldDependencies;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dependency-installer.d.ts","sourceRoot":"","sources":["../../src/utils/dependency-installer.ts"],"names":[],"mappings":"AAWA,KAAK,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAC5C,KAAK,gBAAgB,GAAG,YAAY,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"dependency-installer.d.ts","sourceRoot":"","sources":["../../src/utils/dependency-installer.ts"],"names":[],"mappings":"AAWA,KAAK,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAC5C,KAAK,gBAAgB,GAAG,YAAY,GAAG,MAAM,CAAC;AAwE9C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE;AAqCD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,KAAK,GAAE,aAAyB,EAChC,QAAQ,GAAE,gBAA+B,GACxC,MAAM,EAAE,CAmBV;AAsBD,wBAAsB,2BAA2B,CAC/C,KAAK,GAAE,aAAyB,EAChC,QAAQ,GAAE,gBAA+B,iBAyD1C;AAED,eAAO,MAAM,wBAAwB,oCAA8B,CAAC"}
|
|
@@ -68,26 +68,44 @@ function detectPackageManager(pkgJson) {
|
|
|
68
68
|
return 'bun';
|
|
69
69
|
return 'npm';
|
|
70
70
|
}
|
|
71
|
-
function
|
|
71
|
+
export function isCanaryVersion(version) {
|
|
72
|
+
return version?.includes('canary') === true;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Canary builds pin every hypequery package to a `0.0.0-canary-*` version, which
|
|
76
|
+
* sorts below every published semver range. Any third-party peer range on a
|
|
77
|
+
* hypequery package is therefore unsatisfiable — `chdb` declares
|
|
78
|
+
* `peerOptional @hypequery/clickhouse@">=2.1.2"` — and npm aborts the whole
|
|
79
|
+
* install with ERESOLVE, leaving the scaffold without its dependencies.
|
|
80
|
+
*
|
|
81
|
+
* Only npm needs this: pnpm (strict-peer-dependencies defaults to false), yarn
|
|
82
|
+
* and bun all install through peer conflicts rather than failing. Stable
|
|
83
|
+
* installs keep strict peer checking on every manager.
|
|
84
|
+
*/
|
|
85
|
+
function getPeerRelaxFlags(manager, canary) {
|
|
86
|
+
return canary && manager === 'npm' ? ['--legacy-peer-deps'] : [];
|
|
87
|
+
}
|
|
88
|
+
function getInstallArgs(manager, packages, canary = false) {
|
|
89
|
+
const relaxFlags = getPeerRelaxFlags(manager, canary);
|
|
72
90
|
switch (manager) {
|
|
73
91
|
case 'pnpm':
|
|
74
|
-
return ['add', ...packages];
|
|
92
|
+
return ['add', ...relaxFlags, ...packages];
|
|
75
93
|
case 'yarn':
|
|
76
|
-
return ['add', ...packages];
|
|
94
|
+
return ['add', ...relaxFlags, ...packages];
|
|
77
95
|
case 'bun':
|
|
78
|
-
return ['add', ...packages];
|
|
96
|
+
return ['add', ...relaxFlags, ...packages];
|
|
79
97
|
case 'npm':
|
|
80
98
|
default:
|
|
81
|
-
return ['install', ...packages];
|
|
99
|
+
return ['install', ...relaxFlags, ...packages];
|
|
82
100
|
}
|
|
83
101
|
}
|
|
84
|
-
function formatManualCommand(manager, packages) {
|
|
85
|
-
return
|
|
102
|
+
function formatManualCommand(manager, packages, canary = false) {
|
|
103
|
+
return [MANUAL_COMMANDS[manager], ...getPeerRelaxFlags(manager, canary), ...packages].join(' ');
|
|
86
104
|
}
|
|
87
105
|
export function resolveScaffoldPackages(cliVersion, style = 'queries', database = 'clickhouse') {
|
|
88
106
|
const includeDatasets = style === 'datasets';
|
|
89
107
|
const includeChdb = database === 'chdb';
|
|
90
|
-
if (cliVersion
|
|
108
|
+
if (isCanaryVersion(cliVersion)) {
|
|
91
109
|
return [
|
|
92
110
|
`@hypequery/clickhouse@${cliVersion}`,
|
|
93
111
|
`@hypequery/serve@${cliVersion}`,
|
|
@@ -141,9 +159,10 @@ export async function installScaffoldDependencies(style = 'queries', database =
|
|
|
141
159
|
if (missing.length === 0) {
|
|
142
160
|
return;
|
|
143
161
|
}
|
|
162
|
+
const canary = isCanaryVersion(cliPkgJson?.version);
|
|
144
163
|
const manager = detectPackageManager(pkgJson);
|
|
145
164
|
const command = manager === 'npm' ? 'npm' : manager;
|
|
146
|
-
const args = getInstallArgs(manager, missing);
|
|
165
|
+
const args = getInstallArgs(manager, missing, canary);
|
|
147
166
|
logger.info(`Installing ${missing.join(', ')} with ${manager}...`);
|
|
148
167
|
try {
|
|
149
168
|
await new Promise((resolve, reject) => {
|
|
@@ -165,7 +184,7 @@ export async function installScaffoldDependencies(style = 'queries', database =
|
|
|
165
184
|
}
|
|
166
185
|
catch (error) {
|
|
167
186
|
logger.warn('Failed to install hypequery packages automatically.');
|
|
168
|
-
logger.info(`Run manually: ${formatManualCommand(manager, missing)}`);
|
|
187
|
+
logger.info(`Run manually: ${formatManualCommand(manager, missing, canary)}`);
|
|
169
188
|
if (error instanceof Error && error.message) {
|
|
170
189
|
logger.info(error.message);
|
|
171
190
|
}
|
package/dist/utils/prompts.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raised when the user aborts a prompt with Ctrl+C or Esc.
|
|
3
|
+
*/
|
|
4
|
+
export declare class PromptCancelledError extends Error {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
7
|
+
export declare function isPromptCancelled(error: unknown): error is PromptCancelledError;
|
|
1
8
|
/**
|
|
2
9
|
* Prompt for ClickHouse connection details
|
|
3
10
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/utils/prompts.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;;CAK9C;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,oBAAoB,CAE/E;AA8BD;;GAEG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,CAAC,CAyCR;AAED,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,MAAM,CAAC;AAEjD;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAahE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA4BrE;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CA6B7D;AAED,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;AAE/C,wBAAsB,eAAe,IAAI,OAAO,CAAC,SAAS,CAAC,CAa1D;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,CAAC;AAE9C;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAahE;AAED;;GAEG;AACH,wBAAsB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASnF;AAED;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAS9D;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0BnF;AAED;;GAEG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,EAAE,EAChB,aAAa,GAAE,MAAM,EAAO,GAC3B,OAAO,CAAC,MAAM,EAAE,CAAC,CA2BnB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CASxE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASnE;AAED;;GAEG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC,CAShE"}
|
package/dist/utils/prompts.js
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
2
|
import { logger } from './logger.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Raised when the user aborts a prompt with Ctrl+C or Esc.
|
|
5
|
+
*/
|
|
6
|
+
export class PromptCancelledError extends Error {
|
|
7
|
+
constructor() {
|
|
8
|
+
super('Prompt cancelled');
|
|
9
|
+
this.name = 'PromptCancelledError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function isPromptCancelled(error) {
|
|
13
|
+
return error instanceof PromptCancelledError;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Ask a question and turn an aborted prompt into a thrown PromptCancelledError.
|
|
17
|
+
*
|
|
18
|
+
* `prompts` only reports cancellation through the `onCancel` callback passed as
|
|
19
|
+
* its second argument — the resolved answers simply omit the cancelled key. So
|
|
20
|
+
* without this wrapper Ctrl+C is indistinguishable from an unanswered question,
|
|
21
|
+
* and each caller's `?? default` silently answers on the user's behalf.
|
|
22
|
+
*/
|
|
23
|
+
async function ask(questions) {
|
|
24
|
+
let cancelled = false;
|
|
25
|
+
const answers = await prompts(questions, {
|
|
26
|
+
onCancel: () => {
|
|
27
|
+
cancelled = true;
|
|
28
|
+
// Returning false stops any remaining questions in the same chain.
|
|
29
|
+
return false;
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
if (cancelled) {
|
|
33
|
+
throw new PromptCancelledError();
|
|
34
|
+
}
|
|
35
|
+
return answers;
|
|
36
|
+
}
|
|
6
37
|
/**
|
|
7
38
|
* Prompt for ClickHouse connection details
|
|
8
39
|
*/
|
|
9
40
|
export async function promptClickHouseConnection() {
|
|
10
|
-
const hostResponse = await
|
|
41
|
+
const hostResponse = await ask({
|
|
11
42
|
type: 'text',
|
|
12
43
|
name: 'host',
|
|
13
44
|
message: 'ClickHouse URL (or skip to configure later):',
|
|
@@ -18,7 +49,7 @@ export async function promptClickHouseConnection() {
|
|
|
18
49
|
if (!hostResponse.host) {
|
|
19
50
|
return null;
|
|
20
51
|
}
|
|
21
|
-
const credentials = await
|
|
52
|
+
const credentials = await ask([
|
|
22
53
|
{
|
|
23
54
|
type: 'text',
|
|
24
55
|
name: 'database',
|
|
@@ -49,7 +80,7 @@ export async function promptClickHouseConnection() {
|
|
|
49
80
|
* Choose between a remote ClickHouse server and embedded chDB.
|
|
50
81
|
*/
|
|
51
82
|
export async function promptInitDatabase() {
|
|
52
|
-
const response = await
|
|
83
|
+
const response = await ask({
|
|
53
84
|
type: 'select',
|
|
54
85
|
name: 'database',
|
|
55
86
|
message: 'Choose your database',
|
|
@@ -67,7 +98,7 @@ export async function promptInitDatabase() {
|
|
|
67
98
|
* or undefined for in-memory.
|
|
68
99
|
*/
|
|
69
100
|
export async function promptChdbStorage() {
|
|
70
|
-
const response = await
|
|
101
|
+
const response = await ask({
|
|
71
102
|
type: 'select',
|
|
72
103
|
name: 'storage',
|
|
73
104
|
message: 'Where should embedded chDB store data?',
|
|
@@ -82,7 +113,7 @@ export async function promptChdbStorage() {
|
|
|
82
113
|
return undefined;
|
|
83
114
|
}
|
|
84
115
|
if (response.storage === 'custom') {
|
|
85
|
-
const customResponse = await
|
|
116
|
+
const customResponse = await ask({
|
|
86
117
|
type: 'text',
|
|
87
118
|
name: 'path',
|
|
88
119
|
message: 'Enter chDB data directory:',
|
|
@@ -96,7 +127,7 @@ export async function promptChdbStorage() {
|
|
|
96
127
|
* Prompt for output directory
|
|
97
128
|
*/
|
|
98
129
|
export async function promptOutputDirectory() {
|
|
99
|
-
const response = await
|
|
130
|
+
const response = await ask({
|
|
100
131
|
type: 'select',
|
|
101
132
|
name: 'directory',
|
|
102
133
|
message: 'Where should we create your analytics files?',
|
|
@@ -111,7 +142,7 @@ export async function promptOutputDirectory() {
|
|
|
111
142
|
return 'analytics'; // Default fallback
|
|
112
143
|
}
|
|
113
144
|
if (response.directory === 'custom') {
|
|
114
|
-
const customResponse = await
|
|
145
|
+
const customResponse = await ask({
|
|
115
146
|
type: 'text',
|
|
116
147
|
name: 'path',
|
|
117
148
|
message: 'Enter custom path:',
|
|
@@ -122,7 +153,7 @@ export async function promptOutputDirectory() {
|
|
|
122
153
|
return response.directory;
|
|
123
154
|
}
|
|
124
155
|
export async function promptInitStyle() {
|
|
125
|
-
const response = await
|
|
156
|
+
const response = await ask({
|
|
126
157
|
type: 'select',
|
|
127
158
|
name: 'style',
|
|
128
159
|
message: 'Choose your dev API style',
|
|
@@ -138,7 +169,7 @@ export async function promptInitStyle() {
|
|
|
138
169
|
* Choose whether generated routes include request-context auth scaffolding.
|
|
139
170
|
*/
|
|
140
171
|
export async function promptInitAuthMode() {
|
|
141
|
-
const response = await
|
|
172
|
+
const response = await ask({
|
|
142
173
|
type: 'select',
|
|
143
174
|
name: 'auth',
|
|
144
175
|
message: 'Choose authentication scaffolding',
|
|
@@ -154,7 +185,7 @@ export async function promptInitAuthMode() {
|
|
|
154
185
|
* Confirm scaffolding when init is run outside a Node project.
|
|
155
186
|
*/
|
|
156
187
|
export async function confirmWithoutPackageJson(directory) {
|
|
157
|
-
const response = await
|
|
188
|
+
const response = await ask({
|
|
158
189
|
type: 'confirm',
|
|
159
190
|
name: 'continue',
|
|
160
191
|
message: `package.json was not found in ${directory}. Continue scaffolding here?`,
|
|
@@ -166,7 +197,7 @@ export async function confirmWithoutPackageJson(directory) {
|
|
|
166
197
|
* Prompt for example query generation
|
|
167
198
|
*/
|
|
168
199
|
export async function promptGenerateExample() {
|
|
169
|
-
const response = await
|
|
200
|
+
const response = await ask({
|
|
170
201
|
type: 'confirm',
|
|
171
202
|
name: 'generate',
|
|
172
203
|
message: 'Generate an example query?',
|
|
@@ -191,7 +222,7 @@ export async function promptTableSelection(tables) {
|
|
|
191
222
|
...tables.slice(0, 10).map(table => ({ title: table, value: table })),
|
|
192
223
|
{ title: 'Skip example', value: null },
|
|
193
224
|
];
|
|
194
|
-
const response = await
|
|
225
|
+
const response = await ask({
|
|
195
226
|
type: 'select',
|
|
196
227
|
name: 'table',
|
|
197
228
|
message: 'Which table should we use for the example?',
|
|
@@ -214,7 +245,7 @@ export async function promptDatasetTableSelection(tables, defaultTables = []) {
|
|
|
214
245
|
logger.newline();
|
|
215
246
|
}
|
|
216
247
|
const defaults = new Set(defaultTables);
|
|
217
|
-
const response = await
|
|
248
|
+
const response = await ask({
|
|
218
249
|
type: 'multiselect',
|
|
219
250
|
name: 'tables',
|
|
220
251
|
message: 'Which tables should we scaffold as datasets?',
|
|
@@ -232,7 +263,7 @@ export async function promptDatasetTableSelection(tables, defaultTables = []) {
|
|
|
232
263
|
* Confirm overwrite of existing files
|
|
233
264
|
*/
|
|
234
265
|
export async function confirmOverwrite(files) {
|
|
235
|
-
const response = await
|
|
266
|
+
const response = await ask({
|
|
236
267
|
type: 'confirm',
|
|
237
268
|
name: 'overwrite',
|
|
238
269
|
message: `The following files will be overwritten:\n${files.map(f => ` • ${f}`).join('\n')}\n\nContinue?`,
|
|
@@ -244,7 +275,7 @@ export async function confirmOverwrite(files) {
|
|
|
244
275
|
* Retry prompt for failed operations
|
|
245
276
|
*/
|
|
246
277
|
export async function promptRetry(message) {
|
|
247
|
-
const response = await
|
|
278
|
+
const response = await ask({
|
|
248
279
|
type: 'confirm',
|
|
249
280
|
name: 'retry',
|
|
250
281
|
message,
|
|
@@ -256,7 +287,7 @@ export async function promptRetry(message) {
|
|
|
256
287
|
* Ask if user wants to continue without DB connection
|
|
257
288
|
*/
|
|
258
289
|
export async function promptContinueWithoutDb() {
|
|
259
|
-
const response = await
|
|
290
|
+
const response = await ask({
|
|
260
291
|
type: 'confirm',
|
|
261
292
|
name: 'continue',
|
|
262
293
|
message: 'Continue setup without database connection?',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypequery/cli",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.1",
|
|
4
4
|
"description": "Command-line interface for hypequery",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"open": "^10.0.0",
|
|
20
20
|
"ora": "^8.0.1",
|
|
21
21
|
"prompts": "^2.4.2",
|
|
22
|
-
"@hypequery/
|
|
23
|
-
"@hypequery/
|
|
22
|
+
"@hypequery/protocol": "0.9.0",
|
|
23
|
+
"@hypequery/deployment": "0.6.0"
|
|
24
24
|
},
|
|
25
25
|
"optionalDependencies": {
|
|
26
26
|
"@napi-rs/keyring": "1.3.0"
|