@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 +65 -6
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +19 -5
- package/dist/commands/deploy.d.ts +16 -3
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +109 -12
- package/dist/commands/deployment.d.ts +5 -0
- package/dist/commands/deployment.d.ts.map +1 -1
- package/dist/commands/deployment.js +10 -9
- package/dist/generators/index.d.ts +2 -2
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +12 -4
- package/package.json +3 -9
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
|
|
201
|
-
|
|
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
|
|
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
|
|
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;
|
|
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('
|
|
158
|
-
.description('Submit a
|
|
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
|
|
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
|
|
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
|
-
|
|
3
|
+
import { buildDeploymentCommand, prepareDeploymentReleaseCommand } from './deployment.js';
|
|
4
|
+
export interface SubmitDeploymentOptions {
|
|
4
5
|
release?: string;
|
|
5
6
|
endpoint?: string;
|
|
6
7
|
}
|
|
7
|
-
export interface
|
|
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
|
|
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":"
|
|
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"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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 =
|
|
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
|
-
|
|
94
|
-
|
|
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;
|
|
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(
|
|
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(
|
|
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(
|
|
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 {
|
|
3
|
-
import {
|
|
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,
|
|
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"}
|
package/dist/generators/index.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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:
|
|
5
|
-
|
|
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.
|
|
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": {
|