@hypequery/cli 1.11.0 → 1.12.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 CHANGED
@@ -25,6 +25,13 @@ Or install it once:
25
25
  npm install -D @hypequery/cli
26
26
  ```
27
27
 
28
+ Ship it to Hypequery Cloud:
29
+
30
+ ```bash
31
+ npx @hypequery/cli login
32
+ npx @hypequery/cli deploy analytics/api.ts
33
+ ```
34
+
28
35
  ## Commands
29
36
 
30
37
  ### `hypequery init`
@@ -140,7 +147,9 @@ semantic keys such as `dataset:orders`.
140
147
 
141
148
  Builds a closed deployment bundle for an exported HypeQuery API. The bundle
142
149
  contains canonical deployment metadata, every referenced runtime artifact, and
143
- a manifest that binds their exact bytes and identities.
150
+ a manifest that binds their exact bytes and identities. `hypequery deploy` runs
151
+ this step for you; reach for it directly in CI pipelines that stage artifacts,
152
+ or when you need the runtime options below.
144
153
 
145
154
  ```bash
146
155
  npx hypequery deployment:build analytics/api.ts
@@ -197,8 +206,9 @@ Use `--cloud-url <origin>` or `HYPEQUERY_CLOUD_URL` for a self-hosted or local
197
206
  Cloud instance. HTTPS is required except for loopback development origins.
198
207
 
199
208
  Once logged in, `hypequery deploy` automatically uses the stored endpoint and
200
- token. The deployment endpoint is returned by Cloud during the token exchange;
201
- it is the authenticated upload API, not the browser login endpoint. For
209
+ token, and resolves the project and environment from the same stored profile.
210
+ The deployment endpoint is returned by Cloud during the token exchange; it is
211
+ the authenticated upload API, not the browser login endpoint. For
202
212
  non-interactive CI usage, set both `HYPEQUERY_API_TOKEN` and
203
213
  `HYPEQUERY_DEPLOYMENT_ENDPOINT` (or pass `--endpoint`).
204
214
 
@@ -223,6 +233,53 @@ npx hypequery logout
223
233
  If the stored profile is unreadable, `logout` still removes the local state and
224
234
  reports that the token was not revoked; it expires on its own.
225
235
 
236
+ ### `hypequery deploy`
237
+
238
+ Builds a deployment bundle from an API module, prepares a target-bound release,
239
+ and submits both. This is the primary Cloud workflow: sign in once, then deploy
240
+ with one command.
241
+
242
+ ```bash
243
+ npx hypequery login
244
+ npx hypequery deploy analytics/api.ts
245
+ ```
246
+
247
+ The bundle is written to `analytics/hypequery-deployment` and the release to
248
+ `analytics/hypequery-deployment.release.json`. The target comes from the stored
249
+ Cloud profile unless you override it:
250
+
251
+ ```bash
252
+ npx hypequery deploy analytics/api.ts \
253
+ --project my-project \
254
+ --environment production
255
+ ```
256
+
257
+ The deployment endpoint and token are resolved before the build, so a missing
258
+ or expired login fails immediately rather than after bundling. The credential
259
+ rules are the same as `hypequery deployment:submit` below.
260
+
261
+ The three steps remain available individually as `deployment:build`,
262
+ `deployment:release`, and `deployment:submit` for CI pipelines that stage
263
+ artifacts, and for the cases `deploy` does not cover: `deploy` always builds the
264
+ runtime artifact itself, so Python deployments and prebuilt runtime artifacts
265
+ (`--runtime`, `--runtime-artifact`, `--runtime-file`) need `deployment:build`.
266
+
267
+ Options:
268
+
269
+ - `--project <project>`: target project identifier; defaults to the logged-in
270
+ target and must be paired with `--environment`
271
+ - `--environment <environment>`: target environment identifier; defaults to the
272
+ logged-in target and must be paired with `--project`
273
+ - `--bundle-output <directory>`: bundle directory, default
274
+ `analytics/hypequery-deployment`
275
+ - `--release-output <path>`: release JSON path, default beside the bundle
276
+ - `--endpoint <url>`: HTTPS submission endpoint; requires `HYPEQUERY_API_TOKEN`
277
+
278
+ > **Deprecated:** `hypequery deploy <bundle> --release <file>` still submits a
279
+ > prebuilt bundle and prints a deprecation warning. Use
280
+ > `hypequery deployment:submit` instead. `--release` cannot be combined with
281
+ > `--project`, `--environment`, `--bundle-output`, or `--release-output`.
282
+
226
283
  ### `hypequery deployment:release`
