@dudousxd/nestjs-telescope-ui 2.0.0 → 3.0.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/CHANGELOG.md +771 -0
- package/README.md +35 -0
- package/dist/client/console-url.d.ts +11 -0
- package/dist/client/console-url.d.ts.map +1 -0
- package/dist/client/console-url.js +21 -0
- package/dist/client/console-url.js.map +1 -0
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +4 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/telescope-client.d.ts +82 -11
- package/dist/client/telescope-client.d.ts.map +1 -1
- package/dist/client/telescope-client.js +101 -54
- package/dist/client/telescope-client.js.map +1 -1
- package/dist/client/types.d.ts +431 -30
- package/dist/client/types.d.ts.map +1 -1
- package/dist/react/components/batch-timeline.js +2 -2
- package/dist/react/components/batch-timeline.js.map +1 -1
- package/dist/react/components/cache-badge.d.ts +14 -6
- package/dist/react/components/cache-badge.d.ts.map +1 -1
- package/dist/react/components/cache-badge.js +26 -12
- package/dist/react/components/cache-badge.js.map +1 -1
- package/dist/react/components/charts/area-chart-card.d.ts +11 -3
- package/dist/react/components/charts/area-chart-card.d.ts.map +1 -1
- package/dist/react/components/charts/area-chart-card.js +33 -6
- package/dist/react/components/charts/area-chart-card.js.map +1 -1
- package/dist/react/components/charts/bar-chart-card.d.ts +18 -7
- package/dist/react/components/charts/bar-chart-card.d.ts.map +1 -1
- package/dist/react/components/charts/bar-chart-card.js +18 -9
- package/dist/react/components/charts/bar-chart-card.js.map +1 -1
- package/dist/react/components/charts/breakdown-card.d.ts +17 -0
- package/dist/react/components/charts/breakdown-card.d.ts.map +1 -0
- package/dist/react/components/charts/breakdown-card.js +43 -0
- package/dist/react/components/charts/breakdown-card.js.map +1 -0
- package/dist/react/components/charts/chart-card.d.ts +7 -0
- package/dist/react/components/charts/chart-card.d.ts.map +1 -1
- package/dist/react/components/charts/chart-card.js +10 -3
- package/dist/react/components/charts/chart-card.js.map +1 -1
- package/dist/react/components/charts/chart-selection.d.ts +44 -0
- package/dist/react/components/charts/chart-selection.d.ts.map +1 -0
- package/dist/react/components/charts/chart-selection.js +36 -0
- package/dist/react/components/charts/chart-selection.js.map +1 -0
- package/dist/react/components/charts/chart-theme.d.ts +62 -19
- package/dist/react/components/charts/chart-theme.d.ts.map +1 -1
- package/dist/react/components/charts/chart-theme.js +72 -13
- package/dist/react/components/charts/chart-theme.js.map +1 -1
- package/dist/react/components/charts/distribution-chart-card.d.ts +17 -0
- package/dist/react/components/charts/distribution-chart-card.d.ts.map +1 -0
- package/dist/react/components/charts/distribution-chart-card.js +46 -0
- package/dist/react/components/charts/distribution-chart-card.js.map +1 -0
- package/dist/react/components/charts/gauge-card.d.ts +12 -0
- package/dist/react/components/charts/gauge-card.d.ts.map +1 -0
- package/dist/react/components/charts/gauge-card.js +17 -0
- package/dist/react/components/charts/gauge-card.js.map +1 -0
- package/dist/react/components/charts/index.d.ts +1 -0
- package/dist/react/components/charts/index.d.ts.map +1 -1
- package/dist/react/components/charts/index.js +1 -0
- package/dist/react/components/charts/index.js.map +1 -1
- package/dist/react/components/charts/stacked-area-chart-card.d.ts +17 -3
- package/dist/react/components/charts/stacked-area-chart-card.d.ts.map +1 -1
- package/dist/react/components/charts/stacked-area-chart-card.js +31 -8
- package/dist/react/components/charts/stacked-area-chart-card.js.map +1 -1
- package/dist/react/components/entries-table.d.ts.map +1 -1
- package/dist/react/components/entries-table.js +17 -3
- package/dist/react/components/entries-table.js.map +1 -1
- package/dist/react/components/entry-detail.d.ts +2 -0
- package/dist/react/components/entry-detail.d.ts.map +1 -1
- package/dist/react/components/entry-detail.js +186 -20
- package/dist/react/components/entry-detail.js.map +1 -1
- package/dist/react/components/entry-insights.d.ts.map +1 -1
- package/dist/react/components/entry-insights.js +28 -17
- package/dist/react/components/entry-insights.js.map +1 -1
- package/dist/react/components/entry-types.d.ts +29 -0
- package/dist/react/components/entry-types.d.ts.map +1 -1
- package/dist/react/components/entry-types.js +60 -0
- package/dist/react/components/entry-types.js.map +1 -1
- package/dist/react/components/export-json-toolbar.js +2 -2
- package/dist/react/components/export-json-toolbar.js.map +1 -1
- package/dist/react/components/extensions/panel-column-menu.d.ts +19 -0
- package/dist/react/components/extensions/panel-column-menu.d.ts.map +1 -0
- package/dist/react/components/extensions/panel-column-menu.js +47 -0
- package/dist/react/components/extensions/panel-column-menu.js.map +1 -0
- package/dist/react/components/extensions/panel-renderer.d.ts +46 -0
- package/dist/react/components/extensions/panel-renderer.d.ts.map +1 -0
- package/dist/react/components/extensions/panel-renderer.js +122 -0
- package/dist/react/components/extensions/panel-renderer.js.map +1 -0
- package/dist/react/components/extensions/panel-table-header.d.ts +18 -0
- package/dist/react/components/extensions/panel-table-header.d.ts.map +1 -0
- package/dist/react/components/extensions/panel-table-header.js +82 -0
- package/dist/react/components/extensions/panel-table-header.js.map +1 -0
- package/dist/react/components/extensions/panel-table.d.ts +27 -0
- package/dist/react/components/extensions/panel-table.d.ts.map +1 -0
- package/dist/react/components/extensions/panel-table.js +87 -0
- package/dist/react/components/extensions/panel-table.js.map +1 -0
- package/dist/react/components/extensions/stat-card.d.ts +18 -0
- package/dist/react/components/extensions/stat-card.d.ts.map +1 -0
- package/dist/react/components/extensions/stat-card.js +44 -0
- package/dist/react/components/extensions/stat-card.js.map +1 -0
- package/dist/react/components/extensions/table-columns.d.ts +32 -0
- package/dist/react/components/extensions/table-columns.d.ts.map +1 -0
- package/dist/react/components/extensions/table-columns.js +51 -0
- package/dist/react/components/extensions/table-columns.js.map +1 -0
- package/dist/react/components/extensions/table-features.d.ts +47 -0
- package/dist/react/components/extensions/table-features.d.ts.map +1 -0
- package/dist/react/components/extensions/table-features.js +45 -0
- package/dist/react/components/extensions/table-features.js.map +1 -0
- package/dist/react/components/extensions/table-query.d.ts +53 -0
- package/dist/react/components/extensions/table-query.d.ts.map +1 -0
- package/dist/react/components/extensions/table-query.js +51 -0
- package/dist/react/components/extensions/table-query.js.map +1 -0
- package/dist/react/components/flamegraph-view.d.ts +18 -0
- package/dist/react/components/flamegraph-view.d.ts.map +1 -0
- package/dist/react/components/flamegraph-view.js +48 -0
- package/dist/react/components/flamegraph-view.js.map +1 -0
- package/dist/react/components/flamegraph.d.ts +34 -0
- package/dist/react/components/flamegraph.d.ts.map +1 -0
- package/dist/react/components/flamegraph.js +54 -0
- package/dist/react/components/flamegraph.js.map +1 -0
- package/dist/react/components/inertia-badge.d.ts +33 -0
- package/dist/react/components/inertia-badge.d.ts.map +1 -0
- package/dist/react/components/inertia-badge.js +72 -0
- package/dist/react/components/inertia-badge.js.map +1 -0
- package/dist/react/components/inertia-body.d.ts +11 -0
- package/dist/react/components/inertia-body.d.ts.map +1 -0
- package/dist/react/components/inertia-body.js +127 -0
- package/dist/react/components/inertia-body.js.map +1 -0
- package/dist/react/components/official-event.d.ts +16 -0
- package/dist/react/components/official-event.d.ts.map +1 -0
- package/dist/react/components/official-event.js +88 -0
- package/dist/react/components/official-event.js.map +1 -0
- package/dist/react/components/pulse-panel.d.ts.map +1 -1
- package/dist/react/components/pulse-panel.js +6 -6
- package/dist/react/components/pulse-panel.js.map +1 -1
- package/dist/react/components/queues/EnqueueJobForm.d.ts.map +1 -1
- package/dist/react/components/queues/EnqueueJobForm.js +2 -1
- package/dist/react/components/queues/EnqueueJobForm.js.map +1 -1
- package/dist/react/components/queues/JobActions.d.ts.map +1 -1
- package/dist/react/components/queues/JobActions.js +11 -9
- package/dist/react/components/queues/JobActions.js.map +1 -1
- package/dist/react/components/queues/JobDetailDrawer.d.ts.map +1 -1
- package/dist/react/components/queues/JobDetailDrawer.js +8 -13
- package/dist/react/components/queues/JobDetailDrawer.js.map +1 -1
- package/dist/react/components/queues/JobTable.d.ts.map +1 -1
- package/dist/react/components/queues/JobTable.js +0 -0
- package/dist/react/components/queues/JobTable.js.map +1 -1
- package/dist/react/components/queues/QueueList.d.ts.map +1 -1
- package/dist/react/components/queues/QueueList.js +6 -6
- package/dist/react/components/queues/QueueList.js.map +1 -1
- package/dist/react/components/queues/QueueStateTabs.d.ts.map +1 -1
- package/dist/react/components/queues/QueueStateTabs.js +9 -7
- package/dist/react/components/queues/QueueStateTabs.js.map +1 -1
- package/dist/react/components/queues/queue-format.d.ts +5 -1
- package/dist/react/components/queues/queue-format.d.ts.map +1 -1
- package/dist/react/components/queues/queue-format.js +11 -7
- package/dist/react/components/queues/queue-format.js.map +1 -1
- package/dist/react/components/queues-panel.js +1 -1
- package/dist/react/components/queues-panel.js.map +1 -1
- package/dist/react/components/request-timeline.d.ts.map +1 -1
- package/dist/react/components/request-timeline.js +2 -2
- package/dist/react/components/request-timeline.js.map +1 -1
- package/dist/react/components/retention-indicator.d.ts.map +1 -1
- package/dist/react/components/retention-indicator.js +1 -1
- package/dist/react/components/retention-indicator.js.map +1 -1
- package/dist/react/components/sparkline.d.ts.map +1 -1
- package/dist/react/components/sparkline.js +1 -1
- package/dist/react/components/sparkline.js.map +1 -1
- package/dist/react/components/tag-autocomplete.d.ts +21 -4
- package/dist/react/components/tag-autocomplete.d.ts.map +1 -1
- package/dist/react/components/tag-autocomplete.js +57 -29
- package/dist/react/components/tag-autocomplete.js.map +1 -1
- package/dist/react/components/to-csv.d.ts +25 -0
- package/dist/react/components/to-csv.d.ts.map +1 -0
- package/dist/react/components/to-csv.js +78 -0
- package/dist/react/components/to-csv.js.map +1 -0
- package/dist/react/components/user-tag.d.ts +15 -0
- package/dist/react/components/user-tag.d.ts.map +1 -1
- package/dist/react/components/user-tag.js +19 -0
- package/dist/react/components/user-tag.js.map +1 -1
- package/dist/react/components/waterfall-view.d.ts +13 -0
- package/dist/react/components/waterfall-view.d.ts.map +1 -0
- package/dist/react/components/waterfall-view.js +58 -0
- package/dist/react/components/waterfall-view.js.map +1 -0
- package/dist/react/components/window-select.d.ts.map +1 -1
- package/dist/react/components/window-select.js +6 -2
- package/dist/react/components/window-select.js.map +1 -1
- package/dist/react/index.d.ts +7 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +11 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/ui/badge.d.ts +16 -0
- package/dist/react/ui/badge.d.ts.map +1 -0
- package/dist/react/ui/badge.js +28 -0
- package/dist/react/ui/badge.js.map +1 -0
- package/dist/react/ui/button.d.ts +17 -0
- package/dist/react/ui/button.d.ts.map +1 -0
- package/dist/react/ui/button.js +35 -0
- package/dist/react/ui/button.js.map +1 -0
- package/dist/react/ui/chart.d.ts +116 -0
- package/dist/react/ui/chart.d.ts.map +1 -0
- package/dist/react/ui/chart.js +191 -0
- package/dist/react/ui/chart.js.map +1 -0
- package/dist/react/ui/cn.d.ts +8 -0
- package/dist/react/ui/cn.d.ts.map +1 -0
- package/dist/react/ui/cn.js +11 -0
- package/dist/react/ui/cn.js.map +1 -0
- package/dist/react/ui/dialog.d.ts +26 -0
- package/dist/react/ui/dialog.d.ts.map +1 -0
- package/dist/react/ui/dialog.js +40 -0
- package/dist/react/ui/dialog.js.map +1 -0
- package/dist/react/ui/index.d.ts +24 -0
- package/dist/react/ui/index.d.ts.map +1 -0
- package/dist/react/ui/index.js +24 -0
- package/dist/react/ui/index.js.map +1 -0
- package/dist/react/ui/input.d.ts +3 -0
- package/dist/react/ui/input.d.ts.map +1 -0
- package/dist/react/ui/input.js +8 -0
- package/dist/react/ui/input.js.map +1 -0
- package/dist/react/ui/select.d.ts +20 -0
- package/dist/react/ui/select.d.ts.map +1 -0
- package/dist/react/ui/select.js +27 -0
- package/dist/react/ui/select.js.map +1 -0
- package/dist/react/ui/table.d.ts +27 -0
- package/dist/react/ui/table.d.ts.map +1 -0
- package/dist/react/ui/table.js +22 -0
- package/dist/react/ui/table.js.map +1 -0
- package/dist/react/ui/tabs.d.ts +12 -0
- package/dist/react/ui/tabs.d.ts.map +1 -0
- package/dist/react/ui/tabs.js +20 -0
- package/dist/react/ui/tabs.js.map +1 -0
- package/dist/react/ui/tooltip.d.ts +10 -0
- package/dist/react/ui/tooltip.d.ts.map +1 -0
- package/dist/react/ui/tooltip.js +12 -0
- package/dist/react/ui/tooltip.js.map +1 -0
- package/dist/react/use-telescope-queries.d.ts +129 -130
- package/dist/react/use-telescope-queries.d.ts.map +1 -1
- package/dist/react/use-telescope-queries.js +146 -1
- package/dist/react/use-telescope-queries.js.map +1 -1
- package/dist/react/use-telescope-stream.d.ts +10 -0
- package/dist/react/use-telescope-stream.d.ts.map +1 -0
- package/dist/react/use-telescope-stream.js +40 -0
- package/dist/react/use-telescope-stream.js.map +1 -0
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +5 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/telescope-ui.controller.d.ts.map +1 -1
- package/dist/server/telescope-ui.controller.js +3 -1
- package/dist/server/telescope-ui.controller.js.map +1 -1
- package/dist/server/telescope-ui.module.d.ts +28 -1
- package/dist/server/telescope-ui.module.d.ts.map +1 -1
- package/dist/server/telescope-ui.module.js +48 -4
- package/dist/server/telescope-ui.module.js.map +1 -1
- package/dist/server/telescope-ui.options.d.ts +63 -0
- package/dist/server/telescope-ui.options.d.ts.map +1 -1
- package/dist/server/telescope-ui.options.js.map +1 -1
- package/dist/spa/assets/index-BfyQ_2IN.css +1 -0
- package/dist/spa/assets/index-EBJiTdQF.js +159 -0
- package/dist/spa/index.html +2 -2
- package/package.json +75 -36
- package/skills/telescope-ui-dashboard/SKILL.md +203 -0
- package/dist/react/components/type-tabs.d.ts +0 -5
- package/dist/react/components/type-tabs.d.ts.map +0 -1
- package/dist/react/components/type-tabs.js +0 -8
- package/dist/react/components/type-tabs.js.map +0 -1
- package/dist/spa/assets/index-CCzTpxj3.css +0 -1
- package/dist/spa/assets/index-w0XTI5OM.js +0 -135
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,778 @@
|
|
|
1
1
|
# @dudousxd/nestjs-telescope-ui
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- [#183](https://github.com/DavideCarvalho/nestjs-telescope/pull/183) [`1a1d056`](https://github.com/DavideCarvalho/nestjs-telescope/commit/1a1d0560b680349d4e1ce142a61910ddebcb9ae2) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - One `authorize` option decides who may use the console.
|
|
8
|
+
|
|
9
|
+
- `TelescopeModule.forRoot({ authorize })` covers the API, the live stream and the MCP endpoint; `mcpAuthorize` replaces it on MCP alone. `TelescopeUiModule.forRoot({ authorize })` covers the page and its assets, and `TelescopeOtelMetricsModule.forExporter(exporter, { authorize })` covers `GET /metrics`. With `forRootAsync`, `authorize` can come from the factory.
|
|
10
|
+
- `authorize` takes a function `(ctx) => result`, an `@Injectable()` class implementing `ConsoleAuthorizer`, a lazy `() => import(...)`, `{ policy, ability }` for `@nestjs/authorization` (now an optional peer), or a gate name resolved by `@dudousxd/nestjs-authz`.
|
|
11
|
+
- It returns `true`/`false`, `{ allowed }`, `{ allowed: false, reason: 'unauthenticated' }` or `{ redirectTo }`. Denials answer `403 { error: 'forbidden' }` or `401 { error: 'unauthenticated' }`; `redirectTo` gives a 302 for a page navigation and a 401 with `redirectTo` for an API call. A throw denies. A denied page navigation gets an "Access denied" page (403) or a "Sign in required" page (401).
|
|
12
|
+
- New `authorizeByToken({ token })` checks `Authorization: Bearer <token>` in constant time, for coding agents on MCP and Prometheus on `/metrics`. `@UseConsoleAuthorize()` protects controllers you mount yourself with `routes: false`: with no argument it runs `TelescopeModule`'s `authorize`; list it above your authentication guard so that guard runs first. `ConsoleAuthorizeGuard` (or `ConsoleAuthorizeGuard.for({ authorize })`) and `ConsoleAuthorizeFilter` are the guard and the denial filter on their own.
|
|
13
|
+
- The dashboard follows `redirectTo` from a 401 and shows an access-denied screen on a 403. `createTelescopeClient` takes an `onAccessDenied` callback.
|
|
14
|
+
|
|
15
|
+
**Breaking:**
|
|
16
|
+
|
|
17
|
+
- With no `authorize`, the console is open outside production and answers 403 to every request in production, with one warning at boot (also with `routes: false`). The production boot refusal ("refusing to mount undecorated routes with NODE_ENV=production") is removed, and `decorators` no longer count as protection on their own: keep authentication in `decorators` and move the authorization check to `authorize`.
|
|
18
|
+
- `assertConsoleProtected`, `CONSOLE_DECORATORS_EXAMPLE` and `ConsoleProtectionHint` are removed.
|
|
19
|
+
- otel: `requireProtectionInProduction` is removed. `/metrics` follows the console's rule, so it answers 403 in production until you set `authorize`. **If a Prometheus scraper reads `/metrics` without credentials today, it starts getting 403 after this upgrade:** set `authorize: authorizeByToken({ token: process.env.METRICS_TOKEN })` and give the scraper that bearer token, or `authorize: () => true` to keep `/metrics` open when the network already restricts it.
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [[`1a1d056`](https://github.com/DavideCarvalho/nestjs-telescope/commit/1a1d0560b680349d4e1ce142a61910ddebcb9ae2)]:
|
|
24
|
+
- @dudousxd/nestjs-telescope@3.0.0
|
|
25
|
+
|
|
26
|
+
## 2.0.1
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- [#179](https://github.com/DavideCarvalho/nestjs-telescope/pull/179) [`3f6437a`](https://github.com/DavideCarvalho/nestjs-telescope/commit/3f6437ae527264cc5acbbd4be7c0b9ab060cfdc9) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Republish the 2.0 release as 2.0.1. The 2.0.0 versions on npm are an old accidental build from 2026-06-05 (deprecated at the time), so `changeset publish` skipped them as "already published" and `^2.0.0` installs that June build. 2.0.1 is the real 2.0: the first-party NestJS integration and route protection release, with no further changes.
|
|
31
|
+
|
|
3
32
|
## 2.0.0
|
|
4
33
|
|
|
34
|
+
### Major Changes
|
|
35
|
+
|
|
36
|
+
- [#178](https://github.com/DavideCarvalho/nestjs-telescope/pull/178) [`3222eae`](https://github.com/DavideCarvalho/nestjs-telescope/commit/3222eae574429a9807784ba413e8f0e43c3d98d3) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - **Breaking:** the page is now protected only with `@nestjs/authentication` + `@nestjs/authorization`. Add a `decorators` option to `TelescopeUiModule.forRoot` / `forRootAsync` (static top-level on the async variant): the class decorators go on the dashboard controller, which is also marked open to `@nestjs/authorization`'s deny-by-default global guard; a `Can()` passed in `decorators` is still enforced. With `NODE_ENV=production`, mounting the page with no `decorators` (an empty array counts as none) fails the boot (the rule checks that decorators are present, not that they enforce auth); `routes: false` always boots.
|
|
37
|
+
|
|
38
|
+
Removed: the `guards` and `dashboardAuth` options (and `unauthenticatedPage`), the SPA's sign-in screen, sign-out button and `client.auth.*` methods, `meta.auth` in the client types, and the session-minting console launcher (`openTelescopeConsole`, `mintTelescopeConsoleSession`, `telescopeConsoleSessionUrl`, `ConsoleSessionError`, `useOpenTelescopeConsole`, `openTelescopeConsoleMutationOptions`, `<OpenTelescopeConsoleButton>` and the `./react/console` subpath). `telescopeConsoleUrl` stays in `./client`.
|
|
39
|
+
|
|
40
|
+
Migration: `guards: [G]` → `decorators: [UseGuards(G), Can(Policy, 'view')]` (pass the same list to `TelescopeModule`); `dashboardAuth` → your app's own sign-in through `@nestjs/authentication` (the page authenticates from your app's cookie); the launcher → a plain link to `telescopeConsoleUrl(basePath)`.
|
|
41
|
+
|
|
42
|
+
- [#178](https://github.com/DavideCarvalho/nestjs-telescope/pull/178) [`3222eae`](https://github.com/DavideCarvalho/nestjs-telescope/commit/3222eae574429a9807784ba413e8f0e43c3d98d3) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Add `routes: false` to `TelescopeUiModule.forRoot` / `forRootAsync` (static top-level on the async variant): no controller is mounted, and `TelescopeUiController` and `TELESCOPE_UI_OPTIONS` are now exported (the module exports the options provider), so you can serve the page from your own subclass protected with `@Can(...)` / `@UseGuards(...)`.
|
|
43
|
+
|
|
44
|
+
### Minor Changes
|
|
45
|
+
|
|
46
|
+
- [#178](https://github.com/DavideCarvalho/nestjs-telescope/pull/178) [`3222eae`](https://github.com/DavideCarvalho/nestjs-telescope/commit/3222eae574429a9807784ba413e8f0e43c3d98d3) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Cards and nav entries for the entries `@dudousxd/nestjs-telescope-official` records from NestJS's first-party channels: `resilience` (Resilience), `workflow` (Nest workflows) and `auth` (Auth). Each card shows the event as a badge (red for a refusal or failure), its subject (the policy and entrypoint, the workflow and step, or the user / the denied `Policy.ability`), every scalar field the entry carries, the error, and the workflow output or status. The entries table labels them by event and subject, and labels `mail` entries `[status] subject`.
|
|
47
|
+
|
|
48
|
+
### Patch Changes
|
|
49
|
+
|
|
50
|
+
- Updated dependencies [[`3222eae`](https://github.com/DavideCarvalho/nestjs-telescope/commit/3222eae574429a9807784ba413e8f0e43c3d98d3), [`3222eae`](https://github.com/DavideCarvalho/nestjs-telescope/commit/3222eae574429a9807784ba413e8f0e43c3d98d3), [`3222eae`](https://github.com/DavideCarvalho/nestjs-telescope/commit/3222eae574429a9807784ba413e8f0e43c3d98d3)]:
|
|
51
|
+
- @dudousxd/nestjs-telescope@2.0.0
|
|
52
|
+
|
|
53
|
+
## 1.26.0
|
|
54
|
+
|
|
55
|
+
### Minor Changes
|
|
56
|
+
|
|
57
|
+
- [#175](https://github.com/DavideCarvalho/nestjs-telescope/pull/175) [`a884482`](https://github.com/DavideCarvalho/nestjs-telescope/commit/a884482066c847c7dfbb24945f50c72ba5b92d51) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - AI usage and agent run timings are first-class.
|
|
58
|
+
|
|
59
|
+
- **AI screen** (`#/ai`): spend over the window (total, platform and estimated shares, by feature, model and top payers, over time), agent runs with a queue / model / tools bar, steps, tool calls, cost, model and status, the slowest and most expensive runs, a per-step breakdown with links to the trace waterfall, and the calls nobody priced. Backed by `GET <path>/api/ai`, summarized from the `aviary:agent:*` entries `@dudousxd/nestjs-agent` 1.38.0+ (core 0.60.0+) records. An app on an older agent lib gets an empty state that says so.
|
|
60
|
+
- **Metrics** `aviary_ai_cost_usd_total`, `aviary_ai_tokens_total`, `aviary_ai_audio_seconds_total`, `aviary_ai_requests_total` (counters, as Prometheus names them) and `aviary_agent_run_duration_ms`, `aviary_agent_run_queue_ms`, `aviary_agent_run_model_ms`, `aviary_agent_run_tools_ms`, `aviary_agent_tool_duration_ms` (histograms), read straight from the diagnostics channels. No actor, run or thread attributes.
|
|
61
|
+
- `aiMetrics: { prometheus: true }` serves them at `GET <path>/api/metrics` (Prometheus text format) behind the API gate. Off by default.
|
|
62
|
+
- `TelescopeAiMetricsExporter` (`-otel`) pushes them over OTLP/HTTP from a private `MeterProvider`, with its own endpoint. `@opentelemetry/sdk-metrics`, `@opentelemetry/exporter-metrics-otlp-http` and `@opentelemetry/resources` are optional, lazily loaded peers.
|
|
63
|
+
- An importable Grafana dashboard ships at `@dudousxd/nestjs-telescope-otel/grafana/aviary-ai-dashboard.json`.
|
|
64
|
+
- `StackedAreaChartCard` takes an optional `colors` map.
|
|
65
|
+
|
|
66
|
+
## 1.25.0
|
|
67
|
+
|
|
68
|
+
### Minor Changes
|
|
69
|
+
|
|
70
|
+
- [#165](https://github.com/DavideCarvalho/nestjs-telescope/pull/165) [`6a1ecea`](https://github.com/DavideCarvalho/nestjs-telescope/commit/6a1ecea013ea550167c362b69fcc74f27ec1c749) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - `Page` gains an optional `partial` flag, and the dashboard says when a listing is incomplete
|
|
71
|
+
|
|
72
|
+
A store sets `partial: true` on a `get()` page when it answered from a subset of its data — a tiered store whose cold tier could not be read returns its hot entries this way instead of failing. The flag is additive (absent means complete), passes through `GET /entries`, `GET /profiles` and the MCP `list_entries` tool, and the entries list shows a non-blocking notice that older entries are unavailable while the rows it did get stay usable.
|
|
73
|
+
|
|
74
|
+
## 1.24.1
|
|
75
|
+
|
|
76
|
+
### Patch Changes
|
|
77
|
+
|
|
78
|
+
- fix(deps): update dependency @base-ui/react to v1.8.0 ([#138](https://github.com/DavideCarvalho/nestjs-telescope/issues/138))
|
|
79
|
+
|
|
80
|
+
## 1.24.0
|
|
81
|
+
|
|
82
|
+
### Minor Changes
|
|
83
|
+
|
|
84
|
+
- [`8d9f88f`](https://github.com/DavideCarvalho/nestjs-telescope/commit/8d9f88f0ef9653cf3e6cafdf47ceceecc4d2abef) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - The tag filter is a picker over what exists — searched and paged on the server
|
|
85
|
+
|
|
86
|
+
It was a text box with suggestions bolted on: it showed nothing until you typed, asked the server for
|
|
87
|
+
a **prefix** match, and then re-filtered and sliced the answer to ten in the browser. So it could
|
|
88
|
+
only suggest tags whose first characters you already knew, and the ten it kept were the ten it
|
|
89
|
+
happened to fetch.
|
|
90
|
+
|
|
91
|
+
- **Focus opens it.** The list is the answer to "what can I filter by", and requiring a first
|
|
92
|
+
character asks an operator to guess that answer before seeing it.
|
|
93
|
+
- **`search` matches anywhere in the tag** and runs on the server, before the bound. A picker that
|
|
94
|
+
narrowed its own fetched page could only ever find what the bound already let through — and on a
|
|
95
|
+
deployment with real tag cardinality, the bound is precisely what hides the value being looked for.
|
|
96
|
+
- **The list pages as it scrolls**, so the bound is a window rather than a ceiling.
|
|
97
|
+
- Typing something the list does not offer still applies as typed. A bounded list has to stay
|
|
98
|
+
escapable.
|
|
99
|
+
|
|
100
|
+
`GET /tags` gains `search`, `limit` and `offset`; `StorageProvider.tags` gains an optional `TagQuery`
|
|
101
|
+
and now promises an order (count descending, ties alphabetical) — an unordered listing cannot be
|
|
102
|
+
paged, because page two would be cut from a different arrangement of the same rows. A provider that
|
|
103
|
+
ignores the query stays correct: the controller re-applies the page, so a picker never renders more
|
|
104
|
+
than it asked for.
|
|
105
|
+
|
|
106
|
+
## 1.23.1
|
|
107
|
+
|
|
108
|
+
### Patch Changes
|
|
109
|
+
|
|
110
|
+
- [`80392f0`](https://github.com/DavideCarvalho/nestjs-telescope/commit/80392f0e4d038b50b5c8703275cfd91e3328064b) - Add NestJS 12 to the supported peer range.
|
|
111
|
+
|
|
112
|
+
NestJS 12.0.1 shipped the framework as pure ESM and raised its floor to Node >= 20.19. Telescope's
|
|
113
|
+
packages are already `"type": "module"`, so the ESM shift is a non-event here — nothing needed
|
|
114
|
+
porting, and every watcher, storage provider and dashboard route behaves identically on 11 and 12.
|
|
115
|
+
|
|
116
|
+
The declared peer ranges (`@nestjs/common`/`@nestjs/core` at `>=10.0.0`, `>=11.0.0` for the UI
|
|
117
|
+
package, and the satellite peers `@nestjs/bullmq`, `@nestjs/cache-manager`, `@nestjs/event-emitter`,
|
|
118
|
+
`@nestjs/schedule`) already admitted a 12.x resolution, so no range changed — what changed is that
|
|
119
|
+
the claim is now tested. Every package's dev and test matrix moved to the 12.x line, along with the
|
|
120
|
+
example app and the memory-soak harness, and the whole suite builds, typechecks and passes there.
|
|
121
|
+
|
|
122
|
+
Moving the example app and the soak harness matters for more than tidiness: leaving them on
|
|
123
|
+
`@nestjs/platform-express@11` left a second `@nestjs/platform-express` major in the workspace, and
|
|
124
|
+
pnpm's peer resolution then produced two distinct `@nestjs/core@12` instances. `tsc` correctly
|
|
125
|
+
rejected the resulting `ModuleRef` from one instance where the other was expected. That is a
|
|
126
|
+
workspace resolution artifact rather than a NestJS 12 incompatibility, but it is exactly the shape
|
|
127
|
+
of breakage a consumer sees when they upgrade half a dependency graph.
|
|
128
|
+
|
|
129
|
+
No behaviour change — peer ranges only affect what a package manager warns about on install.
|
|
130
|
+
|
|
131
|
+
## 1.23.0
|
|
132
|
+
|
|
133
|
+
### Minor Changes
|
|
134
|
+
|
|
135
|
+
- [#82](https://github.com/DavideCarvalho/nestjs-telescope/pull/82) [`d245d70`](https://github.com/DavideCarvalho/nestjs-telescope/commit/d245d7093fdb748fa398d6dd1c8b24d4110cbfbb) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Let a dashboard section declare `cols: 1` — the full-width row.
|
|
136
|
+
|
|
137
|
+
A section renders as a fixed `grid-cols-N` grid, one panel per cell, with no `colSpan`, and `cols`
|
|
138
|
+
only accepted `2 | 3 | 4`. So the widest panel a dashboard has — a table with ten or more columns —
|
|
139
|
+
could not be given a row of its own. Declared in the narrowest grid available it still got half the
|
|
140
|
+
viewport, scrolled sideways inside its own card, and left the cell beside it empty.
|
|
141
|
+
|
|
142
|
+
That is not hypothetical: `@dudousxd/nestjs-durable-telescope` ships its eleven-column worker table
|
|
143
|
+
as the only panel of a `cols: 2` section, which on a 1418px viewport rendered a 1406px table into a
|
|
144
|
+
575px card with a hole next to it. There was no way to express the fix.
|
|
145
|
+
|
|
146
|
+
Additive: `cols` gains `1`, existing values behave identically, and the grid needs no new responsive
|
|
147
|
+
class for it — it is already `grid-cols-1` at every breakpoint, so a full-width row is the absence
|
|
148
|
+
of an override rather than the presence of one.
|
|
149
|
+
|
|
150
|
+
## 1.22.1
|
|
151
|
+
|
|
152
|
+
### Patch Changes
|
|
153
|
+
|
|
154
|
+
- [#80](https://github.com/DavideCarvalho/nestjs-telescope/pull/80) [`1378075`](https://github.com/DavideCarvalho/nestjs-telescope/commit/137807549d64889222d9119534b8e8be4d5c7651) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Stop a provider that ignores `query.page` from freezing a paged table's pager.
|
|
155
|
+
|
|
156
|
+
`PagerControls` read its current page off the **response**, and its handlers computed `page ± 1`
|
|
157
|
+
from that. When a provider answers with a pinned page — as `@dudousxd/nestjs-agent-telescope`'s
|
|
158
|
+
did, reading `?page=2` as a string and returning page 1 for every request — the result was not a
|
|
159
|
+
stale number but a dead control: the first click moves the caller's state to 2 and refetches, the
|
|
160
|
+
response still says 1, so the second click asks for 2 again, the state does not change, React skips
|
|
161
|
+
the re-render, and neither button does anything again short of a page reload. Prev never re-enables.
|
|
162
|
+
|
|
163
|
+
`PanelView` now takes an optional `requestedPage` — the page the caller has asked for — and prefers
|
|
164
|
+
it over the response's. `ExtensionDashboardPage` passes its own paging state, so every click keeps
|
|
165
|
+
advancing and the worst a broken provider can do is fail to change the rows: visible, and
|
|
166
|
+
recoverable with Prev. Panels whose provider honours paging are unaffected, since the two values
|
|
167
|
+
agree; a caller that passes no `requestedPage` still reads the page off the response exactly as
|
|
168
|
+
before.
|
|
169
|
+
|
|
170
|
+
## 1.22.0
|
|
171
|
+
|
|
172
|
+
### Minor Changes
|
|
173
|
+
|
|
174
|
+
- [#78](https://github.com/DavideCarvalho/nestjs-telescope/pull/78) [`5832622`](https://github.com/DavideCarvalho/nestjs-telescope/commit/58326225e99fa134997d85e5e81952d7d505ad1c) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Rebuild the chart cards on a vendored shadcn chart layer, and give them a legend, a brush and
|
|
175
|
+
drill-down.
|
|
176
|
+
|
|
177
|
+
Every chart in the console — the Overview throughput and by-type areas, the queues bars, the entry
|
|
178
|
+
insights, and every chart-shaped extension panel — was hand-rolled Recharts: each card restated its
|
|
179
|
+
own grid stroke, axis stroke, tick style and the three `contentStyle`/`labelStyle`/`itemStyle`
|
|
180
|
+
objects that make up Recharts' single line of tooltip text. Series colours lived in two places, and
|
|
181
|
+
chrome colours in seven.
|
|
182
|
+
|
|
183
|
+
- **`src/react/ui/chart.tsx`** joins the vendored primitives: `ChartContainer`, `ChartTooltip`,
|
|
184
|
+
`ChartTooltipContent`, `ChartLegend`, `ChartLegendContent` and the `ChartConfig` type, retuned to
|
|
185
|
+
the Aviary tokens. Two departures from upstream shadcn, both deliberate: chart chrome is styled by
|
|
186
|
+
selecting Recharts' own class names off the container (a stylesheet rule beats an SVG presentation
|
|
187
|
+
attribute), and the per-series `--color-<key>` custom properties are set inline instead of through
|
|
188
|
+
shadcn's `dangerouslySetInnerHTML` style tag — a config that can come from an extension-authored
|
|
189
|
+
dashboard spec should not reach an HTML-injection-shaped API.
|
|
190
|
+
- **`chart-theme.ts` is now the only place a series colour is decided**, and the chrome constants it
|
|
191
|
+
used to export are deprecated rather than removed. Breakdown segments resolve through the same
|
|
192
|
+
entry-type hues as everything else, so an `exception` segment is no longer amber in a donut and red
|
|
193
|
+
in the chart beside it.
|
|
194
|
+
- **Rich hover cards** everywhere: label row, one row per series with its own swatch, configured name
|
|
195
|
+
and formatted value. Everything read out of a Recharts payload goes through runtime guards — a
|
|
196
|
+
provider can return anything, and a tooltip rendering `[object Object]` is a bug nobody notices
|
|
197
|
+
until it is in a screenshot.
|
|
198
|
+
- **Clickable legends** on the multi-series charts: an entry toggles its series, which restacks the
|
|
199
|
+
rest. With six entry types stacked, switching the big ones off is the only way to read the small
|
|
200
|
+
ones. The entries are the vendored `Button` with `aria-pressed`, not bare `<button>`s.
|
|
201
|
+
- **Brush on the timeseries charts**, so a long window can be narrowed in place. It appears once a
|
|
202
|
+
series passes 24 points and can be forced either way with `brush`; below that it is a scrollbar for
|
|
203
|
+
a page that already fits.
|
|
204
|
+
- **Drill-down.** A chart-shaped panel that declares `drilldown: { param }` becomes clickable: the
|
|
205
|
+
click sets one dashboard-wide selection, every panel re-resolves with that param merged onto its
|
|
206
|
+
own `data.query`, and a chip in the header says what is filtered (clicking the same item again, or
|
|
207
|
+
the chip's Clear, undoes it). A panel that declares no `drilldown` gets no click handler at all, so
|
|
208
|
+
every dashboard shipping today behaves exactly as before. The cards themselves take a typed
|
|
209
|
+
`onSelect(selection)` and know nothing about dashboards; `BarChartCard.onBarClick` still fires and
|
|
210
|
+
is deprecated in favour of it.
|
|
211
|
+
- Two bugs the rewrite surfaced: a `gauge` panel drew a full half-dial whatever it was reporting
|
|
212
|
+
(with one datum and no explicit polar domain, Recharts scales the arc to the value itself), and a
|
|
213
|
+
`distribution` panel's percentile chips pushed its chart out of the card by exactly their own
|
|
214
|
+
height.
|
|
215
|
+
|
|
216
|
+
- [#77](https://github.com/DavideCarvalho/nestjs-telescope/pull/77) [`b330bfc`](https://github.com/DavideCarvalho/nestjs-telescope/commit/b330bfce9b025dc5bfe1c695eaaeeea80b007f82) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Rebuild the extension-dashboard `table` panel on TanStack Table v9, and give it server-side sort
|
|
217
|
+
and filter.
|
|
218
|
+
|
|
219
|
+
A table panel could only ever be read. Sorting it was not an oversight so much as an unanswered
|
|
220
|
+
question: the panel holds the one page its provider returned, so a sort added in the browser would
|
|
221
|
+
have ordered 50 rows out of 50,000 and presented the result as "the slowest runs" — a control that
|
|
222
|
+
is wrong precisely when someone is relying on it. The answer here is that the choice goes back to
|
|
223
|
+
the provider, which is the only party that can see the whole result set.
|
|
224
|
+
|
|
225
|
+
**The new SPI** (additive; existing panels and providers are untouched). A column opts in:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
columns: [
|
|
229
|
+
{ key: "runId", label: "Run", filterable: true },
|
|
230
|
+
{ key: "duration", label: "Duration", sortable: true },
|
|
231
|
+
{ key: "worker", label: "Worker", hideable: true },
|
|
232
|
+
];
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- `sortable` — the header becomes a button cycling ascending → descending → unsorted, and the
|
|
236
|
+
provider is re-resolved with `sort=<key>` + `dir=asc|desc` (both absent when unsorted).
|
|
237
|
+
- `filterable` — a filter box appears under the header, committed on Enter or blur, sent as
|
|
238
|
+
`filter.<key>=<text>`. Namespaced because a panel scoped to `{ status: 'running' }` carrying a
|
|
239
|
+
filterable `status` column is an ordinary combination, and unprefixed one would silently
|
|
240
|
+
overwrite the other.
|
|
241
|
+
- `hideable` — the column joins the panel's **Columns** menu. Display-only; it never reaches the
|
|
242
|
+
provider, and the menu is absent entirely when no column opts in.
|
|
243
|
+
|
|
244
|
+
Providers read the state with the new `readTableQuery(query)` from `@dudousxd/nestjs-telescope`,
|
|
245
|
+
which returns `{ page?, limit?, sort?: { key, dir }, filters }`. Reading it by hand is the trap it
|
|
246
|
+
exists to close: every value arrives as a **string** off the URL, so `query.page > 1` is silently
|
|
247
|
+
`false` for `'2'`, and `?page=banana` reaches a `LIMIT` clause as `NaN`. It also drops an emptied
|
|
248
|
+
filter box (`filter.status=` means _no_ filter, not "match the empty string") and reads an
|
|
249
|
+
unrecognized direction as ascending.
|
|
250
|
+
|
|
251
|
+
Backward compatibility is the point, not a footnote: a provider that ignores the new params behaves
|
|
252
|
+
exactly as before, and a panel whose columns declare none of the three flags renders the identical
|
|
253
|
+
table — no header buttons, no filter row, no column menu, and the byte-identical query on the wire.
|
|
254
|
+
The query builder returns the panel's own `data.query` _by identity_ when there is nothing to merge,
|
|
255
|
+
so existing dashboards do not even move to a new React Query cache key.
|
|
256
|
+
|
|
257
|
+
- **v9's explicit feature model.** `table-features.ts` is the package's only module that imports
|
|
258
|
+
`@tanstack/react-table`; everything else consumes the hook, `flexRender` and the pre-bound types
|
|
259
|
+
through it. v9 installs a feature's state and instance methods only when it is registered, and an
|
|
260
|
+
unregistered feature is not an error — the method is simply gone, which at the call site is
|
|
261
|
+
indistinguishable from "removed in v9". A contract spec asserts every API the table actually calls.
|
|
262
|
+
- **No client row models are registered**, deliberately. `createSortedRowModel` and friends would
|
|
263
|
+
re-do server-side work over the single page in hand, which is the exact failure this change exists
|
|
264
|
+
to avoid. `rowPaginationFeature` and `columnSizingFeature` are left out too — the pager is driven
|
|
265
|
+
by what the provider returned, and column sizing would default every column of every dashboard to
|
|
266
|
+
a fixed 150px.
|
|
267
|
+
- **A paged table's rows now scroll under a pinned header**, capped at 28rem. A 50-row page was
|
|
268
|
+
otherwise a ~1,500px card that pushed every panel below it off screen, and by row 40 the column
|
|
269
|
+
labels were long gone. A short page never reaches the cap and is unchanged.
|
|
270
|
+
- The vendored `Table` primitive gains `containerClassName`. That wrapper div is already a scroll
|
|
271
|
+
container, so it is the element a sticky header positions against — a `max-h-*` applied anywhere
|
|
272
|
+
further out gives a scrolling ancestor the sticky cells cannot see.
|
|
273
|
+
- `@tanstack/react-table` is declared as an optional peer dependency, alongside `recharts` and
|
|
274
|
+
`@tanstack/react-query`: the bundled SPA carries its own copy, so only a host composing these
|
|
275
|
+
React components itself needs to install it.
|
|
276
|
+
|
|
277
|
+
## 1.21.1
|
|
278
|
+
|
|
279
|
+
### Patch Changes
|
|
280
|
+
|
|
281
|
+
- [#75](https://github.com/DavideCarvalho/nestjs-telescope/pull/75) [`f5ba9bf`](https://github.com/DavideCarvalho/nestjs-telescope/commit/f5ba9bf29c16b55244cf05e41f12e31a202919cd) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Stop an extension dashboard's tables from painting outside their cards.
|
|
282
|
+
|
|
283
|
+
A `table` panel was the one surface in the console still rendering hand-rolled `<table>` markup:
|
|
284
|
+
it never moved onto the vendored shadcn `Table` when that primitive landed, so it also never got
|
|
285
|
+
the scroll container the primitive brings. That matters because a section lays its panels out as
|
|
286
|
+
a `grid-cols-N` of equal cells, and a card is routinely narrower than the table inside it — a
|
|
287
|
+
7-column table in a `cols: 3` section. `w-full` is only a _preferred_ width: `table-layout: auto`
|
|
288
|
+
still lays the table out at its min-content width, and with nothing clipping it the remaining
|
|
289
|
+
columns painted over the neighbouring panel.
|
|
290
|
+
|
|
291
|
+
Measured on flip's `durable.workflows` dashboard: a 379px card holding a 633px "Worker health"
|
|
292
|
+
table (its `STATUS` column landed on top of the panel to its right), and a 575px card holding a
|
|
293
|
+
1154px "Workers" table. `agent.overview` had the same break — `COST (USD)` and `LAST ACTIVITY`
|
|
294
|
+
rendered outside their cards.
|
|
295
|
+
|
|
296
|
+
- Both table variants, paged and not, now render through `Table`/`TableHeader`/`TableBody`/
|
|
297
|
+
`TableRow`/`TableHead`/`TableCell`, so a table too wide for its card scrolls inside it and
|
|
298
|
+
every panel keeps the same row height, header casing and divider colour as the rest of the app.
|
|
299
|
+
- Cells are `whitespace-nowrap`. Wrapping is what turned durable's "Workers" panel into
|
|
300
|
+
three-line rows; with a scroller in place, a long worker id belongs on one line behind a
|
|
301
|
+
scrollbar.
|
|
302
|
+
- The pager's prev/next are the vendored `Button` (`outline`/`xs`) rather than bare `<button>`s.
|
|
303
|
+
|
|
304
|
+
## 1.21.0
|
|
305
|
+
|
|
306
|
+
### Minor Changes
|
|
307
|
+
|
|
308
|
+
- [#73](https://github.com/DavideCarvalho/nestjs-telescope/pull/73) [`5203512`](https://github.com/DavideCarvalho/nestjs-telescope/commit/520351225a9f0f754e11cc7ef3e28a17d4499d11) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Adopt the Aviary console design tokens and a vendored shadcn-on-Base-UI primitive layer.
|
|
309
|
+
|
|
310
|
+
The dashboard was authored against hardcoded Tailwind `zinc`/`emerald` utilities — the only
|
|
311
|
+
Aviary console with no token vocabulary at all. It now declares the canonical tokens from
|
|
312
|
+
`AVIARY-UI.md` (`--bg`, `--panel`, `--panel-2`, `--line`, `--line-soft`, `--text`, `--muted`,
|
|
313
|
+
`--good`, `--warn`, `--bad`, `--live`, `--accent`) and consumes them through Tailwind semantic
|
|
314
|
+
colours, so it reads as a sibling of the agent, durable and media consoles rather than a stranger.
|
|
315
|
+
|
|
316
|
+
- **Light mode actually works.** It was a block of `.light .bg-zinc-900 { … }` overrides that
|
|
317
|
+
covered only the utilities someone had remembered to list, leaving mid-grey panels and
|
|
318
|
+
unreadable status text. The tokens are now declared twice — dark under `:root`, light under
|
|
319
|
+
`.light` — so every token-based surface, border, label and status flips with the theme.
|
|
320
|
+
- **Telescope's accent is magenta** (`#e879f9`). Its de-facto accent was emerald-400, which is
|
|
321
|
+
byte-identical to `--good`: the same hue meant both "healthy" and "interactive", side by side
|
|
322
|
+
on the Overview page. Magenta clears `--good`, `--warn`, `--bad`, `--live`, agent's violet and
|
|
323
|
+
media's cyan.
|
|
324
|
+
- **Vendored shadcn primitives** under `src/react/ui/` on Base UI — `Button`, `Badge`, `Input`,
|
|
325
|
+
`Table`, `Select`, `Tabs`, `Tooltip`, `Dialog` — wired so shadcn's semantic classes resolve to
|
|
326
|
+
the Aviary tokens. Note that shadcn's `accent` is a _hover surface_, so the brand hue is
|
|
327
|
+
exposed as `brand`/`--accent` and never as `bg-accent`.
|
|
328
|
+
- The command palette and the queue job drawer are now one `Dialog` implementation instead of
|
|
329
|
+
two hand-rolled overlays, and the two native `<select>` popups (which the OS drew, unthemed)
|
|
330
|
+
are now themable listboxes.
|
|
331
|
+
|
|
332
|
+
`cacheBadge()` and `inertiaBadges()` gain a `variant` field naming the semantic `Badge` variant.
|
|
333
|
+
`className` is unchanged in shape and still returned, so existing callers keep working; prefer
|
|
334
|
+
`variant` in new code.
|
|
335
|
+
|
|
336
|
+
Also fixes a long-standing packaging bug this work's bundle check surfaced: the `./react` barrel
|
|
337
|
+
reaches `recharts`, `react-router-dom` and `reflect-metadata`, none of which this package declared
|
|
338
|
+
— the exact failure that once broke a host's client build. They are now declared as optional peer
|
|
339
|
+
dependencies. `@base-ui-components/react`, `class-variance-authority`, `clsx` and `tailwind-merge`
|
|
340
|
+
are `dependencies`, because this package publishes React source that hosts bundle. A new
|
|
341
|
+
`published-graph.spec.ts` bundles each published entry with esbuild and asserts every package it
|
|
342
|
+
reaches is declared, so this cannot regress silently.
|
|
343
|
+
|
|
344
|
+
### Patch Changes
|
|
345
|
+
|
|
346
|
+
- [#71](https://github.com/DavideCarvalho/nestjs-telescope/pull/71) [`68e4052`](https://github.com/DavideCarvalho/nestjs-telescope/commit/68e40523200c699dae3a376752b8604d3d68ef1f) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Bound the React peer ranges to the majors this package is actually built and tested against.
|
|
347
|
+
|
|
348
|
+
`react` and `react-dom` were declared `>=18.0.0` and `@tanstack/react-query` `>=5.0.0` — open-ended
|
|
349
|
+
ranges that claim support for every future major. React 20 and Query 6 do not exist yet and
|
|
350
|
+
certainly are not tested here, so the declaration was a promise the package cannot keep; a consumer
|
|
351
|
+
on a future major would get no warning and a runtime surprise instead.
|
|
352
|
+
|
|
353
|
+
Now `^18.0.0 || ^19.0.0` and `^5.0.0`. Both majors are real: the package builds and tests against
|
|
354
|
+
React 18, and its `./react/console` launcher is consumed from a React 19 host.
|
|
355
|
+
|
|
356
|
+
No behaviour change — peer ranges only affect what a package manager warns about on install.
|
|
357
|
+
|
|
358
|
+
## 1.20.1
|
|
359
|
+
|
|
360
|
+
### Patch Changes
|
|
361
|
+
|
|
362
|
+
- [#69](https://github.com/DavideCarvalho/nestjs-telescope/pull/69) [`acdfacb`](https://github.com/DavideCarvalho/nestjs-telescope/commit/acdfacba22495b6517bf89d7e50a25d3032c1933) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Clear the console launcher's pending state when the page is restored from the back/forward cache.
|
|
363
|
+
|
|
364
|
+
`useOpenTelescopeConsole` deliberately keeps `isPending` set after a successful mint so the button
|
|
365
|
+
does not flicker back to idle on a page that is navigating away. With bfcache the page does not die:
|
|
366
|
+
pressing Back restored the launcher with its React state intact, leaving a permanent "Opening…"
|
|
367
|
+
spinner on a button that could never be clicked again. The hook now listens for `pageshow` and
|
|
368
|
+
resets only when `event.persisted` is true, so a fresh load and a mint that is still genuinely in
|
|
369
|
+
flight both keep the original behaviour.
|
|
370
|
+
|
|
371
|
+
## 1.20.0
|
|
372
|
+
|
|
373
|
+
### Minor Changes
|
|
374
|
+
|
|
375
|
+
- [#67](https://github.com/DavideCarvalho/nestjs-telescope/pull/67) [`87c8732`](https://github.com/DavideCarvalho/nestjs-telescope/commit/87c8732006a46eeea50d1dd1536c8a9794a13ae5) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Ship the console launcher on its own subpath: `@dudousxd/nestjs-telescope-ui/react/console`.
|
|
376
|
+
|
|
377
|
+
The launcher was only reachable from the `./react` barrel, which re-exports the whole dashboard
|
|
378
|
+
component set and therefore pulls in `recharts` and `react-router-dom`. Neither is declared by this
|
|
379
|
+
package, and a bundler resolves re-exported modules even when nothing references them — so a host
|
|
380
|
+
that wanted nothing but the launcher button got a hard build failure on a missing dependency
|
|
381
|
+
instead of tree-shaking it away.
|
|
382
|
+
|
|
383
|
+
`./react/console` re-exports the hook, the button and the headless client primitives, and nothing
|
|
384
|
+
else. Its entire dependency footprint is `react`, guarded by a test that walks the import graph.
|
|
385
|
+
|
|
386
|
+
`./react` is unchanged and still exports the launcher, so nothing breaks.
|
|
387
|
+
|
|
388
|
+
## 1.19.0
|
|
389
|
+
|
|
390
|
+
### Minor Changes
|
|
391
|
+
|
|
392
|
+
- [#65](https://github.com/DavideCarvalho/nestjs-telescope/pull/65) [`be97836`](https://github.com/DavideCarvalho/nestjs-telescope/commit/be978365f716cbe9e120b4024abb5d0ff6129d3d) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - **React tier for the console launcher: `useOpenTelescopeConsole` and `<OpenTelescopeConsoleButton>`, exported from `@dudousxd/nestjs-telescope-ui/react`.**
|
|
393
|
+
|
|
394
|
+
The headless `openTelescopeConsole` gave hosts the mint-then-navigate call; every host then wrote the
|
|
395
|
+
same three lines of React around it — an `isPending` flag, an error slot, and a button that has to
|
|
396
|
+
remember not to fire twice. Three tiers now, pick the one that fits and drop a level when it stops
|
|
397
|
+
fitting:
|
|
398
|
+
|
|
399
|
+
```tsx
|
|
400
|
+
import {
|
|
401
|
+
OpenTelescopeConsoleButton,
|
|
402
|
+
useOpenTelescopeConsole,
|
|
403
|
+
openTelescopeConsoleMutationOptions,
|
|
404
|
+
} from "@dudousxd/nestjs-telescope-ui/react";
|
|
405
|
+
|
|
406
|
+
// 1. drop-in
|
|
407
|
+
<OpenTelescopeConsoleButton
|
|
408
|
+
className="btn btn-primary"
|
|
409
|
+
headers={authHeaders}
|
|
410
|
+
/>;
|
|
411
|
+
|
|
412
|
+
// 2. state only, your markup
|
|
413
|
+
const { open, isPending, error, reset } = useOpenTelescopeConsole({
|
|
414
|
+
headers: authHeaders,
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// 3. openTelescopeConsole(...) from `/client` — no React at all
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
- `open()` **never rejects**; the refusal lands in `error` as a `ConsoleSessionError` (with its
|
|
421
|
+
`status` and `url`). It deliberately does not clear `isPending` on success, because the navigation
|
|
422
|
+
is already underway and flipping back to idle flickers "ready to click again" on a page that is
|
|
423
|
+
leaving.
|
|
424
|
+
- `<OpenTelescopeConsoleButton>` is **unstyled on purpose** — a bare `<button>` that forwards
|
|
425
|
+
`className`/`style`/every other button prop, so it inherits the host's design system instead of
|
|
426
|
+
importing CSS that fights it. It renders inside the host app, not inside Telescope's own bundle.
|
|
427
|
+
It disables itself and sets `aria-busy` while in flight, and renders the refusal as
|
|
428
|
+
`<p role="alert">` by default: a launcher that silently does nothing reads as broken rather than
|
|
429
|
+
forbidden. `renderError` substitutes that node; `renderError={null}` opts out entirely.
|
|
430
|
+
- `openTelescopeConsoleMutationOptions()` returns the `{ mutationKey, mutationFn }` shape
|
|
431
|
+
`useMutation` takes, so a host already on TanStack Query gets the launcher in its cache, devtools
|
|
432
|
+
and error handling with no adapter — and this package still never imports `@tanstack/react-query`.
|
|
433
|
+
|
|
434
|
+
React stays an optional peer dependency: a host that only mounts the NestJS module pulls none of
|
|
435
|
+
this in. Additive only; nothing existing changes.
|
|
436
|
+
|
|
437
|
+
## 1.18.0
|
|
438
|
+
|
|
439
|
+
### Minor Changes
|
|
440
|
+
|
|
441
|
+
- [#63](https://github.com/DavideCarvalho/nestjs-telescope/pull/63) [`2d0e76e`](https://github.com/DavideCarvalho/nestjs-telescope/commit/2d0e76ee52e3a556c24b567fdb4b9e6cef25c067) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - **Headless console launcher: `openTelescopeConsole` / `mintTelescopeConsoleSession` / `telescopeConsoleSessionUrl`, exported from `@dudousxd/nestjs-telescope-ui/client`.**
|
|
442
|
+
|
|
443
|
+
The console is entered from the HOST's app: a browser navigation to it carries no identity, so
|
|
444
|
+
something inside the host has to mint the Mode A session cookie first (an XHR that _does_ carry the
|
|
445
|
+
host's auth), then navigate. Every host was writing that by hand, which meant hardcoding two things
|
|
446
|
+
this package owns:
|
|
447
|
+
|
|
448
|
+
- **the session endpoint's path** — `<path>/api/auth/session`. Nothing tells a host when that moves; the break
|
|
449
|
+
only shows up as a runtime 404 after a version bump.
|
|
450
|
+
- **`redirect: 'manual'`** — and this one is a real trap. `fetch` follows redirects by default, so a
|
|
451
|
+
host whose auth layer rewrites a 401 into a sign-in redirect gets a resolved 200 against the
|
|
452
|
+
sign-in HTML. `response.ok` reads true, the caller navigates, and the user lands in a console with
|
|
453
|
+
no session — indistinguishable from a permissions bug. The helper detects the redirect (browser
|
|
454
|
+
opaque response _and_ Node/undici 3xx) and throws a message naming the likely cause.
|
|
455
|
+
|
|
456
|
+
```ts
|
|
457
|
+
import { openTelescopeConsole } from "@dudousxd/nestjs-telescope-ui/client";
|
|
458
|
+
|
|
459
|
+
await openTelescopeConsole({
|
|
460
|
+
headers: () => ({ Authorization: `Bearer ${token()}` }),
|
|
461
|
+
});
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
No UI: the host owns the button, the page and the copy. `headers` accepts a sync or async function
|
|
465
|
+
so a refreshing token is read at call time rather than captured at wiring time. `fetch` and
|
|
466
|
+
`navigate` are injectable (tests, routers, non-browser callers). A refused mint throws
|
|
467
|
+
`ConsoleSessionError` (carrying `status` and `url`) and **does not navigate** — a denied user gets a
|
|
468
|
+
real error instead of the console's "no session" page.
|
|
469
|
+
|
|
470
|
+
Additive only: nothing existing changes.
|
|
471
|
+
|
|
472
|
+
## 1.17.0
|
|
473
|
+
|
|
474
|
+
### Minor Changes
|
|
475
|
+
|
|
476
|
+
- [#61](https://github.com/DavideCarvalho/nestjs-telescope/pull/61) [`c3ee743`](https://github.com/DavideCarvalho/nestjs-telescope/commit/c3ee743fd7c51b34dcc2b349d07659ce9d5d7cbe) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - **`dashboardAuth.unauthenticatedPage` — hosts can now render the dashboard's unauthenticated page themselves.**
|
|
477
|
+
|
|
478
|
+
Under Mode A, a visitor navigating straight to `/telescope` with no cookie got the SPA shell, which
|
|
479
|
+
then rendered the built-in auth screen: _"open this console from your application."_ Deliberately
|
|
480
|
+
generic, because the library cannot know who hosts it — it can't name the host's launcher, link to
|
|
481
|
+
it, or look like the rest of the host's product.
|
|
482
|
+
|
|
483
|
+
```ts
|
|
484
|
+
const dashboardAuth = {
|
|
485
|
+
secret: process.env.TELESCOPE_AUTH_SECRET,
|
|
486
|
+
session: (request) => resolveAdmin(request),
|
|
487
|
+
unauthenticatedPage: ({ request, response, basePath }) => {
|
|
488
|
+
(response as Response)
|
|
489
|
+
.status(401)
|
|
490
|
+
.render("console-locked", { returnTo: basePath });
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
TelescopeModule.forRoot({ enabled: true, dashboardAuth });
|
|
495
|
+
TelescopeUiModule.forRoot({ dashboardAuth }); // <- also here; see below
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
Telescope's auth screen is a React component inside the published bundle — there is no
|
|
499
|
+
server-rendered page to replace. So the hook gates the **SPA shell route**: the session is checked
|
|
500
|
+
before the shell is served, which also means the bundle no longer loads at all for a visitor with no
|
|
501
|
+
session. Hashed assets stay ungated; they carry no data.
|
|
502
|
+
|
|
503
|
+
**`TelescopeUiModule` gains a `dashboardAuth` option, and it must be given the same config.**
|
|
504
|
+
`TelescopeModule` (core) gates the JSON API; `TelescopeUiModule` serves the HTML, so it is the only
|
|
505
|
+
one that can replace that page — the same independence the two modules' `guards` options already
|
|
506
|
+
have. Setting `unauthenticatedPage` on core alone changes nothing a visitor sees. Only `secret`, the
|
|
507
|
+
configured modes and `unauthenticatedPage` are read there; minting and renewal stay core's job.
|
|
508
|
+
|
|
509
|
+
**Mode-A-only by design.** With `login` configured the hook is ignored: under Mode B the login form
|
|
510
|
+
the visitor needs is _inside_ the bundle this page would replace, so gating the shell would lock a
|
|
511
|
+
Mode B host out of its own dashboard.
|
|
512
|
+
|
|
513
|
+
Fail-closed by construction: it only runs when the request carries no valid session cookie (a cookie
|
|
514
|
+
signed with another secret does not count), and every data route stays behind `TelescopeGuard`
|
|
515
|
+
regardless. A hook that throws, or returns without writing, logs one warning and serves the SPA
|
|
516
|
+
rather than hanging the request or turning a navigation into a `500`.
|
|
517
|
+
|
|
518
|
+
The UI shell route became non-passthrough `@Res()` so the host can own the response; its
|
|
519
|
+
`Content-Type`/`Cache-Control` moved from decorators into a new `sendHtml` helper, unchanged. Core
|
|
520
|
+
additionally exports `sendHtml` / `responseAlreadyWritten`.
|
|
521
|
+
|
|
522
|
+
Fully backward compatible — omit the option and the shell is served exactly as before, with no
|
|
523
|
+
session check on that route at all.
|
|
524
|
+
|
|
525
|
+
## 1.16.1
|
|
526
|
+
|
|
527
|
+
### Patch Changes
|
|
528
|
+
|
|
529
|
+
- [`c07d42a`](https://github.com/DavideCarvalho/nestjs-telescope/commit/c07d42a756e77b54ec92db4249ec060d9556e21c) - Docs + regression tests confirming `dashboardAuth`'s `login` hook already receives the submitted password verbatim end-to-end — including an empty string, since the built-in login screen never marks the field `required` and the auth controller only checks it's a string, not a non-empty one. No code path was blocking empty passwords; this closes the gap for hosts whose `login` hook gates on username alone (e.g. email must be an active admin) and deliberately ignores the password. Documented the pass-through in the `dashboardAuth` reference and added tests asserting: the hook is called with `''`, a hook rejecting an empty password still uniform-fails with `401`, and a hook accepting one mints the session.
|
|
530
|
+
|
|
531
|
+
## 1.16.0
|
|
532
|
+
|
|
533
|
+
### Minor Changes
|
|
534
|
+
|
|
535
|
+
- [`46f6bd4`](https://github.com/DavideCarvalho/nestjs-telescope/commit/46f6bd491c962f694ed41066f47da4da29671c3f) - First-class `guards` (+ `imports`) options for the Telescope console, mirroring `@dudousxd/nestjs-agent`'s dashboard module: `TelescopeModule.forRoot`/`forRootAsync` and `TelescopeUiModule.forRoot`/`forRootAsync` now accept `guards: Array<Type<CanActivate> | CanActivate>` fronting the console's controllers, plus `imports` resolving a class guard's own dependencies.
|
|
536
|
+
|
|
537
|
+
This closes the auth seam for hosts with header-only auth: a full-page navigation to the dashboard carries no `Authorization` header, so there was previously no way to hang a cookie/session guard on the page itself. Pass the SAME `guards` (and `imports`) to both modules — they're independent options in separate packages. On core, `guards` **appends** to (never replaces) the existing `TelescopeGuard` gate (`authorizer` / `dashboardAuth` / dev-open-prod-closed default); on `-ui`, `TelescopeUiController` had no guard of its own, so it's a plain replace. See the new "Securing the console with your own guards" docs section.
|
|
538
|
+
|
|
539
|
+
## 1.15.0
|
|
540
|
+
|
|
541
|
+
### Minor Changes
|
|
542
|
+
|
|
543
|
+
- [`dbaf8d2`](https://github.com/DavideCarvalho/nestjs-telescope/commit/dbaf8d2c00c08bc03c8df874cabc0c48741d712f) - Ext-dashboard tables paginate: a table panel may declare `paged: true` — the renderer adds
|
|
544
|
+
prev/next + "Page X of Y" and re-resolves the provider with `query.page`/`query.limit`, expecting
|
|
545
|
+
`{ rows, total, page, limit }`. Non-paged tables are byte-identical. `LinkSpec` documents the two
|
|
546
|
+
href conventions (in-app hash routes — including the trace view at `#/traces/{traceId}` — vs host
|
|
547
|
+
console paths); hash hrefs already navigate in-app.
|
|
548
|
+
|
|
549
|
+
## 1.14.0
|
|
550
|
+
|
|
551
|
+
### Minor Changes
|
|
552
|
+
|
|
553
|
+
- [#33](https://github.com/DavideCarvalho/nestjs-telescope/pull/33) [`996c9d4`](https://github.com/DavideCarvalho/nestjs-telescope/commit/996c9d442eb16f581acf67aca9ead84ce3bbc6c1) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Make cache observability cache-agnostic and richer. `CacheContent` keeps its
|
|
554
|
+
universal core (`operation`/`key`/`hit`) and gains optional, vendor-neutral
|
|
555
|
+
dimensions any cache can map onto: `store`, `tier` (e.g. l1/l2), `stale`
|
|
556
|
+
(stale-while-revalidate / BentoCache grace), `ttlMs`, and a `metadata` escape
|
|
557
|
+
hatch. `operation` widens to include `delete`/`clear`. The cache watcher's
|
|
558
|
+
`{ instrument }` event carries these through (and surfaces store/tier/stale as
|
|
559
|
+
tags), and the auto-patch path now records the set TTL and wraps `del`/`delete`
|
|
560
|
+
so deletes are their own operation instead of being invisible or mislabelled.
|
|
561
|
+
The stats endpoint splits hits/misses by tier and counts stale hits + deletes,
|
|
562
|
+
and the Cache insights view renders per-tier hits, stale hits and delete counts;
|
|
563
|
+
the cache badge labels DEL/CLEAR and flags stale (amber) + tier. Simple caches
|
|
564
|
+
that don't supply the optional fields are unchanged.
|
|
565
|
+
|
|
566
|
+
## 1.13.0
|
|
567
|
+
|
|
568
|
+
### Minor Changes
|
|
569
|
+
|
|
570
|
+
- [#31](https://github.com/DavideCarvalho/nestjs-telescope/pull/31) [`53c944f`](https://github.com/DavideCarvalho/nestjs-telescope/commit/53c944f8dd66540813c1ea45fa751b192a0946b3) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Cross-link entries and harden extension empty states. The entry detail view gains
|
|
571
|
+
a "Related" panel — jump to every entry of the same family, to the originating
|
|
572
|
+
request a non-request entry was recorded under, or to the queue console for a job.
|
|
573
|
+
Extension dashboard `table` and `topN` panels now render an explicit "No data in
|
|
574
|
+
this window" state instead of a blank/broken-looking panel.
|
|
575
|
+
|
|
576
|
+
- [#31](https://github.com/DavideCarvalho/nestjs-telescope/pull/31) [`6e66ec3`](https://github.com/DavideCarvalho/nestjs-telescope/commit/6e66ec355487c488c8290a13acb99b619895f28d) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Add Prunes and Exports screens. The pruner now records every prune run (trigger,
|
|
577
|
+
duration, total deleted and real per-type deletions) in a bounded in-memory ring
|
|
578
|
+
exposed at `GET /prunes` alongside the resolved retention config and the predicted
|
|
579
|
+
next run; a new Prunes page surfaces that activity with per-type chips and a gated
|
|
580
|
+
"Prune now". A new Exports page exports filtered entries (by type / window /
|
|
581
|
+
search) to JSON or CSV entirely client-side, with a session export history and a
|
|
582
|
+
dependency-free CSV serializer.
|
|
583
|
+
|
|
584
|
+
- [#31](https://github.com/DavideCarvalho/nestjs-telescope/pull/31) [`bdc2198`](https://github.com/DavideCarvalho/nestjs-telescope/commit/bdc21987bc90eae6fc95995c99d3de46f0f4fc89) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Surface whether a scheduled cron is currently active. `ScheduledTask` gains a
|
|
585
|
+
`running: boolean | null` field; the `@nestjs/schedule` watcher reads the
|
|
586
|
+
`CronJob.running` flag (null for intervals/timeouts, which expose no state), and
|
|
587
|
+
the Schedules console renders an Active/Stopped badge plus an active/stopped
|
|
588
|
+
summary so a registered-but-stopped cron is obvious at a glance.
|
|
589
|
+
|
|
590
|
+
## 1.12.1
|
|
591
|
+
|
|
592
|
+
### Patch Changes
|
|
593
|
+
|
|
594
|
+
- [#29](https://github.com/DavideCarvalho/nestjs-telescope/pull/29) [`a79c3fa`](https://github.com/DavideCarvalho/nestjs-telescope/commit/a79c3fa6f77c8d02a4150325f082d66d9fdc9227) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Ship TanStack Intent agent skills (SKILL.md) inside the package.
|
|
595
|
+
|
|
596
|
+
## 1.12.0
|
|
597
|
+
|
|
598
|
+
### Minor Changes
|
|
599
|
+
|
|
600
|
+
- [`74a6563`](https://github.com/DavideCarvalho/nestjs-telescope/commit/74a6563557521edec413b0691a011f9568e140cc) - Surface the Inertia v3 render metadata in the entry detail UI: new **Prepend** and **Rescued** prop rows, a **Once cache** section (cache key → prop, with expiry), a **Scroll** section showing the infinite-scroll cursor (`prev ← current → next`, reset), and **except-once** chips on the partial-reload panel. All fields are read defensively, so older diagnostic payloads still render.
|
|
601
|
+
|
|
602
|
+
## 1.11.0
|
|
603
|
+
|
|
604
|
+
### Minor Changes
|
|
605
|
+
|
|
606
|
+
- [#17](https://github.com/DavideCarvalho/nestjs-telescope/pull/17) [`76228a3`](https://github.com/DavideCarvalho/nestjs-telescope/commit/76228a3a33e4e6d649cd8343646472feff97ed16) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - On-demand CPU flamegraph profiling. A new strictly-opt-in `profiling` option
|
|
607
|
+
(OFF by default) captures V8 CPU profiles around sampled or manually-triggered
|
|
608
|
+
requests via Node's `inspector`, aggregates them into a self/total frame tree,
|
|
609
|
+
and persists them as `cpu_profile` entries correlated to their request batch.
|
|
610
|
+
The dashboard gains a Profiles tab with a dependency-light flamegraph renderer,
|
|
611
|
+
a hot-functions table, and an "arm next N requests" trigger. New headless API
|
|
612
|
+
routes: `GET /profiles`, `GET /profiles/:id`, `GET /profiles/status`, and
|
|
613
|
+
`POST /profiles/arm` (gated by the default-deny mutation guard). When profiling
|
|
614
|
+
is disabled there is ZERO inspector usage and no request-path cost beyond a
|
|
615
|
+
single boolean check.
|
|
616
|
+
|
|
617
|
+
- [#17](https://github.com/DavideCarvalho/nestjs-telescope/pull/17) [`76228a3`](https://github.com/DavideCarvalho/nestjs-telescope/commit/76228a3a33e4e6d649cd8343646472feff97ed16) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Ecosystem improvements across the telescope packages.
|
|
618
|
+
|
|
619
|
+
- **Nested trace / batch waterfall view.** Traces and batches now render as a
|
|
620
|
+
nested waterfall, showing child spans nested under their parents with relative
|
|
621
|
+
offsets and durations so the critical path of a request is visible at a glance.
|
|
622
|
+
- **Pulse-style outlier & rollup cards.** New overview cards surface the slowest
|
|
623
|
+
endpoints, slowest queries, slowest jobs, and slowest outbound calls, plus
|
|
624
|
+
load-by-user and CPU/memory history, in the spirit of Laravel Pulse rollups.
|
|
625
|
+
- **Metric-threshold alert rules.** Alerts can now fire on metric thresholds
|
|
626
|
+
(p95 / p99 latency, cache-hit ratio) in addition to existing rules, with
|
|
627
|
+
shared-storage exception deduplication so the same exception is not alerted
|
|
628
|
+
multiple times across replicas.
|
|
629
|
+
- **Improved N+1 detection.** Detection now recognizes the 1+N loop pattern and
|
|
630
|
+
is duration-weighted, reducing false positives and prioritizing the queries
|
|
631
|
+
that actually cost time.
|
|
632
|
+
- **On-demand CPU flamegraph profiling.** A strictly-opt-in `profiling` option
|
|
633
|
+
(OFF by default) captures V8 CPU profiles via Node's `inspector`, aggregates
|
|
634
|
+
them into a self/total frame tree, and persists them as `cpu_profile` entries
|
|
635
|
+
correlated to their request batch. The dashboard gains a Profiles tab with a
|
|
636
|
+
dependency-light flamegraph renderer, a hot-functions table, and an
|
|
637
|
+
"arm next N requests" trigger. When profiling is disabled there is zero
|
|
638
|
+
inspector usage and no request-path cost beyond a single boolean check.
|
|
639
|
+
- **`TelescopeUiModule.forRootAsync`.** The UI module now mirrors
|
|
640
|
+
`TelescopeModule.forRootAsync`, resolving dashboard options via DI.
|
|
641
|
+
- **Realtime dashboards / SSE live-tail.** Dashboards update in realtime over an
|
|
642
|
+
`@Sse` invalidation stream (falling back to polling) with a LIVE indicator.
|
|
643
|
+
- **Packaging hygiene.** `sideEffects` is now declared on each publishable
|
|
644
|
+
package to enable safe tree-shaking for downstream bundlers.
|
|
645
|
+
- **Independent versioning.** The changeset `fixed` group was removed so packages
|
|
646
|
+
version independently going forward.
|
|
647
|
+
|
|
648
|
+
- [#17](https://github.com/DavideCarvalho/nestjs-telescope/pull/17) [`76228a3`](https://github.com/DavideCarvalho/nestjs-telescope/commit/76228a3a33e4e6d649cd8343646472feff97ed16) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Packaging hygiene + `TelescopeUiModule.forRootAsync`.
|
|
649
|
+
|
|
650
|
+
- `TelescopeUiModule` now exposes `forRootAsync({ imports, inject, useFactory, path })`, mirroring `TelescopeModule.forRootAsync`: dashboard options (`assetsDir`) are resolved via DI. As with the core module, the mount `path` is bound at module-build time and is passed statically on the config object (the static value also drives the serve-time asset-base rewrite, so it always matches the route).
|
|
651
|
+
- Added `"sideEffects"` to each publishable package to enable safe tree-shaking for downstream bundlers:
|
|
652
|
+
- `false` on the pure watcher / helper / provider packages (ai, bullmq, cache, events, logs, mail, mikro-orm, mikro-orm-watcher, otel, prisma, redis, redis-watcher, sqs, typeorm, testing) — their entrypoints only re-export classes/types with no module-load side effects.
|
|
653
|
+
- `["./dist/schedule.watcher.js"]` on schedule, which carries a load-bearing bare `import 'reflect-metadata'`.
|
|
654
|
+
- `["./dist/server/*.js", "**/*.css"]` on ui, whose server module/controller emit decorator metadata at load and whose bundled SPA ships CSS.
|
|
655
|
+
- core is left unmarked (treated as side-effecting) because its decorator metadata emit spans many directories.
|
|
656
|
+
|
|
657
|
+
## 1.10.0
|
|
658
|
+
|
|
659
|
+
## 1.9.1
|
|
660
|
+
|
|
661
|
+
## 1.9.0
|
|
662
|
+
|
|
663
|
+
## 1.8.0
|
|
664
|
+
|
|
665
|
+
## 1.7.1
|
|
666
|
+
|
|
667
|
+
### Patch Changes
|
|
668
|
+
|
|
669
|
+
- [`895ebf2`](https://github.com/DavideCarvalho/nestjs-telescope/commit/895ebf2adb0342a3c648f5c22b27df94328a08da) Thanks [@DavideCarvalho](https://github.com/DavideCarvalho)! - Add a **Workflows** nav tab for durable-workflow entries. The dashboard now knows the `durable`
|
|
670
|
+
entry type (recorded by `@dudousxd/nestjs-durable-telescope`'s watcher), so when a host registers
|
|
671
|
+
that watcher the sidebar shows a "Workflows" tab listing every workflow run/step lifecycle event,
|
|
672
|
+
tagged by `workflow:<name>` / `kind:<local|remote|sleep|signal>`. Without the watcher registered the
|
|
673
|
+
tab stays hidden, like every other watcher-driven nav item.
|
|
674
|
+
|
|
675
|
+
## 1.7.0
|
|
676
|
+
|
|
677
|
+
### Minor Changes
|
|
678
|
+
|
|
679
|
+
- [`4a610c3`](https://github.com/DavideCarvalho/nestjs-telescope/commit/4a610c3a3b71d1daa4180da0e92a88a2d7b10472) - Add the Inertia debug panel. The dashboard now renders a rich detail view for
|
|
680
|
+
`inertia` entries (`InertiaBody`): rendered component header with status/partial
|
|
681
|
+
badges, a red version-mismatch (409) callout, the partial-reload Kept/Excluded
|
|
682
|
+
columns, prop classification chips (shared/final/optional/once/merge/deep-merge
|
|
683
|
+
with `matchPropsOn` annotations), deferred groups, the resolved-props tree
|
|
684
|
+
(showing the Recorder's redaction/truncation markers verbatim), history flags and
|
|
685
|
+
page size. Adds `InertiaBadge` (409 / partial / deferred / size chips), an
|
|
686
|
+
`inertia` list summary, and an `Inertia` nav tab that self-hides until the
|
|
687
|
+
`InertiaWatcher` is installed.
|
|
688
|
+
|
|
689
|
+
### Patch Changes
|
|
690
|
+
|
|
691
|
+
- [`10c76f1`](https://github.com/DavideCarvalho/nestjs-telescope/commit/10c76f1c0d9c1034e5bffca2d9775cd16e553200) - Inertia panel polish: log on record failure (was silently swallowed) and warn once on
|
|
692
|
+
an unsupported diagnostic version; collapse `InertiaContent` to
|
|
693
|
+
`Omit<InertiaRenderDiagnostic, …>` with a destructure-rest copy; make the
|
|
694
|
+
`isInertiaDiagnostic` guard honest about what it proves; render the Inertia badge in
|
|
695
|
+
the entries table (parity with the cache badge); data-drive the props rows. Adds a
|
|
696
|
+
committed cross-repo wire-contract fixture (`inertia-render.v1.json`) so producer
|
|
697
|
+
drift fails a test.
|
|
698
|
+
|
|
699
|
+
## 1.6.0
|
|
700
|
+
|
|
701
|
+
## 1.5.0
|
|
702
|
+
|
|
703
|
+
### Minor Changes
|
|
704
|
+
|
|
705
|
+
- [`9e1f318`](https://github.com/DavideCarvalho/nestjs-telescope/commit/9e1f318ba876f3aaf066168b6f8feaa8e20ea5c6) - Fix Slack "Open in Telescope" deep links, and surface cached AI diagnoses on the exception detail page.
|
|
706
|
+
|
|
707
|
+
**Slack deep link landed on an empty page.** The "Open in Telescope" button built `<dashboard>#/entries/<type>/<id>`, but `#/entries/<type>` matches the SPA's type-scoped **list** route (`#/entries/:type`) — so the trailing id was ignored and the recipient saw an empty filtered list instead of the entry. The link now points at the real entry-**detail** route, `#/entries/view/:id`, which renders the same `EntryPage` for both `exception` and `client_exception` entries.
|
|
708
|
+
|
|
709
|
+
**Auto-mode diagnosis was invisible on the detail page.** In `auto` mode the AI diagnosis is computed and cached per family at first-seen (and may already have been sent to Slack), yet the exception detail page still showed a bare **Diagnose with AI** button as if nothing existed. Now:
|
|
710
|
+
|
|
711
|
+
- **Core** adds a read-only `GET <telescope>/api/exceptions/:id/diagnosis` behind the same dashboard read guard as the POST. It serves `{ markdown, cached: true }` from the per-family cache when present and `204 No Content` when absent. It is strictly side-effect-free — it **never** builds context or calls the diagnoser, so a read costs no model tokens.
|
|
712
|
+
- **UI** `DiagnosePanel` fetches that GET on mount (only when `meta.ai.enabled`). A cached diagnosis renders immediately with the **cached** badge and a **Re-run** (force) action; the **Diagnose with AI** button only appears for families that have not been diagnosed yet. The mount fetch shows a subtle "checking" line rather than flashing the button and then swapping it.
|
|
713
|
+
|
|
714
|
+
## 1.4.0
|
|
715
|
+
|
|
716
|
+
### Minor Changes
|
|
717
|
+
|
|
718
|
+
- [`7878ccc`](https://github.com/DavideCarvalho/nestjs-telescope/commit/7878ccc8ca912fd5fc4102c22a5b1c26331443d7) - AI-powered exception diagnosis.
|
|
719
|
+
|
|
720
|
+
New package **`@dudousxd/nestjs-telescope-ai`**: `createAiSdkDiagnoser({ model })` implements core's `ExceptionDiagnoser` SPI using the Vercel AI SDK (`ai` is a peer dependency; the model is provider-agnostic — Bedrock / OpenAI / Anthropic / any AI-SDK `LanguageModel`). It turns a captured exception (class, message, stack), its sibling request (route/method/status/duration), and the request's recent **redacted** SQL into a markdown triage report — probable cause, where to look, a suggested fix, and a confidence rating — bounded by `maxOutputTokens` (default 1024) and a hard 30s timeout.
|
|
721
|
+
|
|
722
|
+
Core gains an `ai` option (`{ diagnoser, mode? }`, shape defined in core so core stays AI-SDK-free):
|
|
723
|
+
|
|
724
|
+
- **On-demand** (default): `POST <telescope>/api/exceptions/:id/diagnose` (behind the normal dashboard read guard) returns `{ markdown, cached }`. Results are cached per error family (bounded, 24h TTL); `?force=true` bypasses. 404 when AI is off or the entry isn't an exception; 502 (safe message) when the diagnoser fails.
|
|
725
|
+
- **Auto** (`mode: 'auto'`): the first time a new exception family is seen, Telescope runs a fire-and-forget diagnosis on the flush path (never blocking capture) and caches it; a firing `new-exception` alert briefly awaits it and attaches it (Slack renders a "Probable cause (AI)" section). `meta.ai` advertises `{ enabled, mode }`.
|
|
726
|
+
|
|
727
|
+
The UI adds a **Diagnose with AI** button on exception / client_exception detail pages (visible when `meta.ai.enabled`), rendering the markdown with loading + error states and a **cached** badge with a re-run (force) action.
|
|
728
|
+
|
|
729
|
+
- [`bc3a0df`](https://github.com/DavideCarvalho/nestjs-telescope/commit/bc3a0df784f31a82753725d9c5e86d75380fee13) - Client error ingestion — Telescope as the frontend error reporter.
|
|
730
|
+
|
|
731
|
+
A new **public** endpoint, `POST <telescope>/api/client-errors`, lets browsers report errors directly to Telescope instead of a hand-rolled reporter. Reports are recorded as `client_exception` entries through the normal pipeline, so they compose with everything: the `new-exception` alert, per-type prune/archive, and the dashboard.
|
|
732
|
+
|
|
733
|
+
- **Opt-in & ungated.** Configure via `clientErrors: { enabled, maxBodyBytes?, rateLimit?, authorize? }`. Disabled by default (a public surface is opt-in) — while off the endpoint returns 404. It carries no dashboard guard (ordinary users' browsers hit it).
|
|
734
|
+
- **Untrusted-body validation.** Dependency-free structural validation: `message` required, every other field optional with type checks + length caps (message ≤ 2 KB, stack/componentStack ≤ 16 KB, url/userAgent ≤ 2 KB). Invalid → 400 with no echo of the payload. Over the byte cap → 413.
|
|
735
|
+
- **Per-IP rate limit.** A bounded in-memory token bucket (default 60/min, ~10k IPs with oldest-IP eviction). Over the limit → 429. Per-pod best-effort (the effective limit is `perMinute × pods` in a multi-replica deployment).
|
|
736
|
+
- **`authorize` hook.** Runs first; `false` → 403 (a throw is a fail-closed denial). Lets hosts validate a session cookie/header.
|
|
737
|
+
- **Composes.** Records `type: client_exception` with a family hash from name + message + top stack frame (the server exception interceptor now uses the same scheme, so both sources group identically), the `failed` / `client` / `user:<id>` tags, and the captured client IP. The `new-exception` rule now fires for `client_exception` too, using the browser URL and user-agent in place of a server route.
|
|
738
|
+
- **Dashboard.** A new watcher-driven **Client errors** tab (shown only when `clientErrors` is enabled) with a detail view rendering message, stack, component stack, URL, and user-agent.
|
|
739
|
+
|
|
740
|
+
See the new recipe: _Reporting frontend errors_.
|
|
741
|
+
|
|
742
|
+
## 1.3.0
|
|
743
|
+
|
|
744
|
+
### Minor Changes
|
|
745
|
+
|
|
746
|
+
- [`7773e0a`](https://github.com/DavideCarvalho/nestjs-telescope/commit/7773e0ad120d2678a07e9eebc4631a19c5c8e381) - Hide the Traces page from the dashboard nav when the host has no `traceContext`.
|
|
747
|
+
|
|
748
|
+
Entries only get a `trace_id` when the host wires a `traceContext` provider, so an app without one had a permanently empty Traces page sitting as a dead nav item. The dashboard now hides that link — mirroring the watcher-driven nav, which already hides entry types whose watcher isn't registered.
|
|
749
|
+
|
|
750
|
+
- Core: `GET /api/meta` now returns `tracesEnabled: boolean` (whether a `traceContext` provider was configured).
|
|
751
|
+
- UI: the **Traces** nav item is hidden when `meta.tracesEnabled === false`. Undefined meta (loading, or an older server predating the field) still shows it — no flash-of-hidden-nav and backward-compatible. The `#/traces` route is untouched, so a direct visit still resolves.
|
|
752
|
+
|
|
753
|
+
- [`8f9b65e`](https://github.com/DavideCarvalho/nestjs-telescope/commit/8f9b65e1b2ec1df664bc173cc76072c6fffdbc59) - Pulse "Slow request hotspots" now require a real slowness threshold.
|
|
754
|
+
|
|
755
|
+
Previously the slow-route (and slow-outgoing-HTTP) hotspots were a pure top-N p99 ranking with no floor, so a quiet host surfaced fast routes like `/health` at 18ms as "hotspots" — a false alarm. A route now only counts as a hotspot when its **p99 ≥ `slowRouteMs`** (default `1000`ms, matching the `slow` request-tag threshold and the `HttpClientWatcher` `slowMs` default).
|
|
756
|
+
|
|
757
|
+
- Configure via `pulse.slowRouteMs` on `TelescopeModule.forRoot({ pulse: { slowRouteMs } })`.
|
|
758
|
+
- The Overview "Slow requests" stat is now labeled **Slow routes** and means "routes over the slow p99 threshold".
|
|
759
|
+
- The Pulse panel shows a friendly empty state ("No routes over the slow threshold") when nothing qualifies.
|
|
760
|
+
- The "Slowest" entries ranking and N+1 hotspots are unchanged — only slow-ROUTE hotspots gained the threshold.
|
|
761
|
+
|
|
762
|
+
## 1.2.1
|
|
763
|
+
|
|
764
|
+
## 1.2.0
|
|
765
|
+
|
|
766
|
+
### Minor Changes
|
|
767
|
+
|
|
768
|
+
- [`0ba0c24`](https://github.com/DavideCarvalho/nestjs-telescope/commit/0ba0c24ac68c34ad75fe51775dc7089e308c3126) - Three dashboard improvements:
|
|
769
|
+
|
|
770
|
+
- **Criticality-first Overview.** The Overview is reorganized so operational triage sits above the fold: a focused stat row (Requests, **Error rate** = exceptions ÷ requests over the window — red above 5%, Failed jobs, and **Slow requests** = routes over their p99 budget), then Recent failures, a newly-mounted **N+1 query hotspots** card, Slowest, and a **Queues needing attention** card that lists only queues with failed jobs or a large pending backlog (and says "All queues healthy" when clean). Trends and Telescope self-health (throughput, by-type, server, health, retention) move below. All figures derive from data already served by `/pulse` and `/queues` — no new endpoints.
|
|
771
|
+
- **Watcher-driven navigation.** The sidebar Watchers list renders only types whose watcher is registered (from `meta.watchers`); `request` and `exception` always show, direct URLs to hidden types still work, and everything shows while `meta` is loading (no flash of hidden nav).
|
|
772
|
+
- **Dedicated User filter.** The entries filter bar gains a User combobox over the `user:` tag namespace (bare ids + counts); selecting one applies the `tag=user:<id>` filter but renders as a `User: <id>` chip, and a `user:` tag arriving via `?tag=` (the entries-table pivot links) is recognized and shown in the User control instead of the generic tag chip.
|
|
773
|
+
|
|
774
|
+
## 1.1.0
|
|
775
|
+
|
|
5
776
|
### Minor Changes
|
|
6
777
|
|
|
7
778
|
- [`8d91d59`](https://github.com/DavideCarvalho/nestjs-telescope/commit/8d91d59563d731e9125bef65a38651c96ec06e0b) - Gate the dashboard SPA behind `dashboardAuth` when the host enables it.
|