@bakery-framework/plugin-dashboard 2.0.0-alpha.14 → 2.0.0-alpha.15
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/package.json +4 -4
- package/src/client/parts/logs.ts +9 -2
- package/src/endpoints/logs-socket.ts +72 -0
- package/src/setup.ts +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bakery-framework/plugin-dashboard",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.15",
|
|
4
4
|
"description": "Bakery dashboard plugin.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bakery",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"!src/tests"
|
|
34
34
|
],
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@bakery-framework/core": "^2.0.0-alpha.
|
|
37
|
-
"@bakery-framework/plugin-analytics": "^2.0.0-alpha.
|
|
36
|
+
"@bakery-framework/core": "^2.0.0-alpha.15",
|
|
37
|
+
"@bakery-framework/plugin-analytics": "^2.0.0-alpha.15"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
|
-
"@bakery-framework/orm": "^2.0.0-alpha.
|
|
40
|
+
"@bakery-framework/orm": "^2.0.0-alpha.15"
|
|
41
41
|
},
|
|
42
42
|
"engines": {
|
|
43
43
|
"bun": ">=1.4.0"
|
package/src/client/parts/logs.ts
CHANGED
|
@@ -77,12 +77,19 @@ export function initLogsWebSocket() {
|
|
|
77
77
|
'<div style="color: var(--text-muted);">Connecting to server log stream...</div>'
|
|
78
78
|
|
|
79
79
|
try {
|
|
80
|
-
|
|
80
|
+
// `/_dashboard/logs`, not `/_livereload`. The live-reload socket is
|
|
81
|
+
// registered only under `DEV`, so this panel answered 400 on every
|
|
82
|
+
// production server and sat on "Connecting..." for ever. The console has
|
|
83
|
+
// its own socket now, behind the console's own door.
|
|
84
|
+
logsWs = new WebSocket(getWebSocketUrl('/_dashboard/logs'))
|
|
81
85
|
|
|
82
86
|
logsWs.onopen = () => {
|
|
83
87
|
consoleEl.innerHTML =
|
|
84
88
|
'<div style="color: var(--ok); display: flex; align-items: center; gap: 0.25rem;"><span>Connected to logs pipeline. Listening for events...</span></div>'
|
|
85
|
-
|
|
89
|
+
// No `subscribe_logger` frame: membership is the handler's `open`, so
|
|
90
|
+
// there is nothing to ask for. That message was `LiveReloadHandler`'s
|
|
91
|
+
// protocol, and it is what an app page still sends to forward its own
|
|
92
|
+
// console in development.
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
logsWs.onmessage = event => {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { WebSocketHandler } from '@bakery-framework/core/handlers'
|
|
2
|
+
import { connectedLoggers } from '@bakery-framework/core/logger'
|
|
3
|
+
import { isAnalyticsAuthorized } from '@bakery-framework/plugin-analytics/stats'
|
|
4
|
+
import type { ServerWebSocket } from 'bun'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The console's log stream.
|
|
8
|
+
*
|
|
9
|
+
* **The Logs panel was dead in production**, and only in production. Its client
|
|
10
|
+
* connected to `/_livereload`, which `LiveReloadHandler` serves — and that
|
|
11
|
+
* handler is registered only under `DEV` and refuses in `canHandle` besides.
|
|
12
|
+
* So a production server answered 400 on the upgrade, nothing ever joined
|
|
13
|
+
* `connectedLoggers`, and the panel sat on "Connecting to server log
|
|
14
|
+
* stream..." for the life of the process. Measured against `bun run serve`
|
|
15
|
+
* before this existed: `/_livereload` → 400, console → 200.
|
|
16
|
+
*
|
|
17
|
+
* Same shape as the bundle ETag bug and the timescale import before it: a dev
|
|
18
|
+
* server takes a different branch, so the thing works on the machine where it
|
|
19
|
+
* is written and nowhere else.
|
|
20
|
+
*
|
|
21
|
+
* **Not fixed by registering `LiveReloadHandler` in production.** That socket
|
|
22
|
+
* is the *watcher's*: it publishes `force_reload` to every subscriber and
|
|
23
|
+
* echoes `client_log` frames between browsers. Shipping it to production would
|
|
24
|
+
* be adding a surface, not repairing one. The console owns its own panel, so
|
|
25
|
+
* it owns its own socket, which is the same split analytics already has with
|
|
26
|
+
* `/_analytics_ws`.
|
|
27
|
+
*
|
|
28
|
+
* Membership is the only thing this does. Core owns the registry
|
|
29
|
+
* (`logger/clients.ts`) and the dashboard's `setLogCallback` does the
|
|
30
|
+
* broadcasting; in development `LiveReloadHandler` adds app pages to the same
|
|
31
|
+
* Set when they forward their console, which is why those lines show up here
|
|
32
|
+
* too.
|
|
33
|
+
*/
|
|
34
|
+
export class DashboardLogsHandler extends WebSocketHandler {
|
|
35
|
+
static override readonly namespace = '/_dashboard'
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* **The door is checked here because there is nowhere later.**
|
|
39
|
+
*
|
|
40
|
+
* `router.ts` attempts the upgrade before `onRoute`, before `onRequest` and
|
|
41
|
+
* before any fetch handler resolves, so a plugin hook cannot gate a socket.
|
|
42
|
+
* `AnalyticsWSHandler` carries the same note for the same reason.
|
|
43
|
+
*
|
|
44
|
+
* It is the console's own door: `isAnalyticsAuthorized` is what guards
|
|
45
|
+
* `/_dashboard` itself, so a stream of every server log line is admitted by
|
|
46
|
+
* exactly what admits the page that renders it. Anything weaker would hand
|
|
47
|
+
* out log lines to someone who cannot open the console.
|
|
48
|
+
*
|
|
49
|
+
* Async because `authorize` may be a predicate the application supplies; the
|
|
50
|
+
* registry awaits a promise-returning `canHandle`.
|
|
51
|
+
*
|
|
52
|
+
* The path sits inside `/_dashboard`, which `DashboardHandler` claims for
|
|
53
|
+
* *fetch* at priority 120. That is not a collision: the upgrade is dispatched
|
|
54
|
+
* from a separate registry and runs first, so the fetch handler never sees
|
|
55
|
+
* this request.
|
|
56
|
+
*/
|
|
57
|
+
static override async canHandle(
|
|
58
|
+
path: string,
|
|
59
|
+
req?: Request,
|
|
60
|
+
): Promise<boolean> {
|
|
61
|
+
if (path !== '/_dashboard/logs') return false
|
|
62
|
+
return req ? await isAnalyticsAuthorized(req) : false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
static override open(ws: ServerWebSocket<any>) {
|
|
66
|
+
connectedLoggers.add(ws)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static override close(ws: ServerWebSocket<any>) {
|
|
70
|
+
connectedLoggers.delete(ws)
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/setup.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
handleGetSessions,
|
|
32
32
|
handleUpdateSession,
|
|
33
33
|
} from './endpoints/sessions'
|
|
34
|
+
import { DashboardLogsHandler } from './endpoints/logs-socket'
|
|
34
35
|
import { pluginPath } from './paths'
|
|
35
36
|
import renderDashboardShell from './shell'
|
|
36
37
|
|
|
@@ -129,6 +130,12 @@ export function setupDashboard(
|
|
|
129
130
|
// plugin's own directory — no bespoke asset route, no hand-rolled caching.
|
|
130
131
|
mountRoutes('/_dashboard', pluginPath('../public'))
|
|
131
132
|
|
|
133
|
+
// The console's log stream, and it is registered in every mode. The Logs
|
|
134
|
+
// panel used to ride on `/_livereload`, which exists only under `DEV` — so
|
|
135
|
+
// the panel worked on the machine it was written on and answered 400
|
|
136
|
+
// everywhere else. See `endpoints/logs-socket.ts`.
|
|
137
|
+
Bakery.handlers.websocket.set(DashboardLogsHandler)
|
|
138
|
+
|
|
132
139
|
Bakery.handlers.fetch.set(DashboardHandler, 120)
|
|
133
140
|
}
|
|
134
141
|
|