227
284
 
228
285
  Prepares a deterministic release request from a verified deployment bundle and
@@ -259,14 +316,16 @@ Options:
259
316
  logged-in target and must be paired with `--project`
260
317
  - `--output <path>`: release JSON path, default beside the bundle
261
318
 
262
- ### `hypequery deploy`
319
+ ### `hypequery deployment:submit`
263
320
 
264
321
  Submits a verified deployment bundle with an already-prepared target-bound
265
322
  release. The command verifies both inputs again, requires their bundle
266
- identities to match, and streams only the files declared by the bundle.
323
+ identities to match, and streams only the files declared by the bundle. Use it
324
+ when the bundle and release were produced by an earlier pipeline step; for the
325
+ ordinary path, use `hypequery deploy`.
267
326
 
268
327
  ```bash
269
- npx hypequery deploy analytics/hypequery-deployment \
328
+ npx hypequery deployment:submit analytics/hypequery-deployment \
270
329
  --release analytics/hypequery-deployment.release.json
271
330
  ```
272
331
 
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;AAuBpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAa9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;AAoMD,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyBpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAa9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;AAsND,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import { generateCommand } from './commands/generate.js';
7
7
  import { generateDatasetsCommand } from './commands/generate-datasets.js';
8
8
  import { generateManifestCommand } from './commands/generate-manifest.js';
9
9
  import { buildDeploymentCommand, prepareDeploymentReleaseCommand, validateDeploymentCommand, } from './commands/deployment.js';
10
- import { deployCommand, } from './commands/deploy.js';
10
+ import { deployCommand, submitDeploymentCommand, } from './commands/deploy.js';
11
11
  import { loginCommand, logoutCommand, } from './commands/login.js';
12
12
  const program = new Command();
13
13
  function getCliVersion() {
@@ -154,12 +154,24 @@ program
154
154
  await prepareDeploymentReleaseCommand(bundle, options);
155
155
  }));
156
156
  program
157
- .command('deploy <bundle>')
158
- .description('Submit a verified deployment bundle and release')
157
+ .command('deployment:submit <bundle>')
158
+ .description('Submit a prebuilt deployment bundle and release')
159
159
  .requiredOption('--release <path>', 'Target-bound release JSON path')
160
160
  .option('--endpoint <url>', 'HTTPS submission endpoint; requires HYPEQUERY_API_TOKEN')
161
161
  .action(runCommand(async (bundle, options) => {
162
- await deployCommand(bundle, options);
162
+ await submitDeploymentCommand(bundle, options);
163
+ }));
164
+ program
165
+ .command('deploy <source>')
166
+ .description('Build, prepare, and deploy a Hypequery API module')
167
+ .option('--bundle-output <directory>', 'Bundle directory (default: analytics/hypequery-deployment)')
168
+ .option('--release-output <path>', 'Release JSON path (default: beside the bundle)')
169
+ .option('--project <project>', 'Target project identifier (advanced override)')
170
+ .option('--environment <environment>', 'Target environment identifier (advanced override)')
171
+ .option('--release <path>', 'Submit a prebuilt bundle with this release (legacy)')
172
+ .option('--endpoint <url>', 'HTTPS submission endpoint; requires HYPEQUERY_API_TOKEN')
173
+ .action(runCommand(async (source, options) => {
174
+ await deployCommand(source, options);
163
175
  }));
