Compare commits
2
Commits
main
...
release/1.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30f8503100 | ||
|
|
2f47ea4ce9 |
No files matched your search
+25
-5
@@ -5,14 +5,18 @@ All notable changes to the qqq CLI and its packages. Versions follow [semver](ht
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
## [1.1.0] - 2026-11-05
|
||||
|
||||
- TypeScript 5.8.3 to 6.0.3 and `@types/node` 22.15.3 to 26.6.6 across the workspace, `packages/tui` and `packages/tui-spike`. TypeScript 6 no longer loads every `@types/*` package implicitly, so `tsconfig.base.json` now lists `"types": ["node"]`; `@types/node` 26 no longer accepts an `undefined` assertion message, so one conformance test passes a real fallback message. TypeScript 7 is not adopted yet: `openapi-typescript` 7.13.0 (the client generator, peer `typescript ^5.x`) calls the TypeScript JS API (`ts.factory`), which the native 7 compiler does not provide. No behaviour change.
|
||||
`qqq` 1.1: the terminal UI's Shift bank and two-row F-key bar, F12 for the Assistant panel, Save as PDF
|
||||
from the printer picker, a boot splash and a profile picker on start, rendered assistant answers, and the
|
||||
client regenerated from UI API 1.10.0 with the current extension documents. Servers: UI API 1.6.0 up to
|
||||
2.0, unchanged; servers on 1.9.0 and later also read the case-insensitive criteria option `qqq` sends, and the
|
||||
table variant the CLI sends on inserts, updates and deletes (`qqq ui` does not send it on writes yet).
|
||||
|
||||
### Fixed
|
||||
Versions: `@qrun-io/qqq-ui-api-client` 1.10.0, `@qrun-io/qqq-core` 1.1.0, `@qrun-io/qqq-cli` 1.1.0,
|
||||
`@qrun-io/qqq-ui-api-conformance` 1.6.0 (unchanged: its checks validate against the server's own
|
||||
document, so no contract changed).
|
||||
|
||||
- The screen saver's Online tile said "nobody around" with two terminals signed in. It now counts signed-in sessions first (the session store's table: sessions active in the last 10 minutes and their users, your own included, "2 sessions · 1 user (you ×2)"), else you plus the people in collaboration presence; it never says nobody is around while you are signed in. The saver also keeps its presence lease on the screen under it (the extension has no idle state), so other clients see you still viewing it instead of gone. A server that stores no sessions and merges presence per user (mock auth) shows both terminals as "1 online · you".
|
||||
- Query in the screen saver looked like a different dog. All sizes are now generated from the drawing on https://www.qrun.io/query/ (`scripts/gen-query-art.mjs`) in its indigo, with a new medium size (25×13 cells, used where there is room) between the large (42×22) and the small (17×9).
|
||||
### Added
|
||||
|
||||
- **F12 shows and hides the Assistant panel** on every screen (Ctrl+G, `:ask` and a click on `12Ask` do
|
||||
@@ -67,11 +71,27 @@ All notable changes to the qqq CLI and its packages. Versions follow [semver](ht
|
||||
|
||||
### Changed
|
||||
|
||||
- **`@qrun-io/qqq-ui-api-client` 1.10.0**, generated from qqq `develop` 7825261ab (UI API 1.10.0) and the
|
||||
extension documents on each qbit's `develop` (printing: `main`); 222 operations, 156 from extensions
|
||||
(`docs/extensions.md`, `openapi/extension-sources.json`). New since 1.8.0: `FilterCriteria.options`
|
||||
(`CASE_INSENSITIVE`), `tableVariant` on insert, update and delete, `joins` on export, `isStepBack` on
|
||||
step, url-encoded process bodies, a typed `statisticsGroupData`, native session login and logout
|
||||
(`nativeSessionLogin`, `nativeSessionLogout`, `authenticationFlow`, `expectedNonce`,
|
||||
`nativeLogoutData`); assistant 1.7.0 (`AssistantConfigResponseV1.message`); printing 2.3.0 (the
|
||||
operator printer catalog, submit and request operations, and media profiles); collaboration 1.2.0 now
|
||||
from `develop`, where per-session presence is merged.
|
||||
- `scripts/merge-spec.mjs` accepts an extension's older copy of a core schema (the same schema without
|
||||
properties or enum values added since) and keeps the newer one, with a warning: data-analysis 1.5.0
|
||||
still carries the pre-1.9.0 `FilterCriteria`.
|
||||
- The CLI's `--variant` note on writes now says only servers before UI API 1.9.0 ignore the variant.
|
||||
- TypeScript 5.8.3 to 6.0.3 and `@types/node` 22.15.3 to 26.6.6 across the workspace, `packages/tui` and `packages/tui-spike`. TypeScript 6 no longer loads every `@types/*` package implicitly, so `tsconfig.base.json` now lists `"types": ["node"]`; `@types/node` 26 no longer accepts an `undefined` assertion message, so one conformance test passes a real fallback message. TypeScript 7 is not adopted yet: `openapi-typescript` 7.13.0 (the client generator, peer `typescript ^5.x`) calls the TypeScript JS API (`ts.factory`), which the native 7 compiler does not provide. No behaviour change.
|
||||
- With several profiles and none named, `qqq ui` asks which to connect to instead of using the default
|
||||
profile (`--profile` or `QQQ_PROFILE` keeps the old behaviour).
|
||||
|
||||
### Fixed
|
||||
|
||||
- The screen saver's Online tile said "nobody around" with two terminals signed in. It now counts signed-in sessions first (the session store's table: sessions active in the last 10 minutes and their users, your own included, "2 sessions · 1 user (you ×2)"), else you plus the people in collaboration presence; it never says nobody is around while you are signed in. The saver also keeps its presence lease on the screen under it (the extension has no idle state), so other clients see you still viewing it instead of gone. A server that stores no sessions and merges presence per user (mock auth) shows both terminals as "1 online · you".
|
||||
- Query in the screen saver looked like a different dog. All sizes are now generated from the drawing on https://www.qrun.io/query/ (`scripts/gen-query-art.mjs`) in its indigo, with a new medium size (25×13 cells, used where there is room) between the large (42×22) and the small (17×9).
|
||||
- **The assistant's answers render** instead of showing raw markdown, in the TUI panel and in
|
||||
`qqq assistant ask`: HTML entities decoded (`healthy:` was shown as is), headings, wrapped
|
||||
paragraphs, lists, bold and code, and pipe tables laid out as a grid (CLI: sub-tables) instead of `| --- |`
|
||||
|
||||
@@ -6,8 +6,7 @@ uses, so apps, tables, fields, processes, widgets and extensions all come from t
|
||||
one binary works against any QQQ application.
|
||||
|
||||
This repository also holds the TypeScript libraries `qqq` is built on, for anyone writing their own CLI,
|
||||
TUI or native client. Current release: **1.0.0** ([release notes](docs/release-notes/1.0.0.md),
|
||||
[CHANGELOG](CHANGELOG.md)).
|
||||
TUI or native client. Current release: **1.1.0** ([CHANGELOG](CHANGELOG.md); 1.0.0: [release notes](docs/release-notes/1.0.0.md)).
|
||||
|
||||
- [Install](#install)
|
||||
- [The CLI in 60 seconds](#the-cli-in-60-seconds)
|
||||
@@ -29,7 +28,7 @@ musl for Alpine) and Windows (x64).
|
||||
|
||||
```sh
|
||||
curl -fsSL https://raw.githubusercontent.com/QRun-IO/qqq-cli/main/scripts/install.sh | sh
|
||||
curl -fsSL https://raw.githubusercontent.com/QRun-IO/qqq-cli/main/scripts/install.sh | sh -s -- --version 1.0.0 --dir /usr/local/bin
|
||||
curl -fsSL https://raw.githubusercontent.com/QRun-IO/qqq-cli/main/scripts/install.sh | sh -s -- --version 1.1.0 --dir /usr/local/bin
|
||||
```
|
||||
|
||||
**Homebrew** (macOS and Linux, from [`QRun-IO/homebrew-tap`](https://github.com/QRun-IO/homebrew-tap);
|
||||
@@ -248,7 +247,7 @@ and settings: [`packages/tui/README.md`](packages/tui/README.md).
|
||||
| npm packages | Node.js 20 or later. `@qrun-io/qqq-ui-api-client` needs only `fetch` and Web Crypto (no Node built-ins), so it runs on Bun and Deno too; `@qrun-io/qqq-core` and the CLI use Node built-ins (files, keyring). |
|
||||
|
||||
Versioning: `qqq` and `@qrun-io/qqq-core` follow semver from 1.0.0. `@qrun-io/qqq-ui-api-client`
|
||||
follows the UI API version of the document it is generated from (1.8.0 here), and
|
||||
follows the UI API version of the document it is generated from (1.10.0 here), and
|
||||
`@qrun-io/qqq-ui-api-conformance` has its own version. All four are released together; see
|
||||
[CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
@@ -256,9 +255,9 @@ follows the UI API version of the document it is generated from (1.8.0 here), an
|
||||
|
||||
| Package | Version | What it is |
|
||||
|---|---|---|
|
||||
| [`@qrun-io/qqq-cli`](packages/cli) | 1.0.0 | `qqq`, the CLI, and its program as a library (`runCli`) |
|
||||
| [`@qrun-io/qqq-core`](packages/core) | 1.0.0 | the client kernel: sessions and keyring, metadata cache, filter grammar, forms, processes, records, render model, output formats. No terminal code |
|
||||
| [`@qrun-io/qqq-ui-api-client`](packages/ui-api-client) | 1.8.0 | a typed TypeScript client generated from the merged UI API document (core plus 14 extensions), with OAuth2 device-flow and PKCE sign-in, token refresh and the realtime (SSE) stream |
|
||||
| [`@qrun-io/qqq-cli`](packages/cli) | 1.1.0 | `qqq`, the CLI, and its program as a library (`runCli`) |
|
||||
| [`@qrun-io/qqq-core`](packages/core) | 1.1.0 | the client kernel: sessions and keyring, metadata cache, filter grammar, forms, processes, records, render model, output formats. No terminal code |
|
||||
| [`@qrun-io/qqq-ui-api-client`](packages/ui-api-client) | 1.10.0 | a typed TypeScript client generated from the merged UI API document (core plus 14 extensions), with OAuth2 device-flow and PKCE sign-in, token refresh and the realtime (SSE) stream |
|
||||
| [`@qrun-io/qqq-ui-api-conformance`](packages/conformance) | 1.6.0 | a read-only conformance suite for any UI API server, and `qqq-dev-idp`, a local OIDC provider for testing native clients |
|
||||
| [`packages/tui`](packages/tui) | in the binaries | `qqq ui`, the full-screen terminal UI (OpenTUI on Bun), bundled into every `qqq` binary; not an npm package |
|
||||
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@
|
||||
|
||||
| Version | Supported |
|
||||
|---|---|
|
||||
| 1.0.x (`qqq` 1.0, `@qrun-io/qqq-core` 1.0, `@qrun-io/qqq-ui-api-client` 1.8, `@qrun-io/qqq-ui-api-conformance` 1.6) | yes |
|
||||
| 1.0.0 release candidates, 0.x | no; upgrade to the latest 1.0.x |
|
||||
| 1.1.x (`qqq` 1.1, `@qrun-io/qqq-core` 1.1, `@qrun-io/qqq-ui-api-client` 1.10, `@qrun-io/qqq-ui-api-conformance` 1.6) | yes |
|
||||
| 1.0.x, 1.0.0 release candidates, 0.x | no; upgrade to the latest 1.1.x |
|
||||
|
||||
Fixes are released as a new patch version of the affected packages and binaries.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Try qqq against the sample server
|
||||
|
||||
A hands-on walkthrough of qqq 1.0.0 (the CLI and `qqq ui`) from a source checkout, against a local QQQ
|
||||
A hands-on walkthrough of qqq 1.1.0 (the CLI and `qqq ui`) from a source checkout, against a local QQQ
|
||||
sample server. Each section says what exists and the command that runs it. To install a release instead,
|
||||
see [Install](README.md#install) in the README; every command below works the same with an installed `qqq`.
|
||||
|
||||
@@ -28,7 +28,7 @@ and the terminal UI in one file, no Node or Bun. It is the same build a user dow
|
||||
from-source launcher. Both use the same profiles and keychain items.
|
||||
|
||||
```sh
|
||||
qqq-bin --version # qqq 1.0.0 (darwin-arm64 binary with ui, <commit>, bun 1.4.4)
|
||||
qqq-bin --version # qqq 1.1.0 (darwin-arm64 binary with ui, <commit>, bun 1.4.4)
|
||||
qqq-bin doctor # first line: the build, runtime and platform; then server, sign-in, terminal
|
||||
qqq-bin --profile sample ui # the terminal UI from the binary
|
||||
qqq-bin ui --check # the terminal check, with the build line support asks for
|
||||
|
||||
+31
-23
@@ -1,36 +1,44 @@
|
||||
# Extension documents in the client
|
||||
|
||||
The client document (`packages/ui-api-client/openapi/qqq-v1.json`) is the sample server's live
|
||||
document for core (QQQ 4.1.0-SNAPSHOT, `develop` 6ac64fc66, UI API 1.8.0, which already carries esb)
|
||||
merged with the extension document each repository commits at `src/main/resources/openapi/qqq-v1/`.
|
||||
Rebuild it with the sample server running:
|
||||
The client document (`packages/ui-api-client/openapi/qqq-v1.json`) is qqq's committed core document
|
||||
(`qqq-middleware-javalin/src/main/resources/openapi/v1/openapi.yaml`, qqq `develop` 7825261ab, UI API
|
||||
1.10.0) merged with the extension document each repository commits at `src/main/resources/openapi/qqq-v1/`
|
||||
(esb and health from the same qqq commit). Rebuild it from checkouts at the refs below:
|
||||
|
||||
```sh
|
||||
npm run spec:merge-extensions && npm run generate # writes openapi/extension-sources.json too
|
||||
npm run spec:merge-extensions -- --core <qqq>/qqq-middleware-javalin/src/main/resources/openapi/v1/openapi.yaml
|
||||
npm run generate # writes openapi/extension-sources.json too
|
||||
```
|
||||
|
||||
Versions merged on 2026-10-31 (machine-readable copy: `packages/ui-api-client/openapi/extension-sources.json`):
|
||||
Without `--core` the script reads the sample server's live document (`http://localhost:8077`), which is
|
||||
only as new as the server that is running. For 1.10.0 the documents were exported (`git archive`) from
|
||||
each repository's `origin/develop` (`origin/main` for qbit-printing, which has no `develop`) into one
|
||||
directory passed as `--root`, and `extension-sources.json` records those refs.
|
||||
|
||||
Versions merged on 2026-11-05 (machine-readable copy: `packages/ui-api-client/openapi/extension-sources.json`):
|
||||
|
||||
| Extension | Version | Prefix | Operations | Repository at | Minimum the client needs |
|
||||
|---|---|---|---|---|---|
|
||||
| esb | 1.1.0 | `/esb` | 5 | qqq `develop` 6ac64fc66 (qqq-esb) | 1.1.0 (operationIds, UI-API-CHANGELOG) |
|
||||
| health | 1.1.0 | `/health` | 4 | qqq `develop` 6ac64fc66 (qqq-middleware-javalin) | 1.1.0 (same) |
|
||||
| alerts | 1.2.0 | `/alerts` | 6 | qbit-alerts `develop` a3fc6ac | |
|
||||
| assistant | 1.6.0 | `/assistant` | 16 | qbit-assistant `develop` bcf173f | |
|
||||
| collaboration | 1.2.0 | `/qbit/collaboration` | 45 | qbit-collaboration `feat/per-session-presence` 0ae1e62 (local worktree `.worktrees/qbit-collab-sessions`, not yet on `develop`) | 1.1.0 (presence schemas, error contract); 1.2.0 adds per-connection presence (`connections`, `leaseCount`, `perConnection`), used when present |
|
||||
| data-analysis | 1.5.0 | `/qbit/data-analysis` | 21 | qbit-data-analysis `develop` 368d2c0 | |
|
||||
| db-performance | 1.0.0 | `/qbit/db-performance` | 4 | qbit-db-performance `develop` 4fd2c30 | |
|
||||
| edi | 1.1.0 | `/qbit/edi` | 4 | qbit-edi `develop` 75a4e6b | |
|
||||
| qa-capture | 1.0.0 | `/qbit/qa-capture` | 2 | qbit-qa-capture `develop` 1aee6cb | |
|
||||
| quick-search | 1.1.0 | `/qbit/quick-search` | 2 | qbit-quick-search `develop` bd50e1f | |
|
||||
| release-notes | 1.0.0 | `/qbit/release-notes` | 3 | qbit-release-notes `develop` 8fed18e | |
|
||||
| secured-data | 1.1.0 | `/qbit/secured-data` | 3 | qbit-secured-data `develop` 7b302ed | |
|
||||
| sql-workbench | 1.1.0 | `/sql-workbench` | 21 | qbit-sql-workbench `develop` a182076 | |
|
||||
| printing | 2.1.0 | `/qbit/printing` | 17 | qbit-printing `feat/print-anything` | 2.0.0 (realtime-v1); 2.1.0 adds the table-list and text prints Ctrl+P uses |
|
||||
| esb | 1.1.0 | `/esb` | 5 | qqq `develop` 7825261ab (qqq-esb) | 1.1.0 (operationIds, UI-API-CHANGELOG) |
|
||||
| health | 1.1.0 | `/health` | 4 | qqq `develop` 7825261ab (qqq-middleware-javalin) | 1.1.0 (same) |
|
||||
| alerts | 1.2.0 | `/alerts` | 6 | qbit-alerts `develop` 420cc69 | |
|
||||
| assistant | 1.7.0 | `/assistant` | 16 | qbit-assistant `develop` 67bdd32 | |
|
||||
| collaboration | 1.2.0 | `/qbit/collaboration` | 45 | qbit-collaboration `develop` 7d61f29 (per-session presence is merged there) | 1.1.0 (presence schemas, error contract); 1.2.0 adds per-connection presence (`connections`, `leaseCount`, `perConnection`), used when present |
|
||||
| data-analysis | 1.5.0 | `/qbit/data-analysis` | 21 | qbit-data-analysis `develop` f2fd8b1 | |
|
||||
| db-performance | 1.0.0 | `/qbit/db-performance` | 4 | qbit-db-performance `develop` b70c234 | |
|
||||
| edi | 1.1.0 | `/qbit/edi` | 4 | qbit-edi `develop` 683995c | |
|
||||
| printing | 2.3.0 | `/qbit/printing` | 20 | qbit-printing `main` 0ab07fc | 2.0.0 (realtime-v1); 2.1.0 adds the table-list and text prints Ctrl+P uses |
|
||||
| qa-capture | 1.0.0 | `/qbit/qa-capture` | 2 | qbit-qa-capture `develop` 8ca3fd7 | |
|
||||
| quick-search | 1.1.0 | `/qbit/quick-search` | 2 | qbit-quick-search `develop` e3aa05e | |
|
||||
| release-notes | 1.0.0 | `/qbit/release-notes` | 3 | qbit-release-notes `develop` 8abbe6f | |
|
||||
| secured-data | 1.1.0 | `/qbit/secured-data` | 3 | qbit-secured-data `develop` 5987cb5 | |
|
||||
| sql-workbench | 1.1.0 | `/sql-workbench` | 21 | qbit-sql-workbench `develop` 1784a5b | |
|
||||
|
||||
219 operations in all, 153 from extensions (printing was appended on 2026-11-01 with
|
||||
`scripts/merge-spec.mjs`, keeping the other documents as they were). No extension document conflicted with core or another
|
||||
(identical shared schemas such as `BasicErrorResponseV1`). There is no `qbit-middleware-health`: the
|
||||
222 operations in all, 156 from extensions. Shared schemas are identical (such as `BasicErrorResponseV1`)
|
||||
except one: data-analysis 1.5.0 still carries `FilterCriteria` as it was before UI API 1.9.0 (without
|
||||
`options`). `scripts/merge-spec.mjs` accepts an extension's older copy of a schema (the same schema
|
||||
without the properties and enum values added since) and keeps the newer core one, with a warning; a copy
|
||||
that differs in any other way still fails the merge. There is no `qbit-middleware-health`: the
|
||||
health extension lives in qqq's `qqq-middleware-javalin`. Other qbits in the workspace (authentik,
|
||||
jobs, help, middleware-mcp, ...) register no UI API extension.
|
||||
|
||||
|
||||
Generated
+6
-6
@@ -2954,11 +2954,11 @@
|
||||
},
|
||||
"packages/cli": {
|
||||
"name": "@qrun-io/qqq-cli",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@qrun-io/qqq-core": "1.0.0",
|
||||
"@qrun-io/qqq-ui-api-client": "1.8.0",
|
||||
"@qrun-io/qqq-core": "1.1.0",
|
||||
"@qrun-io/qqq-ui-api-client": "1.10.0",
|
||||
"@qrun-io/qqq-ui-api-conformance": "1.6.0",
|
||||
"commander": "15.0.0"
|
||||
},
|
||||
@@ -2986,10 +2986,10 @@
|
||||
},
|
||||
"packages/core": {
|
||||
"name": "@qrun-io/qqq-core",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@qrun-io/qqq-ui-api-client": "1.8.0",
|
||||
"@qrun-io/qqq-ui-api-client": "1.10.0",
|
||||
"jmespath": "0.16.0",
|
||||
"yaml": "2.9.1"
|
||||
},
|
||||
@@ -3002,7 +3002,7 @@
|
||||
},
|
||||
"packages/ui-api-client": {
|
||||
"name": "@qrun-io/qqq-ui-api-client",
|
||||
"version": "1.8.0",
|
||||
"version": "1.10.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"openapi-fetch": "0.17.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qrun-io/qqq-cli",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"description": "Reference command-line client for QQQ applications, built only on the QQQ UI API (/qqq/v1).",
|
||||
"keywords": [
|
||||
"qqq",
|
||||
@@ -58,8 +58,8 @@
|
||||
"prepack": "node ../../scripts/copy-license.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@qrun-io/qqq-core": "1.0.0",
|
||||
"@qrun-io/qqq-ui-api-client": "1.8.0",
|
||||
"@qrun-io/qqq-core": "1.1.0",
|
||||
"@qrun-io/qqq-ui-api-client": "1.10.0",
|
||||
"@qrun-io/qqq-ui-api-conformance": "1.6.0",
|
||||
"commander": "15.0.0"
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export async function chooseVariant(c: Context, meta: Json, typed: string | unde
|
||||
throw new UsageError(`${meta.label} needs a ${label}: --variant <id|name>${variants.length ? ` (${variants.slice(0, 10).map((v) => `${v.name ?? v.id} (${v.id})`).join(', ')}${variants.length > 10 ? ', …' : ''})` : '; the server lists none'}`)
|
||||
}
|
||||
if (chosen && usesVariants(meta)) rememberVariant(c.server, table, chosen)
|
||||
// UI API 1.8.0 reads tableVariant on query, count, get, export and processes only (docs/server-findings.md #19)
|
||||
if (options.write) c.note(`note: the server may ignore the ${label} on inserts, updates and deletes (UI API ${'1.8.0'}); see docs/server-findings.md #19`)
|
||||
// servers before UI API 1.9.0 read tableVariant on query, count, get, export and processes only (docs/server-findings.md #19)
|
||||
if (options.write) c.note(`note: servers before UI API 1.9.0 ignore the ${label} on inserts, updates and deletes; see docs/server-findings.md #19`)
|
||||
return chosen
|
||||
}
|
||||
@@ -195,7 +195,7 @@ describe('doctor', () => {
|
||||
const { versionSupport } = await import('../commands/doctor.js')
|
||||
assert.equal(versionSupport('1.8.0', [1]).status, 'ok')
|
||||
assert.equal(versionSupport('1.5.2', [1]).status, 'fail')
|
||||
assert.equal(versionSupport('1.9.0', [1]).status, 'warn')
|
||||
assert.equal(versionSupport('1.11.0', [1]).status, 'warn')
|
||||
assert.equal(versionSupport('2.0.0', [2]).status, 'fail')
|
||||
})
|
||||
test('doctor words the supported UI API range exactly as --version does', async () => {
|
||||
@@ -204,13 +204,13 @@ describe('doctor', () => {
|
||||
assert.equal(UI_API_RANGE, '>=1.6.0 <2.0.0')
|
||||
const version = await runCli(['--version'], box.env)
|
||||
assert.match(version.stdout, new RegExp(`servers UI API ${UI_API_RANGE}`))
|
||||
for (const [server, status] of [['1.6.0', 'ok'], ['1.8.0', 'ok'], ['1.9.0', 'warn'], ['1.5.2', 'fail']] as const) {
|
||||
for (const [server, status] of [['1.6.0', 'ok'], ['1.8.0', 'ok'], ['1.10.0', 'ok'], ['1.11.0', 'warn'], ['1.5.2', 'fail']] as const) {
|
||||
const result = versionSupport(server, [1])
|
||||
assert.equal(result.status, status, server)
|
||||
assert.ok(result.detail.includes(UI_API_RANGE), `${server}: ${result.detail}`)
|
||||
assert.ok(!/supports \d+\.\d+\.\d+ to /.test(result.detail), `${server}: ${result.detail}`)
|
||||
}
|
||||
assert.match(versionSupport('1.9.0', [1]).detail, /^1\.9\.0; supported \(/)
|
||||
assert.match(versionSupport('1.11.0', [1]).detail, /^1\.11\.0; supported \(/)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -3,17 +3,17 @@ extension noun installed status client minimum o
|
||||
esb qqq esb 1.1.0 ok 1.1.0 1.1.0 5
|
||||
health qqq health not installed 1.1.0 1.1.0 4
|
||||
alerts qqq alerts not installed 1.2.0 6
|
||||
assistant qqq assistant not installed 1.6.0 16
|
||||
assistant qqq assistant not installed 1.7.0 16
|
||||
collaboration qqq collab not installed 1.2.0 1.1.0 45 record:{table}:{pk} table:{table} user:me
|
||||
data-analysis qqq data-analysis not installed 1.5.0 21
|
||||
db-performance qqq db-performance not installed 1.0.0 4
|
||||
edi qqq edi not installed 1.1.0 4
|
||||
printing qqq printing not installed 2.3.0 2.0.0 20
|
||||
qa-capture qqq qa-capture not installed 1.0.0 2
|
||||
quick-search qqq quick-search not installed 1.1.0 2
|
||||
release-notes qqq release-notes not installed 1.0.0 3
|
||||
secured-data qqq secured-data not installed 1.1.0 3
|
||||
sql-workbench qqq sql-workbench not installed 1.1.0 21
|
||||
printing qqq printing not installed 2.1.0 2.0.0 17
|
||||
(installed: esb 1.1.0; 153 extension operations in this client)
|
||||
(installed: esb 1.1.0; 156 extension operations in this client)
|
||||
--- stderr ---
|
||||
--- exit 0
|
||||
@@ -18,7 +18,7 @@ declare const QQQ_BUILD_SHA: string | undefined
|
||||
declare const QQQ_BUILD_TARGET: string | undefined
|
||||
declare const QQQ_BUILD_UI: boolean | undefined
|
||||
|
||||
export const CLI_VERSION = '1.0.0'
|
||||
export const CLI_VERSION = '1.1.0'
|
||||
|
||||
/** The oldest UI API a server may serve for this CLI (operationIds, clientCapabilities and traceId since 1.6.0). */
|
||||
export const UI_API_MIN_VERSION = '1.6.0'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qrun-io/qqq-core",
|
||||
"version": "1.0.0",
|
||||
"version": "1.1.0",
|
||||
"description": "Client kernel for QQQ terminal clients: sessions, metadata, filter grammar, records, processes, jobs, render model and output formats. No terminal code.",
|
||||
"keywords": [
|
||||
"qqq",
|
||||
@@ -50,7 +50,7 @@
|
||||
"prepack": "node ../../scripts/copy-license.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@qrun-io/qqq-ui-api-client": "1.8.0",
|
||||
"@qrun-io/qqq-ui-api-client": "1.10.0",
|
||||
"jmespath": "0.16.0",
|
||||
"yaml": "2.9.1"
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Apache License, Version 2.0 (see LICENSE).
|
||||
*/
|
||||
|
||||
// Generated by scripts/gen-operations.mjs from the UI API 1.8.0 document (core and 14 extensions). Do not edit.
|
||||
// Generated by scripts/gen-operations.mjs from the UI API 1.10.0 document (core and 14 extensions). Do not edit.
|
||||
|
||||
export interface OperationInfo {
|
||||
id: string
|
||||
@@ -26,24 +26,24 @@ export interface DocumentExtension {
|
||||
description?: string
|
||||
}
|
||||
|
||||
export const UI_API_DOCUMENT_VERSION = "1.8.0"
|
||||
export const UI_API_DOCUMENT_VERSION = "1.10.0"
|
||||
|
||||
/** The extensions merged into the client document, with the versions it was generated from. */
|
||||
export const DOCUMENT_EXTENSIONS: DocumentExtension[] = [
|
||||
{"name":"esb","version":"1.1.0","pathPrefix":"/esb","description":"ESB overview, the ESB of tables and processes, and messages and dead letters on destinations."},
|
||||
{"name":"health","version":"1.1.0","pathPrefix":"/health","description":"Central health summary, components, history and on-demand checks."},
|
||||
{"name":"alerts","version":"1.2.0","pathPrefix":"/alerts","description":"Alerts inbox and record panel"},
|
||||
{"name":"assistant","version":"1.6.0","pathPrefix":"/assistant","description":"QQQ Assistant: conversations, streamed turns, feedback, pending actions and data access explanations"},
|
||||
{"name":"assistant","version":"1.7.0","pathPrefix":"/assistant","description":"QQQ Assistant: conversations, streamed turns, feedback, pending actions and data access explanations"},
|
||||
{"name":"collaboration","version":"1.2.0","pathPrefix":"/qbit/collaboration","description":"Record collaboration: favorites, recents, attachments, tags, conversations, following, timeline, people and presence"},
|
||||
{"name":"data-analysis","version":"1.5.0","pathPrefix":"/qbit/data-analysis","description":"Profiles, pivots, comparisons, distribution shifts, correlations, scatter samples, crosstabs and anomaly watch previews as the signed-in user."},
|
||||
{"name":"db-performance","version":"1.0.0","pathPrefix":"/qbit/db-performance","description":"Database performance, live activity and audited query plans"},
|
||||
{"name":"edi","version":"1.1.0","pathPrefix":"/qbit/edi","description":"EDI sandbox and mapper, using the signed-in user's permissions."},
|
||||
{"name":"printing","version":"2.3.0","pathPrefix":"/qbit/printing","description":"Native current-user printing with secondary device proof, device-control-v1 and realtime-v1; record, table-list and text printing processes; render to PDF with "},
|
||||
{"name":"qa-capture","version":"1.0.0","pathPrefix":"/qbit/qa-capture","description":"QA bug capture: the user's capture capability and QA report creation"},
|
||||
{"name":"quick-search","version":"1.1.0","pathPrefix":"/qbit/quick-search","description":"Quick Search administration and suggestions"},
|
||||
{"name":"release-notes","version":"1.0.0","pathPrefix":"/qbit/release-notes","description":"What's new: published release notes and each user's unread count"},
|
||||
{"name":"secured-data","version":"1.1.0","pathPrefix":"/qbit/secured-data","description":"Reveal grants and break-glass status"},
|
||||
{"name":"sql-workbench","version":"1.1.0","pathPrefix":"/sql-workbench","description":"Audited SQL execution and notebooks"},
|
||||
{"name":"printing","version":"2.1.0","pathPrefix":"/qbit/printing","description":"Native current-user printing with secondary device proof, device-control-v1 and realtime-v1; record, table-list and text printing processes."},
|
||||
]
|
||||
|
||||
export const OPERATIONS: OperationInfo[] = [
|
||||
@@ -59,7 +59,7 @@ export const OPERATIONS: OperationInfo[] = [
|
||||
{"id":"chooseDeliveryTargets","method":"POST","path":"/qqq/v1/delivery/destinations/{name}/targets","summary":"Describe the next delivery target","tag":"General","pathParams":["name"],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"countTable","method":"POST","path":"/qqq/v1/table/{tableName}/count","summary":"Count records in a table","tag":"Tables","pathParams":["tableName"],"queryParams":["includeDistinct"],"bodyTypes":["application/json"]},
|
||||
{"id":"dbPerformanceActivity","method":"GET","path":"/qqq/v1/qbit/db-performance/activity","summary":"Database Performance activity","tag":"","pathParams":[],"queryParams":["backend"],"bodyTypes":[],"extension":"db-performance"},
|
||||
{"id":"dbPerformanceExplain","method":"POST","path":"/qqq/v1/qbit/db-performance/explain","summary":"Explain a PostgreSQL query","tag":"","pathParams":[],"queryParams":[],"bodyTypes":["application/json"],"extension":"db-performance"},
|
||||
{"id":"dbPerformanceExplain","method":"POST","path":"/qqq/v1/qbit/db-performance/explain","summary":"Explain a query (PostgreSQL JSON or H2 text plan)","tag":"","pathParams":[],"queryParams":[],"bodyTypes":["application/json"],"extension":"db-performance"},
|
||||
{"id":"dbPerformanceLookup","method":"GET","path":"/qqq/v1/qbit/db-performance/statements/lookup","summary":"Database Performance lookup","tag":"","pathParams":[],"queryParams":["backend","sql"],"bodyTypes":[],"extension":"db-performance"},
|
||||
{"id":"dbPerformanceOverview","method":"GET","path":"/qqq/v1/qbit/db-performance/overview","summary":"Database Performance overview","tag":"","pathParams":[],"queryParams":["backend"],"bodyTypes":[],"extension":"db-performance"},
|
||||
{"id":"deleteAssistantConversationsById","method":"DELETE","path":"/qqq/v1/assistant/conversations/{id}","summary":"Delete a conversation","tag":"assistant","pathParams":["id"],"queryParams":[],"bodyTypes":[],"extension":"assistant"},
|
||||
@@ -69,7 +69,7 @@ export const OPERATIONS: OperationInfo[] = [
|
||||
{"id":"deleteQbitCollaborationPresence","method":"DELETE","path":"/qqq/v1/qbit/collaboration/presence","summary":"Leave presence","tag":"collaboration","pathParams":[],"queryParams":[],"bodyTypes":["application/json"],"extension":"collaboration"},
|
||||
{"id":"deleteQbitCollaborationRecordsByTableByPkFollow","method":"DELETE","path":"/qqq/v1/qbit/collaboration/records/{table}/{pk}/follow","summary":"Unfollow a record","tag":"collaboration","pathParams":["table","pk"],"queryParams":[],"bodyTypes":[],"extension":"collaboration"},
|
||||
{"id":"deleteQbitDataAnalysisSavedByIdStar","method":"DELETE","path":"/qqq/v1/qbit/data-analysis/saved/{id}/star","summary":"Unstar a saved analysis","tag":"data-analysis","pathParams":["id"],"queryParams":[],"bodyTypes":[],"extension":"data-analysis"},
|
||||
{"id":"deleteRecord","method":"DELETE","path":"/qqq/v1/table/{tableName}/{primaryKey}","summary":"Delete a record from a table","tag":"Tables","pathParams":["tableName","primaryKey"],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"deleteRecord","method":"DELETE","path":"/qqq/v1/table/{tableName}/{primaryKey}","summary":"Delete a record from a table","tag":"Tables","pathParams":["tableName","primaryKey"],"queryParams":["tableVariant"],"bodyTypes":[]},
|
||||
{"id":"download","method":"GET","path":"/qqq/v1/download/{file}","summary":"Download a file","tag":"General","pathParams":["file"],"queryParams":["filePath","storageTableName","storageReference"],"bodyTypes":[]},
|
||||
{"id":"downloadRecordFieldFile","method":"GET","path":"/qqq/v1/table/{tableName}/{primaryKey}/{fieldName}/{filename}","summary":"Download a field value from a record","tag":"Tables","pathParams":["tableName","primaryKey","fieldName","filename"],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"exportTable","method":"POST","path":"/qqq/v1/table/{tableName}/export","summary":"Export records from a table","tag":"Tables","pathParams":["tableName"],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
@@ -140,8 +140,8 @@ export const OPERATIONS: OperationInfo[] = [
|
||||
{"id":"getTableMetaData","method":"GET","path":"/qqq/v1/metaData/table/{tableName}","summary":"Get table metaData","tag":"Tables","pathParams":["tableName"],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"getVersion","method":"GET","path":"/qqq/v1/version","summary":"Get the UI API version","tag":"General","pathParams":[],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"getWidgetData","method":"POST","path":"/qqq/v1/widget/{widgetName}","summary":"Render a widget","tag":"Widgets","pathParams":["widgetName"],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"initProcess","method":"POST","path":"/qqq/v1/processes/{processName}/init","summary":"Initialize a process","tag":"Processes","pathParams":["processName"],"queryParams":["tableVariant"],"bodyTypes":["multipart/form-data"]},
|
||||
{"id":"insertRecord","method":"POST","path":"/qqq/v1/table/{tableName}","summary":"Insert a record into a table","tag":"Tables","pathParams":["tableName"],"queryParams":[],"bodyTypes":["application/json","multipart/form-data"]},
|
||||
{"id":"initProcess","method":"POST","path":"/qqq/v1/processes/{processName}/init","summary":"Initialize a process","tag":"Processes","pathParams":["processName"],"queryParams":["tableVariant"],"bodyTypes":["multipart/form-data","application/x-www-form-urlencoded"]},
|
||||
{"id":"insertRecord","method":"POST","path":"/qqq/v1/table/{tableName}","summary":"Insert a record into a table","tag":"Tables","pathParams":["tableName"],"queryParams":["tableVariant"],"bodyTypes":["application/json","multipart/form-data"]},
|
||||
{"id":"launchProcessJob","method":"POST","path":"/qqq/v1/processes/{processName}/jobs","summary":"Run a process as a durable background job","tag":"Processes","pathParams":["processName"],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"listDeliveryDestinations","method":"GET","path":"/qqq/v1/delivery/destinations","summary":"List authorized output destinations","tag":"General","pathParams":[],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"listJobs","method":"GET","path":"/qqq/v1/jobs","summary":"Jobs: list","tag":"Processes","pathParams":[],"queryParams":["scope","state","limit","processName"],"bodyTypes":[]},
|
||||
@@ -149,7 +149,7 @@ export const OPERATIONS: OperationInfo[] = [
|
||||
{"id":"listRecordDeveloperPanels","method":"GET","path":"/qqq/v1/table/{tableName}/{primaryKey}/developer/panels","summary":"Get a record's developer panels","tag":"Tables","pathParams":["tableName","primaryKey"],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"listTableApis","method":"GET","path":"/qqq/v1/table/{tableName}/apis","summary":"List the APIs that expose a table","tag":"Tables","pathParams":["tableName"],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"listTableVariants","method":"GET","path":"/qqq/v1/table/{tableName}/variants","summary":"List a table's backend variants","tag":"Tables","pathParams":["tableName"],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"logout","method":"POST","path":"/qqq/v1/logout","summary":"Logout and invalidate session","tag":"Authentication","pathParams":[],"queryParams":[],"bodyTypes":[]},
|
||||
{"id":"logout","method":"POST","path":"/qqq/v1/logout","summary":"Logout and invalidate session","tag":"Authentication","pathParams":[],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"lookupAvatars","method":"POST","path":"/qqq/v1/avatars/lookup","summary":"Look up users' avatars","tag":"Authentication","pathParams":[],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"manageSession","method":"POST","path":"/qqq/v1/manageSession","summary":"Create a session","tag":"Authentication","pathParams":[],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"oidcBackChannelLogout","method":"POST","path":"/qqq/v1/oidc/backchannel-logout","summary":"OIDC Back-Channel Logout","tag":"Authentication","pathParams":[],"queryParams":[],"bodyTypes":[]},
|
||||
@@ -208,6 +208,9 @@ export const OPERATIONS: OperationInfo[] = [
|
||||
{"id":"printingEvent","method":"POST","path":"/qqq/v1/qbit/printing/device/jobs/{jobId}/events","summary":"Printing Event","tag":"printing","pathParams":["jobId"],"queryParams":[],"bodyTypes":["application/json"],"extension":"printing"},
|
||||
{"id":"printingHeartbeat","method":"POST","path":"/qqq/v1/qbit/printing/device/heartbeat","summary":"Printing Heartbeat","tag":"printing","pathParams":[],"queryParams":[],"bodyTypes":["application/json"],"extension":"printing"},
|
||||
{"id":"printingInventory","method":"PUT","path":"/qqq/v1/qbit/printing/device/printers","summary":"Printing Inventory","tag":"printing","pathParams":[],"queryParams":[],"bodyTypes":["application/json"],"extension":"printing"},
|
||||
{"id":"printingOperatorCatalog","method":"GET","path":"/qqq/v1/qbit/printing/operator/printers","summary":"Printing OperatorCatalog","tag":"printing","pathParams":[],"queryParams":["limit","after"],"bodyTypes":[],"extension":"printing"},
|
||||
{"id":"printingOperatorRequest","method":"GET","path":"/qqq/v1/qbit/printing/operator/requests/{requestId}","summary":"Printing OperatorRequest","tag":"printing","pathParams":["requestId"],"queryParams":[],"bodyTypes":[],"extension":"printing"},
|
||||
{"id":"printingOperatorSubmit","method":"POST","path":"/qqq/v1/qbit/printing/operator/jobs","summary":"Printing OperatorSubmit","tag":"printing","pathParams":[],"queryParams":[],"bodyTypes":["application/json"],"extension":"printing"},
|
||||
{"id":"printingPoll","method":"POST","path":"/qqq/v1/qbit/printing/device/control/poll","summary":"Printing Poll","tag":"printing","pathParams":[],"queryParams":[],"bodyTypes":["application/json"],"extension":"printing"},
|
||||
{"id":"printingQueued","method":"GET","path":"/qqq/v1/qbit/printing/device/jobs/queued","summary":"Printing Queued","tag":"printing","pathParams":[],"queryParams":[],"bodyTypes":[],"extension":"printing"},
|
||||
{"id":"printingReceipt","method":"POST","path":"/qqq/v1/qbit/printing/device/control/commands/{commandId}/receipt","summary":"Printing Receipt","tag":"printing","pathParams":["commandId"],"queryParams":[],"bodyTypes":["application/json"],"extension":"printing"},
|
||||
@@ -257,13 +260,13 @@ export const OPERATIONS: OperationInfo[] = [
|
||||
{"id":"sqlWorkbenchPublishNotebook","method":"POST","path":"/qqq/v1/sql-workbench/notebooks/{id}/publish","summary":"Publish or withdraw an owned notebook with share permission","tag":"sql-workbench","pathParams":["id"],"queryParams":[],"bodyTypes":["application/json"],"extension":"sql-workbench"},
|
||||
{"id":"sqlWorkbenchRestoreVersion","method":"POST","path":"/qqq/v1/sql-workbench/notebooks/{id}/versions/{n}/restore","summary":"Restore an owned notebook version as a new version","tag":"sql-workbench","pathParams":["id","n"],"queryParams":[],"bodyTypes":["application/json"],"extension":"sql-workbench"},
|
||||
{"id":"sqlWorkbenchUpdateNotebook","method":"PUT","path":"/qqq/v1/sql-workbench/notebooks/{id}","summary":"Update an owned notebook and record a version","tag":"sql-workbench","pathParams":["id"],"queryParams":[],"bodyTypes":["application/json"],"extension":"sql-workbench"},
|
||||
{"id":"stepProcess","method":"POST","path":"/qqq/v1/processes/{processName}/{processUUID}/step/{stepName}","summary":"Run a step in a process","tag":"Processes","pathParams":["processName","processUUID","stepName"],"queryParams":["tableVariant"],"bodyTypes":["multipart/form-data"]},
|
||||
{"id":"stepProcess","method":"POST","path":"/qqq/v1/processes/{processName}/{processUUID}/step/{stepName}","summary":"Run a step in a process","tag":"Processes","pathParams":["processName","processUUID","stepName"],"queryParams":["isStepBack","tableVariant"],"bodyTypes":["multipart/form-data","application/x-www-form-urlencoded"]},
|
||||
{"id":"storeAssociatedScript","method":"POST","path":"/qqq/v1/table/{tableName}/{primaryKey}/developer/associatedScript/{fieldName}","summary":"Store a new revision of a record's associated script (developer mode)","tag":"Tables","pathParams":["tableName","primaryKey","fieldName"],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"suggestBulkLoadMapping","method":"POST","path":"/qqq/v1/bulkLoad/{tableName}/suggestMapping","summary":"Suggest a bulk load mapping for an uploaded file","tag":"Bulk Load","pathParams":["tableName"],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"trackJob","method":"POST","path":"/qqq/v1/jobs/track","summary":"Jobs: track","tag":"Processes","pathParams":[],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"updatePreferenceSection","method":"PATCH","path":"/qqq/v1/preferences/{sectionName}","summary":"Partially update the signed-in user's preferences","tag":"General","pathParams":["sectionName"],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"updateRealtimeSubscriptions","method":"POST","path":"/qqq/v1/realtime/subscriptions","summary":"Change realtime subscriptions","tag":"General","pathParams":[],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
{"id":"updateRecord","method":"PATCH","path":"/qqq/v1/table/{tableName}/{primaryKey}","summary":"Update a record in a table","tag":"Tables","pathParams":["tableName","primaryKey"],"queryParams":["expectedVersion"],"bodyTypes":["application/json","multipart/form-data"]},
|
||||
{"id":"updateRecord","method":"PATCH","path":"/qqq/v1/table/{tableName}/{primaryKey}","summary":"Update a record in a table","tag":"Tables","pathParams":["tableName","primaryKey"],"queryParams":["expectedVersion","tableVariant"],"bodyTypes":["application/json","multipart/form-data"]},
|
||||
{"id":"upload","method":"POST","path":"/qqq/v1/uploads","summary":"Upload a file for a job or a bulk load","tag":"Processes","pathParams":[],"queryParams":["fileName"],"bodyTypes":["multipart/form-data","application/octet-stream"]},
|
||||
{"id":"validateBulkLoad","method":"POST","path":"/qqq/v1/bulkLoad/{tableName}/validate","summary":"Dry-run a bulk load profile over an uploaded file","tag":"Bulk Load","pathParams":["tableName"],"queryParams":[],"bodyTypes":["application/json"]},
|
||||
]
|
||||
|
||||
@@ -37,7 +37,7 @@ shared with the CLI. `QQQ_UI_NO_SPLASH=1` (as `--no-splash`). `QQQ_UI_NO_QUIT=1`
|
||||
## Starting
|
||||
|
||||
`qqq ui` opens on a **splash**: Query (the qrun.io mascot) blinking, his tail wagging while it works, the
|
||||
`qqq` wordmark, "Terminal client for QQQ", the version (`qqq 1.0.0 · UI API client 1.8.0`) and one status
|
||||
`qqq` wordmark, "Terminal client for QQQ", the version (`qqq 1.1.0 · UI API client 1.10.0`) and one status
|
||||
line that follows the boot: reading profiles, connecting to the server, signing in, loading metadata (with
|
||||
the table count). The large Query needs about 34 rows; smaller terminals (80×24) get the small Query beside
|
||||
the wordmark, very small ones the text alone; `--ascii` draws it all in plain characters. Any key stops the
|
||||
|
||||
@@ -41,7 +41,7 @@ export interface SplashSeg {
|
||||
|
||||
export const SPLASH_TAGLINE = 'Terminal client for QQQ'
|
||||
|
||||
/** `qqq 1.0.0 · UI API client 1.8.0` */
|
||||
/** `qqq 1.1.0 · UI API client 1.10.0` */
|
||||
export function versionLine(): string {
|
||||
return `qqq ${CLI_VERSION} · UI API client ${UI_API_VERSION}`
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ for await (const message of openRealtimeStream({ baseUrl, token: () => tokens.ac
|
||||
## Compatibility and versioning
|
||||
|
||||
- The package version follows the UI API version of the document it was generated from
|
||||
(`UI_API_VERSION`, 1.8.0 for this release). The client works with any server on UI API 1.6.0 up to 2.0:
|
||||
(`UI_API_VERSION`, 1.10.0 for this release). The client works with any server on UI API 1.6.0 up to 2.0:
|
||||
operations newer than a server answer 404, and unknown enum values and extra fields are tolerated.
|
||||
`GET /qqq/v1/version` tells you the server's version, features and installed extensions.
|
||||
- A new UI API minor version means a new minor version of this package; a 2.0 UI API would be a new major.
|
||||
|
||||
@@ -1,103 +1,103 @@
|
||||
{
|
||||
"core": "http://localhost:8077/qqq/v1/openapi.json",
|
||||
"core": "qqq/qqq-middleware-javalin/src/main/resources/openapi/v1/openapi.yaml (qqq origin/develop 7825261ab)",
|
||||
"extensions": [
|
||||
{
|
||||
"name": "esb",
|
||||
"version": "1.1.0",
|
||||
"document": ".worktrees/qqq-develop/qqq-esb/src/main/resources/openapi/qqq-v1/esb.yaml",
|
||||
"branch": "HEAD",
|
||||
"commit": "6ac64fc66"
|
||||
"document": "qqq/qqq-esb/src/main/resources/openapi/qqq-v1/esb.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "7825261ab"
|
||||
},
|
||||
{
|
||||
"name": "health",
|
||||
"version": "1.1.0",
|
||||
"document": ".worktrees/qqq-develop/qqq-middleware-javalin/src/main/resources/openapi/qqq-v1/health.yaml",
|
||||
"branch": "HEAD",
|
||||
"commit": "6ac64fc66"
|
||||
"document": "qqq/qqq-middleware-javalin/src/main/resources/openapi/qqq-v1/health.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "7825261ab"
|
||||
},
|
||||
{
|
||||
"name": "alerts",
|
||||
"version": "1.2.0",
|
||||
"document": "qbit-alerts/src/main/resources/openapi/qqq-v1/alerts.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "a3fc6ac"
|
||||
"commit": "420cc69"
|
||||
},
|
||||
{
|
||||
"name": "assistant",
|
||||
"version": "1.6.0",
|
||||
"version": "1.7.0",
|
||||
"document": "qbit-assistant/qbit-assistant/src/main/resources/openapi/qqq-v1/assistant.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "bcf173f"
|
||||
"commit": "67bdd32"
|
||||
},
|
||||
{
|
||||
"name": "collaboration",
|
||||
"version": "1.2.0",
|
||||
"document": ".worktrees/qbit-collab-sessions/src/main/resources/openapi/qqq-v1/collaboration.yaml",
|
||||
"branch": "feat/per-session-presence",
|
||||
"commit": "0ae1e62"
|
||||
"document": "qbit-collaboration/src/main/resources/openapi/qqq-v1/collaboration.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "7d61f29"
|
||||
},
|
||||
{
|
||||
"name": "data-analysis",
|
||||
"version": "1.5.0",
|
||||
"document": "qbit-data-analysis/src/main/resources/openapi/qqq-v1/data-analysis.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "368d2c0"
|
||||
"commit": "f2fd8b1"
|
||||
},
|
||||
{
|
||||
"name": "db-performance",
|
||||
"version": "1.0.0",
|
||||
"document": "qbit-db-performance/src/main/resources/openapi/qqq-v1/db-performance.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "4fd2c30"
|
||||
"commit": "b70c234"
|
||||
},
|
||||
{
|
||||
"name": "edi",
|
||||
"version": "1.1.0",
|
||||
"document": "qbit-edi/src/main/resources/openapi/qqq-v1/edi.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "75a4e6b"
|
||||
"commit": "683995c"
|
||||
},
|
||||
{
|
||||
"name": "printing",
|
||||
"version": "2.3.0",
|
||||
"document": "qbit-printing/src/main/resources/openapi/qqq-v1/printing.yaml",
|
||||
"branch": "main",
|
||||
"commit": "0ab07fc"
|
||||
},
|
||||
{
|
||||
"name": "qa-capture",
|
||||
"version": "1.0.0",
|
||||
"document": "qbit-qa-capture/src/main/resources/openapi/qqq-v1/qa-capture.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "1aee6cb"
|
||||
"commit": "8ca3fd7"
|
||||
},
|
||||
{
|
||||
"name": "quick-search",
|
||||
"version": "1.1.0",
|
||||
"document": "qbit-quick-search/src/main/resources/openapi/qqq-v1/quick-search.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "bd50e1f"
|
||||
"commit": "e3aa05e"
|
||||
},
|
||||
{
|
||||
"name": "release-notes",
|
||||
"version": "1.0.0",
|
||||
"document": "qbit-release-notes/src/main/resources/openapi/qqq-v1/release-notes.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "8fed18e"
|
||||
"commit": "8abbe6f"
|
||||
},
|
||||
{
|
||||
"name": "secured-data",
|
||||
"version": "1.1.0",
|
||||
"document": "qbit-secured-data/src/main/resources/openapi/qqq-v1/secured-data.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "7b302ed"
|
||||
"commit": "5987cb5"
|
||||
},
|
||||
{
|
||||
"name": "sql-workbench",
|
||||
"version": "1.1.0",
|
||||
"document": "qbit-sql-workbench/src/main/resources/openapi/qqq-v1/sql-workbench.yaml",
|
||||
"branch": "develop",
|
||||
"commit": "a182076"
|
||||
},
|
||||
{
|
||||
"name": "printing",
|
||||
"version": "2.1.0",
|
||||
"document": "qbit-printing/src/main/resources/openapi/qqq-v1/printing.yaml",
|
||||
"branch": "feat/print-anything",
|
||||
"commit": "bda172a"
|
||||
"commit": "1784a5b"
|
||||
}
|
||||
]
|
||||
}
|
||||
+25674
-24709
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@qrun-io/qqq-ui-api-client",
|
||||
"version": "1.8.0",
|
||||
"version": "1.10.0",
|
||||
"description": "Typed TypeScript client for the QQQ UI API (/qqq/v1), generated from the merged OpenAPI document (core + extensions), with OAuth2 device-flow sign-in, token refresh and a realtime (SSE) reader.",
|
||||
"keywords": [
|
||||
"qqq",
|
||||
|
||||
@@ -14,4 +14,4 @@ export type { RealtimeMessage, RealtimeStreamOptions } from './realtime.js'
|
||||
export type { paths, components, operations } from './schema.js'
|
||||
|
||||
/** The UI API version this client was generated from (info.version of the merged document). */
|
||||
export const UI_API_VERSION = '1.8.0'
|
||||
export const UI_API_VERSION = '1.10.0'
|
||||
+2842
-2306
File diff suppressed because it is too large.
Load diff
+26
-1
@@ -14,7 +14,10 @@
|
||||
* A server's own GET /qqq/v1/openapi.json is already merged and can be used directly instead.
|
||||
*
|
||||
* Rules: paths and operations are unioned (a duplicate method on one path is an error); component
|
||||
* schemas are unioned (a name defined twice must be identical, e.g. BasicErrorResponseV1); the
|
||||
* schemas are unioned (a name defined twice must be identical, e.g. BasicErrorResponseV1, or an
|
||||
* extension's copy may be an older copy of the one already merged: the same schema without the
|
||||
* properties and enum values added since, which a MINOR UI API version may add; the newer one is
|
||||
* kept and a warning printed); the
|
||||
* core document's info, servers and securitySchemes are kept; tags are unioned; every extension's
|
||||
* name, version, path prefix and operationIds are recorded in info.x-qqq-extensions.
|
||||
*
|
||||
@@ -73,6 +76,24 @@ function stable(value) {
|
||||
return value
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether `older` is `newer` as it was before additive (MINOR) changes: every key of `older` is in
|
||||
* `newer` with an older-or-equal value, `newer` may have extra entries only under `properties`, and
|
||||
* an array in `older` (an enum, `required` excepted) may lack values `newer` has.
|
||||
*/
|
||||
function isOlderCopy(newer, older, key) {
|
||||
if (Array.isArray(older) && Array.isArray(newer)) {
|
||||
const have = new Set(newer.map((v) => JSON.stringify(stable(v))))
|
||||
if (key === 'required') return older.length === newer.length && older.every((v) => have.has(JSON.stringify(stable(v))))
|
||||
return older.every((v) => have.has(JSON.stringify(stable(v))))
|
||||
}
|
||||
if (older && newer && typeof older === 'object' && typeof newer === 'object' && !Array.isArray(older) && !Array.isArray(newer)) {
|
||||
for (const k of Object.keys(older)) if (!(k in newer) || !isOlderCopy(newer[k], older[k], k)) return false
|
||||
return key === 'properties' || Object.keys(newer).every((k) => k in older)
|
||||
}
|
||||
return JSON.stringify(stable(newer)) === JSON.stringify(stable(older))
|
||||
}
|
||||
|
||||
const [coreSource, ...extensionSources] = inputs
|
||||
const merged = await load(coreSource)
|
||||
merged.paths ??= {}
|
||||
@@ -107,6 +128,10 @@ for (const source of extensionSources) {
|
||||
for (const [schemaName, schema] of Object.entries(doc.components?.schemas ?? {})) {
|
||||
const existing = merged.components.schemas[schemaName]
|
||||
if (existing && JSON.stringify(stable(existing)) !== JSON.stringify(stable(schema))) {
|
||||
if (isOlderCopy(existing, schema)) {
|
||||
console.warn(`warning: ${name} carries an older copy of schema ${schemaName} (without later additions); keeping the newer one`)
|
||||
continue
|
||||
}
|
||||
throw new Error(`schema ${schemaName} differs between the core document and ${name}`)
|
||||
}
|
||||
merged.components.schemas[schemaName] = schema
|
||||
|
||||
Reference in new issue
Block a user