litestar-vite-plugin 0.26.1 → 0.28.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.js +4 -0
- package/dist/js/dev-server-index.html +2 -2
- package/dist/js/helpers/channels.d.ts +31 -0
- package/dist/js/helpers/channels.js +37 -0
- package/dist/js/helpers/index.d.ts +4 -0
- package/dist/js/helpers/index.js +8 -0
- 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.js +4 -0
- package/dist/js/install-hint.d.ts +8 -1
- package/dist/js/install-hint.js +20 -8
- package/dist/js/nuxt.js +10 -16
- 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 +3 -3
- package/dist/js/shared/constants.d.ts +5 -2
- package/dist/js/shared/constants.js +5 -1
- 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.js +4 -3
- package/dist/js/svelte/index.d.ts +27 -0
- package/dist/js/svelte/index.js +51 -0
- package/dist/js/sveltekit.js +2 -0
- package/dist/js/vue/index.d.ts +29 -0
- package/dist/js/vue/index.js +57 -0
- package/package.json +47 -4
package/README.md
CHANGED
|
@@ -20,19 +20,10 @@ npm install litestar-vite-plugin
|
|
|
20
20
|
## Quick Start
|
|
21
21
|
|
|
22
22
|
```python
|
|
23
|
-
import os
|
|
24
|
-
from pathlib import Path
|
|
25
23
|
from litestar import Litestar
|
|
26
|
-
from litestar_vite import
|
|
24
|
+
from litestar_vite import VitePlugin
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
app = Litestar(
|
|
31
|
-
plugins=[VitePlugin(config=ViteConfig(
|
|
32
|
-
dev_mode=DEV_MODE,
|
|
33
|
-
paths=PathConfig(root=Path(__file__).parent),
|
|
34
|
-
))]
|
|
35
|
-
)
|
|
26
|
+
app = Litestar(plugins=[VitePlugin()])
|
|
36
27
|
```
|
|
37
28
|
|
|
38
29
|
```bash
|
|
@@ -41,14 +32,42 @@ litestar assets install
|
|
|
41
32
|
litestar run --reload
|
|
42
33
|
```
|
|
43
34
|
|
|
44
|
-
|
|
35
|
+
`VitePlugin()` detects development and production behavior without manual `VITE_DEV_MODE` parsing. The effective
|
|
36
|
+
`litestar run --host/--port` values are also passed to the frontend environment and `.litestar.json` bridge.
|
|
37
|
+
|
|
38
|
+
### Optional Granian native static serving
|
|
39
|
+
|
|
40
|
+
Granian 0.16+ can serve eligible production bundle files before the request enters Python:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from litestar import Litestar
|
|
44
|
+
from litestar_granian import GranianPlugin
|
|
45
|
+
from litestar_vite import VitePlugin
|
|
46
|
+
|
|
47
|
+
app = Litestar(
|
|
48
|
+
plugins=[
|
|
49
|
+
VitePlugin(),
|
|
50
|
+
GranianPlugin(static="auto"),
|
|
51
|
+
]
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This is an optimization, not a separate application configuration. The Litestar static route stays registered, so
|
|
56
|
+
Uvicorn and other ASGI servers serve the same files. Granian automatically falls back to Litestar when assets are
|
|
57
|
+
protected, customized, missing, or otherwise unsafe to intercept.
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
Native hits bypass ASGI middleware, guards, compression, custom headers, and Python access logging. Keep protected or
|
|
60
|
+
customized assets on the Litestar fallback path. See the
|
|
61
|
+
[production guide](https://litestar-org.github.io/litestar-vite/latest/usage/production.html) for the server matrix and
|
|
62
|
+
advanced configuration.
|
|
63
|
+
|
|
64
|
+
## Documentation
|
|
50
65
|
|
|
51
|
-
|
|
66
|
+
- Get started: <https://litestar-org.github.io/litestar-vite/latest/usage/index.html>
|
|
67
|
+
- Framework guides: <https://litestar-org.github.io/litestar-vite/latest/frameworks/index.html>
|
|
68
|
+
- Inertia: <https://litestar-org.github.io/litestar-vite/latest/frameworks/inertia/index.html>
|
|
69
|
+
- API reference: <https://litestar-org.github.io/litestar-vite/latest/reference/index.html>
|
|
70
|
+
- Changelog: <https://litestar-org.github.io/litestar-vite/latest/changelog.html>
|
|
52
71
|
|
|
53
72
|
## Common Commands
|
|
54
73
|
|
|
@@ -76,7 +95,7 @@ litestar-vite now defaults Inertia apps to script-element bootstrap. Inertia v3
|
|
|
76
95
|
|
|
77
96
|
## Links
|
|
78
97
|
|
|
79
|
-
- Docs: <https://litestar-org.github.io/litestar-vite/>
|
|
98
|
+
- Docs: <https://litestar-org.github.io/litestar-vite/latest/>
|
|
80
99
|
- Examples: `examples/` (React, Vue, Svelte, HTMX, Inertia, Astro, Nuxt, SvelteKit, Angular)
|
|
81
100
|
- Real-world example: [litestar-fullstack](https://github.com/litestar-org/litestar-fullstack)
|
|
82
101
|
- Issues: <https://github.com/litestar-org/litestar-vite/issues/>
|
package/dist/js/astro.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { readBridgeConfig } from "./shared/bridge-schema.js";
|
|
4
|
+
import { installManagedShutdown } from "./shared/managed-shutdown.js";
|
|
4
5
|
import { normalizeHost, resolveHotFilePath, resolveLitestarPort } from "./shared/network.js";
|
|
5
6
|
import { createLitestarTypeGenPlugin, resolveTypesConfig } from "./shared/typegen-plugin.js";
|
|
6
7
|
import { hmrServerConfig } from "./shared/vite-compat.js";
|
|
@@ -91,6 +92,9 @@ function createProxyPlugin(config) {
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
};
|
|
95
|
+
},
|
|
96
|
+
configureServer(server) {
|
|
97
|
+
installManagedShutdown(server);
|
|
94
98
|
}
|
|
95
99
|
};
|
|
96
100
|
}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
9
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" />
|
|
10
|
-
<style rel="stylesheet" crossorigin>/*! tailwindcss v4.3.
|
|
11
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-duration:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@layer theme{:root,:host{--font-sans:"Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--font-mono:"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--spacing:.25rem;--container-lg:32rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--font-weight-light:300;--font-weight-medium:500;--font-weight-semibold:600;--tracking-widest:.1em;--leading-relaxed:1.625;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-navy:#202235;--color-navy-surface:#2a2d40;--color-navy-surface-variant:#1a1c2e;--color-gold:#edb641;--color-gold-light:#ffd480;--color-on-surface:#f8fafc;--color-on-surface-muted:#cbd5e1;--color-on-surface-subtle:#94a3b8;--color-outline:#334155;--color-success:#4ade80;--radius-brand:8px;--radius-brand-lg:12px;--shadow-text-glow-dark:0 0 24px #edb64138}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.relative{position:relative}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-10{margin-bottom:calc(var(--spacing) * 10)}.mb-12{margin-bottom:calc(var(--spacing) * 12)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-auto{width:auto}.w-full{width:100%}.max-w-lg{max-width:var(--container-lg)}.min-w-0{min-width:0}.flex-1{flex:1}.flex-none{flex:none}.animate-pulse-dot{animation:2s ease-in-out infinite pulse-dot}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.rounded-brand{border-radius:var(--radius-brand)}.rounded-brand-lg{border-radius:var(--radius-brand-lg)}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-\[3px\]{border-left-style:var(--tw-border-style);border-left-width:3px}.border-outline{border-color:var(--color-outline)}.border-l-gold{border-left-color:var(--color-gold)}.bg-navy-surface{background-color:var(--color-navy-surface)}.bg-navy-surface-variant{background-color:var(--color-navy-surface-variant)}.bg-success{background-color:var(--color-success)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-16{padding-block:calc(var(--spacing) * 16)}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.text-gold{color:var(--color-gold)}.text-on-surface{color:var(--color-on-surface)}.text-on-surface-muted{color:var(--color-on-surface-muted)}.text-on-surface-subtle{color:var(--color-on-surface-subtle)}.uppercase{text-transform:uppercase}.opacity-60{opacity:.6}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.select-all{-webkit-user-select:all;user-select:all}.text-brand-glow{text-shadow:var(--shadow-text-glow-dark)}@media (hover:hover){.group-hover\:translate-x-0\.5:is(:where(.group):hover *){--tw-translate-x:calc(var(--spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.hover\:bg-navy:hover{background-color:var(--color-navy)}.hover\:text-gold:hover{color:var(--color-gold)}.hover\:text-gold-light:hover{color:var(--color-gold-light)}.hover\:opacity-80:hover{opacity:.8}}@media (width>=40rem){.sm\:px-10{padding-inline:calc(var(--spacing) * 10)}.sm\:py-10{padding-block:calc(var(--spacing) * 10)}.sm\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}}}html{font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{background-color:var(--color-navy);color:var(--color-on-surface-muted);background-image:radial-gradient(#f8fafc0a 1px,#0000 1px);background-size:24px 24px}@keyframes pulse-dot{0%,to{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(.92)}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}
|
|
10
|
+
<style rel="stylesheet" crossorigin>/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
11
|
+
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-duration:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@layer theme{:root,:host{--font-sans:"Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;--font-mono:"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--spacing:.25rem;--container-lg:32rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--font-weight-light:300;--font-weight-medium:500;--font-weight-semibold:600;--tracking-widest:.1em;--leading-relaxed:1.625;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-navy:#202235;--color-navy-surface:#2a2d40;--color-navy-surface-variant:#1a1c2e;--color-gold:#edb641;--color-gold-light:#ffd480;--color-on-surface:#f8fafc;--color-on-surface-muted:#cbd5e1;--color-on-surface-subtle:#94a3b8;--color-outline:#334155;--color-success:#4ade80;--radius-brand:8px;--radius-brand-lg:12px;--shadow-text-glow-dark:0 0 24px #edb64138}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.absolute{position:absolute}.relative{position:relative}.mt-8{margin-top:calc(var(--spacing) * 8)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-10{margin-bottom:calc(var(--spacing) * 10)}.mb-12{margin-bottom:calc(var(--spacing) * 12)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.inline{display:inline}.inline-flex{display:inline-flex}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-auto{width:auto}.w-full{width:100%}.max-w-lg{max-width:var(--container-lg)}.min-w-0{min-width:0}.flex-1{flex:1}.flex-none{flex:none}.animate-pulse-dot{animation:2s ease-in-out infinite pulse-dot}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-6{gap:calc(var(--spacing) * 6)}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 8) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse)))}.rounded-brand{border-radius:var(--radius-brand)}.rounded-brand-lg{border-radius:var(--radius-brand-lg)}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-\[3px\]{border-left-style:var(--tw-border-style);border-left-width:3px}.border-outline{border-color:var(--color-outline)}.border-l-gold{border-left-color:var(--color-gold)}.bg-navy-surface{background-color:var(--color-navy-surface)}.bg-navy-surface-variant{background-color:var(--color-navy-surface-variant)}.bg-success{background-color:var(--color-success)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-16{padding-block:calc(var(--spacing) * 16)}.text-center{text-align:center}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-all{word-break:break-all}.text-gold{color:var(--color-gold)}.text-on-surface{color:var(--color-on-surface)}.text-on-surface-muted{color:var(--color-on-surface-muted)}.text-on-surface-subtle{color:var(--color-on-surface-subtle)}.uppercase{text-transform:uppercase}.opacity-60{opacity:.6}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.select-all{-webkit-user-select:all;user-select:all}.text-brand-glow{text-shadow:var(--shadow-text-glow-dark)}@media (hover:hover){.group-hover\:translate-x-0\.5:is(:where(.group):hover *){--tw-translate-x:calc(var(--spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.hover\:bg-navy:hover{background-color:var(--color-navy)}.hover\:text-gold:hover{color:var(--color-gold)}.hover\:text-gold-light:hover{color:var(--color-gold-light)}.hover\:opacity-80:hover{opacity:.8}}@media (width>=40rem){.sm\:px-10{padding-inline:calc(var(--spacing) * 10)}.sm\:py-10{padding-block:calc(var(--spacing) * 10)}.sm\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}}}html{font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{background-color:var(--color-navy);color:var(--color-on-surface-muted);background-image:radial-gradient(#f8fafc0a 1px,#0000 1px);background-size:24px 24px}@keyframes pulse-dot{0%,to{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(.92)}}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}
|
|
12
12
|
/*$vite$:1*/</style>
|
|
13
13
|
</head>
|
|
14
14
|
<body class="flex min-h-screen items-center justify-center px-6 py-16">
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser helper for WebSocket routes generated by Litestar's ChannelsPlugin.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { createChannelsStream } from "litestar-vite-plugin/helpers"
|
|
7
|
+
*
|
|
8
|
+
* const stream = createChannelsStream({
|
|
9
|
+
* basePath: "/ws",
|
|
10
|
+
* channel: "notifications",
|
|
11
|
+
* onEvent: (event) => console.log(event),
|
|
12
|
+
* })
|
|
13
|
+
* stream.connect()
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import { type EventStream, type EventStreamConfig } from "./stream.js";
|
|
19
|
+
export type ChannelName = string | (() => string);
|
|
20
|
+
export interface ChannelsStreamOptions<TFrame = unknown> extends Omit<EventStreamConfig<TFrame>, "EventSourceCtor" | "sseEvents" | "transport"> {
|
|
21
|
+
channel: ChannelName;
|
|
22
|
+
basePath?: string;
|
|
23
|
+
transformUrl?: (url: URL) => string | URL;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Create a stream for a WebSocket route generated by ChannelsPlugin.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Channel name, server route prefix, and stream callbacks.
|
|
29
|
+
* @returns A disposable stream that connects only when `connect()` is called.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createChannelsStream<TFrame = unknown>(options: ChannelsStreamOptions<TFrame>): EventStream;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser helper for WebSocket routes generated by Litestar's ChannelsPlugin.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { createChannelsStream } from "litestar-vite-plugin/helpers"
|
|
7
|
+
*
|
|
8
|
+
* const stream = createChannelsStream({
|
|
9
|
+
* basePath: "/ws",
|
|
10
|
+
* channel: "notifications",
|
|
11
|
+
* onEvent: (event) => console.log(event),
|
|
12
|
+
* })
|
|
13
|
+
* stream.connect()
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
import { createEventStream, resolveStreamUrl } from "./stream.js";
|
|
19
|
+
/**
|
|
20
|
+
* Create a stream for a WebSocket route generated by ChannelsPlugin.
|
|
21
|
+
*
|
|
22
|
+
* @param options - Channel name, server route prefix, and stream callbacks.
|
|
23
|
+
* @returns A disposable stream that connects only when `connect()` is called.
|
|
24
|
+
*/
|
|
25
|
+
export function createChannelsStream(options) {
|
|
26
|
+
const { basePath = "/", channel, transformUrl, ...streamOptions } = options;
|
|
27
|
+
return createEventStream({
|
|
28
|
+
...streamOptions,
|
|
29
|
+
buildUrl: () => {
|
|
30
|
+
const channelName = typeof channel === "function" ? channel() : channel;
|
|
31
|
+
const prefix = basePath.endsWith("/") ? basePath : `${basePath}/`;
|
|
32
|
+
const url = new URL(resolveStreamUrl(`${prefix}${encodeURIComponent(channelName)}`, "websocket"));
|
|
33
|
+
return transformUrl?.(url) ?? url;
|
|
34
|
+
},
|
|
35
|
+
transport: "websocket",
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -39,5 +39,9 @@
|
|
|
39
39
|
* @module
|
|
40
40
|
*/
|
|
41
41
|
export { csrfFetch, csrfHeaders, 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
|
@@ -40,7 +40,15 @@
|
|
|
40
40
|
*/
|
|
41
41
|
// CSRF utilities
|
|
42
42
|
export { csrfFetch, csrfHeaders, 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 {};
|