@hypequery/cli 1.14.0 → 1.15.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/README.md +19 -128
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +25 -0
- package/dist/utils/deployment-runtime-artifact.d.ts.map +1 -1
- package/dist/utils/deployment-runtime-artifact.js +15 -5
- package/dist/utils/git-branch.d.ts +9 -0
- package/dist/utils/git-branch.d.ts.map +1 -0
- package/dist/utils/git-branch.js +26 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -25,13 +25,6 @@ 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
|
-
|
|
35
28
|
## Commands
|
|
36
29
|
|
|
37
30
|
### `hypequery init`
|
|
@@ -156,9 +149,9 @@ semantic keys such as `dataset:orders`.
|
|
|
156
149
|
|
|
157
150
|
Builds a closed deployment bundle for an exported HypeQuery API. The bundle
|
|
158
151
|
contains canonical deployment metadata, every referenced runtime artifact, and
|
|
159
|
-
a manifest that binds their exact bytes and identities.
|
|
160
|
-
|
|
161
|
-
|
|
152
|
+
a manifest that binds their exact bytes and identities. It is the first step of
|
|
153
|
+
a deployment pipeline, and produces the input `deployment:release` binds to a
|
|
154
|
+
target.
|
|
162
155
|
|
|
163
156
|
```bash
|
|
164
157
|
npx hypequery deployment:build analytics/api.ts
|
|
@@ -200,112 +193,16 @@ are still accepted for metadata-only validation.
|
|
|
200
193
|
npx hypequery deployment:validate analytics/hypequery-deployment
|
|
201
194
|
```
|
|
202
195
|
|
|
203
|
-
### `hypequery login`
|
|
204
|
-
|
|
205
|
-
Authorizes the local CLI through your existing Hypequery Cloud browser
|
|
206
|
-
session. The command uses an S256 PKCE loopback flow, then stores the
|
|
207
|
-
target-scoped deployment token in the operating-system credential vault.
|
|
208
|
-
Tokens expire after 12 hours.
|
|
209
|
-
|
|
210
|
-
```bash
|
|
211
|
-
npx hypequery login
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
Use `--cloud-url <origin>` or `HYPEQUERY_CLOUD_URL` for a self-hosted or local
|
|
215
|
-
Cloud instance. HTTPS is required except for loopback development origins.
|
|
216
|
-
|
|
217
|
-
Once logged in, `hypequery deploy` automatically uses the stored endpoint and
|
|
218
|
-
token, and resolves the project and environment from the same stored profile.
|
|
219
|
-
The deployment endpoint is returned by Cloud during the token exchange; it is
|
|
220
|
-
the authenticated upload API, not the browser login endpoint. For
|
|
221
|
-
non-interactive CI usage, set both `HYPEQUERY_API_TOKEN` and
|
|
222
|
-
`HYPEQUERY_DEPLOYMENT_ENDPOINT` (or pass `--endpoint`).
|
|
223
|
-
|
|
224
|
-
Because the CLI also loads a project `.env`, a `HYPEQUERY_API_TOKEN` left there
|
|
225
|
-
takes precedence over the login flow and is rejected unless it is paired with an
|
|
226
|
-
endpoint. Unset it to use `hypequery login`.
|
|
227
|
-
|
|
228
|
-
Token storage requires an operating-system credential vault (Keychain,
|
|
229
|
-
Credential Manager, or a Secret Service implementation such as
|
|
230
|
-
gnome-keyring/KWallet). Headless environments without one should use
|
|
231
|
-
`HYPEQUERY_API_TOKEN` instead of `hypequery login`.
|
|
232
|
-
|
|
233
|
-
### `hypequery logout`
|
|
234
|
-
|
|
235
|
-
Revokes the current Cloud token and removes it from the operating-system
|
|
236
|
-
credential vault:
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
npx hypequery logout
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
If the stored profile is unreadable, `logout` still removes the local state and
|
|
243
|
-
reports that the token was not revoked; it expires on its own.
|
|
244
|
-
|
|
245
|
-
### `hypequery deploy`
|
|
246
|
-
|
|
247
|
-
Builds a deployment bundle from an API module, prepares a target-bound release,
|
|
248
|
-
and submits both. This is the primary Cloud workflow: sign in once, then deploy
|
|
249
|
-
with one command.
|
|
250
|
-
|
|
251
|
-
```bash
|
|
252
|
-
npx hypequery login
|
|
253
|
-
npx hypequery deploy analytics/api.ts
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
The bundle is written to `analytics/hypequery-deployment` and the release to
|
|
257
|
-
`analytics/hypequery-deployment.release.json`. The target comes from the stored
|
|
258
|
-
Cloud profile unless you override it:
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
npx hypequery deploy analytics/api.ts \
|
|
262
|
-
--project my-project \
|
|
263
|
-
--environment production
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
The deployment endpoint and token are resolved before the build, so a missing
|
|
267
|
-
or expired login fails immediately rather than after bundling. The credential
|
|
268
|
-
rules are the same as `hypequery deployment:submit` below.
|
|
269
|
-
|
|
270
|
-
The three steps remain available individually as `deployment:build`,
|
|
271
|
-
`deployment:release`, and `deployment:submit` for CI pipelines that stage
|
|
272
|
-
artifacts, and for the cases `deploy` does not cover: `deploy` always builds the
|
|
273
|
-
runtime artifact itself, so Python deployments and prebuilt runtime artifacts
|
|
274
|
-
(`--runtime`, `--runtime-artifact`, `--runtime-file`) need `deployment:build`.
|
|
275
|
-
|
|
276
|
-
Options:
|
|
277
|
-
|
|
278
|
-
- `--project <project>`: target project identifier; defaults to the logged-in
|
|
279
|
-
target and must be paired with `--environment`
|
|
280
|
-
- `--environment <environment>`: target environment identifier; defaults to the
|
|
281
|
-
logged-in target and must be paired with `--project`
|
|
282
|
-
- `--bundle-output <directory>`: bundle directory, default
|
|
283
|
-
`analytics/hypequery-deployment`
|
|
284
|
-
- `--release-output <path>`: release JSON path, default beside the bundle
|
|
285
|
-
- `--endpoint <url>`: HTTPS submission endpoint; requires `HYPEQUERY_API_TOKEN`
|
|
286
|
-
|
|
287
|
-
> **Deprecated:** `hypequery deploy <bundle> --release <file>` still submits a
|
|
288
|
-
> prebuilt bundle and prints a deprecation warning. Use
|
|
289
|
-
> `hypequery deployment:submit` instead. `--release` cannot be combined with
|
|
290
|
-
> `--project`, `--environment`, `--bundle-output`, or `--release-output`.
|
|
291
|
-
|
|
292
196
|
### `hypequery deployment:release`
|
|
293
197
|
|
|
294
198
|
Prepares a deterministic release request from a verified deployment bundle and
|
|
295
199
|
a project/environment target. This command does not upload, authorize, or
|
|
296
200
|
execute the release.
|
|
297
201
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
npx hypequery deployment:release analytics/hypequery-deployment
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
To target something other than the logged-in project and environment, pass both
|
|
306
|
-
flags. A half-specified override is rejected rather than completed from the
|
|
307
|
-
stored profile, so an unset shell variable fails loudly instead of silently
|
|
308
|
-
retargeting the release:
|
|
202
|
+
Pass the target as both flags. A half-specified target is rejected rather than
|
|
203
|
+
completed from anywhere else, so an unset shell variable fails loudly instead of
|
|
204
|
+
silently retargeting the release. The resolved target is printed alongside the
|
|
205
|
+
release identity:
|
|
309
206
|
|
|
310
207
|
```bash
|
|
311
208
|
npx hypequery deployment:release analytics/hypequery-deployment \
|
|
@@ -319,36 +216,30 @@ invalidate bundle verification.
|
|
|
319
216
|
|
|
320
217
|
Options:
|
|
321
218
|
|
|
322
|
-
- `--project <project>`: target project identifier;
|
|
323
|
-
|
|
324
|
-
- `--environment <environment>`: target environment identifier;
|
|
325
|
-
|
|
219
|
+
- `--project <project>`: target project identifier; must be paired with
|
|
220
|
+
`--environment`
|
|
221
|
+
- `--environment <environment>`: target environment identifier; must be paired
|
|
222
|
+
with `--project`
|
|
326
223
|
- `--output <path>`: release JSON path, default beside the bundle
|
|
327
224
|
|
|
328
225
|
### `hypequery deployment:submit`
|
|
329
226
|
|
|
330
227
|
Submits a verified deployment bundle with an already-prepared target-bound
|
|
331
228
|
release. The command verifies both inputs again, requires their bundle
|
|
332
|
-
identities to match, and streams only the files declared by the bundle.
|
|
333
|
-
when the bundle and release were produced by an earlier pipeline step; for the
|
|
334
|
-
ordinary path, use `hypequery deploy`.
|
|
229
|
+
identities to match, and streams only the files declared by the bundle.
|
|
335
230
|
|
|
336
231
|
```bash
|
|
337
232
|
npx hypequery deployment:submit analytics/hypequery-deployment \
|
|
338
233
|
--release analytics/hypequery-deployment.release.json
|
|
339
234
|
```
|
|
340
235
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
except for `127.0.0.1`/`localhost`, which is permitted for local Cloud
|
|
349
|
-
development and warns that the token is sent in cleartext. The release identity
|
|
350
|
-
is sent as the idempotency key, so an unchanged release can be submitted safely
|
|
351
|
-
again.
|
|
236
|
+
Set `HYPEQUERY_API_TOKEN` together with either `--endpoint` or
|
|
237
|
+
`HYPEQUERY_DEPLOYMENT_ENDPOINT`. Tokens are never accepted as command-line
|
|
238
|
+
arguments, keeping them out of shell history. The submission endpoint must not
|
|
239
|
+
contain credentials or a URL fragment, and must use HTTPS except for
|
|
240
|
+
`127.0.0.1`/`localhost`, which is permitted for local development and warns that
|
|
241
|
+
the token is sent in cleartext. The release identity is sent as the idempotency
|
|
242
|
+
key, so an unchanged release can be submitted safely again.
|
|
352
243
|
|
|
353
244
|
This command submits immutable deployment inputs. Activation, status changes,
|
|
354
245
|
promotion, and rollback remain control-plane operations.
|
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;AA0BpC,QAAA,MAAM,OAAO,SAAgB,CAAC;AAa9B,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAKpE;
|
|
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;AA+ND,OAAO,EAAE,OAAO,EAAE,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -34,6 +34,7 @@ program
|
|
|
34
34
|
.command('login')
|
|
35
35
|
.description('Authorize this machine with Hypequery Cloud')
|
|
36
36
|
.option('--cloud-url <url>', 'Cloud origin (or HYPEQUERY_CLOUD_URL)')
|
|
37
|
+
.option('--no-branch', 'Do not send the current Git branch (or HYPEQUERY_CLI_SEND_BRANCH=0)')
|
|
37
38
|
.action(runCommand(async (options) => {
|
|
38
39
|
await loginCommand(options);
|
|
39
40
|
}));
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { deleteCloudCredential, loadCloudCredential, saveCloudCredential } from '../utils/cloud-credential-store.js';
|
|
2
2
|
export interface LoginOptions {
|
|
3
3
|
readonly cloudUrl?: string;
|
|
4
|
+
/** Commander sets this to false for `--no-branch`. */
|
|
5
|
+
readonly branch?: boolean;
|
|
4
6
|
}
|
|
5
7
|
export interface LoginDependencies {
|
|
6
8
|
readonly fetch?: typeof fetch;
|
|
9
|
+
readonly getGitBranch?: () => Promise<string | null>;
|
|
7
10
|
readonly openBrowser?: (url: string) => Promise<unknown>;
|
|
8
11
|
readonly now?: () => number;
|
|
9
12
|
readonly requestTimeoutMs?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,qBAAqB,EACrB,mBAAmB,EAGnB,mBAAmB,EAEpB,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,qBAAqB,EACrB,mBAAmB,EAGnB,mBAAmB,EAEpB,MAAM,oCAAoC,CAAC;AAiB5C,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,sDAAsD;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACrD,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACrD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAaD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IAC9B,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACrD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,qBAAqB,CAAC;IACzD,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAsJD,wBAAsB,YAAY,CAChC,OAAO,GAAE,YAAiB,EAC1B,YAAY,GAAE,iBAAsB,iBAkErC;AAED,wBAAsB,aAAa,CAAC,YAAY,GAAE,kBAAuB,iBAoCxE"}
|
package/dist/commands/login.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createServer } from 'node:http';
|
|
|
3
3
|
import open from 'open';
|
|
4
4
|
import { validateProtocolDeploymentReleaseTarget } from '@hypequery/protocol';
|
|
5
5
|
import { CLOUD_DEPLOYMENT_SCOPE, deleteCloudCredential, loadCloudCredential, normalizeCloudDeploymentEndpoint, normalizeCloudOrigin, saveCloudCredential, } from '../utils/cloud-credential-store.js';
|
|
6
|
+
import { currentGitBranch } from '../utils/git-branch.js';
|
|
6
7
|
import { logger } from '../utils/logger.js';
|
|
7
8
|
const DEFAULT_CLOUD_URL = 'https://cloud.hypequery.com';
|
|
8
9
|
const LOGIN_TIMEOUT_MS = 5 * 60_000;
|
|
@@ -16,6 +17,17 @@ const MAX_TOKEN_LIFETIME_MS = 13 * 60 * 60_000;
|
|
|
16
17
|
// CLI the day Cloud rotates its token format.
|
|
17
18
|
const TOKEN_PATTERN = /^hqdp_[A-Za-z0-9_-]{16,512}$/;
|
|
18
19
|
const utf8Decoder = new TextDecoder('utf-8', { fatal: true });
|
|
20
|
+
/**
|
|
21
|
+
* Branch names carry internal detail (customer names, embargoed identifiers),
|
|
22
|
+
* so both an explicit `--no-branch` and the environment variable suppress the
|
|
23
|
+
* parameter. The flag wins because it is the more specific signal.
|
|
24
|
+
*/
|
|
25
|
+
function branchContextEnabled(options) {
|
|
26
|
+
if (options.branch === false)
|
|
27
|
+
return false;
|
|
28
|
+
const configured = process.env.HYPEQUERY_CLI_SEND_BRANCH?.trim().toLowerCase();
|
|
29
|
+
return configured !== '0' && configured !== 'false' && configured !== 'no';
|
|
30
|
+
}
|
|
19
31
|
function callbackHtml(success) {
|
|
20
32
|
const title = success ? 'CLI authorized' : 'Authorization failed';
|
|
21
33
|
const message = success
|
|
@@ -162,12 +174,20 @@ export async function loginCommand(options = {}, dependencies = {}) {
|
|
|
162
174
|
const state = randomBytes(24).toString('base64url');
|
|
163
175
|
const verifier = randomBytes(32).toString('base64url');
|
|
164
176
|
const challenge = createHash('sha256').update(verifier).digest('base64url');
|
|
177
|
+
// Resolve branch context before the loopback listener opens: shelling out to
|
|
178
|
+
// git should not hold a server socket, and a caller-supplied resolver that
|
|
179
|
+
// rejects must not leak one.
|
|
180
|
+
const branch = branchContextEnabled(options)
|
|
181
|
+
? await (dependencies.getGitBranch ?? currentGitBranch)()
|
|
182
|
+
: null;
|
|
165
183
|
const callback = await callbackServer(state, dependencies.timeoutMs ?? LOGIN_TIMEOUT_MS);
|
|
166
184
|
const authorizeUrl = new URL('/cli/authorize', origin);
|
|
167
185
|
authorizeUrl.searchParams.set('redirect_uri', callback.redirectUri);
|
|
168
186
|
authorizeUrl.searchParams.set('code_challenge', challenge);
|
|
169
187
|
authorizeUrl.searchParams.set('code_challenge_method', 'S256');
|
|
170
188
|
authorizeUrl.searchParams.set('state', state);
|
|
189
|
+
if (branch)
|
|
190
|
+
authorizeUrl.searchParams.set('branch', branch);
|
|
171
191
|
try {
|
|
172
192
|
logger.info('Opening your browser to authorize Hypequery CLI…');
|
|
173
193
|
await (dependencies.openBrowser ?? open)(authorizeUrl.toString());
|
|
@@ -195,6 +215,11 @@ export async function loginCommand(options = {}, dependencies = {}) {
|
|
|
195
215
|
const credential = tokenResponse(body, origin, (dependencies.now ?? Date.now)());
|
|
196
216
|
await (dependencies.saveCredential ?? saveCloudCredential)(credential);
|
|
197
217
|
logger.success('Logged in to Hypequery Cloud');
|
|
218
|
+
// Cloud resolves the target, and branch context only expresses intent, so
|
|
219
|
+
// print what was actually issued rather than what was requested.
|
|
220
|
+
if (credential.target) {
|
|
221
|
+
logger.info(`Deployments target ${credential.target.project} / ${credential.target.environment}`);
|
|
222
|
+
}
|
|
198
223
|
logger.info(`Credential expires ${new Date(credential.expiresAt).toLocaleString()}`);
|
|
199
224
|
}
|
|
200
225
|
finally {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployment-runtime-artifact.d.ts","sourceRoot":"","sources":["../../src/utils/deployment-runtime-artifact.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD;AASD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CA6BjF;
|
|
1
|
+
{"version":3,"file":"deployment-runtime-artifact.d.ts","sourceRoot":"","sources":["../../src/utils/deployment-runtime-artifact.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;CAChD;AASD,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CA6BjF;AAiED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,kBAAkB,EAAE,SAAS,MAAM,EAAE,EACrC,gBAAgB,SAAY,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CAmD9B"}
|
|
@@ -69,15 +69,25 @@ function runtimeEntrySource(apiSpecifier, runtimeEntrypoints, entrypointPrefix)
|
|
|
69
69
|
' ...(argument.context === undefined ? {} : { context: argument.context }),',
|
|
70
70
|
' ...(argument.request === undefined ? {} : { request: argument.request }),',
|
|
71
71
|
' ...(argument.requestId === undefined ? {} : { requestId: argument.requestId }),',
|
|
72
|
+
// A null principal means "no trusted principal"; forwarding it would skip the
|
|
73
|
+
// API's own auth strategies instead of falling through to them.
|
|
74
|
+
' ...(argument.trustedAuth == null ? {} : { trustedAuth: argument.trustedAuth }),',
|
|
72
75
|
' });',
|
|
73
76
|
' }',
|
|
74
77
|
' const entry = api.queries?.[name];',
|
|
75
78
|
' const query = entry?.query;',
|
|
76
|
-
'
|
|
77
|
-
' if (
|
|
78
|
-
'
|
|
79
|
-
' }',
|
|
80
|
-
'
|
|
79
|
+
' let run;',
|
|
80
|
+
' if (typeof query === "function") run = query;',
|
|
81
|
+
' else if (query && typeof query === "object" && typeof query.run === "function") run = query.run.bind(query);',
|
|
82
|
+
' if (!run) throw new Error(`Runtime entrypoint ${name} is unavailable.`);',
|
|
83
|
+
' // Without a Serve execute() pipeline there is nothing to enforce roles, scopes,',
|
|
84
|
+
' // or tenancy, so refuse a trusted principal instead of silently ignoring it.',
|
|
85
|
+
' return (argument = {}) => {',
|
|
86
|
+
' if (argument?.trustedAuth != null) {',
|
|
87
|
+
' throw new Error(`Runtime entrypoint ${name} cannot enforce a trusted principal without a Serve execute() pipeline.`);',
|
|
88
|
+
' }',
|
|
89
|
+
' return run(argument);',
|
|
90
|
+
' };',
|
|
81
91
|
'};',
|
|
82
92
|
`const runtimeEntries = Object.freeze(Object.fromEntries(${names}.map(name => [name, resolveQuery(name)])));`,
|
|
83
93
|
`export const ${prefix[0]} = ${registryExpression};`,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the checked-out branch name, or null when there isn't one.
|
|
3
|
+
*
|
|
4
|
+
* `git symbolic-ref` exits non-zero on a detached HEAD and outside a
|
|
5
|
+
* repository, and the binary may be missing entirely, so every failure mode
|
|
6
|
+
* collapses to "no branch context" rather than an error the caller must handle.
|
|
7
|
+
*/
|
|
8
|
+
export declare function currentGitBranch(cwd?: string): Promise<string | null>;
|
|
9
|
+
//# sourceMappingURL=git-branch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-branch.d.ts","sourceRoot":"","sources":["../../src/utils/git-branch.ts"],"names":[],"mappings":"AAOA;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBxB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
const GIT_TIMEOUT_MS = 5_000;
|
|
5
|
+
/**
|
|
6
|
+
* Resolves the checked-out branch name, or null when there isn't one.
|
|
7
|
+
*
|
|
8
|
+
* `git symbolic-ref` exits non-zero on a detached HEAD and outside a
|
|
9
|
+
* repository, and the binary may be missing entirely, so every failure mode
|
|
10
|
+
* collapses to "no branch context" rather than an error the caller must handle.
|
|
11
|
+
*/
|
|
12
|
+
export async function currentGitBranch(cwd = process.cwd()) {
|
|
13
|
+
try {
|
|
14
|
+
const { stdout } = await execFileAsync('git', ['symbolic-ref', '--quiet', '--short', 'HEAD'], {
|
|
15
|
+
cwd,
|
|
16
|
+
encoding: 'utf8',
|
|
17
|
+
timeout: GIT_TIMEOUT_MS,
|
|
18
|
+
windowsHide: true,
|
|
19
|
+
});
|
|
20
|
+
const branch = stdout.trim();
|
|
21
|
+
return branch.length > 0 ? branch : null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypequery/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "Command-line interface for hypequery",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@vitest/coverage-v8": "^3.2.6",
|
|
35
35
|
"typescript": "^5.7.3",
|
|
36
36
|
"vitest": "^3.2.6",
|
|
37
|
-
"@hypequery/serve": "0.
|
|
37
|
+
"@hypequery/serve": "0.15.0"
|
|
38
38
|
},
|
|
39
39
|
"repository": {
|
|
40
40
|
"type": "git",
|