@quazardous/qdadm 2.17.0 → 2.17.2
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quazardous/qdadm",
|
|
3
|
-
"version": "2.17.
|
|
3
|
+
"version": "2.17.2",
|
|
4
4
|
"description": "Vue 3 framework for admin dashboards with PrimeVue",
|
|
5
5
|
"author": "quazardous",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"format": "prettier --write src/",
|
|
26
26
|
"build:types": "vue-tsc --declaration --emitDeclarationOnly --outDir dist/types",
|
|
27
27
|
"build:node": "tsc -p tsconfig.node.json",
|
|
28
|
-
"
|
|
28
|
+
"prepare": "npm run build:node"
|
|
29
29
|
},
|
|
30
30
|
"exports": {
|
|
31
31
|
".": "./src/index.ts",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"dist/node"
|
|
55
55
|
],
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@quazardous/qdcore": "^1.1.
|
|
57
|
+
"@quazardous/qdcore": "^1.1.2",
|
|
58
58
|
"@quazardous/qddebug": "^1.1.0",
|
|
59
59
|
"@quazardous/quarkernel": "^2.1.0",
|
|
60
60
|
"yaml": "^2.8.4"
|
|
@@ -15,6 +15,7 @@ import { StackHydrator } from '../chain/StackHydrator.js'
|
|
|
15
15
|
import { Orchestrator } from '../orchestrator/Orchestrator'
|
|
16
16
|
import type { EntityAuthAdapter } from '../entity/auth/EntityAuthAdapter'
|
|
17
17
|
import type { Kernel } from './Kernel'
|
|
18
|
+
import type { SSEConfig } from './Kernel.types'
|
|
18
19
|
// #1196 Phase B — this-typing against the real Kernel shape (was Self = any)
|
|
19
20
|
type Self = Kernel
|
|
20
21
|
|
|
@@ -217,12 +218,72 @@ export function applyRegistryMethods(KernelClass: { prototype: Kernel }): void {
|
|
|
217
218
|
/**
|
|
218
219
|
* Create SSEBridge for Server-Sent Events to SignalBus integration
|
|
219
220
|
*/
|
|
221
|
+
/**
|
|
222
|
+
* Warn about unrecognised `sse` keys (#1898 lot A).
|
|
223
|
+
*
|
|
224
|
+
* A consumer configured `sse.getToken` against a version that predated it.
|
|
225
|
+
* It was not rejected — it was ignored, and the bridge fell back to the
|
|
226
|
+
* session's DURABLE token, which then travelled in the query string of every
|
|
227
|
+
* `/events` request and into logs that outlive the session by months. No
|
|
228
|
+
* error, no warning, and a stream that worked perfectly.
|
|
229
|
+
*
|
|
230
|
+
* The warning therefore names what happens INSTEAD, not merely that the key
|
|
231
|
+
* was ignored: "ignored" reads as "no effect", not as "falls back to a more
|
|
232
|
+
* sensitive secret". That reading is what made the failure invisible.
|
|
233
|
+
*/
|
|
234
|
+
proto._validateSseConfig = function (this: Self, sse: SSEConfig): void {
|
|
235
|
+
const known = new Set([
|
|
236
|
+
'url',
|
|
237
|
+
'reconnectDelay',
|
|
238
|
+
'signalPrefix',
|
|
239
|
+
'autoConnect',
|
|
240
|
+
'withCredentials',
|
|
241
|
+
'tokenParam',
|
|
242
|
+
'events',
|
|
243
|
+
'entities',
|
|
244
|
+
'getToken',
|
|
245
|
+
'connectOnSignal',
|
|
246
|
+
'disconnectOnSignal',
|
|
247
|
+
])
|
|
248
|
+
|
|
249
|
+
const unknown = Object.keys(sse).filter((key) => !known.has(key))
|
|
250
|
+
if (!unknown.length) return
|
|
251
|
+
|
|
252
|
+
// What the app loses by having the key ignored, wherever we can say it.
|
|
253
|
+
const consequences: Record<string, string> = {
|
|
254
|
+
getToken:
|
|
255
|
+
'the session auth token will be sent in the stream URL instead — ' +
|
|
256
|
+
'and query strings reach access logs',
|
|
257
|
+
entities: 'no entity cache will be invalidated from the stream',
|
|
258
|
+
tokenParam: 'the token will be sent under the default name "token"',
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
for (const key of unknown) {
|
|
262
|
+
const near = [...known].find(
|
|
263
|
+
(k) => k.toLowerCase() === key.toLowerCase() || k.startsWith(key) || key.startsWith(k)
|
|
264
|
+
)
|
|
265
|
+
// Look the consequence up under the NEAREST KNOWN key: a typo like
|
|
266
|
+
// `getTokens` means `getToken` is absent, and it is that absence whose
|
|
267
|
+
// effect the reader needs to hear.
|
|
268
|
+
const consequence = consequences[key] ?? (near ? consequences[near] : undefined)
|
|
269
|
+
const because = consequence ? ` — ${consequence}` : ''
|
|
270
|
+
const suggestion = near ? ` Did you mean "${near}"?` : ''
|
|
271
|
+
console.warn(
|
|
272
|
+
`[Kernel] sse.${key} is not a recognised option and is IGNORED${because}.` +
|
|
273
|
+
`${suggestion} This usually means the installed qdadm predates the option ` +
|
|
274
|
+
`— check the version before assuming the key has no effect.`
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
220
279
|
proto._createSSEBridge = function (this: Self): void {
|
|
221
280
|
const { sse, authAdapter } = this.options
|
|
222
281
|
if (!sse?.url) return
|
|
223
282
|
|
|
224
283
|
const debug = this.options.debug ?? false
|
|
225
284
|
|
|
285
|
+
this._validateSseConfig(sse)
|
|
286
|
+
|
|
226
287
|
// An explicit sse.getToken wins — including an explicit null, which means
|
|
227
288
|
// "send no token" and must not fall back to the auth adapter.
|
|
228
289
|
const getToken =
|
|
@@ -259,6 +320,29 @@ export function applyRegistryMethods(KernelClass: { prototype: Kernel }): void {
|
|
|
259
320
|
})
|
|
260
321
|
}
|
|
261
322
|
|
|
323
|
+
// A restored session must connect the stream too (#1898 lot C).
|
|
324
|
+
//
|
|
325
|
+
// The bridge waits for `auth:login`, which is emitted by the LOGIN PAGE —
|
|
326
|
+
// by the interface, not by the authentication state. So reloading a page
|
|
327
|
+
// with a valid session, or revalidating one without going through our
|
|
328
|
+
// login form, left the stream permanently disconnected.
|
|
329
|
+
//
|
|
330
|
+
// Deliberately NOT fixed by emitting `auth:login` at boot: the kernel
|
|
331
|
+
// listens to it in _setupAuthInvalidation and remounts the whole app, so
|
|
332
|
+
// announcing a restored session that way would remount on every reload.
|
|
333
|
+
// Connecting the bridge directly says the same thing without the blast
|
|
334
|
+
// radius.
|
|
335
|
+
// `in`, not `??`: an EXPLICIT null means "I drive the connection myself",
|
|
336
|
+
// and `??` would treat it as absent and override the opt-out.
|
|
337
|
+
const connectsOnSignal =
|
|
338
|
+
('connectOnSignal' in sse ? sse.connectOnSignal : 'auth:login') !== null
|
|
339
|
+
if (!sse.autoConnect && connectsOnSignal && authAdapter?.isAuthenticated?.()) {
|
|
340
|
+
if (debug) {
|
|
341
|
+
console.debug('[Kernel] session already authenticated → connecting SSE')
|
|
342
|
+
}
|
|
343
|
+
void this.sseBridge.connect()
|
|
344
|
+
}
|
|
345
|
+
|
|
262
346
|
if (sse.entities) {
|
|
263
347
|
this.liveEntityRouter = createLiveEntityRouter({
|
|
264
348
|
signals: this.signals!,
|
package/src/kernel/Kernel.ts
CHANGED
|
@@ -51,6 +51,7 @@ import type {
|
|
|
51
51
|
KernelOptions,
|
|
52
52
|
InternalLayoutComponents,
|
|
53
53
|
AxiosLikeClient,
|
|
54
|
+
SSEConfig as SSEConfigType,
|
|
54
55
|
} from './Kernel.types'
|
|
55
56
|
|
|
56
57
|
// Re-export public types
|
|
@@ -440,6 +441,7 @@ export interface Kernel {
|
|
|
440
441
|
_createStackHydrator(): void
|
|
441
442
|
_createDeferredRegistry(): void
|
|
442
443
|
_createEventRouter(): void
|
|
444
|
+
_validateSseConfig(sse: SSEConfigType): void
|
|
443
445
|
_createSSEBridge(): void
|
|
444
446
|
|
|
445
447
|
// Vue (Kernel.vue.ts)
|