litestar-vite-plugin 0.27.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -18
- package/dist/js/astro.d.ts +12 -121
- package/dist/js/astro.js +8 -55
- package/dist/js/helpers/channels.d.ts +31 -0
- package/dist/js/helpers/channels.js +37 -0
- package/dist/js/helpers/csrf.d.ts +3 -1
- package/dist/js/helpers/csrf.js +26 -12
- package/dist/js/helpers/expression.d.ts +3 -0
- package/dist/js/helpers/expression.js +524 -0
- package/dist/js/helpers/htmx.d.ts +1 -1
- package/dist/js/helpers/htmx.js +33 -140
- package/dist/js/helpers/index.d.ts +5 -1
- package/dist/js/helpers/index.js +9 -1
- package/dist/js/helpers/queues.d.ts +61 -0
- package/dist/js/helpers/queues.js +117 -0
- package/dist/js/helpers/stream-element.d.ts +79 -0
- package/dist/js/helpers/stream-element.js +229 -0
- package/dist/js/helpers/stream.d.ts +76 -0
- package/dist/js/helpers/stream.js +242 -0
- package/dist/js/index.d.ts +4 -106
- package/dist/js/index.js +4 -0
- package/dist/js/install-hint.js +8 -15
- package/dist/js/nuxt.d.ts +12 -128
- package/dist/js/nuxt.js +17 -74
- package/dist/js/react/index.d.ts +28 -0
- package/dist/js/react/index.js +54 -0
- package/dist/js/shared/bridge-schema.d.ts +10 -7
- package/dist/js/shared/bridge-schema.js +6 -0
- package/dist/js/shared/emit-page-props-types.js +22 -6
- package/dist/js/shared/emit-static-props-types.js +6 -2
- package/dist/js/shared/integration-config.d.ts +75 -0
- package/dist/js/shared/integration-config.js +59 -0
- package/dist/js/shared/logger.d.ts +0 -4
- package/dist/js/shared/logger.js +1 -2
- package/dist/js/shared/managed-shutdown.d.ts +8 -0
- package/dist/js/shared/managed-shutdown.js +26 -0
- package/dist/js/shared/network.d.ts +4 -3
- package/dist/js/shared/typegen-core.d.ts +2 -9
- package/dist/js/shared/typegen-core.js +0 -1
- package/dist/js/shared/typegen-plugin.d.ts +84 -0
- package/dist/js/shared/vite-compat.d.ts +0 -4
- package/dist/js/shared/vite-compat.js +1 -3
- package/dist/js/svelte/index.d.ts +27 -0
- package/dist/js/svelte/index.js +51 -0
- package/dist/js/sveltekit.d.ts +12 -128
- package/dist/js/sveltekit.js +6 -55
- package/dist/js/vue/index.d.ts +29 -0
- package/dist/js/vue/index.js +57 -0
- package/package.json +47 -4
package/dist/js/helpers/htmx.js
CHANGED
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
*
|
|
28
28
|
* @module
|
|
29
29
|
*/
|
|
30
|
-
import {
|
|
30
|
+
import { getCsrfHeaderName, getCsrfToken } from "./csrf.js";
|
|
31
|
+
import { compileExpression } from "./expression.js";
|
|
31
32
|
function getHeadersFromConfigRequestEvent(evt) {
|
|
32
33
|
const detail = evt.detail;
|
|
33
34
|
if (!detail || typeof detail !== "object")
|
|
@@ -80,12 +81,13 @@ export function registerHtmxExtension() {
|
|
|
80
81
|
onEvent(name, evt) {
|
|
81
82
|
if (name === "htmx:configRequest") {
|
|
82
83
|
const token = getCsrfToken();
|
|
84
|
+
const headerName = getCsrfHeaderName();
|
|
83
85
|
const headers = getHeadersFromConfigRequestEvent(evt);
|
|
84
86
|
if (token && headers) {
|
|
85
87
|
if (headers instanceof Headers)
|
|
86
|
-
headers.set(
|
|
88
|
+
headers.set(headerName, token);
|
|
87
89
|
else
|
|
88
|
-
headers[
|
|
90
|
+
headers[headerName] = token;
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
93
|
return true;
|
|
@@ -194,6 +196,28 @@ function swapKids(start, end, ctx, parse = false) {
|
|
|
194
196
|
current = (r ?? current).nextSibling;
|
|
195
197
|
}
|
|
196
198
|
}
|
|
199
|
+
function wrapEvent(event) {
|
|
200
|
+
const eventTarget = event.target;
|
|
201
|
+
let target = null;
|
|
202
|
+
if (eventTarget instanceof HTMLInputElement || eventTarget instanceof HTMLSelectElement || eventTarget instanceof HTMLTextAreaElement) {
|
|
203
|
+
target = Object.freeze({
|
|
204
|
+
value: eventTarget.value,
|
|
205
|
+
name: eventTarget.name,
|
|
206
|
+
checked: eventTarget instanceof HTMLInputElement ? eventTarget.checked : false,
|
|
207
|
+
id: eventTarget.id,
|
|
208
|
+
type: eventTarget instanceof HTMLInputElement ? eventTarget.type : "",
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
else if (eventTarget instanceof Element) {
|
|
212
|
+
target = Object.freeze({ value: "", name: "", checked: false, id: eventTarget.id, type: "" });
|
|
213
|
+
}
|
|
214
|
+
return Object.freeze({
|
|
215
|
+
type: event.type,
|
|
216
|
+
target,
|
|
217
|
+
preventDefault: () => event.preventDefault(),
|
|
218
|
+
stopPropagation: () => event.stopPropagation(),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
197
221
|
const directives = [
|
|
198
222
|
// :attr="expr" - attribute binding
|
|
199
223
|
{
|
|
@@ -246,7 +270,7 @@ const directives = [
|
|
|
246
270
|
if (!current)
|
|
247
271
|
return;
|
|
248
272
|
const eventCtx = Object.create(current);
|
|
249
|
-
eventCtx.$event = e;
|
|
273
|
+
eventCtx.$event = wrapEvent(e);
|
|
250
274
|
g(eventCtx);
|
|
251
275
|
});
|
|
252
276
|
};
|
|
@@ -458,131 +482,6 @@ function childCtx(parent, data, index, key) {
|
|
|
458
482
|
// =============================================================================
|
|
459
483
|
// Expression Compiler
|
|
460
484
|
// =============================================================================
|
|
461
|
-
/** Identifiers that must never appear as standalone words in expressions */
|
|
462
|
-
const BLOCKED_GLOBALS = [
|
|
463
|
-
"window",
|
|
464
|
-
"document",
|
|
465
|
-
"globalThis",
|
|
466
|
-
"self",
|
|
467
|
-
"top",
|
|
468
|
-
"frames",
|
|
469
|
-
"Function",
|
|
470
|
-
"eval",
|
|
471
|
-
"setTimeout",
|
|
472
|
-
"setInterval",
|
|
473
|
-
"constructor",
|
|
474
|
-
"__proto__",
|
|
475
|
-
"prototype",
|
|
476
|
-
"import",
|
|
477
|
-
"require",
|
|
478
|
-
];
|
|
479
|
-
/** Build a single regex: matches any blocked word at a word boundary */
|
|
480
|
-
const BLOCKED_RE = new RegExp(`\\b(${BLOCKED_GLOBALS.join("|")})\\b`);
|
|
481
|
-
/** Strip string literals and template strings before checking for blocked patterns */
|
|
482
|
-
function stripStrings(s) {
|
|
483
|
-
return s
|
|
484
|
-
.replace(/`(?:[^`\\]|\\.)*`/g, "") // template literals
|
|
485
|
-
.replace(/"(?:[^"\\]|\\.)*"/g, "") // double-quoted strings
|
|
486
|
-
.replace(/'(?:[^'\\]|\\.)*'/g, ""); // single-quoted strings
|
|
487
|
-
}
|
|
488
|
-
function readQuotedLiteral(s, start) {
|
|
489
|
-
const quote = s[start];
|
|
490
|
-
if (quote !== "'" && quote !== '"' && quote !== "`")
|
|
491
|
-
return null;
|
|
492
|
-
let value = "";
|
|
493
|
-
for (let i = start + 1; i < s.length; i++) {
|
|
494
|
-
const ch = s[i];
|
|
495
|
-
if (ch === "\\") {
|
|
496
|
-
if (i + 1 >= s.length)
|
|
497
|
-
return null;
|
|
498
|
-
const escaped = readEscapedCharacter(s, i + 1);
|
|
499
|
-
if (!escaped)
|
|
500
|
-
return null;
|
|
501
|
-
value += escaped.value;
|
|
502
|
-
i = escaped.end - 1;
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
if (quote === "`" && ch === "$" && s[i + 1] === "{") {
|
|
506
|
-
return null;
|
|
507
|
-
}
|
|
508
|
-
if (ch === quote) {
|
|
509
|
-
return { end: i + 1, value };
|
|
510
|
-
}
|
|
511
|
-
value += ch;
|
|
512
|
-
}
|
|
513
|
-
return null;
|
|
514
|
-
}
|
|
515
|
-
function readEscapedCharacter(s, start) {
|
|
516
|
-
const ch = s[start];
|
|
517
|
-
if (ch === "u") {
|
|
518
|
-
if (s[start + 1] === "{") {
|
|
519
|
-
const close = s.indexOf("}", start + 2);
|
|
520
|
-
if (close === -1)
|
|
521
|
-
return null;
|
|
522
|
-
const codePoint = Number.parseInt(s.slice(start + 2, close), 16);
|
|
523
|
-
return Number.isFinite(codePoint) ? { end: close + 1, value: String.fromCodePoint(codePoint) } : null;
|
|
524
|
-
}
|
|
525
|
-
const codePoint = Number.parseInt(s.slice(start + 1, start + 5), 16);
|
|
526
|
-
return Number.isFinite(codePoint) ? { end: start + 5, value: String.fromCharCode(codePoint) } : null;
|
|
527
|
-
}
|
|
528
|
-
if (ch === "x") {
|
|
529
|
-
const codePoint = Number.parseInt(s.slice(start + 1, start + 3), 16);
|
|
530
|
-
return Number.isFinite(codePoint) ? { end: start + 3, value: String.fromCharCode(codePoint) } : null;
|
|
531
|
-
}
|
|
532
|
-
const escapes = { b: "\b", f: "\f", n: "\n", r: "\r", t: "\t", v: "\v" };
|
|
533
|
-
return { end: start + 1, value: escapes[ch] ?? ch };
|
|
534
|
-
}
|
|
535
|
-
function skipTrivia(s, start) {
|
|
536
|
-
let i = start;
|
|
537
|
-
while (i < s.length) {
|
|
538
|
-
while (/\s/.test(s[i] ?? ""))
|
|
539
|
-
i += 1;
|
|
540
|
-
if (s[i] === "/" && s[i + 1] === "/") {
|
|
541
|
-
i = s.indexOf("\n", i + 2);
|
|
542
|
-
if (i === -1)
|
|
543
|
-
return s.length;
|
|
544
|
-
continue;
|
|
545
|
-
}
|
|
546
|
-
if (s[i] === "/" && s[i + 1] === "*") {
|
|
547
|
-
const close = s.indexOf("*/", i + 2);
|
|
548
|
-
if (close === -1)
|
|
549
|
-
return s.length;
|
|
550
|
-
i = close + 2;
|
|
551
|
-
continue;
|
|
552
|
-
}
|
|
553
|
-
break;
|
|
554
|
-
}
|
|
555
|
-
return i;
|
|
556
|
-
}
|
|
557
|
-
function hasBlockedStringConcatenation(s) {
|
|
558
|
-
for (let i = 0; i < s.length; i++) {
|
|
559
|
-
const first = readQuotedLiteral(s, i);
|
|
560
|
-
if (!first)
|
|
561
|
-
continue;
|
|
562
|
-
const parts = [first.value];
|
|
563
|
-
let cursor = skipTrivia(s, first.end);
|
|
564
|
-
while (s[cursor] === "+") {
|
|
565
|
-
const nextStart = skipTrivia(s, cursor + 1);
|
|
566
|
-
const next = readQuotedLiteral(s, nextStart);
|
|
567
|
-
if (!next)
|
|
568
|
-
break;
|
|
569
|
-
parts.push(next.value);
|
|
570
|
-
cursor = skipTrivia(s, next.end);
|
|
571
|
-
}
|
|
572
|
-
if (parts.length > 1 && BLOCKED_GLOBALS.includes(parts.join(""))) {
|
|
573
|
-
return true;
|
|
574
|
-
}
|
|
575
|
-
i = first.end - 1;
|
|
576
|
-
}
|
|
577
|
-
return false;
|
|
578
|
-
}
|
|
579
|
-
function isExpressionSafe(s) {
|
|
580
|
-
if (hasBlockedStringConcatenation(s)) {
|
|
581
|
-
return false;
|
|
582
|
-
}
|
|
583
|
-
const stripped = stripStrings(s);
|
|
584
|
-
return !BLOCKED_RE.test(stripped);
|
|
585
|
-
}
|
|
586
485
|
function expr(s) {
|
|
587
486
|
if (!s)
|
|
588
487
|
return null;
|
|
@@ -593,22 +492,16 @@ function expr(s) {
|
|
|
593
492
|
expressionCache.set(s, cached);
|
|
594
493
|
return cached;
|
|
595
494
|
}
|
|
596
|
-
|
|
495
|
+
const compiled = compileExpression(s);
|
|
496
|
+
if (!compiled) {
|
|
597
497
|
if (debug)
|
|
598
498
|
console.warn(`[litestar] blocked expression: ${s}`);
|
|
599
499
|
cacheExpression(s, null);
|
|
600
500
|
return null;
|
|
601
501
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
cacheExpression(s, fn);
|
|
606
|
-
return fn;
|
|
607
|
-
}
|
|
608
|
-
catch {
|
|
609
|
-
cacheExpression(s, null);
|
|
610
|
-
return null;
|
|
611
|
-
}
|
|
502
|
+
const fn = (context) => compiled(context);
|
|
503
|
+
cacheExpression(s, fn);
|
|
504
|
+
return fn;
|
|
612
505
|
}
|
|
613
506
|
/** Compile text with ${expr} interpolation - escapes backticks and backslashes */
|
|
614
507
|
function compileTextExpr(t) {
|
|
@@ -38,6 +38,10 @@
|
|
|
38
38
|
*
|
|
39
39
|
* @module
|
|
40
40
|
*/
|
|
41
|
-
export { csrfFetch, csrfHeaders, getCsrfToken } from "./csrf.js";
|
|
41
|
+
export { csrfFetch, csrfHeaders, getCsrfHeaderName, getCsrfToken } from "./csrf.js";
|
|
42
|
+
export { createChannelsStream, type ChannelName, type ChannelsStreamOptions } from "./channels.js";
|
|
42
43
|
export { addDirective, registerHtmxExtension, setDebug as setHtmxDebug, swapJson } from "./htmx.js";
|
|
44
|
+
export { createQueueEventStream, QUEUE_SSE_EVENTS, type QueueEventStreamOptions, type QueueStreamTarget, type QueueStreamValue } from "./queues.js";
|
|
43
45
|
export { createRouteHelpers, currentRoute, isCurrentRoute, isRoute, type RouteDefinition, type RouteDefinitions, type RouteHelpers, toRoute } from "./routes.js";
|
|
46
|
+
export { createEventStream, type EventStream, type EventStreamOptions, type StreamGap } from "./stream.js";
|
|
47
|
+
export { defineStreamElement, LitestarStreamElement, type StreamElementOptions } from "./stream-element.js";
|
package/dist/js/helpers/index.js
CHANGED
|
@@ -39,8 +39,16 @@
|
|
|
39
39
|
* @module
|
|
40
40
|
*/
|
|
41
41
|
// CSRF utilities
|
|
42
|
-
export { csrfFetch, csrfHeaders, getCsrfToken } from "./csrf.js";
|
|
42
|
+
export { csrfFetch, csrfHeaders, getCsrfHeaderName, getCsrfToken } from "./csrf.js";
|
|
43
|
+
// Litestar Channels utilities
|
|
44
|
+
export { createChannelsStream } from "./channels.js";
|
|
43
45
|
// HTMX utilities
|
|
44
46
|
export { addDirective, registerHtmxExtension, setDebug as setHtmxDebug, swapJson } from "./htmx.js";
|
|
47
|
+
// Litestar Queues utilities
|
|
48
|
+
export { createQueueEventStream, QUEUE_SSE_EVENTS } from "./queues.js";
|
|
45
49
|
// Route matching utilities
|
|
46
50
|
export { createRouteHelpers, currentRoute, isCurrentRoute, isRoute, toRoute } from "./routes.js";
|
|
51
|
+
// Realtime stream utilities
|
|
52
|
+
export { createEventStream } from "./stream.js";
|
|
53
|
+
// Declarative realtime stream element
|
|
54
|
+
export { defineStreamElement, LitestarStreamElement } from "./stream-element.js";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser helper for routes generated by Litestar Queues EventStreamConfig.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { createQueueEventStream } from "litestar-vite-plugin/helpers"
|
|
7
|
+
*
|
|
8
|
+
* const stream = createQueueEventStream({
|
|
9
|
+
* scope: "task",
|
|
10
|
+
* taskId: "01J...",
|
|
11
|
+
* onEvent: (event) => console.log(event),
|
|
12
|
+
* })
|
|
13
|
+
* stream.connect()
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import { type EventStream, type EventStreamConfig, type StreamUrl } from "./stream.js";
|
|
19
|
+
export declare const QUEUE_SSE_EVENTS: readonly ["task.started", "task.progress", "task.log", "task.event", "task.completed", "task.failed", "task.cancelled", "task.claim_lost", "task.stale_failed", "worker.heartbeat", "worker.stale_recovery"];
|
|
20
|
+
export type QueueStreamValue = string | (() => string);
|
|
21
|
+
export type QueueStreamTarget = {
|
|
22
|
+
scope: "task";
|
|
23
|
+
taskId: QueueStreamValue;
|
|
24
|
+
} | {
|
|
25
|
+
scope: "queue";
|
|
26
|
+
queue: QueueStreamValue;
|
|
27
|
+
} | {
|
|
28
|
+
scope: "worker";
|
|
29
|
+
workerId: QueueStreamValue;
|
|
30
|
+
} | {
|
|
31
|
+
scope: "global";
|
|
32
|
+
} | {
|
|
33
|
+
scope: "custom";
|
|
34
|
+
scopeKey: QueueStreamValue;
|
|
35
|
+
};
|
|
36
|
+
type QueueRouteStreamOptions = QueueStreamTarget & {
|
|
37
|
+
url?: never;
|
|
38
|
+
buildUrl?: never;
|
|
39
|
+
basePath?: string;
|
|
40
|
+
};
|
|
41
|
+
type QueueDirectStreamOptions = {
|
|
42
|
+
url: StreamUrl;
|
|
43
|
+
buildUrl?: never;
|
|
44
|
+
basePath?: never;
|
|
45
|
+
} | {
|
|
46
|
+
url?: never;
|
|
47
|
+
buildUrl: () => string | URL;
|
|
48
|
+
basePath?: never;
|
|
49
|
+
};
|
|
50
|
+
export type QueueEventStreamOptions<TFrame = unknown> = EventStreamConfig<TFrame> & (QueueRouteStreamOptions | QueueDirectStreamOptions) & {
|
|
51
|
+
basePath?: string;
|
|
52
|
+
transformUrl?: (url: URL) => string | URL;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Create a stream for routes generated by QueuePlugin EventStreamConfig.
|
|
56
|
+
*
|
|
57
|
+
* @param options - Queue target, transport, and stream callbacks.
|
|
58
|
+
* @returns A disposable stream that connects only when `connect()` is called.
|
|
59
|
+
*/
|
|
60
|
+
export declare function createQueueEventStream<TFrame = unknown>(options: QueueEventStreamOptions<TFrame>): EventStream;
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser helper for routes generated by Litestar Queues EventStreamConfig.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { createQueueEventStream } from "litestar-vite-plugin/helpers"
|
|
7
|
+
*
|
|
8
|
+
* const stream = createQueueEventStream({
|
|
9
|
+
* scope: "task",
|
|
10
|
+
* taskId: "01J...",
|
|
11
|
+
* onEvent: (event) => console.log(event),
|
|
12
|
+
* })
|
|
13
|
+
* stream.connect()
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import { createEventStream, resolveStreamUrl } from "./stream.js";
|
|
19
|
+
export const QUEUE_SSE_EVENTS = [
|
|
20
|
+
"task.started",
|
|
21
|
+
"task.progress",
|
|
22
|
+
"task.log",
|
|
23
|
+
"task.event",
|
|
24
|
+
"task.completed",
|
|
25
|
+
"task.failed",
|
|
26
|
+
"task.cancelled",
|
|
27
|
+
"task.claim_lost",
|
|
28
|
+
"task.stale_failed",
|
|
29
|
+
"worker.heartbeat",
|
|
30
|
+
"worker.stale_recovery",
|
|
31
|
+
];
|
|
32
|
+
function asRecord(value) {
|
|
33
|
+
return typeof value === "object" && value !== null ? value : undefined;
|
|
34
|
+
}
|
|
35
|
+
function defaultQueueIsHeartbeat(frame) {
|
|
36
|
+
return asRecord(frame)?.type === "ping";
|
|
37
|
+
}
|
|
38
|
+
function defaultQueueGetEventKey(frame) {
|
|
39
|
+
const record = asRecord(frame);
|
|
40
|
+
const key = record?.eventKey ?? record?.id;
|
|
41
|
+
return typeof key === "string" ? key : undefined;
|
|
42
|
+
}
|
|
43
|
+
function defaultQueueGetSequence(frame) {
|
|
44
|
+
const record = asRecord(frame);
|
|
45
|
+
const sequence = record?.sequence;
|
|
46
|
+
const taskId = record?.taskId;
|
|
47
|
+
const attempt = record?.attempt;
|
|
48
|
+
if (typeof sequence !== "number" || !Number.isFinite(sequence) || typeof taskId !== "string" || (typeof attempt !== "string" && typeof attempt !== "number")) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return { stream: `${taskId}:${attempt}`, value: sequence };
|
|
52
|
+
}
|
|
53
|
+
function resolveValue(value) {
|
|
54
|
+
return typeof value === "function" ? value() : value;
|
|
55
|
+
}
|
|
56
|
+
function queueRouteSuffix(target) {
|
|
57
|
+
switch (target.scope) {
|
|
58
|
+
case "task":
|
|
59
|
+
return `tasks/${encodeURIComponent(resolveValue(target.taskId))}`;
|
|
60
|
+
case "queue":
|
|
61
|
+
return `queues/${encodeURIComponent(resolveValue(target.queue))}`;
|
|
62
|
+
case "worker":
|
|
63
|
+
return `workers/${encodeURIComponent(resolveValue(target.workerId))}`;
|
|
64
|
+
case "global":
|
|
65
|
+
return "global";
|
|
66
|
+
case "custom":
|
|
67
|
+
return `custom/${encodeURIComponent(resolveValue(target.scopeKey))}`;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function queueStreamUrl(target, basePath, transport) {
|
|
71
|
+
const root = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
|
|
72
|
+
const transportPath = transport === "sse" ? "sse/" : "";
|
|
73
|
+
return new URL(resolveStreamUrl(`${root}/${transportPath}${queueRouteSuffix(target)}`, transport));
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a stream for routes generated by QueuePlugin EventStreamConfig.
|
|
77
|
+
*
|
|
78
|
+
* @param options - Queue target, transport, and stream callbacks.
|
|
79
|
+
* @returns A disposable stream that connects only when `connect()` is called.
|
|
80
|
+
*/
|
|
81
|
+
export function createQueueEventStream(options) {
|
|
82
|
+
const { baseDelayMs, basePath = "/queues/events", dedupWindow, EventSourceCtor, getEventKey = defaultQueueGetEventKey, getSequence = defaultQueueGetSequence, isHeartbeat = defaultQueueIsHeartbeat, maxDelayMs, onEvent, onClose, onGap, onHealthChange, onOpen, onReconnect, parseFrame, shouldReconnect, sseEvents = QUEUE_SSE_EVENTS, transformUrl, transport = "websocket", WebSocketCtor, } = options;
|
|
83
|
+
return createEventStream({
|
|
84
|
+
baseDelayMs,
|
|
85
|
+
buildUrl: () => {
|
|
86
|
+
let endpoint;
|
|
87
|
+
if ("buildUrl" in options && options.buildUrl !== undefined) {
|
|
88
|
+
endpoint = options.buildUrl();
|
|
89
|
+
}
|
|
90
|
+
else if ("url" in options && options.url !== undefined) {
|
|
91
|
+
endpoint = typeof options.url === "function" ? options.url() : options.url;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
endpoint = queueStreamUrl(options, basePath, transport);
|
|
95
|
+
}
|
|
96
|
+
const url = new URL(resolveStreamUrl(endpoint, transport));
|
|
97
|
+
return transformUrl?.(url) ?? url;
|
|
98
|
+
},
|
|
99
|
+
dedupWindow,
|
|
100
|
+
EventSourceCtor,
|
|
101
|
+
getEventKey,
|
|
102
|
+
getSequence,
|
|
103
|
+
isHeartbeat,
|
|
104
|
+
maxDelayMs,
|
|
105
|
+
onEvent,
|
|
106
|
+
onClose,
|
|
107
|
+
onGap,
|
|
108
|
+
onHealthChange,
|
|
109
|
+
onOpen,
|
|
110
|
+
onReconnect,
|
|
111
|
+
parseFrame,
|
|
112
|
+
shouldReconnect,
|
|
113
|
+
sseEvents,
|
|
114
|
+
transport,
|
|
115
|
+
WebSocketCtor,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative lifecycle binding for JSON WebSocket and SSE streams.
|
|
3
|
+
*
|
|
4
|
+
* This element replaces `htmx-ext-ws` and `htmx-ext-sse` for JSON streams.
|
|
5
|
+
* Do not layer both reconnect implementations on the same endpoint.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```html
|
|
9
|
+
* <litestar-stream url="/events" transport="sse" swap="json">
|
|
10
|
+
* <template ls-for="item in $data.items"><p>${item}</p></template>
|
|
11
|
+
* </litestar-stream>
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* @module
|
|
15
|
+
*/
|
|
16
|
+
import { type EventStreamConfig } from "./stream.js";
|
|
17
|
+
type StreamCallbackConfig = Pick<EventStreamConfig, "EventSourceCtor" | "WebSocketCtor" | "getEventKey" | "getSequence" | "isHeartbeat" | "onEvent" | "onGap" | "onHealthChange" | "onReconnect" | "parseFrame" | "shouldReconnect">;
|
|
18
|
+
type HTMLElementConstructor = new (...args: never[]) => HTMLElement;
|
|
19
|
+
declare const HTMLElementBase: HTMLElementConstructor;
|
|
20
|
+
export interface StreamElementOptions {
|
|
21
|
+
tagName?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare class LitestarStreamElement extends HTMLElementBase {
|
|
24
|
+
static readonly observedAttributes: string[];
|
|
25
|
+
private stream;
|
|
26
|
+
private _buildUrl;
|
|
27
|
+
private _onEvent;
|
|
28
|
+
private _onGap;
|
|
29
|
+
private _onHealthChange;
|
|
30
|
+
private _onReconnect;
|
|
31
|
+
private _shouldReconnect;
|
|
32
|
+
private _isHeartbeat;
|
|
33
|
+
private _getEventKey;
|
|
34
|
+
private _getSequence;
|
|
35
|
+
private _parseFrame;
|
|
36
|
+
private _WebSocketCtor;
|
|
37
|
+
private _EventSourceCtor;
|
|
38
|
+
constructor();
|
|
39
|
+
get buildUrl(): (() => string | URL) | undefined;
|
|
40
|
+
set buildUrl(value: (() => string | URL) | undefined);
|
|
41
|
+
get onEvent(): StreamCallbackConfig["onEvent"] | undefined;
|
|
42
|
+
set onEvent(value: StreamCallbackConfig["onEvent"] | undefined);
|
|
43
|
+
get onGap(): StreamCallbackConfig["onGap"];
|
|
44
|
+
set onGap(value: StreamCallbackConfig["onGap"]);
|
|
45
|
+
get onHealthChange(): StreamCallbackConfig["onHealthChange"];
|
|
46
|
+
set onHealthChange(value: StreamCallbackConfig["onHealthChange"]);
|
|
47
|
+
get onReconnect(): StreamCallbackConfig["onReconnect"];
|
|
48
|
+
set onReconnect(value: StreamCallbackConfig["onReconnect"]);
|
|
49
|
+
get shouldReconnect(): StreamCallbackConfig["shouldReconnect"];
|
|
50
|
+
set shouldReconnect(value: StreamCallbackConfig["shouldReconnect"]);
|
|
51
|
+
get isHeartbeat(): StreamCallbackConfig["isHeartbeat"];
|
|
52
|
+
set isHeartbeat(value: StreamCallbackConfig["isHeartbeat"]);
|
|
53
|
+
get getEventKey(): StreamCallbackConfig["getEventKey"];
|
|
54
|
+
set getEventKey(value: StreamCallbackConfig["getEventKey"]);
|
|
55
|
+
get getSequence(): StreamCallbackConfig["getSequence"];
|
|
56
|
+
set getSequence(value: StreamCallbackConfig["getSequence"]);
|
|
57
|
+
get parseFrame(): StreamCallbackConfig["parseFrame"];
|
|
58
|
+
set parseFrame(value: StreamCallbackConfig["parseFrame"]);
|
|
59
|
+
get WebSocketCtor(): StreamCallbackConfig["WebSocketCtor"];
|
|
60
|
+
set WebSocketCtor(value: StreamCallbackConfig["WebSocketCtor"]);
|
|
61
|
+
get EventSourceCtor(): StreamCallbackConfig["EventSourceCtor"];
|
|
62
|
+
set EventSourceCtor(value: StreamCallbackConfig["EventSourceCtor"]);
|
|
63
|
+
get healthy(): boolean;
|
|
64
|
+
connectedCallback(): void;
|
|
65
|
+
disconnectedCallback(): void;
|
|
66
|
+
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
67
|
+
private upgradeProperty;
|
|
68
|
+
private start;
|
|
69
|
+
private stop;
|
|
70
|
+
private restart;
|
|
71
|
+
private dispatchStreamEvent;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Register the declarative stream element.
|
|
75
|
+
*
|
|
76
|
+
* @param options - Optional custom tag name.
|
|
77
|
+
*/
|
|
78
|
+
export declare function defineStreamElement(options?: StreamElementOptions): void;
|
|
79
|
+
export {};
|