@swifttui/web 0.0.13 → 0.0.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/README.md +24 -10
- package/dist/index.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/manifest.d.ts +2 -0
- package/dist/manifest.js +2 -0
- package/dist/src/AccessibilityTree.js +156 -0
- package/dist/src/AccessibilityTree.js.map +1 -0
- package/dist/src/BoxDrawingRenderer.js +1106 -0
- package/dist/src/BoxDrawingRenderer.js.map +1 -0
- package/dist/src/WebHostApp.d.ts +41 -0
- package/dist/src/WebHostApp.js +135 -0
- package/dist/src/WebHostApp.js.map +1 -0
- package/dist/src/WebHostSceneManifest.d.ts +18 -0
- package/dist/src/WebHostSceneManifest.js +70 -0
- package/dist/src/WebHostSceneManifest.js.map +1 -0
- package/dist/src/WebHostSceneRuntime.d.ts +112 -0
- package/dist/src/WebHostSceneRuntime.js +651 -0
- package/dist/src/WebHostSceneRuntime.js.map +1 -0
- package/dist/src/WebHostSurfaceTransport.d.ts +166 -0
- package/dist/src/WebHostSurfaceTransport.js +252 -0
- package/dist/src/WebHostSurfaceTransport.js.map +1 -0
- package/dist/src/WebHostTerminalStyle.d.ts +92 -0
- package/dist/src/WebHostTerminalStyle.js +277 -0
- package/dist/src/WebHostTerminalStyle.js.map +1 -0
- package/dist/src/WebHostTestFixtures.d.ts +5 -0
- package/dist/src/WebHostTestFixtures.js +9 -0
- package/dist/src/WebHostTestFixtures.js.map +1 -0
- package/dist/src/WebSocketSceneBridge.d.ts +53 -0
- package/dist/src/WebSocketSceneBridge.js +124 -0
- package/dist/src/WebSocketSceneBridge.js.map +1 -0
- package/dist/src/wasi/BrowserWASIBridge.d.ts +33 -0
- package/dist/src/wasi/BrowserWASIBridge.js +97 -0
- package/dist/src/wasi/BrowserWASIBridge.js.map +1 -0
- package/dist/src/wasi/SharedInputQueue.d.ts +31 -0
- package/dist/src/wasi/SharedInputQueue.js +102 -0
- package/dist/src/wasi/SharedInputQueue.js.map +1 -0
- package/dist/src/wasi/StdIOPipe.d.ts +15 -0
- package/dist/src/wasi/StdIOPipe.js +56 -0
- package/dist/src/wasi/StdIOPipe.js.map +1 -0
- package/dist/src/wasi/WasiPollScheduler.js +114 -0
- package/dist/src/wasi/WasiPollScheduler.js.map +1 -0
- package/dist/src/wasi/WasmSceneRuntime.d.ts +23 -0
- package/dist/src/wasi/WasmSceneRuntime.js +119 -0
- package/dist/src/wasi/WasmSceneRuntime.js.map +1 -0
- package/dist/src/wasi/WasmSceneWorker.d.ts +27 -0
- package/dist/src/wasi/WasmSceneWorker.js +109 -0
- package/dist/src/wasi/WasmSceneWorker.js.map +1 -0
- package/dist/testing.d.ts +2 -0
- package/dist/testing.js +2 -0
- package/dist/wasi-worker.d.ts +2 -0
- package/dist/wasi-worker.js +2 -0
- package/dist/wasi.d.ts +6 -0
- package/dist/wasi.js +6 -0
- package/dist/websocket.d.ts +2 -0
- package/dist/websocket.js +2 -0
- package/package.json +49 -18
- package/AGENTS.md +0 -52
- package/cli.ts +0 -168
- package/index.html +0 -50
- package/index.ts +0 -8
- package/manifest.ts +0 -1
- package/src/AccessibilityTree.ts +0 -262
- package/src/BoxDrawingRenderer.ts +0 -585
- package/src/PublicEntrypointBoundary.test.ts +0 -20
- package/src/WebHostApp.test.ts +0 -222
- package/src/WebHostApp.ts +0 -269
- package/src/WebHostSceneManifest.test.ts +0 -38
- package/src/WebHostSceneManifest.ts +0 -156
- package/src/WebHostSceneRuntime.test.ts +0 -1982
- package/src/WebHostSceneRuntime.ts +0 -1142
- package/src/WebHostSurfaceTransport.test.ts +0 -362
- package/src/WebHostSurfaceTransport.ts +0 -691
- package/src/WebHostTerminalStyle.test.ts +0 -123
- package/src/WebHostTerminalStyle.ts +0 -471
- package/src/WebHostTestFixtures.ts +0 -10
- package/src/WebSocketSceneBridge.test.ts +0 -198
- package/src/WebSocketSceneBridge.ts +0 -233
- package/src/browser.ts +0 -59
- package/src/wasi/BrowserWASIBridge.test.ts +0 -168
- package/src/wasi/BrowserWASIBridge.ts +0 -167
- package/src/wasi/SharedInputQueue.test.ts +0 -146
- package/src/wasi/SharedInputQueue.ts +0 -199
- package/src/wasi/StdIOPipe.ts +0 -72
- package/src/wasi/WasiPollScheduler.test.ts +0 -176
- package/src/wasi/WasiPollScheduler.ts +0 -305
- package/src/wasi/WasmSceneRuntime.ts +0 -205
- package/src/wasi/WasmSceneWorker.ts +0 -182
- package/testing.ts +0 -1
- package/tsconfig.json +0 -29
- package/wasi-worker.ts +0 -1
- package/wasi.ts +0 -4
- package/websocket.ts +0 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
//#region src/WebHostTerminalStyle.d.ts
|
|
2
|
+
type WebHostTerminalCursorStyle = "block" | "bar" | "underline";
|
|
3
|
+
interface WebHostANSIColors {
|
|
4
|
+
black?: string;
|
|
5
|
+
red?: string;
|
|
6
|
+
green?: string;
|
|
7
|
+
yellow?: string;
|
|
8
|
+
blue?: string;
|
|
9
|
+
magenta?: string;
|
|
10
|
+
cyan?: string;
|
|
11
|
+
white?: string;
|
|
12
|
+
brightBlack?: string;
|
|
13
|
+
brightRed?: string;
|
|
14
|
+
brightGreen?: string;
|
|
15
|
+
brightYellow?: string;
|
|
16
|
+
brightBlue?: string;
|
|
17
|
+
brightMagenta?: string;
|
|
18
|
+
brightCyan?: string;
|
|
19
|
+
brightWhite?: string;
|
|
20
|
+
}
|
|
21
|
+
interface WebHostTerminalPalette {
|
|
22
|
+
foreground?: string;
|
|
23
|
+
background?: string;
|
|
24
|
+
cursor?: string;
|
|
25
|
+
selectionBackground?: string;
|
|
26
|
+
selectionForeground?: string;
|
|
27
|
+
ansi?: WebHostANSIColors;
|
|
28
|
+
}
|
|
29
|
+
interface WebHostTerminalTheme {
|
|
30
|
+
foreground?: string;
|
|
31
|
+
background?: string;
|
|
32
|
+
tint?: string;
|
|
33
|
+
separator?: string;
|
|
34
|
+
selection?: string;
|
|
35
|
+
placeholder?: string;
|
|
36
|
+
link?: string;
|
|
37
|
+
fill?: string;
|
|
38
|
+
windowBackground?: string;
|
|
39
|
+
success?: string;
|
|
40
|
+
warning?: string;
|
|
41
|
+
danger?: string;
|
|
42
|
+
info?: string;
|
|
43
|
+
muted?: string;
|
|
44
|
+
}
|
|
45
|
+
interface WebHostTerminalStyle {
|
|
46
|
+
fontSize?: number;
|
|
47
|
+
fontFamily?: string;
|
|
48
|
+
cursorStyle?: WebHostTerminalCursorStyle;
|
|
49
|
+
cursorBlink?: boolean;
|
|
50
|
+
backgroundOpacity?: number;
|
|
51
|
+
palette?: WebHostTerminalPalette;
|
|
52
|
+
theme?: WebHostTerminalTheme;
|
|
53
|
+
}
|
|
54
|
+
interface ResolvedWebHostTerminalPalette {
|
|
55
|
+
foreground: string;
|
|
56
|
+
background: string;
|
|
57
|
+
cursor: string;
|
|
58
|
+
selectionBackground: string;
|
|
59
|
+
selectionForeground: string;
|
|
60
|
+
ansi: Required<WebHostANSIColors>;
|
|
61
|
+
}
|
|
62
|
+
interface ResolvedWebHostTerminalStyle {
|
|
63
|
+
fontSize: number;
|
|
64
|
+
fontFamily: string;
|
|
65
|
+
cursorStyle: WebHostTerminalCursorStyle;
|
|
66
|
+
cursorBlink: boolean;
|
|
67
|
+
backgroundOpacity: number;
|
|
68
|
+
palette: ResolvedWebHostTerminalPalette;
|
|
69
|
+
theme: Required<WebHostTerminalTheme>;
|
|
70
|
+
}
|
|
71
|
+
interface WebHostTerminalRenderStyle {
|
|
72
|
+
appearance: WebHostTerminalAppearance;
|
|
73
|
+
theme?: WebHostTerminalTheme;
|
|
74
|
+
}
|
|
75
|
+
interface WebHostTerminalAppearance {
|
|
76
|
+
foregroundColor: string;
|
|
77
|
+
backgroundColor: string;
|
|
78
|
+
tintColor: string;
|
|
79
|
+
palette: Record<string, string>;
|
|
80
|
+
colorSchemeContrast: "standard" | "increased";
|
|
81
|
+
source: "activeQuery" | "environmentHeuristics" | "fallback" | "override";
|
|
82
|
+
}
|
|
83
|
+
declare function normalizeWebHostTerminalStyle(style?: WebHostTerminalStyle): ResolvedWebHostTerminalStyle;
|
|
84
|
+
declare function mergeWebHostTerminalStyle(base: WebHostTerminalStyle, patch: WebHostTerminalStyle): ResolvedWebHostTerminalStyle;
|
|
85
|
+
declare function resolveWebHostTerminalRenderStyle(style: WebHostTerminalStyle): WebHostTerminalRenderStyle;
|
|
86
|
+
declare function encodeWebHostTerminalRenderStyleBase64(style: WebHostTerminalStyle): string;
|
|
87
|
+
declare function decodeWebHostTerminalRenderStyleBase64(encoded: string): WebHostTerminalRenderStyle | undefined;
|
|
88
|
+
declare function webTUITerminalBackgroundColor(style: WebHostTerminalStyle): string;
|
|
89
|
+
declare function applyWebHostTerminalStyle(element: HTMLElement, style: WebHostTerminalStyle): void;
|
|
90
|
+
//#endregion
|
|
91
|
+
export { ResolvedWebHostTerminalPalette, ResolvedWebHostTerminalStyle, WebHostANSIColors, WebHostTerminalAppearance, WebHostTerminalCursorStyle, WebHostTerminalPalette, WebHostTerminalRenderStyle, WebHostTerminalStyle, WebHostTerminalTheme, applyWebHostTerminalStyle, decodeWebHostTerminalRenderStyleBase64, encodeWebHostTerminalRenderStyleBase64, mergeWebHostTerminalStyle, normalizeWebHostTerminalStyle, resolveWebHostTerminalRenderStyle, webTUITerminalBackgroundColor };
|
|
92
|
+
//# sourceMappingURL=WebHostTerminalStyle.d.ts.map
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
//#region src/WebHostTerminalStyle.ts
|
|
2
|
+
const defaultFontFamily = "\"SFMono-Regular\", \"SF Mono\", \"Menlo\", \"Monaco\", \"Consolas\", \"Liberation Mono\", monospace";
|
|
3
|
+
const defaultPalette = {
|
|
4
|
+
foreground: "#eceff4",
|
|
5
|
+
background: "#1e222a",
|
|
6
|
+
cursor: "#56b6c2",
|
|
7
|
+
selectionBackground: "#2e3440",
|
|
8
|
+
selectionForeground: "#eceff4",
|
|
9
|
+
ansi: {
|
|
10
|
+
black: "#20242c",
|
|
11
|
+
red: "#e05757",
|
|
12
|
+
green: "#61c67b",
|
|
13
|
+
yellow: "#ebb33c",
|
|
14
|
+
blue: "#5ba3ff",
|
|
15
|
+
magenta: "#b46eff",
|
|
16
|
+
cyan: "#56b6c2",
|
|
17
|
+
white: "#eceff4",
|
|
18
|
+
brightBlack: "#8c92ac",
|
|
19
|
+
brightRed: "#ff7b72",
|
|
20
|
+
brightGreen: "#7ee787",
|
|
21
|
+
brightYellow: "#f2cc60",
|
|
22
|
+
brightBlue: "#79c0ff",
|
|
23
|
+
brightMagenta: "#d2a8ff",
|
|
24
|
+
brightCyan: "#7de2d1",
|
|
25
|
+
brightWhite: "#ffffff"
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const defaultTheme = {
|
|
29
|
+
foreground: "#eceff4",
|
|
30
|
+
background: "#1e222a",
|
|
31
|
+
tint: "#56b6c2",
|
|
32
|
+
separator: "#4c566a",
|
|
33
|
+
selection: "#2e3440",
|
|
34
|
+
placeholder: "#8c92ac",
|
|
35
|
+
link: "#5ba3ff",
|
|
36
|
+
fill: "#2b303b",
|
|
37
|
+
windowBackground: "#15181e",
|
|
38
|
+
success: "#61c67b",
|
|
39
|
+
warning: "#ebb33c",
|
|
40
|
+
danger: "#e05757",
|
|
41
|
+
info: "#56b6c2",
|
|
42
|
+
muted: "#8c92ac"
|
|
43
|
+
};
|
|
44
|
+
function normalizeWebHostTerminalStyle(style = {}) {
|
|
45
|
+
const palette = normalizePalette(style.palette, defaultPalette);
|
|
46
|
+
const theme = normalizeTheme(style.theme, palette, defaultTheme);
|
|
47
|
+
return {
|
|
48
|
+
fontSize: normalizeFontSize(style.fontSize ?? 14),
|
|
49
|
+
fontFamily: style.fontFamily ?? defaultFontFamily,
|
|
50
|
+
cursorStyle: style.cursorStyle ?? "block",
|
|
51
|
+
cursorBlink: style.cursorBlink ?? false,
|
|
52
|
+
backgroundOpacity: normalizeOpacity(style.backgroundOpacity ?? 1),
|
|
53
|
+
palette,
|
|
54
|
+
theme
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function mergeWebHostTerminalStyle(base, patch) {
|
|
58
|
+
const resolvedBase = normalizeWebHostTerminalStyle(base);
|
|
59
|
+
return normalizeWebHostTerminalStyle({
|
|
60
|
+
...resolvedBase,
|
|
61
|
+
...patch,
|
|
62
|
+
palette: mergePalette(resolvedBase.palette, patch.palette),
|
|
63
|
+
theme: patch.theme ? {
|
|
64
|
+
...resolvedBase.theme,
|
|
65
|
+
...patch.theme
|
|
66
|
+
} : resolvedBase.theme
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
function resolveWebHostTerminalRenderStyle(style) {
|
|
70
|
+
const normalized = normalizeWebHostTerminalStyle(style);
|
|
71
|
+
return {
|
|
72
|
+
appearance: {
|
|
73
|
+
foregroundColor: normalized.theme.foreground,
|
|
74
|
+
backgroundColor: normalized.theme.background,
|
|
75
|
+
tintColor: normalized.theme.tint,
|
|
76
|
+
palette: paletteToIndexedMap(normalized.palette.ansi),
|
|
77
|
+
colorSchemeContrast: contrastRatio(normalized.theme.foreground, normalized.theme.background) >= 7 ? "increased" : "standard",
|
|
78
|
+
source: "override"
|
|
79
|
+
},
|
|
80
|
+
theme: { ...normalized.theme }
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function encodeWebHostTerminalRenderStyleBase64(style) {
|
|
84
|
+
return encodeBase64(JSON.stringify(resolveWebHostTerminalRenderStyle(style)));
|
|
85
|
+
}
|
|
86
|
+
function decodeWebHostTerminalRenderStyleBase64(encoded) {
|
|
87
|
+
const json = decodeBase64(encoded);
|
|
88
|
+
if (!json) return;
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(json);
|
|
91
|
+
} catch {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function webTUITerminalBackgroundColor(style) {
|
|
96
|
+
const normalized = normalizeWebHostTerminalStyle(style);
|
|
97
|
+
return hexToRgba(normalized.theme.background, normalized.backgroundOpacity);
|
|
98
|
+
}
|
|
99
|
+
function applyWebHostTerminalStyle(element, style) {
|
|
100
|
+
const normalized = normalizeWebHostTerminalStyle(style);
|
|
101
|
+
element.style.fontFamily = normalized.fontFamily;
|
|
102
|
+
element.style.fontSize = `${normalized.fontSize}px`;
|
|
103
|
+
element.style.background = hexToRgba(normalized.theme.background, normalized.backgroundOpacity);
|
|
104
|
+
element.style.color = normalized.theme.foreground;
|
|
105
|
+
}
|
|
106
|
+
function normalizePalette(input, defaults) {
|
|
107
|
+
return {
|
|
108
|
+
foreground: normalizeHexColor(input?.foreground ?? defaults.foreground),
|
|
109
|
+
background: normalizeHexColor(input?.background ?? defaults.background),
|
|
110
|
+
cursor: normalizeHexColor(input?.cursor ?? defaults.cursor),
|
|
111
|
+
selectionBackground: normalizeHexColor(input?.selectionBackground ?? defaults.selectionBackground),
|
|
112
|
+
selectionForeground: normalizeHexColor(input?.selectionForeground ?? defaults.selectionForeground),
|
|
113
|
+
ansi: normalizeANSI(input?.ansi, defaults.ansi)
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function mergePalette(base, patch) {
|
|
117
|
+
if (!patch) return base;
|
|
118
|
+
return {
|
|
119
|
+
...base,
|
|
120
|
+
...patch,
|
|
121
|
+
ansi: patch.ansi ? {
|
|
122
|
+
...base.ansi,
|
|
123
|
+
...patch.ansi
|
|
124
|
+
} : base.ansi
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function normalizeANSI(input, defaults) {
|
|
128
|
+
return {
|
|
129
|
+
black: normalizeHexColor(input?.black ?? defaults.black),
|
|
130
|
+
red: normalizeHexColor(input?.red ?? defaults.red),
|
|
131
|
+
green: normalizeHexColor(input?.green ?? defaults.green),
|
|
132
|
+
yellow: normalizeHexColor(input?.yellow ?? defaults.yellow),
|
|
133
|
+
blue: normalizeHexColor(input?.blue ?? defaults.blue),
|
|
134
|
+
magenta: normalizeHexColor(input?.magenta ?? defaults.magenta),
|
|
135
|
+
cyan: normalizeHexColor(input?.cyan ?? defaults.cyan),
|
|
136
|
+
white: normalizeHexColor(input?.white ?? defaults.white),
|
|
137
|
+
brightBlack: normalizeHexColor(input?.brightBlack ?? defaults.brightBlack),
|
|
138
|
+
brightRed: normalizeHexColor(input?.brightRed ?? defaults.brightRed),
|
|
139
|
+
brightGreen: normalizeHexColor(input?.brightGreen ?? defaults.brightGreen),
|
|
140
|
+
brightYellow: normalizeHexColor(input?.brightYellow ?? defaults.brightYellow),
|
|
141
|
+
brightBlue: normalizeHexColor(input?.brightBlue ?? defaults.brightBlue),
|
|
142
|
+
brightMagenta: normalizeHexColor(input?.brightMagenta ?? defaults.brightMagenta),
|
|
143
|
+
brightCyan: normalizeHexColor(input?.brightCyan ?? defaults.brightCyan),
|
|
144
|
+
brightWhite: normalizeHexColor(input?.brightWhite ?? defaults.brightWhite)
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function normalizeTheme(input, palette, defaults) {
|
|
148
|
+
const derived = themeFromPalette(palette, defaults);
|
|
149
|
+
return {
|
|
150
|
+
foreground: normalizeHexColor(input?.foreground ?? derived.foreground),
|
|
151
|
+
background: normalizeHexColor(input?.background ?? derived.background),
|
|
152
|
+
tint: normalizeHexColor(input?.tint ?? derived.tint),
|
|
153
|
+
separator: normalizeHexColor(input?.separator ?? derived.separator),
|
|
154
|
+
selection: normalizeHexColor(input?.selection ?? derived.selection),
|
|
155
|
+
placeholder: normalizeHexColor(input?.placeholder ?? derived.placeholder),
|
|
156
|
+
link: normalizeHexColor(input?.link ?? derived.link),
|
|
157
|
+
fill: normalizeHexColor(input?.fill ?? derived.fill),
|
|
158
|
+
windowBackground: normalizeHexColor(input?.windowBackground ?? derived.windowBackground),
|
|
159
|
+
success: normalizeHexColor(input?.success ?? derived.success),
|
|
160
|
+
warning: normalizeHexColor(input?.warning ?? derived.warning),
|
|
161
|
+
danger: normalizeHexColor(input?.danger ?? derived.danger),
|
|
162
|
+
info: normalizeHexColor(input?.info ?? derived.info),
|
|
163
|
+
muted: normalizeHexColor(input?.muted ?? derived.muted)
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function themeFromPalette(palette, defaults) {
|
|
167
|
+
return {
|
|
168
|
+
foreground: palette.foreground,
|
|
169
|
+
background: palette.background,
|
|
170
|
+
tint: palette.cursor,
|
|
171
|
+
separator: palette.ansi.brightBlack,
|
|
172
|
+
selection: palette.selectionBackground,
|
|
173
|
+
placeholder: palette.ansi.brightBlack,
|
|
174
|
+
link: palette.ansi.blue,
|
|
175
|
+
fill: defaults.fill,
|
|
176
|
+
windowBackground: palette.background,
|
|
177
|
+
success: palette.ansi.green,
|
|
178
|
+
warning: palette.ansi.yellow,
|
|
179
|
+
danger: palette.ansi.red,
|
|
180
|
+
info: palette.ansi.cyan,
|
|
181
|
+
muted: palette.ansi.brightBlack
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function paletteToIndexedMap(ansi) {
|
|
185
|
+
return {
|
|
186
|
+
0: ansi.black,
|
|
187
|
+
1: ansi.red,
|
|
188
|
+
2: ansi.green,
|
|
189
|
+
3: ansi.yellow,
|
|
190
|
+
4: ansi.blue,
|
|
191
|
+
5: ansi.magenta,
|
|
192
|
+
6: ansi.cyan,
|
|
193
|
+
7: ansi.white,
|
|
194
|
+
8: ansi.brightBlack,
|
|
195
|
+
9: ansi.brightRed,
|
|
196
|
+
10: ansi.brightGreen,
|
|
197
|
+
11: ansi.brightYellow,
|
|
198
|
+
12: ansi.brightBlue,
|
|
199
|
+
13: ansi.brightMagenta,
|
|
200
|
+
14: ansi.brightCyan,
|
|
201
|
+
15: ansi.brightWhite
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function normalizeFontSize(fontSize) {
|
|
205
|
+
return Number.isFinite(fontSize) && fontSize > 0 ? fontSize : 14;
|
|
206
|
+
}
|
|
207
|
+
function normalizeOpacity(opacity) {
|
|
208
|
+
if (!Number.isFinite(opacity)) return 1;
|
|
209
|
+
return Math.min(1, Math.max(0, opacity));
|
|
210
|
+
}
|
|
211
|
+
function normalizeHexColor(value) {
|
|
212
|
+
const trimmed = value.trim();
|
|
213
|
+
const normalized = trimmed.startsWith("#") ? trimmed : `#${trimmed}`;
|
|
214
|
+
if (!/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(normalized)) throw new Error(`Invalid hex color: ${value}`);
|
|
215
|
+
return normalized.toLowerCase();
|
|
216
|
+
}
|
|
217
|
+
function hexToRgba(color, opacity) {
|
|
218
|
+
const normalized = normalizeHexColor(color);
|
|
219
|
+
const alpha = normalizeOpacity(opacity);
|
|
220
|
+
const channels = parseHexColor(normalized);
|
|
221
|
+
if (!channels) return normalized;
|
|
222
|
+
const finalAlpha = Math.round(channels.alpha * alpha * 1e3) / 1e3;
|
|
223
|
+
return `rgba(${channels.red}, ${channels.green}, ${channels.blue}, ${finalAlpha})`;
|
|
224
|
+
}
|
|
225
|
+
function parseHexColor(color) {
|
|
226
|
+
const hex = color.startsWith("#") ? color.slice(1) : color;
|
|
227
|
+
const normalized = hex.length === 3 || hex.length === 4 ? hex.split("").map((ch) => ch + ch).join("") : hex;
|
|
228
|
+
if (normalized.length !== 6 && normalized.length !== 8) return;
|
|
229
|
+
return {
|
|
230
|
+
red: Number.parseInt(normalized.slice(0, 2), 16),
|
|
231
|
+
green: Number.parseInt(normalized.slice(2, 4), 16),
|
|
232
|
+
blue: Number.parseInt(normalized.slice(4, 6), 16),
|
|
233
|
+
alpha: normalized.length === 8 ? Number.parseInt(normalized.slice(6, 8), 16) / 255 : 1
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function contrastRatio(foreground, background) {
|
|
237
|
+
const fg = relativeLuminance(foreground);
|
|
238
|
+
const bg = relativeLuminance(background);
|
|
239
|
+
const lighter = Math.max(fg, bg);
|
|
240
|
+
const darker = Math.min(fg, bg);
|
|
241
|
+
return (lighter + .05) / (darker + .05);
|
|
242
|
+
}
|
|
243
|
+
function relativeLuminance(color) {
|
|
244
|
+
const channels = parseHexColor(normalizeHexColor(color));
|
|
245
|
+
if (!channels) return 0;
|
|
246
|
+
const toLinear = (channel) => {
|
|
247
|
+
const value = channel / 255;
|
|
248
|
+
return value <= .03928 ? value / 12.92 : ((value + .055) / 1.055) ** 2.4;
|
|
249
|
+
};
|
|
250
|
+
return .2126 * toLinear(channels.red) + .7152 * toLinear(channels.green) + .0722 * toLinear(channels.blue);
|
|
251
|
+
}
|
|
252
|
+
function encodeBase64(value) {
|
|
253
|
+
if (typeof btoa === "function") {
|
|
254
|
+
const bytes = new TextEncoder().encode(value);
|
|
255
|
+
let binary = "";
|
|
256
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
257
|
+
return btoa(binary);
|
|
258
|
+
}
|
|
259
|
+
return Buffer.from(value, "utf8").toString("base64");
|
|
260
|
+
}
|
|
261
|
+
function decodeBase64(value) {
|
|
262
|
+
try {
|
|
263
|
+
if (typeof atob === "function") {
|
|
264
|
+
const binary = atob(value);
|
|
265
|
+
const bytes = new Uint8Array(binary.length);
|
|
266
|
+
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
267
|
+
return new TextDecoder().decode(bytes);
|
|
268
|
+
}
|
|
269
|
+
return Buffer.from(value, "base64").toString("utf8");
|
|
270
|
+
} catch {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
//#endregion
|
|
275
|
+
export { applyWebHostTerminalStyle, decodeWebHostTerminalRenderStyleBase64, encodeWebHostTerminalRenderStyleBase64, mergeWebHostTerminalStyle, normalizeWebHostTerminalStyle, resolveWebHostTerminalRenderStyle, webTUITerminalBackgroundColor };
|
|
276
|
+
|
|
277
|
+
//# sourceMappingURL=WebHostTerminalStyle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebHostTerminalStyle.js","names":[],"sources":["../../src/WebHostTerminalStyle.ts"],"sourcesContent":["export type WebHostTerminalCursorStyle = \"block\" | \"bar\" | \"underline\";\n\nexport interface WebHostANSIColors {\n black?: string;\n red?: string;\n green?: string;\n yellow?: string;\n blue?: string;\n magenta?: string;\n cyan?: string;\n white?: string;\n brightBlack?: string;\n brightRed?: string;\n brightGreen?: string;\n brightYellow?: string;\n brightBlue?: string;\n brightMagenta?: string;\n brightCyan?: string;\n brightWhite?: string;\n}\n\nexport interface WebHostTerminalPalette {\n foreground?: string;\n background?: string;\n cursor?: string;\n selectionBackground?: string;\n selectionForeground?: string;\n ansi?: WebHostANSIColors;\n}\n\nexport interface WebHostTerminalTheme {\n foreground?: string;\n background?: string;\n tint?: string;\n separator?: string;\n selection?: string;\n placeholder?: string;\n link?: string;\n fill?: string;\n windowBackground?: string;\n success?: string;\n warning?: string;\n danger?: string;\n info?: string;\n muted?: string;\n}\n\nexport interface WebHostTerminalStyle {\n fontSize?: number;\n fontFamily?: string;\n cursorStyle?: WebHostTerminalCursorStyle;\n cursorBlink?: boolean;\n backgroundOpacity?: number;\n palette?: WebHostTerminalPalette;\n theme?: WebHostTerminalTheme;\n}\n\nexport interface ResolvedWebHostTerminalPalette {\n foreground: string;\n background: string;\n cursor: string;\n selectionBackground: string;\n selectionForeground: string;\n ansi: Required<WebHostANSIColors>;\n}\n\nexport interface ResolvedWebHostTerminalStyle {\n fontSize: number;\n fontFamily: string;\n cursorStyle: WebHostTerminalCursorStyle;\n cursorBlink: boolean;\n backgroundOpacity: number;\n palette: ResolvedWebHostTerminalPalette;\n theme: Required<WebHostTerminalTheme>;\n}\n\nexport interface WebHostTerminalRenderStyle {\n appearance: WebHostTerminalAppearance;\n theme?: WebHostTerminalTheme;\n}\n\nexport interface WebHostTerminalAppearance {\n foregroundColor: string;\n backgroundColor: string;\n tintColor: string;\n palette: Record<string, string>;\n colorSchemeContrast: \"standard\" | \"increased\";\n source: \"activeQuery\" | \"environmentHeuristics\" | \"fallback\" | \"override\";\n}\n\nconst defaultFontFamily =\n '\"SFMono-Regular\", \"SF Mono\", \"Menlo\", \"Monaco\", \"Consolas\", \"Liberation Mono\", monospace';\n\nconst defaultANSI: Required<WebHostANSIColors> = {\n black: \"#20242c\",\n red: \"#e05757\",\n green: \"#61c67b\",\n yellow: \"#ebb33c\",\n blue: \"#5ba3ff\",\n magenta: \"#b46eff\",\n cyan: \"#56b6c2\",\n white: \"#eceff4\",\n brightBlack: \"#8c92ac\",\n brightRed: \"#ff7b72\",\n brightGreen: \"#7ee787\",\n brightYellow: \"#f2cc60\",\n brightBlue: \"#79c0ff\",\n brightMagenta: \"#d2a8ff\",\n brightCyan: \"#7de2d1\",\n brightWhite: \"#ffffff\",\n};\n\nconst defaultPalette: ResolvedWebHostTerminalPalette = {\n foreground: \"#eceff4\",\n background: \"#1e222a\",\n cursor: \"#56b6c2\",\n selectionBackground: \"#2e3440\",\n selectionForeground: \"#eceff4\",\n ansi: defaultANSI,\n};\n\nconst defaultTheme: Required<WebHostTerminalTheme> = {\n foreground: \"#eceff4\",\n background: \"#1e222a\",\n tint: \"#56b6c2\",\n separator: \"#4c566a\",\n selection: \"#2e3440\",\n placeholder: \"#8c92ac\",\n link: \"#5ba3ff\",\n fill: \"#2b303b\",\n windowBackground: \"#15181e\",\n success: \"#61c67b\",\n warning: \"#ebb33c\",\n danger: \"#e05757\",\n info: \"#56b6c2\",\n muted: \"#8c92ac\",\n};\n\nexport function normalizeWebHostTerminalStyle(\n style: WebHostTerminalStyle = {}\n): ResolvedWebHostTerminalStyle {\n const palette = normalizePalette(style.palette, defaultPalette);\n const theme = normalizeTheme(style.theme, palette, defaultTheme);\n return {\n fontSize: normalizeFontSize(style.fontSize ?? 14),\n fontFamily: style.fontFamily ?? defaultFontFamily,\n cursorStyle: style.cursorStyle ?? \"block\",\n cursorBlink: style.cursorBlink ?? false,\n backgroundOpacity: normalizeOpacity(style.backgroundOpacity ?? 1),\n palette,\n theme,\n };\n}\n\nexport function mergeWebHostTerminalStyle(\n base: WebHostTerminalStyle,\n patch: WebHostTerminalStyle\n): ResolvedWebHostTerminalStyle {\n const resolvedBase = normalizeWebHostTerminalStyle(base);\n return normalizeWebHostTerminalStyle({\n ...resolvedBase,\n ...patch,\n palette: mergePalette(resolvedBase.palette, patch.palette),\n theme: patch.theme ? { ...resolvedBase.theme, ...patch.theme } : resolvedBase.theme,\n });\n}\n\nexport function resolveWebHostTerminalRenderStyle(\n style: WebHostTerminalStyle\n): WebHostTerminalRenderStyle {\n const normalized = normalizeWebHostTerminalStyle(style);\n return {\n appearance: {\n foregroundColor: normalized.theme.foreground,\n backgroundColor: normalized.theme.background,\n tintColor: normalized.theme.tint,\n palette: paletteToIndexedMap(normalized.palette.ansi),\n colorSchemeContrast: contrastRatio(normalized.theme.foreground, normalized.theme.background) >= 7\n ? \"increased\"\n : \"standard\",\n source: \"override\",\n },\n theme: { ...normalized.theme },\n };\n}\n\nexport function encodeWebHostTerminalRenderStyleBase64(\n style: WebHostTerminalStyle\n): string {\n return encodeBase64(JSON.stringify(resolveWebHostTerminalRenderStyle(style)));\n}\n\nexport function decodeWebHostTerminalRenderStyleBase64(\n encoded: string\n): WebHostTerminalRenderStyle | undefined {\n const json = decodeBase64(encoded);\n if (!json) {\n return undefined;\n }\n\n try {\n return JSON.parse(json) as WebHostTerminalRenderStyle;\n } catch {\n return undefined;\n }\n}\n\nexport function webTUITerminalBackgroundColor(\n style: WebHostTerminalStyle\n): string {\n const normalized = normalizeWebHostTerminalStyle(style);\n return hexToRgba(normalized.theme.background, normalized.backgroundOpacity);\n}\n\nexport function applyWebHostTerminalStyle(\n element: HTMLElement,\n style: WebHostTerminalStyle\n): void {\n const normalized = normalizeWebHostTerminalStyle(style);\n element.style.fontFamily = normalized.fontFamily;\n element.style.fontSize = `${normalized.fontSize}px`;\n element.style.background = hexToRgba(normalized.theme.background, normalized.backgroundOpacity);\n element.style.color = normalized.theme.foreground;\n}\n\nfunction normalizePalette(\n input: WebHostTerminalPalette | undefined,\n defaults: ResolvedWebHostTerminalPalette\n): ResolvedWebHostTerminalPalette {\n return {\n foreground: normalizeHexColor(input?.foreground ?? defaults.foreground),\n background: normalizeHexColor(input?.background ?? defaults.background),\n cursor: normalizeHexColor(input?.cursor ?? defaults.cursor),\n selectionBackground: normalizeHexColor(\n input?.selectionBackground ?? defaults.selectionBackground\n ),\n selectionForeground: normalizeHexColor(\n input?.selectionForeground ?? defaults.selectionForeground\n ),\n ansi: normalizeANSI(input?.ansi, defaults.ansi),\n };\n}\n\nfunction mergePalette(\n base: ResolvedWebHostTerminalPalette,\n patch: WebHostTerminalPalette | undefined\n): WebHostTerminalPalette {\n if (!patch) {\n return base;\n }\n\n return {\n ...base,\n ...patch,\n ansi: patch.ansi ? { ...base.ansi, ...patch.ansi } : base.ansi,\n };\n}\n\nfunction normalizeANSI(\n input: WebHostANSIColors | undefined,\n defaults: Required<WebHostANSIColors>\n): Required<WebHostANSIColors> {\n return {\n black: normalizeHexColor(input?.black ?? defaults.black),\n red: normalizeHexColor(input?.red ?? defaults.red),\n green: normalizeHexColor(input?.green ?? defaults.green),\n yellow: normalizeHexColor(input?.yellow ?? defaults.yellow),\n blue: normalizeHexColor(input?.blue ?? defaults.blue),\n magenta: normalizeHexColor(input?.magenta ?? defaults.magenta),\n cyan: normalizeHexColor(input?.cyan ?? defaults.cyan),\n white: normalizeHexColor(input?.white ?? defaults.white),\n brightBlack: normalizeHexColor(input?.brightBlack ?? defaults.brightBlack),\n brightRed: normalizeHexColor(input?.brightRed ?? defaults.brightRed),\n brightGreen: normalizeHexColor(input?.brightGreen ?? defaults.brightGreen),\n brightYellow: normalizeHexColor(input?.brightYellow ?? defaults.brightYellow),\n brightBlue: normalizeHexColor(input?.brightBlue ?? defaults.brightBlue),\n brightMagenta: normalizeHexColor(input?.brightMagenta ?? defaults.brightMagenta),\n brightCyan: normalizeHexColor(input?.brightCyan ?? defaults.brightCyan),\n brightWhite: normalizeHexColor(input?.brightWhite ?? defaults.brightWhite),\n };\n}\n\nfunction normalizeTheme(\n input: WebHostTerminalTheme | undefined,\n palette: ResolvedWebHostTerminalPalette,\n defaults: Required<WebHostTerminalTheme>\n): Required<WebHostTerminalTheme> {\n const derived = themeFromPalette(palette, defaults);\n return {\n foreground: normalizeHexColor(input?.foreground ?? derived.foreground),\n background: normalizeHexColor(input?.background ?? derived.background),\n tint: normalizeHexColor(input?.tint ?? derived.tint),\n separator: normalizeHexColor(input?.separator ?? derived.separator),\n selection: normalizeHexColor(input?.selection ?? derived.selection),\n placeholder: normalizeHexColor(input?.placeholder ?? derived.placeholder),\n link: normalizeHexColor(input?.link ?? derived.link),\n fill: normalizeHexColor(input?.fill ?? derived.fill),\n windowBackground: normalizeHexColor(input?.windowBackground ?? derived.windowBackground),\n success: normalizeHexColor(input?.success ?? derived.success),\n warning: normalizeHexColor(input?.warning ?? derived.warning),\n danger: normalizeHexColor(input?.danger ?? derived.danger),\n info: normalizeHexColor(input?.info ?? derived.info),\n muted: normalizeHexColor(input?.muted ?? derived.muted),\n };\n}\n\nfunction themeFromPalette(\n palette: ResolvedWebHostTerminalPalette,\n defaults: Required<WebHostTerminalTheme>\n): Required<WebHostTerminalTheme> {\n return {\n foreground: palette.foreground,\n background: palette.background,\n tint: palette.cursor,\n separator: palette.ansi.brightBlack,\n selection: palette.selectionBackground,\n placeholder: palette.ansi.brightBlack,\n link: palette.ansi.blue,\n fill: defaults.fill,\n windowBackground: palette.background,\n success: palette.ansi.green,\n warning: palette.ansi.yellow,\n danger: palette.ansi.red,\n info: palette.ansi.cyan,\n muted: palette.ansi.brightBlack,\n };\n}\n\nfunction paletteToIndexedMap(\n ansi: Required<WebHostANSIColors>\n): Record<string, string> {\n return {\n 0: ansi.black,\n 1: ansi.red,\n 2: ansi.green,\n 3: ansi.yellow,\n 4: ansi.blue,\n 5: ansi.magenta,\n 6: ansi.cyan,\n 7: ansi.white,\n 8: ansi.brightBlack,\n 9: ansi.brightRed,\n 10: ansi.brightGreen,\n 11: ansi.brightYellow,\n 12: ansi.brightBlue,\n 13: ansi.brightMagenta,\n 14: ansi.brightCyan,\n 15: ansi.brightWhite,\n };\n}\n\nfunction normalizeFontSize(fontSize: number): number {\n return Number.isFinite(fontSize) && fontSize > 0 ? fontSize : 14;\n}\n\nfunction normalizeOpacity(opacity: number): number {\n if (!Number.isFinite(opacity)) {\n return 1;\n }\n\n return Math.min(1, Math.max(0, opacity));\n}\n\nfunction normalizeHexColor(value: string): string {\n const trimmed = value.trim();\n const normalized = trimmed.startsWith(\"#\") ? trimmed : `#${trimmed}`;\n if (!/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(normalized)) {\n throw new Error(`Invalid hex color: ${value}`);\n }\n\n return normalized.toLowerCase();\n}\n\nfunction hexToRgba(\n color: string,\n opacity: number\n): string {\n const normalized = normalizeHexColor(color);\n const alpha = normalizeOpacity(opacity);\n const channels = parseHexColor(normalized);\n if (!channels) {\n return normalized;\n }\n\n const finalAlpha = Math.round(channels.alpha * alpha * 1000) / 1000;\n return `rgba(${channels.red}, ${channels.green}, ${channels.blue}, ${finalAlpha})`;\n}\n\nfunction parseHexColor(\n color: string\n): {\n red: number;\n green: number;\n blue: number;\n alpha: number;\n} | undefined {\n const hex = color.startsWith(\"#\") ? color.slice(1) : color;\n const normalized = hex.length === 3 || hex.length === 4\n ? hex.split(\"\").map((ch) => ch + ch).join(\"\")\n : hex;\n\n if (normalized.length !== 6 && normalized.length !== 8) {\n return undefined;\n }\n\n const red = Number.parseInt(normalized.slice(0, 2), 16);\n const green = Number.parseInt(normalized.slice(2, 4), 16);\n const blue = Number.parseInt(normalized.slice(4, 6), 16);\n const alpha = normalized.length === 8\n ? Number.parseInt(normalized.slice(6, 8), 16) / 255\n : 1;\n return { red, green, blue, alpha };\n}\n\nfunction contrastRatio(\n foreground: string,\n background: string\n): number {\n const fg = relativeLuminance(foreground);\n const bg = relativeLuminance(background);\n const lighter = Math.max(fg, bg);\n const darker = Math.min(fg, bg);\n return (lighter + 0.05) / (darker + 0.05);\n}\n\nfunction relativeLuminance(color: string): number {\n const channels = parseHexColor(normalizeHexColor(color));\n if (!channels) {\n return 0;\n }\n\n const toLinear = (channel: number) => {\n const value = channel / 255;\n return value <= 0.03928\n ? value / 12.92\n : ((value + 0.055) / 1.055) ** 2.4;\n };\n\n return 0.2126 * toLinear(channels.red) + 0.7152 * toLinear(channels.green)\n + 0.0722 * toLinear(channels.blue);\n}\n\nfunction encodeBase64(value: string): string {\n if (typeof btoa === \"function\") {\n const bytes = new TextEncoder().encode(value);\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary);\n }\n\n return Buffer.from(value, \"utf8\").toString(\"base64\");\n}\n\nfunction decodeBase64(value: string): string | undefined {\n try {\n if (typeof atob === \"function\") {\n const binary = atob(value);\n const bytes = new Uint8Array(binary.length);\n for (let index = 0; index < binary.length; index += 1) {\n bytes[index] = binary.charCodeAt(index);\n }\n return new TextDecoder().decode(bytes);\n }\n\n return Buffer.from(value, \"base64\").toString(\"utf8\");\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
//#region src/WebHostTestFixtures.ts
|
|
3
|
+
function transportFixture(basename) {
|
|
4
|
+
return readFileSync(new URL(`../../../Fixtures/Transport/${basename}.txt`, import.meta.url), "utf8").replaceAll("\\u001E", "");
|
|
5
|
+
}
|
|
6
|
+
//#endregion
|
|
7
|
+
export { transportFixture };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=WebHostTestFixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebHostTestFixtures.js","names":[],"sources":["../../src/WebHostTestFixtures.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\n\nexport function transportFixture(\n basename: string\n): string {\n return readFileSync(\n new URL(`../../../Fixtures/Transport/${basename}.txt`, import.meta.url),\n \"utf8\"\n ).replaceAll(\"\\\\u001E\", \"\\u001E\");\n}\n"],"mappings":";;AAEA,SAAgB,iBACd,UACQ;CACR,OAAO,aACL,IAAI,IAAI,+BAA+B,SAAS,OAAO,OAAO,KAAK,GAAG,GACtE,MACF,CAAC,CAAC,WAAW,WAAW,GAAQ;AAClC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { WebHostTerminalStyle } from "./WebHostTerminalStyle.js";
|
|
2
|
+
import { WebHostOutputSink } from "./WebHostSurfaceTransport.js";
|
|
3
|
+
import { WebHostSceneBridge } from "./WebHostSceneRuntime.js";
|
|
4
|
+
|
|
5
|
+
//#region src/WebSocketSceneBridge.d.ts
|
|
6
|
+
interface WebSocketSceneBridgeOptions {
|
|
7
|
+
sceneId: string;
|
|
8
|
+
token: string;
|
|
9
|
+
baseURL?: string | URL;
|
|
10
|
+
webSocketURL?: string | URL;
|
|
11
|
+
webSocketFactory?: WebSocketSceneBridgeFactory;
|
|
12
|
+
}
|
|
13
|
+
type WebSocketSceneBridgeFactory = (url: string | URL) => WebSocketSceneSocket;
|
|
14
|
+
interface WebSocketSceneSocket {
|
|
15
|
+
binaryType: BinaryType;
|
|
16
|
+
readonly readyState: number;
|
|
17
|
+
send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;
|
|
18
|
+
close(code?: number, reason?: string): void;
|
|
19
|
+
addEventListener(type: "open", listener: (event: Event) => void): void;
|
|
20
|
+
addEventListener(type: "message", listener: (event: MessageEvent) => void): void;
|
|
21
|
+
addEventListener(type: "close", listener: (event: CloseEvent) => void): void;
|
|
22
|
+
addEventListener(type: "error", listener: (event: Event) => void): void;
|
|
23
|
+
removeEventListener(type: "open", listener: (event: Event) => void): void;
|
|
24
|
+
removeEventListener(type: "message", listener: (event: MessageEvent) => void): void;
|
|
25
|
+
removeEventListener(type: "close", listener: (event: CloseEvent) => void): void;
|
|
26
|
+
removeEventListener(type: "error", listener: (event: Event) => void): void;
|
|
27
|
+
}
|
|
28
|
+
declare class WebSocketSceneBridge implements WebHostSceneBridge {
|
|
29
|
+
readonly url: URL;
|
|
30
|
+
private readonly socket;
|
|
31
|
+
private readonly decoder;
|
|
32
|
+
private readonly queuedInput;
|
|
33
|
+
private readonly queuedOutput;
|
|
34
|
+
private sink?;
|
|
35
|
+
private disposed;
|
|
36
|
+
private readonly handleOpen;
|
|
37
|
+
private readonly handleMessage;
|
|
38
|
+
private readonly handleClose;
|
|
39
|
+
private readonly handleError;
|
|
40
|
+
constructor(options: WebSocketSceneBridgeOptions);
|
|
41
|
+
bindOutput(sink: WebHostOutputSink): void;
|
|
42
|
+
resize(columns: number, rows: number, cellWidth?: number, cellHeight?: number): void;
|
|
43
|
+
updateRenderStyle(style: WebHostTerminalStyle): void;
|
|
44
|
+
sendInput(chunk: Uint8Array): void;
|
|
45
|
+
dispose(): void;
|
|
46
|
+
private receive;
|
|
47
|
+
private deliver;
|
|
48
|
+
private flushQueuedInput;
|
|
49
|
+
}
|
|
50
|
+
declare function webSocketSceneURL(options: Pick<WebSocketSceneBridgeOptions, "baseURL" | "webSocketURL" | "sceneId" | "token">): URL;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { WebSocketSceneBridge, WebSocketSceneBridgeFactory, WebSocketSceneBridgeOptions, WebSocketSceneSocket, webSocketSceneURL };
|
|
53
|
+
//# sourceMappingURL=WebSocketSceneBridge.d.ts.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { WebHostOutputDecoder, encodeRenderStyleControlMessage, encodeResizeControlMessage } from "./WebHostSurfaceTransport.js";
|
|
2
|
+
//#region src/WebSocketSceneBridge.ts
|
|
3
|
+
const socketOpenState = 1;
|
|
4
|
+
const textEncoder = new TextEncoder();
|
|
5
|
+
var WebSocketSceneBridge = class {
|
|
6
|
+
url;
|
|
7
|
+
socket;
|
|
8
|
+
decoder = new WebHostOutputDecoder();
|
|
9
|
+
queuedInput = [];
|
|
10
|
+
queuedOutput = [];
|
|
11
|
+
sink;
|
|
12
|
+
disposed = false;
|
|
13
|
+
handleOpen = () => {
|
|
14
|
+
this.flushQueuedInput();
|
|
15
|
+
};
|
|
16
|
+
handleMessage = (event) => {
|
|
17
|
+
this.receive(event.data);
|
|
18
|
+
};
|
|
19
|
+
handleClose = () => {
|
|
20
|
+
for (const record of this.decoder.flush()) this.deliver(record);
|
|
21
|
+
};
|
|
22
|
+
handleError = () => {};
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.url = webSocketSceneURL(options);
|
|
25
|
+
this.socket = (options.webSocketFactory ?? defaultWebSocketFactory)(this.url);
|
|
26
|
+
this.socket.binaryType = "arraybuffer";
|
|
27
|
+
this.socket.addEventListener("open", this.handleOpen);
|
|
28
|
+
this.socket.addEventListener("message", this.handleMessage);
|
|
29
|
+
this.socket.addEventListener("close", this.handleClose);
|
|
30
|
+
this.socket.addEventListener("error", this.handleError);
|
|
31
|
+
}
|
|
32
|
+
bindOutput(sink) {
|
|
33
|
+
this.sink = sink;
|
|
34
|
+
while (this.queuedOutput.length > 0) this.deliver(this.queuedOutput.shift());
|
|
35
|
+
}
|
|
36
|
+
resize(columns, rows, cellWidth, cellHeight) {
|
|
37
|
+
this.sendInput(encodeResizeControlMessage(columns, rows, cellWidth, cellHeight));
|
|
38
|
+
}
|
|
39
|
+
updateRenderStyle(style) {
|
|
40
|
+
this.sendInput(encodeRenderStyleControlMessage(style));
|
|
41
|
+
}
|
|
42
|
+
sendInput(chunk) {
|
|
43
|
+
if (this.disposed) return;
|
|
44
|
+
const copy = new Uint8Array(chunk);
|
|
45
|
+
if (this.socket.readyState === socketOpenState) this.socket.send(copy);
|
|
46
|
+
else this.queuedInput.push(copy);
|
|
47
|
+
}
|
|
48
|
+
dispose() {
|
|
49
|
+
if (this.disposed) return;
|
|
50
|
+
this.disposed = true;
|
|
51
|
+
this.socket.removeEventListener("open", this.handleOpen);
|
|
52
|
+
this.socket.removeEventListener("message", this.handleMessage);
|
|
53
|
+
this.socket.removeEventListener("close", this.handleClose);
|
|
54
|
+
this.socket.removeEventListener("error", this.handleError);
|
|
55
|
+
this.queuedInput.length = 0;
|
|
56
|
+
this.queuedOutput.length = 0;
|
|
57
|
+
this.socket.close(1e3, "WebHost scene disposed");
|
|
58
|
+
}
|
|
59
|
+
async receive(message) {
|
|
60
|
+
if (this.disposed) return;
|
|
61
|
+
const bytes = await bytesFromWebSocketMessage(message);
|
|
62
|
+
if (!bytes) return;
|
|
63
|
+
for (const record of this.decoder.feed(bytes)) this.deliver(record);
|
|
64
|
+
}
|
|
65
|
+
deliver(record) {
|
|
66
|
+
const sink = this.sink;
|
|
67
|
+
if (!sink) {
|
|
68
|
+
this.queuedOutput.push(record);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
switch (record.type) {
|
|
72
|
+
case "surface":
|
|
73
|
+
sink.presentSurface(record.frame);
|
|
74
|
+
break;
|
|
75
|
+
case "clipboard":
|
|
76
|
+
sink.writeClipboard?.(record.text);
|
|
77
|
+
break;
|
|
78
|
+
case "runtimeIssue":
|
|
79
|
+
sink.notifyRuntimeIssue?.(record.issue);
|
|
80
|
+
break;
|
|
81
|
+
case "frameDiagnostic":
|
|
82
|
+
sink.recordFrameDiagnostic?.(record.diagnostic);
|
|
83
|
+
break;
|
|
84
|
+
case "text":
|
|
85
|
+
sink.writeOutput?.(record.text);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
flushQueuedInput() {
|
|
90
|
+
if (this.disposed || this.socket.readyState !== socketOpenState) return;
|
|
91
|
+
while (this.queuedInput.length > 0) this.socket.send(this.queuedInput.shift());
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
function webSocketSceneURL(options) {
|
|
95
|
+
if (options.webSocketURL) {
|
|
96
|
+
const explicit = new URL(String(options.webSocketURL), currentPageURL());
|
|
97
|
+
explicit.searchParams.set("token", options.token);
|
|
98
|
+
return explicit;
|
|
99
|
+
}
|
|
100
|
+
const url = new URL(String(options.baseURL ?? currentPageURL()), currentPageURL());
|
|
101
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
102
|
+
url.pathname = `${url.pathname.endsWith("/") ? url.pathname.slice(0, -1) : url.pathname}/ws/scene/${encodeURIComponent(options.sceneId)}`;
|
|
103
|
+
url.search = "";
|
|
104
|
+
url.searchParams.set("token", options.token);
|
|
105
|
+
return url;
|
|
106
|
+
}
|
|
107
|
+
async function bytesFromWebSocketMessage(message) {
|
|
108
|
+
if (typeof message === "string") return textEncoder.encode(message);
|
|
109
|
+
if (message instanceof Uint8Array) return message;
|
|
110
|
+
if (message instanceof ArrayBuffer) return new Uint8Array(message);
|
|
111
|
+
if (ArrayBuffer.isView(message)) return new Uint8Array(message.buffer, message.byteOffset, message.byteLength);
|
|
112
|
+
if (typeof Blob !== "undefined" && message instanceof Blob) return new Uint8Array(await message.arrayBuffer());
|
|
113
|
+
}
|
|
114
|
+
function defaultWebSocketFactory(url) {
|
|
115
|
+
if (typeof WebSocket === "undefined") throw new Error("WebSocket is not available");
|
|
116
|
+
return new WebSocket(url);
|
|
117
|
+
}
|
|
118
|
+
function currentPageURL() {
|
|
119
|
+
return globalThis.location?.href ?? "http://127.0.0.1/";
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { WebSocketSceneBridge, webSocketSceneURL };
|
|
123
|
+
|
|
124
|
+
//# sourceMappingURL=WebSocketSceneBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebSocketSceneBridge.js","names":[],"sources":["../../src/WebSocketSceneBridge.ts"],"sourcesContent":["import {\n WebHostOutputDecoder,\n encodeRenderStyleControlMessage,\n encodeResizeControlMessage,\n type WebHostOutputRecord,\n type WebHostOutputSink,\n} from \"./WebHostSurfaceTransport.ts\";\nimport type { WebHostTerminalStyle } from \"./WebHostTerminalStyle.ts\";\nimport type { WebHostSceneBridge } from \"./WebHostSceneRuntime.ts\";\n\nexport interface WebSocketSceneBridgeOptions {\n sceneId: string;\n token: string;\n baseURL?: string | URL;\n webSocketURL?: string | URL;\n webSocketFactory?: WebSocketSceneBridgeFactory;\n}\n\nexport type WebSocketSceneBridgeFactory = (url: string | URL) => WebSocketSceneSocket;\n\nexport interface WebSocketSceneSocket {\n binaryType: BinaryType;\n readonly readyState: number;\n send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;\n close(code?: number, reason?: string): void;\n addEventListener(type: \"open\", listener: (event: Event) => void): void;\n addEventListener(type: \"message\", listener: (event: MessageEvent) => void): void;\n addEventListener(type: \"close\", listener: (event: CloseEvent) => void): void;\n addEventListener(type: \"error\", listener: (event: Event) => void): void;\n removeEventListener(type: \"open\", listener: (event: Event) => void): void;\n removeEventListener(type: \"message\", listener: (event: MessageEvent) => void): void;\n removeEventListener(type: \"close\", listener: (event: CloseEvent) => void): void;\n removeEventListener(type: \"error\", listener: (event: Event) => void): void;\n}\n\nconst socketOpenState = 1;\nconst textEncoder = new TextEncoder();\n\nexport class WebSocketSceneBridge implements WebHostSceneBridge {\n readonly url: URL;\n\n private readonly socket: WebSocketSceneSocket;\n private readonly decoder = new WebHostOutputDecoder();\n private readonly queuedInput: Uint8Array[] = [];\n private readonly queuedOutput: WebHostOutputRecord[] = [];\n private sink?: WebHostOutputSink;\n private disposed = false;\n\n private readonly handleOpen = () => {\n this.flushQueuedInput();\n };\n\n private readonly handleMessage = (event: MessageEvent) => {\n void this.receive(event.data);\n };\n\n private readonly handleClose = () => {\n for (const record of this.decoder.flush()) {\n this.deliver(record);\n }\n };\n\n private readonly handleError = () => {};\n\n constructor(options: WebSocketSceneBridgeOptions) {\n this.url = webSocketSceneURL(options);\n this.socket = (options.webSocketFactory ?? defaultWebSocketFactory)(this.url);\n this.socket.binaryType = \"arraybuffer\";\n this.socket.addEventListener(\"open\", this.handleOpen);\n this.socket.addEventListener(\"message\", this.handleMessage);\n this.socket.addEventListener(\"close\", this.handleClose);\n this.socket.addEventListener(\"error\", this.handleError);\n }\n\n bindOutput(\n sink: WebHostOutputSink\n ): void {\n this.sink = sink;\n while (this.queuedOutput.length > 0) {\n this.deliver(this.queuedOutput.shift()!);\n }\n }\n\n resize(\n columns: number,\n rows: number,\n cellWidth?: number,\n cellHeight?: number\n ): void {\n this.sendInput(encodeResizeControlMessage(columns, rows, cellWidth, cellHeight));\n }\n\n updateRenderStyle(\n style: WebHostTerminalStyle\n ): void {\n this.sendInput(encodeRenderStyleControlMessage(style));\n }\n\n sendInput(\n chunk: Uint8Array\n ): void {\n if (this.disposed) {\n return;\n }\n\n const copy = new Uint8Array(chunk);\n if (this.socket.readyState === socketOpenState) {\n this.socket.send(copy);\n } else {\n this.queuedInput.push(copy);\n }\n }\n\n dispose(): void {\n if (this.disposed) {\n return;\n }\n this.disposed = true;\n this.socket.removeEventListener(\"open\", this.handleOpen);\n this.socket.removeEventListener(\"message\", this.handleMessage);\n this.socket.removeEventListener(\"close\", this.handleClose);\n this.socket.removeEventListener(\"error\", this.handleError);\n this.queuedInput.length = 0;\n this.queuedOutput.length = 0;\n this.socket.close(1000, \"WebHost scene disposed\");\n }\n\n private async receive(\n message: unknown\n ): Promise<void> {\n if (this.disposed) {\n return;\n }\n\n const bytes = await bytesFromWebSocketMessage(message);\n if (!bytes) {\n return;\n }\n\n for (const record of this.decoder.feed(bytes)) {\n this.deliver(record);\n }\n }\n\n private deliver(\n record: WebHostOutputRecord\n ): void {\n const sink = this.sink;\n if (!sink) {\n this.queuedOutput.push(record);\n return;\n }\n\n switch (record.type) {\n case \"surface\":\n sink.presentSurface(record.frame);\n break;\n case \"clipboard\":\n void sink.writeClipboard?.(record.text);\n break;\n case \"runtimeIssue\":\n sink.notifyRuntimeIssue?.(record.issue);\n break;\n case \"frameDiagnostic\":\n sink.recordFrameDiagnostic?.(record.diagnostic);\n break;\n case \"text\":\n sink.writeOutput?.(record.text);\n break;\n }\n }\n\n private flushQueuedInput(): void {\n if (this.disposed || this.socket.readyState !== socketOpenState) {\n return;\n }\n while (this.queuedInput.length > 0) {\n this.socket.send(this.queuedInput.shift()!);\n }\n }\n}\n\nexport function webSocketSceneURL(\n options: Pick<WebSocketSceneBridgeOptions, \"baseURL\" | \"webSocketURL\" | \"sceneId\" | \"token\">\n): URL {\n if (options.webSocketURL) {\n const explicit = new URL(String(options.webSocketURL), currentPageURL());\n explicit.searchParams.set(\"token\", options.token);\n return explicit;\n }\n\n const url = new URL(String(options.baseURL ?? currentPageURL()), currentPageURL());\n url.protocol = url.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const basePath = url.pathname.endsWith(\"/\") ? url.pathname.slice(0, -1) : url.pathname;\n url.pathname = `${basePath}/ws/scene/${encodeURIComponent(options.sceneId)}`;\n url.search = \"\";\n url.searchParams.set(\"token\", options.token);\n return url;\n}\n\nasync function bytesFromWebSocketMessage(\n message: unknown\n): Promise<Uint8Array | undefined> {\n if (typeof message === \"string\") {\n return textEncoder.encode(message);\n }\n if (message instanceof Uint8Array) {\n return message;\n }\n if (message instanceof ArrayBuffer) {\n return new Uint8Array(message);\n }\n if (ArrayBuffer.isView(message)) {\n return new Uint8Array(message.buffer, message.byteOffset, message.byteLength);\n }\n if (typeof Blob !== \"undefined\" && message instanceof Blob) {\n return new Uint8Array(await message.arrayBuffer());\n }\n return undefined;\n}\n\nfunction defaultWebSocketFactory(\n url: string | URL\n): WebSocketSceneSocket {\n if (typeof WebSocket === \"undefined\") {\n throw new Error(\"WebSocket is not available\");\n }\n return new WebSocket(url) as WebSocketSceneSocket;\n}\n\nfunction currentPageURL(): string {\n return globalThis.location?.href ?? \"http://127.0.0.1/\";\n}\n"],"mappings":"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"}
|