164
176
  // Help command
165
177
  program
@@ -193,10 +205,12 @@ program.on('--help', () => {
193
205
  console.log(' hypequery generate:types --output analytics/schema.ts');
194
206
  console.log(' hypequery generate:datasets');
195
207
  console.log(' hypequery generate:manifest analytics/api.ts --output analytics/hypequery-manifest.json');
208
+ console.log(' hypequery deploy analytics/api.ts');
209
+ console.log(' hypequery deploy analytics/api.ts --project my-project --environment production');
196
210
  console.log(' hypequery deployment:build analytics/api.ts');
197
211
  console.log(' hypequery deployment:validate analytics/hypequery-deployment');
198
212
  console.log(' hypequery deployment:release analytics/hypequery-deployment --project my-project --environment production');
199
- console.log(' hypequery deploy analytics/hypequery-deployment --release analytics/hypequery-deployment.release.json');
213
+ console.log(' hypequery deployment:submit analytics/hypequery-deployment --release analytics/hypequery-deployment.release.json');
200
214
  console.log('');
201
215
  console.log('Docs: https://hypequery.com/docs');
202
216
  });
@@ -1,13 +1,26 @@
1
1
  import { createHttpDeploymentUploadTransport, type DeploymentSubmissionResponse } from '../utils/deployment-upload.js';
2
2
  import { type StoredCloudCredential } from '../utils/cloud-credential-store.js';
3
- export interface DeployOptions {
3
+ import { buildDeploymentCommand, prepareDeploymentReleaseCommand } from './deployment.js';
4
+ export interface SubmitDeploymentOptions {
4
5
  release?: string;
5
6
  endpoint?: string;
6
7
  }
7
- export interface DeployDependencies {
8
+ export interface DeployOptions extends SubmitDeploymentOptions {
9
+ project?: string;
10
+ environment?: string;
11
+ bundleOutput?: string;
12
+ releaseOutput?: string;
13
+ }
14
+ export interface SubmitDeploymentDependencies {
8
15
  readonly env?: Readonly<Record<string, string | undefined>>;
9
16
  readonly createTransport?: typeof createHttpDeploymentUploadTransport;
10
17
  readonly loadCredential?: () => Promise<StoredCloudCredential | null>;
11
18
  }
12
- export declare function deployCommand(bundlePath: string | undefined, options?: DeployOptions, dependencies?: DeployDependencies): Promise<DeploymentSubmissionResponse>;
19
+ export interface DeployDependencies extends SubmitDeploymentDependencies {
20
+ readonly buildDeployment?: typeof buildDeploymentCommand;
21
+ readonly prepareDeploymentRelease?: typeof prepareDeploymentReleaseCommand;
22
+ readonly submitDeployment?: typeof submitDeploymentCommand;
23
+ }
24
+ export declare function submitDeploymentCommand(bundlePath: string | undefined, options?: SubmitDeploymentOptions, dependencies?: SubmitDeploymentDependencies): Promise<DeploymentSubmissionResponse>;
25
+ export declare function deployCommand(sourcePath: string | undefined, options?: DeployOptions, dependencies?: DeployDependencies): Promise<DeploymentSubmissionResponse>;
13
26
  //# sourceMappingURL=deploy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,mCAAmC,EAEnC,KAAK,4BAA4B,EAElC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAK5C,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,mCAAmC,CAAC;IACtE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;CACvE;AA4DD,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,aAAkB,EAC3B,YAAY,GAAE,kBAAuB,GACpC,OAAO,CAAC,4BAA4B,CAAC,CAoFvC"}
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AASA,OAAO,EACL,mCAAmC,EAEnC,KAAK,4BAA4B,EAElC,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAChC,MAAM,iBAAiB,CAAC;AAMzB,MAAM,WAAW,uBAAuB;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAc,SAAQ,uBAAuB;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,mCAAmC,CAAC;IACtE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;CACvE;AAED,MAAM,WAAW,kBAAmB,SAAQ,4BAA4B;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,sBAAsB,CAAC;IACzD,QAAQ,CAAC,wBAAwB,CAAC,EAAE,OAAO,+BAA+B,CAAC;IAC3E,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,uBAAuB,CAAC;CAC5D;AA8GD,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,uBAA4B,EACrC,YAAY,GAAE,4BAAiC,GAC9C,OAAO,CAAC,4BAA4B,CAAC,CAwDvC;AAmDD,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,aAAkB,EAC3B,YAAY,GAAE,kBAAuB,GACpC,OAAO,CAAC,4BAA4B,CAAC,CAmDvC"}
@@ -1,10 +1,13 @@
1
- import { constants, open } from 'node:fs/promises';
1
+ import { access, constants, open } from 'node:fs/promises';
2
+ import path from 'node:path';
2
3
  import { prepareProtocolDeploymentReleaseEnvelope, } from '@hypequery/protocol';
3
- import { verifyDeploymentBundle } from '../utils/deployment-bundle.js';
4
+ import { DEPLOYMENT_BUNDLE_MANIFEST, verifyDeploymentBundle, } from '../utils/deployment-bundle.js';
4
5
  import { createHttpDeploymentUploadTransport, DeploymentUploadError, } from '../utils/deployment-upload.js';
5
6
  import { logger } from '../utils/logger.js';
6
7
  import { loadCloudCredential, } from '../utils/cloud-credential-store.js';
8
+ import { buildDeploymentCommand, prepareDeploymentReleaseCommand, } from './deployment.js';
7
9
  const MAX_RELEASE_FILE_BYTES = 16 * 1024;
10
+ const DEFAULT_BUNDLE_PATH = 'analytics/hypequery-deployment';
8
11
  const utf8Decoder = new TextDecoder('utf-8', { fatal: true });
9
12
  async function readReleaseFile(releasePath) {
10
13
  let handle;
@@ -61,15 +64,14 @@ function requiredConfiguration(value, message) {
61
64
  throw new Error(message);
62
65
  return value;
63
66
  }
64
- export async function deployCommand(bundlePath, options = {}, dependencies = {}) {
65
- if (!bundlePath) {
66
- throw new Error('Missing deployment bundle path.\n\n'
67
- + 'Usage: hypequery deploy analytics/hypequery-deployment '
68
- + '--release analytics/hypequery-deployment.release.json');
69
- }
70
- const releasePath = requiredConfiguration(options.release, 'Missing required --release <path>.');
67
+ /**
68
+ * Resolves the submission endpoint and token. Kept separate from
69
+ * `submitDeploymentCommand` so `deployCommand` can run it as a preflight
70
+ * before the bundle build.
71
+ */
72
+ async function resolveDeploymentCredential(endpointOption, dependencies) {
71
73
  const env = dependencies.env ?? process.env;
72
- let deploymentEndpoint = options.endpoint ?? env.HYPEQUERY_DEPLOYMENT_ENDPOINT;
74
+ let deploymentEndpoint = endpointOption ?? env.HYPEQUERY_DEPLOYMENT_ENDPOINT;
73
75
  let token = env.HYPEQUERY_API_TOKEN;
74
76
  const hasExplicitEndpoint = Boolean(deploymentEndpoint);
75
77
  const hasExplicitToken = Boolean(token);
@@ -90,8 +92,19 @@ export async function deployCommand(bundlePath, options = {}, dependencies = {})
90
92
  token = credential.token;
91
93
  }
92
94
  }
93
- deploymentEndpoint = requiredConfiguration(deploymentEndpoint, 'Missing deployment endpoint. Run `hypequery login`, pass --endpoint, or set HYPEQUERY_DEPLOYMENT_ENDPOINT.');
94
- token = requiredConfiguration(token, 'Missing deployment credential. Run `hypequery login` or set HYPEQUERY_API_TOKEN.');
95
+ return {
96
+ endpoint: requiredConfiguration(deploymentEndpoint, 'Missing deployment endpoint. Run `hypequery login`, pass --endpoint, or set HYPEQUERY_DEPLOYMENT_ENDPOINT.'),
97
+ token: requiredConfiguration(token, 'Missing deployment credential. Run `hypequery login` or set HYPEQUERY_API_TOKEN.'),
98
+ };
99
+ }
100
+ export async function submitDeploymentCommand(bundlePath, options = {}, dependencies = {}) {
101
+ if (!bundlePath) {
102
+ throw new Error('Missing deployment bundle path.\n\n'
103
+ + 'Usage: hypequery deployment:submit analytics/hypequery-deployment '
104
+ + '--release analytics/hypequery-deployment.release.json');
105
+ }
106
+ const releasePath = requiredConfiguration(options.release, 'Missing required --release <path>.');
107
+ const { endpoint: deploymentEndpoint, token } = await resolveDeploymentCredential(options.endpoint, dependencies);
95
108
  let bundle;
96
109
  try {
97
110
  bundle = await verifyDeploymentBundle(bundlePath);
@@ -125,3 +138,87 @@ export async function deployCommand(bundlePath, options = {}, dependencies = {})
125
138
  logger.info(`Bundle identity: ${result.bundleIdentity}`);
126
139
  return result;
127
140
  }
141
+ /**
142
+ * `deploy` takes an API module, but the deprecated form took a bundle
143
+ * directory. Dropping `--release` from an existing script would otherwise hand
144
+ * a bundle to the module loader and fail inside esbuild.
145
+ */
146
+ async function rejectBundleDirectorySource(sourcePath) {
147
+ try {
148
+ await access(path.join(sourcePath, DEPLOYMENT_BUNDLE_MANIFEST));
149
+ }
150
+ catch {
151
+ return;
152
+ }
153
+ throw new Error(`Cannot deploy a prebuilt bundle directory: ${sourcePath}\n\n`
154
+ + '`hypequery deploy` takes the API module to build, for example '
155
+ + '`hypequery deploy analytics/api.ts`.\n'
156
+ + 'To upload this bundle, use `hypequery deployment:submit '
157
+ + `${sourcePath} --release <file>\`.`);
158
+ }
159
+ /**
160
+ * `deploy` exposes no runtime flags, so a runtime error from the shared build
161
+ * command would otherwise point at flags this command does not accept.
162
+ */
163
+ function withRuntimeFlagHint(error) {
164
+ if (!(error instanceof Error) || !error.message.includes('--runtime'))
165
+ return error;
166
+ return new Error(`${error.message}\n\n`
167
+ + 'Runtime overrides are not available on `hypequery deploy`. Build with '
168
+ + '`hypequery deployment:build` (which accepts --runtime, --runtime-artifact, '
169
+ + 'and --runtime-file), then upload with `hypequery deployment:submit`.');
170
+ }
171
+ function rejectLegacyOrchestrationOptions(options) {
172
+ if (options.project !== undefined
173
+ || options.environment !== undefined
174
+ || options.bundleOutput !== undefined
175
+ || options.releaseOutput !== undefined) {
176
+ throw new Error('--release selects prebuilt submission mode and cannot be combined with '
177
+ + '--project, --environment, --bundle-output, or --release-output. '
178
+ + 'Use `hypequery deployment:submit` for explicit prebuilt uploads.');
179
+ }
180
+ }
181
+ export async function deployCommand(sourcePath, options = {}, dependencies = {}) {
182
+ if (!sourcePath) {
183
+ throw new Error('Missing API module path.\n\n'
184
+ + 'Usage: hypequery deploy analytics/api.ts');
185
+ }
186
+ if (options.release !== undefined) {
187
+ rejectLegacyOrchestrationOptions(options);
188
+ logger.warn('`hypequery deploy <bundle> --release <file>` is deprecated. '
189
+ + 'Use `hypequery deployment:submit <bundle> --release <file>` instead.');
190
+ return submitDeploymentCommand(sourcePath, {
191
+ release: options.release,
192
+ endpoint: options.endpoint,
193
+ }, dependencies);
194
+ }
195
+ await rejectBundleDirectorySource(sourcePath);
196
+ const bundlePath = options.bundleOutput ?? DEFAULT_BUNDLE_PATH;
197
+ const releasePath = options.releaseOutput
198
+ ?? `${bundlePath.replace(/[\\/]+$/, '')}.release.json`;
199
+ const build = dependencies.buildDeployment ?? buildDeploymentCommand;
200
+ const prepareRelease = dependencies.prepareDeploymentRelease
201
+ ?? prepareDeploymentReleaseCommand;
202
+ const submit = dependencies.submitDeployment ?? submitDeploymentCommand;
203
+ // Resolve credentials up front. Submission is the last step, so without this
204
+ // a missing or expired login only surfaces after a full bundle build.
205
+ await resolveDeploymentCredential(options.endpoint, dependencies);
206
+ try {
207
+ await build(sourcePath, { bundleOutput: bundlePath });
208
+ }
209
+ catch (error) {
210
+ throw withRuntimeFlagHint(error);
211
+ }
212
+ await prepareRelease(bundlePath, {
213
+ project: options.project,
214
+ environment: options.environment,
215
+ output: releasePath,
216
+ }, {
217
+ loadCredential: dependencies.loadCredential,
218
+ outputFlagLabel: '--release-output',
219
+ });
220
+ return submit(bundlePath, {
221
+ release: releasePath,
222
+ endpoint: options.endpoint,
223
+ }, dependencies);
224
+ }
@@ -17,6 +17,11 @@ export interface PrepareDeploymentReleaseOptions {
17
17
  }
18
18
  export interface PrepareDeploymentReleaseDependencies {
19
19
  loadCredential?: () => Promise<StoredCloudCredential | null>;
20
+ /**
21
+ * Flag name to quote in output-path errors. `hypequery deploy` delegates
22
+ * here but spells the same option `--release-output`.
23
+ */
24
+ outputFlagLabel?: string;
20
25
  }
21
26
  export declare function buildDeploymentCommand(apiPath: string | undefined, options?: BuildDeploymentOptions): Promise<ProtocolDeploymentContract>;
22
27
  export declare function validateDeploymentCommand(artifactPath: string | undefined): Promise<ProtocolDeploymentContract>;
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../src/commands/deployment.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,iCAAiC,EACvC,MAAM,qBAAqB,CAAC;AAc7B,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAI5C,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oCAAoC;IACnD,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;CAC9D;AAoDD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAwIrC;AAED,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,0BAA0B,CAAC,CA2ErC;AA0DD,wBAAsB,+BAA+B,CACnD,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,+BAAoC,EAC7C,YAAY,GAAE,oCAAyC,GACtD,OAAO,CAAC,iCAAiC,CAAC,CAgE5C"}
1
+ {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../src/commands/deployment.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,0BAA0B,EAC/B,KAAK,iCAAiC,EACvC,MAAM,qBAAqB,CAAC;AAc7B,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,oCAAoC,CAAC;AAI5C,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oCAAoC;IACnD,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;IAC7D;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAoDD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,0BAA0B,CAAC,CAwIrC;AAED,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,0BAA0B,CAAC,CA2ErC;AAiED,wBAAsB,+BAA+B,CACnD,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,OAAO,GAAE,+BAAoC,EAC7C,YAAY,GAAE,oCAAyC,GACtD,OAAO,CAAC,iCAAiC,CAAC,CAkE5C"}
@@ -218,7 +218,7 @@ export async function validateDeploymentCommand(artifactPath) {
218
218
  logger.info(`Identity: ${digest}`);
219
219
  return contract;
220
220
  }
221
- function assertOutputOutsideBundle(bundlePath, outputPath) {
221
+ function assertOutputOutsideBundle(bundlePath, outputPath, outputFlag) {
222
222
  const bundle = path.resolve(bundlePath);
223
223
  const output = path.resolve(outputPath);
224
224
  const relative = path.relative(bundle, output);
@@ -226,10 +226,10 @@ function assertOutputOutsideBundle(bundlePath, outputPath) {
226
226
  || relative.startsWith(`..${path.sep}`)
227
227
  || path.isAbsolute(relative);
228
228
  if (relative === '' || !outside) {
229
- throw new Error('--output must be outside the closed deployment bundle directory.');
229
+ throw new Error(`${outputFlag} must be outside the closed deployment bundle directory.`);
230
230
  }
231
231
  }
232
- async function prospectiveRealPath(inputPath) {
232
+ async function prospectiveRealPath(inputPath, outputFlag) {
233
233
  let current = path.resolve(inputPath);
234
234
  const missingSegments = [];
235
235
  for (;;) {
@@ -244,7 +244,7 @@ async function prospectiveRealPath(inputPath) {
244
244
  try {
245
245
  const stat = await lstat(current);
246
246
  if (stat.isSymbolicLink()) {
247
- throw new Error('--output must not traverse a dangling symbolic link.');
247
+ throw new Error(`${outputFlag} must not traverse a dangling symbolic link.`);
248
248
  }
249
249
  }
250
250
  catch (lstatError) {
@@ -261,11 +261,11 @@ async function prospectiveRealPath(inputPath) {
261
261
  }
262
262
  }
263
263
  }
264
- async function assertOutputIsNotSymbolicLink(outputPath) {
264
+ async function assertOutputIsNotSymbolicLink(outputPath, outputFlag) {
265
265
  try {
266
266
  const outputStat = await lstat(outputPath);
267
267
  if (outputStat.isSymbolicLink()) {
268
- throw new Error('--output must not be a symbolic link.');
268
+ throw new Error(`${outputFlag} must not be a symbolic link.`);
269
269
  }
270
270
  }
271
271
  catch (error) {
@@ -303,8 +303,9 @@ export async function prepareDeploymentReleaseCommand(bundlePath, options = {},
303
303
  + '--project <project> and --environment <environment>.');
304
304
  }
305
305
  }
306
+ const outputFlag = dependencies.outputFlagLabel ?? '--output';
306
307
  const outputPath = options.output ?? `${bundlePath.replace(/[\\/]+$/, '')}.release.json`;
307
- assertOutputOutsideBundle(bundlePath, outputPath);
308
+ assertOutputOutsideBundle(bundlePath, outputPath, outputFlag);
308
309
  let bundle;
309
310
  try {
310
311
  bundle = await verifyDeploymentBundle(bundlePath);
@@ -313,7 +314,7 @@ export async function prepareDeploymentReleaseCommand(bundlePath, options = {},
313
314
  throw new Error(`Cannot prepare a release from an invalid deployment bundle: ${bundlePath}\n\n`
314
315
  + (error instanceof Error ? error.message : String(error)));
315
316
  }
316
- assertOutputOutsideBundle(bundle.directory, await prospectiveRealPath(outputPath));
317
+ assertOutputOutsideBundle(bundle.directory, await prospectiveRealPath(outputPath, outputFlag), outputFlag);
317
318
  const prepared = prepareProtocolDeploymentReleaseEnvelope({
318
319
  kind: 'hypequery-deployment-release',
319
320
  version: 1,
@@ -324,7 +325,7 @@ export async function prepareDeploymentReleaseCommand(bundlePath, options = {},
324
325
  },
325
326
  });
326
327
  await mkdir(path.dirname(outputPath), { recursive: true });
327
- await assertOutputIsNotSymbolicLink(outputPath);
328
+ await assertOutputIsNotSymbolicLink(outputPath, outputFlag);
328
329
  await writeFile(outputPath, `${prepared.canonical}\n`, 'utf8');
329
330
  logger.success(`Deployment release written to ${outputPath}`);
330
331
  logger.info(`Target: ${project}/${environment}`);
@@ -1,6 +1,6 @@
1
1
  import type { DatabaseType } from '../utils/detect-database.js';
2
- import { type ClickHouseGeneratorOptions } from './clickhouse.js';
3
- import { type ChdbGeneratorOptions } from './chdb.js';
2
+ import type { ClickHouseGeneratorOptions } from './clickhouse.js';
3
+ import type { ChdbGeneratorOptions } from './chdb.js';
4
4
  export type TypeGeneratorOptions = ClickHouseGeneratorOptions & ChdbGeneratorOptions;
5
5
  type GeneratorFn = (options: TypeGeneratorOptions) => Promise<void>;
6
6
  export declare function getTypeGenerator(dbType: DatabaseType): GeneratorFn;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAA2B,KAAK,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAC3F,OAAO,EAAqB,KAAK,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEzE,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG,oBAAoB,CAAC;AAErF,KAAK,WAAW,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAOpE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAYlE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,iBAAiB,CAAC;AAClE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG,oBAAoB,CAAC;AAErF,KAAK,WAAW,GAAG,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAiBpE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,WAAW,CAYlE"}
@@ -1,8 +1,16 @@
1
- import { generateClickHouseTypes } from './clickhouse.js';
2
- import { generateChdbTypes } from './chdb.js';
1
+ // Loaded on demand. Both generators pull in `@hypequery/clickhouse/cli`, and importing
2
+ // that eagerly puts it on the module graph of every command — a resolution failure there
3
+ // took down even `hypequery --help`. Deferring it keeps the blast radius on the commands
4
+ // that actually generate types.
3
5
  const generators = {
4
- clickhouse: generateClickHouseTypes,
5
- chdb: generateChdbTypes,
6
+ clickhouse: async (options) => {
7
+ const { generateClickHouseTypes } = await import('./clickhouse.js');
8
+ await generateClickHouseTypes(options);
9
+ },
10
+ chdb: async (options) => {
11
+ const { generateChdbTypes } = await import('./chdb.js');
12
+ await generateChdbTypes(options);
13
+ },
6
14
  };
7
15
  export function getTypeGenerator(dbType) {
8
16
  const generator = generators[dbType];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypequery/cli",
3
- "version": "1.11.0",
3
+ "version": "1.12.1",
4
4
  "description": "Command-line interface for hypequery",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -20,27 +20,21 @@
20
20
  "ora": "^8.0.1",
21
21
  "prompts": "^2.4.2",
22
22
  "@hypequery/deployment": "0.6.0",
23
- "@hypequery/protocol": "0.9.0"
23
+ "@hypequery/protocol": "0.9.0",
24
+ "@hypequery/clickhouse": "2.5.2"
24
25
  },
25
26
  "optionalDependencies": {
26
27
  "@napi-rs/keyring": "1.3.0"
27
28
  },
28
29
  "peerDependencies": {
29
- "@hypequery/clickhouse": "*",
30
30
  "@hypequery/serve": "*"
31
31
  },
32
- "peerDependenciesMeta": {
33
- "@hypequery/clickhouse": {
34
- "optional": true
35
- }
36
- },
37
32
  "devDependencies": {
38
33
  "@types/node": "^20.11.30",
39
34
  "@types/prompts": "^2.4.9",
40
35
  "@vitest/coverage-v8": "^3.2.6",
41
36
  "typescript": "^5.7.3",
42
37
  "vitest": "^3.2.6",
43
- "@hypequery/clickhouse": "2.5.2",
44
38
  "@hypequery/serve": "0.14.0"
45
39
  },
46
40
  "repository": {