@stencil/dev-server 0.0.19-0 → 5.0.0-next.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.
@@ -0,0 +1,1050 @@
1
+ //#region src/client/constants.ts
2
+ /**
3
+ * Client-side constants for dev server.
4
+ */
5
+ const DEV_SERVER_URL = "/~dev-server";
6
+ const DEV_SERVER_INIT_URL = `${DEV_SERVER_URL}-init`;
7
+ const OPEN_IN_EDITOR_URL = `${DEV_SERVER_URL}-open-in-editor`;
8
+ const BUILD_LOG = "devserver:buildlog";
9
+ const BUILD_RESULTS = "devserver:buildresults";
10
+ const BUILD_STATUS = "devserver:buildstatus";
11
+ const NODE_TYPE_ELEMENT = 1;
12
+ const NODE_TYPE_DOCUMENT_FRAGMENT = 11;
13
+ const RECONNECT_ATTEMPTS = 1e3;
14
+ const RECONNECT_RETRY_MS = 2500;
15
+ const NORMAL_CLOSURE_CODE = 1e3;
16
+ const REQUEST_BUILD_RESULTS_INTERVAL_MS = 500;
17
+
18
+ //#endregion
19
+ //#region src/client/events.ts
20
+ /**
21
+ * Client-side event system for dev server.
22
+ */
23
+ const emitBuildLog = (win, buildLog) => {
24
+ win.dispatchEvent(new CustomEvent(BUILD_LOG, { detail: buildLog }));
25
+ };
26
+ const emitBuildResults = (win, buildResults) => {
27
+ win.dispatchEvent(new CustomEvent(BUILD_RESULTS, { detail: buildResults }));
28
+ };
29
+ const emitBuildStatus = (win, buildStatus) => {
30
+ win.dispatchEvent(new CustomEvent(BUILD_STATUS, { detail: buildStatus }));
31
+ };
32
+ const onBuildLog = (win, cb) => {
33
+ win.addEventListener(BUILD_LOG, ((ev) => {
34
+ cb(ev.detail);
35
+ }));
36
+ };
37
+ const onBuildResults = (win, cb) => {
38
+ win.addEventListener(BUILD_RESULTS, ((ev) => {
39
+ cb(ev.detail);
40
+ }));
41
+ };
42
+ const onBuildStatus = (win, cb) => {
43
+ win.addEventListener(BUILD_STATUS, ((ev) => {
44
+ cb(ev.detail);
45
+ }));
46
+ };
47
+
48
+ //#endregion
49
+ //#region ../../node_modules/.pnpm/style-inject@0.3.0/node_modules/style-inject/dist/style-inject.es.js
50
+ function styleInject(css, ref) {
51
+ if (ref === void 0) ref = {};
52
+ var insertAt = ref.insertAt;
53
+ if (!css || typeof document === "undefined") return;
54
+ var head = document.head || document.getElementsByTagName("head")[0];
55
+ var style = document.createElement("style");
56
+ style.type = "text/css";
57
+ if (insertAt === "top") if (head.firstChild) head.insertBefore(style, head.firstChild);
58
+ else head.appendChild(style);
59
+ else head.appendChild(style);
60
+ if (style.styleSheet) style.styleSheet.cssText = css;
61
+ else style.appendChild(document.createTextNode(css));
62
+ }
63
+
64
+ //#endregion
65
+ //#region src/client/error.css
66
+ var css_248z = "#dev-server-modal * {\n box-sizing: border-box !important;\n}\n\n/* Backdrop overlay */\n#dev-server-modal {\n direction: ltr !important;\n display: block;\n position: fixed !important;\n top: 0 !important;\n left: 0 !important;\n width: 100% !important;\n height: 100% !important;\n z-index: 99999 !important;\n margin: 0 !important;\n padding: 0 !important;\n background: rgba(0, 0, 0, 0.66) !important;\n overflow-y: auto !important;\n -webkit-overflow-scrolling: touch !important;\n font-family: -apple-system, 'Roboto', BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol' !important;\n font-size: 14px !important;\n line-height: 1.5 !important;\n -webkit-font-smoothing: antialiased;\n text-rendering: optimizeLegibility;\n text-size-adjust: none;\n word-wrap: break-word;\n user-select: auto;\n}\n\n/* Modal window */\n#dev-server-modal-inner {\n position: relative !important;\n max-width: 80vw !important;\n margin: 30px auto !important;\n padding: 25px !important;\n background-color: white !important;\n border-radius: 8px !important;\n box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5) !important;\n color: #333 !important;\n}\n\n.dev-server-diagnostic {\n margin: 20px !important;\n border: 1px solid #ddd !important;\n border-radius: 3px !important;\n}\n\n.dev-server-diagnostic-masthead {\n padding: 8px 12px 12px 12px !important;\n}\n\n.dev-server-diagnostic-title {\n margin: 0 !important;\n font-weight: bold !important;\n color: #222 !important;\n}\n\n.dev-server-diagnostic-message {\n margin-top: 4px !important;\n color: #555 !important;\n}\n\n.dev-server-diagnostic-file {\n position: relative !important;\n border-top: 1px solid #ddd !important;\n}\n\n.dev-server-diagnostic-file-header {\n display: block !important;\n padding: 5px 10px !important;\n color: #555 !important;\n border-bottom: 1px solid #ddd !important;\n border-top-left-radius: 2px !important;\n border-top-right-radius: 2px !important;\n background-color: #f9f9f9 !important;\n font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;\n font-size: 12px !important;\n}\n\na.dev-server-diagnostic-file-header {\n color: #0000ee !important;\n text-decoration: underline !important;\n}\n\na.dev-server-diagnostic-file-header:hover {\n text-decoration: none !important;\n background-color: #f4f4f4 !important;\n}\n\n.dev-server-diagnostic-file-name {\n font-weight: bold !important;\n}\n\n.dev-server-diagnostic-blob {\n overflow-x: auto !important;\n overflow-y: hidden !important;\n border-bottom-right-radius: 3px !important;\n border-bottom-left-radius: 3px !important;\n}\n\n.dev-server-diagnostic-table {\n margin: 0 !important;\n padding: 0 !important;\n border-spacing: 0 !important;\n border-collapse: collapse !important;\n border-width: 0 !important;\n border-style: none !important;\n -moz-tab-size: 2;\n tab-size: 2;\n}\n\n.dev-server-diagnostic-table td,\n.dev-server-diagnostic-table th {\n padding: 0 !important;\n border-width: 0 !important;\n border-style: none !important;\n}\n\ntd.dev-server-diagnostic-blob-num {\n padding-right: 10px !important;\n padding-left: 10px !important;\n width: 1% !important;\n min-width: 50px !important;\n font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;\n font-size: 12px !important;\n line-height: 20px !important;\n color: rgba(0, 0, 0, 0.3) !important;\n text-align: right !important;\n white-space: nowrap !important;\n vertical-align: top !important;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n border: solid #eee !important;\n border-width: 0 1px 0 0 !important;\n}\n\ntd.dev-server-diagnostic-blob-num::before {\n content: attr(data-line-number) !important;\n}\n\n.dev-server-diagnostic-error-line td.dev-server-diagnostic-blob-num {\n background-color: #ffdddd !important;\n border-color: #ffc9c9 !important;\n}\n\n.dev-server-diagnostic-error-line td.dev-server-diagnostic-blob-code {\n background: rgba(255, 221, 221, 0.25) !important;\n z-index: -1;\n}\n\n.dev-server-diagnostic-open-in-editor td.dev-server-diagnostic-blob-num:hover {\n cursor: pointer;\n background-color: #ffffe3 !important;\n font-weight: bold;\n}\n\n.dev-server-diagnostic-open-in-editor.dev-server-diagnostic-error-line td.dev-server-diagnostic-blob-num:hover {\n background-color: #ffdada !important;\n}\n\ntd.dev-server-diagnostic-blob-code {\n position: relative !important;\n padding-right: 10px !important;\n padding-left: 10px !important;\n line-height: 20px !important;\n vertical-align: top !important;\n overflow: visible !important;\n font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace !important;\n font-size: 12px !important;\n color: #333 !important;\n word-wrap: normal !important;\n white-space: pre !important;\n}\n\ntd.dev-server-diagnostic-blob-code::before {\n content: '' !important;\n}\n\n.dev-server-diagnostic-error-chr {\n position: relative !important;\n}\n\n.dev-server-diagnostic-error-chr::before {\n position: absolute !important;\n z-index: -1;\n top: -3px !important;\n left: 0px !important;\n width: 8px !important;\n height: 20px !important;\n background-color: #ffdddd !important;\n content: '' !important;\n}\n\n/**\n * GitHub Gist Theme\n * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro\n * https://highlightjs.org/\n */\n.hljs-comment,\n.hljs-meta {\n color: #969896;\n}\n\n.hljs-string,\n.hljs-variable,\n.hljs-template-variable,\n.hljs-strong,\n.hljs-emphasis,\n.hljs-quote {\n color: #df5000;\n}\n\n.hljs-keyword,\n.hljs-selector-tag,\n.hljs-type {\n color: #a71d5d;\n}\n\n.hljs-literal,\n.hljs-symbol,\n.hljs-bullet,\n.hljs-attribute {\n color: #0086b3;\n}\n\n.hljs-section,\n.hljs-name {\n color: #63a35c;\n}\n\n.hljs-tag {\n color: #333333;\n}\n\n.hljs-title,\n.hljs-attr,\n.hljs-selector-id,\n.hljs-selector-class,\n.hljs-selector-attr,\n.hljs-selector-pseudo {\n color: #795da3;\n}\n\n.hljs-addition {\n color: #55a532;\n background-color: #eaffea;\n}\n\n.hljs-deletion {\n color: #bd2c00;\n background-color: #ffecec;\n}\n\n.hljs-link {\n text-decoration: underline;\n}\n\n/* Error badge - bottom left corner indicator */\n.dev-server-error-badge {\n position: fixed !important;\n bottom: 20px !important;\n left: 20px !important;\n z-index: 99998 !important;\n display: flex !important;\n align-items: center !important;\n gap: 8px !important;\n padding: 10px 16px !important;\n background: #ff5555 !important;\n color: white !important;\n border: none !important;\n border-radius: 8px !important;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica Neue', sans-serif !important;\n font-size: 14px !important;\n font-weight: 600 !important;\n cursor: pointer !important;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;\n transition: transform 0.2s, box-shadow 0.2s !important;\n}\n\n.dev-server-error-badge:hover {\n transform: translateY(-2px) !important;\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4) !important;\n}\n\n.error-badge-icon {\n display: flex !important;\n align-items: center !important;\n justify-content: center !important;\n width: 20px !important;\n height: 20px !important;\n background: white !important;\n color: #ff5555 !important;\n border-radius: 50% !important;\n font-weight: bold !important;\n font-size: 14px !important;\n}\n\n.error-badge-count {\n font-size: 14px !important;\n font-weight: 600 !important;\n}\n";
67
+ styleInject(css_248z);
68
+
69
+ //#endregion
70
+ //#region src/client/error.ts
71
+ let errorCount = 0;
72
+ const appError = (data) => {
73
+ const results = {
74
+ diagnostics: [],
75
+ status: null
76
+ };
77
+ if (data && data.window && Array.isArray(data.buildResults.diagnostics)) {
78
+ const diagnostics = data.buildResults.diagnostics.filter((diagnostic) => diagnostic.level === "error");
79
+ if (diagnostics.length > 0) {
80
+ errorCount = diagnostics.length;
81
+ const modal = getDevServerModal(data.window.document, data.openInEditor);
82
+ diagnostics.forEach((diagnostic) => {
83
+ results.diagnostics.push(diagnostic);
84
+ appendDiagnostic(data.window.document, data.openInEditor, modal, diagnostic);
85
+ });
86
+ removeErrorBadge(data.window.document);
87
+ results.status = "error";
88
+ }
89
+ }
90
+ return results;
91
+ };
92
+ const appendDiagnostic = (doc, openInEditor, modal, diagnostic) => {
93
+ const card = doc.createElement("div");
94
+ card.className = "dev-server-diagnostic";
95
+ const masthead = doc.createElement("div");
96
+ masthead.className = "dev-server-diagnostic-masthead";
97
+ masthead.title = `${escapeHtml(diagnostic.type)} error: ${escapeHtml(diagnostic.code ?? "unknown error")}`;
98
+ card.appendChild(masthead);
99
+ const title = doc.createElement("div");
100
+ title.className = "dev-server-diagnostic-title";
101
+ if (typeof diagnostic.header === "string" && diagnostic.header.trim().length > 0) title.textContent = diagnostic.header;
102
+ else title.textContent = `${titleCase(diagnostic.type)} ${titleCase(diagnostic.level)}`;
103
+ masthead.appendChild(title);
104
+ const message = doc.createElement("div");
105
+ message.className = "dev-server-diagnostic-message";
106
+ message.textContent = diagnostic.messageText;
107
+ masthead.appendChild(message);
108
+ const file = doc.createElement("div");
109
+ file.className = "dev-server-diagnostic-file";
110
+ card.appendChild(file);
111
+ const isUrl = typeof diagnostic.absFilePath === "string" && diagnostic.absFilePath.indexOf("http") === 0;
112
+ const canOpenInEditor = typeof openInEditor === "function" && typeof diagnostic.absFilePath === "string" && !isUrl;
113
+ if (isUrl) {
114
+ const fileHeader = doc.createElement("a");
115
+ fileHeader.href = diagnostic.absFilePath ?? "";
116
+ fileHeader.setAttribute("target", "_blank");
117
+ fileHeader.setAttribute("rel", "noopener noreferrer");
118
+ fileHeader.className = "dev-server-diagnostic-file-header";
119
+ const filePath = doc.createElement("span");
120
+ filePath.className = "dev-server-diagnostic-file-path";
121
+ filePath.textContent = diagnostic.absFilePath ?? "";
122
+ fileHeader.appendChild(filePath);
123
+ file.appendChild(fileHeader);
124
+ } else if (diagnostic.relFilePath) {
125
+ const fileHeader = doc.createElement(canOpenInEditor ? "a" : "div");
126
+ fileHeader.className = "dev-server-diagnostic-file-header";
127
+ if (diagnostic.absFilePath) {
128
+ fileHeader.title = escapeHtml(diagnostic.absFilePath);
129
+ if (canOpenInEditor) addOpenInEditor(openInEditor, fileHeader, diagnostic.absFilePath, diagnostic.lineNumber, diagnostic.columnNumber);
130
+ }
131
+ const parts = diagnostic.relFilePath.split("/");
132
+ const fileName = doc.createElement("span");
133
+ fileName.className = "dev-server-diagnostic-file-name";
134
+ fileName.textContent = parts.pop() ?? "";
135
+ const filePath = doc.createElement("span");
136
+ filePath.className = "dev-server-diagnostic-file-path";
137
+ filePath.textContent = parts.join("/") + "/";
138
+ fileHeader.appendChild(filePath);
139
+ fileHeader.appendChild(fileName);
140
+ file.appendChild(fileHeader);
141
+ }
142
+ if (diagnostic.lines && diagnostic.lines.length > 0) {
143
+ const blob = doc.createElement("div");
144
+ blob.className = "dev-server-diagnostic-blob";
145
+ file.appendChild(blob);
146
+ const table = doc.createElement("table");
147
+ table.className = "dev-server-diagnostic-table";
148
+ blob.appendChild(table);
149
+ prepareLines(diagnostic.lines).forEach((l) => {
150
+ const tr = doc.createElement("tr");
151
+ if (l.errorCharStart > 0) tr.classList.add("dev-server-diagnostic-error-line");
152
+ if (canOpenInEditor) tr.classList.add("dev-server-diagnostic-open-in-editor");
153
+ table.appendChild(tr);
154
+ const tdNum = doc.createElement("td");
155
+ tdNum.className = "dev-server-diagnostic-blob-num";
156
+ if (l.lineNumber > 0) {
157
+ tdNum.setAttribute("data-line-number", l.lineNumber + "");
158
+ tdNum.title = escapeHtml(diagnostic.relFilePath ?? "") + ", line " + l.lineNumber;
159
+ const maybeFile = diagnostic.absFilePath;
160
+ if (canOpenInEditor && maybeFile) {
161
+ const column = l.lineNumber === diagnostic.lineNumber ? diagnostic.columnNumber : 1;
162
+ addOpenInEditor(openInEditor, tdNum, maybeFile, l.lineNumber, column);
163
+ }
164
+ }
165
+ tr.appendChild(tdNum);
166
+ const tdCode = doc.createElement("td");
167
+ tdCode.className = "dev-server-diagnostic-blob-code";
168
+ tdCode.innerHTML = highlightError(l.text ?? "", l.errorCharStart, l.errorLength ?? 0);
169
+ tr.appendChild(tdCode);
170
+ });
171
+ }
172
+ modal.appendChild(card);
173
+ };
174
+ const addOpenInEditor = (openInEditor, elm, file, line, column) => {
175
+ if (elm.tagName === "A") elm.href = "#open-in-editor";
176
+ const lineNumber = typeof line !== "number" || line < 1 ? 1 : line;
177
+ const columnNumber = typeof column !== "number" || column < 1 ? 1 : column;
178
+ elm.addEventListener("click", (ev) => {
179
+ ev.preventDefault();
180
+ ev.stopPropagation();
181
+ openInEditor({
182
+ file,
183
+ line: lineNumber,
184
+ column: columnNumber
185
+ });
186
+ });
187
+ };
188
+ const getDevServerModal = (doc, _openInEditor) => {
189
+ let outer = doc.getElementById(DEV_SERVER_MODAL);
190
+ let isNewModal = false;
191
+ if (!outer) {
192
+ isNewModal = true;
193
+ outer = doc.createElement("div");
194
+ outer.id = DEV_SERVER_MODAL;
195
+ outer.setAttribute("role", "dialog");
196
+ doc.body.appendChild(outer);
197
+ outer.innerHTML = `<style>${css_248z}</style><div id="${DEV_SERVER_MODAL}-inner"></div>`;
198
+ const closeOnEsc = (e) => {
199
+ if (e.key === "Escape" || e.code === "Escape") closeDevServerModal(doc);
200
+ };
201
+ doc.addEventListener("keydown", closeOnEsc);
202
+ outer.__closeOnEsc = closeOnEsc;
203
+ outer.addEventListener("click", (e) => {
204
+ if (e.target === outer) closeDevServerModal(doc);
205
+ });
206
+ }
207
+ outer.style.display = "block";
208
+ const inner = doc.getElementById(`${DEV_SERVER_MODAL}-inner`);
209
+ inner.innerHTML = "";
210
+ if (isNewModal) inner.addEventListener("click", (e) => {
211
+ e.stopPropagation();
212
+ });
213
+ return inner;
214
+ };
215
+ const closeDevServerModal = (doc) => {
216
+ const outer = doc.getElementById(DEV_SERVER_MODAL);
217
+ if (outer) {
218
+ outer.style.display = "none";
219
+ showErrorBadge(doc);
220
+ }
221
+ };
222
+ const clearAppErrorModal = (data) => {
223
+ const appErrorElm = data.window.document.getElementById(DEV_SERVER_MODAL);
224
+ if (appErrorElm) {
225
+ const closeOnEsc = appErrorElm.__closeOnEsc;
226
+ if (closeOnEsc) data.window.document.removeEventListener("keydown", closeOnEsc);
227
+ if (appErrorElm.parentNode) appErrorElm.parentNode.removeChild(appErrorElm);
228
+ }
229
+ removeErrorBadge(data.window.document);
230
+ errorCount = 0;
231
+ };
232
+ const showErrorBadge = (doc) => {
233
+ if (errorCount === 0) return;
234
+ let badge = doc.getElementById(ERROR_BADGE_ID);
235
+ if (!badge) {
236
+ badge = doc.createElement("button");
237
+ badge.id = ERROR_BADGE_ID;
238
+ badge.className = "dev-server-error-badge";
239
+ badge.setAttribute("aria-label", "Show build errors");
240
+ doc.body.appendChild(badge);
241
+ badge.addEventListener("click", () => {
242
+ const modal = doc.getElementById(DEV_SERVER_MODAL);
243
+ if (modal) {
244
+ modal.style.display = "block";
245
+ removeErrorBadge(doc);
246
+ }
247
+ });
248
+ }
249
+ badge.innerHTML = `<span class="error-badge-icon">!</span><span class="error-badge-count">${errorCount}</span>`;
250
+ badge.style.display = "flex";
251
+ };
252
+ const removeErrorBadge = (doc) => {
253
+ const badge = doc.getElementById(ERROR_BADGE_ID);
254
+ if (badge) badge.style.display = "none";
255
+ };
256
+ const escapeHtml = (unsafe) => {
257
+ if (typeof unsafe === "number" || typeof unsafe === "boolean") return unsafe.toString();
258
+ if (typeof unsafe === "string") return unsafe.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#039;");
259
+ return "";
260
+ };
261
+ const titleCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
262
+ const highlightError = (text, errorCharStart, errorLength) => {
263
+ if (typeof text !== "string") return "";
264
+ const errorCharEnd = errorCharStart + errorLength;
265
+ return text.split("").map((inputChar, charIndex) => {
266
+ let outputChar;
267
+ if (inputChar === `<`) outputChar = `&lt;`;
268
+ else if (inputChar === `>`) outputChar = `&gt;`;
269
+ else if (inputChar === `"`) outputChar = `&quot;`;
270
+ else if (inputChar === `'`) outputChar = `&#039;`;
271
+ else if (inputChar === `&`) outputChar = `&amp;`;
272
+ else outputChar = inputChar;
273
+ if (charIndex >= errorCharStart && charIndex < errorCharEnd) outputChar = `<span class="dev-server-diagnostic-error-chr">${outputChar}</span>`;
274
+ return outputChar;
275
+ }).join("");
276
+ };
277
+ const prepareLines = (orgLines) => {
278
+ const lines = JSON.parse(JSON.stringify(orgLines));
279
+ for (let i = 0; i < 100; i++) {
280
+ if (!eachLineHasLeadingWhitespace(lines)) return lines;
281
+ for (let i = 0; i < lines.length; i++) {
282
+ lines[i].text = lines[i].text?.slice(1) ?? "";
283
+ lines[i].errorCharStart--;
284
+ if (!lines[i].text?.length) return lines;
285
+ }
286
+ }
287
+ return lines;
288
+ };
289
+ const eachLineHasLeadingWhitespace = (lines) => {
290
+ if (!lines.length) return false;
291
+ for (let i = 0; i < lines.length; i++) {
292
+ if (!lines[i].text || (lines[i].text?.length ?? 0) < 1) return false;
293
+ const firstChar = lines[i].text?.charAt(0);
294
+ if (firstChar !== " " && firstChar !== " ") return false;
295
+ }
296
+ return true;
297
+ };
298
+ const DEV_SERVER_MODAL = `dev-server-modal`;
299
+ const ERROR_BADGE_ID = "dev-server-error-badge";
300
+
301
+ //#endregion
302
+ //#region src/client/hmr/utils.ts
303
+ const getHmrHref = (versionId, fileName, testUrl) => {
304
+ if (typeof testUrl === "string" && testUrl.trim() !== "") {
305
+ if (getUrlFileName(fileName) === getUrlFileName(testUrl)) return setHmrQueryString(testUrl, versionId);
306
+ }
307
+ return testUrl;
308
+ };
309
+ const getUrlFileName = (url) => {
310
+ const splt = url.split("/");
311
+ return splt[splt.length - 1].split("&")[0].split("?")[0];
312
+ };
313
+ const parseQuerystring = (oldQs) => {
314
+ const newQs = {};
315
+ if (typeof oldQs === "string") oldQs.split("&").forEach((kv) => {
316
+ const splt = kv.split("=");
317
+ newQs[splt[0]] = splt[1] ? splt[1] : "";
318
+ });
319
+ return newQs;
320
+ };
321
+ const stringifyQuerystring = (qs) => Object.keys(qs).map((key) => key + "=" + qs[key]).join("&");
322
+ const setQueryString = (url, qsKey, qsValue) => {
323
+ const urlSplt = url.split("?");
324
+ const urlPath = urlSplt[0];
325
+ const qs = parseQuerystring(urlSplt[1]);
326
+ qs[qsKey] = qsValue;
327
+ return urlPath + "?" + stringifyQuerystring(qs);
328
+ };
329
+ const setHmrQueryString = (url, versionId) => setQueryString(url, "s-hmr", versionId);
330
+ const updateCssUrlValue = (versionId, fileName, oldCss) => {
331
+ const reg = /url\((['"]?)(.*)\1\)/gi;
332
+ let result;
333
+ let newCss = oldCss;
334
+ while ((result = reg.exec(oldCss)) !== null) {
335
+ const url = result[2];
336
+ newCss = newCss.replace(url, getHmrHref(versionId, fileName, url));
337
+ }
338
+ return newCss;
339
+ };
340
+ /**
341
+ * Determine whether a given element is a `<link>` tag pointing to a stylesheet
342
+ *
343
+ * @param elm the element to check
344
+ * @returns whether or not the element is a link stylesheet
345
+ */
346
+ const isLinkStylesheet = (elm) => elm.nodeName.toLowerCase() === "link" && !!elm.href && !!elm.rel && elm.rel.toLowerCase() === "stylesheet";
347
+ /**
348
+ * Determine whether or not a given element is a template element
349
+ *
350
+ * @param elm the element to check
351
+ * @returns whether or not the element of interest is a template element
352
+ */
353
+ const isTemplate = (elm) => elm.nodeName.toLowerCase() === "template" && !!elm.content && elm.content.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT;
354
+ /**
355
+ * Set a new hmr version ID into the `data-hmr` attribute on an element.
356
+ *
357
+ * @param elm the element on which to set the property
358
+ * @param versionId a new HMR version id
359
+ */
360
+ const setHmrAttr = (elm, versionId) => {
361
+ elm.setAttribute("data-hmr", versionId);
362
+ };
363
+ /**
364
+ * Determine whether or not an element has a shadow root
365
+ *
366
+ * @param elm the element to check
367
+ * @returns whether or not it has a shadow root
368
+ */
369
+ const hasShadowRoot = (elm) => !!elm.shadowRoot && elm.shadowRoot.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && elm.shadowRoot !== elm;
370
+ /**
371
+ * Determine whether or not an element is an element node
372
+ *
373
+ * @param elm the element to check
374
+ * @returns whether or not it is an element node
375
+ */
376
+ const isElement = (elm) => !!elm && elm.nodeType === NODE_TYPE_ELEMENT && !!elm.getAttribute;
377
+
378
+ //#endregion
379
+ //#region src/client/hmr/component.ts
380
+ const hmrComponents = (element, versionId, hmrTagNames) => {
381
+ const updatedTags = [];
382
+ hmrTagNames.forEach((hmrTagName) => {
383
+ hmrComponent(updatedTags, element, versionId, hmrTagName);
384
+ });
385
+ return updatedTags.sort();
386
+ };
387
+ const hmrComponent = (updatedTags, element, versionId, cmpTagName) => {
388
+ if (element.nodeName.toLowerCase() === cmpTagName && typeof element["s-hmr"] === "function") {
389
+ element["s-hmr"](versionId);
390
+ setHmrAttr(element, versionId);
391
+ if (updatedTags.indexOf(cmpTagName) === -1) updatedTags.push(cmpTagName);
392
+ }
393
+ if (hasShadowRoot(element)) hmrComponent(updatedTags, element.shadowRoot, versionId, cmpTagName);
394
+ if (element.children) for (let i = 0; i < element.children.length; i++) hmrComponent(updatedTags, element.children[i], versionId, cmpTagName);
395
+ };
396
+
397
+ //#endregion
398
+ //#region src/client/hmr/image.ts
399
+ const hmrImages = (win, doc, versionId, imageFileNames) => {
400
+ if (win.location.protocol !== "file:" && doc.styleSheets) hmrStyleSheetsImages(doc, versionId, imageFileNames);
401
+ hmrImagesElements(win, doc.documentElement, versionId, imageFileNames);
402
+ return imageFileNames.sort();
403
+ };
404
+ const hmrStyleSheetsImages = (doc, versionId, imageFileNames) => {
405
+ const cssImageProps = Object.keys(doc.documentElement.style).filter((cssProp) => {
406
+ return cssProp.endsWith("Image");
407
+ });
408
+ for (let i = 0; i < doc.styleSheets.length; i++) hmrStyleSheetImages(cssImageProps, doc.styleSheets[i], versionId, imageFileNames);
409
+ };
410
+ const hmrStyleSheetImages = (cssImageProps, styleSheet, versionId, imageFileNames) => {
411
+ try {
412
+ const cssRules = styleSheet.cssRules;
413
+ for (let i = 0; i < cssRules.length; i++) {
414
+ const cssRule = cssRules[i];
415
+ switch (cssRule.type) {
416
+ case CSSRule.IMPORT_RULE:
417
+ hmrStyleSheetImages(cssImageProps, cssRule.styleSheet, versionId, imageFileNames);
418
+ break;
419
+ case CSSRule.STYLE_RULE:
420
+ hmrStyleSheetRuleImages(cssImageProps, cssRule, versionId, imageFileNames);
421
+ break;
422
+ case CSSRule.MEDIA_RULE:
423
+ hmrStyleSheetImages(cssImageProps, cssRule, versionId, imageFileNames);
424
+ break;
425
+ }
426
+ }
427
+ } catch (e) {
428
+ console.error("hmrStyleSheetImages:", e);
429
+ }
430
+ };
431
+ const hmrStyleSheetRuleImages = (cssImageProps, cssRule, versionId, imageFileNames) => {
432
+ cssImageProps.forEach((cssImageProp) => {
433
+ imageFileNames.forEach((imageFileName) => {
434
+ const oldCssText = cssRule.style[cssImageProp];
435
+ const newCssText = updateCssUrlValue(versionId, imageFileName, oldCssText);
436
+ if (oldCssText !== newCssText) cssRule.style[cssImageProp] = newCssText;
437
+ });
438
+ });
439
+ };
440
+ const hmrImagesElements = (win, elm, versionId, imageFileNames) => {
441
+ const tagName = elm.nodeName.toLowerCase();
442
+ if (tagName === "img") hmrImgElement(elm, versionId, imageFileNames);
443
+ if (isElement(elm)) {
444
+ const styleAttr = elm.getAttribute("style");
445
+ if (styleAttr) hmrUpdateStyleAttr(elm, versionId, imageFileNames, styleAttr);
446
+ }
447
+ if (tagName === "style") hmrUpdateStyleElementUrl(elm, versionId, imageFileNames);
448
+ if (win.location.protocol !== "file:" && isLinkStylesheet(elm)) hmrUpdateLinkElementUrl(elm, versionId, imageFileNames);
449
+ if (isTemplate(elm)) hmrImagesElements(win, elm.content, versionId, imageFileNames);
450
+ if (hasShadowRoot(elm)) hmrImagesElements(win, elm.shadowRoot, versionId, imageFileNames);
451
+ if (elm.children) for (let i = 0; i < elm.children.length; i++) hmrImagesElements(win, elm.children[i], versionId, imageFileNames);
452
+ };
453
+ const hmrImgElement = (imgElm, versionId, imageFileNames) => {
454
+ imageFileNames.forEach((imageFileName) => {
455
+ const orgSrc = imgElm.getAttribute("src");
456
+ const newSrc = getHmrHref(versionId, imageFileName, orgSrc || "");
457
+ if (newSrc !== orgSrc) {
458
+ imgElm.setAttribute("src", newSrc);
459
+ setHmrAttr(imgElm, versionId);
460
+ }
461
+ });
462
+ };
463
+ const hmrUpdateStyleElementUrl = (styleElm, versionId, imageFileNames) => {
464
+ imageFileNames.forEach((imageFileName) => {
465
+ const oldCssText = styleElm.innerHTML;
466
+ const newCssText = updateCssUrlValue(versionId, imageFileName, oldCssText);
467
+ if (newCssText !== oldCssText) {
468
+ styleElm.innerHTML = newCssText;
469
+ setHmrAttr(styleElm, versionId);
470
+ }
471
+ });
472
+ };
473
+ const hmrUpdateLinkElementUrl = (linkElm, versionId, imageFileNames) => {
474
+ linkElm.href = setQueryString(linkElm.href, "s-hmr-urls", imageFileNames.sort().join(","));
475
+ linkElm.href = setHmrQueryString(linkElm.href, versionId);
476
+ linkElm.setAttribute("data-hmr", versionId);
477
+ };
478
+ const hmrUpdateStyleAttr = (elm, versionId, imageFileNames, oldStyleAttr) => {
479
+ imageFileNames.forEach((imageFileName) => {
480
+ const newStyleAttr = updateCssUrlValue(versionId, imageFileName, oldStyleAttr);
481
+ if (newStyleAttr !== oldStyleAttr) {
482
+ elm.setAttribute("style", newStyleAttr);
483
+ setHmrAttr(elm, versionId);
484
+ }
485
+ });
486
+ };
487
+
488
+ //#endregion
489
+ //#region src/client/hmr/style.ts
490
+ const STYLE_ID_ATTR = "sty-id";
491
+ const hmrExternalStyles = (elm, versionId, cssFileNames) => {
492
+ if (isLinkStylesheet(elm)) cssFileNames.forEach((cssFileName) => {
493
+ hmrStylesheetLink(elm, versionId, cssFileName);
494
+ });
495
+ if (isTemplate(elm)) hmrExternalStyles(elm.content, versionId, cssFileNames);
496
+ if (hasShadowRoot(elm)) hmrExternalStyles(elm.shadowRoot, versionId, cssFileNames);
497
+ if (elm.children) for (let i = 0; i < elm.children.length; i++) hmrExternalStyles(elm.children[i], versionId, cssFileNames);
498
+ return cssFileNames.sort();
499
+ };
500
+ const hmrStylesheetLink = (styleSheetElm, versionId, cssFileName) => {
501
+ const orgHref = styleSheetElm.getAttribute("href");
502
+ const newHref = getHmrHref(versionId, cssFileName, styleSheetElm.href);
503
+ if (newHref !== orgHref) {
504
+ styleSheetElm.setAttribute("href", newHref);
505
+ setHmrAttr(styleSheetElm, versionId);
506
+ }
507
+ };
508
+ const hmrInlineStyles = (elm, versionId, stylesUpdatedData) => {
509
+ const trackers = stylesUpdatedData.map((styleUpdate) => ({
510
+ styleUpdate,
511
+ updated: false
512
+ }));
513
+ hmrInlineStylesTraverse(elm, versionId, trackers);
514
+ for (const tracker of trackers) if (!tracker.updated && tracker.styleUpdate.styleText) createStyleElementsForComponent(elm, versionId, tracker.styleUpdate);
515
+ return stylesUpdatedData.map((s) => s.styleTag).reduce((arr, v) => {
516
+ if (arr.indexOf(v) === -1) arr.push(v);
517
+ return arr;
518
+ }, []).sort();
519
+ };
520
+ /**
521
+ * Traverse the DOM looking for style elements to update or remove.
522
+ */
523
+ const hmrInlineStylesTraverse = (elm, versionId, trackers) => {
524
+ if (isElement(elm) && elm.nodeName.toLowerCase() === "style") trackers.forEach((tracker) => {
525
+ if (hmrStyleElement(elm, versionId, tracker.styleUpdate)) tracker.updated = true;
526
+ });
527
+ if (isTemplate(elm)) hmrInlineStylesTraverse(elm.content, versionId, trackers);
528
+ if (hasShadowRoot(elm)) hmrInlineStylesTraverse(elm.shadowRoot, versionId, trackers);
529
+ if (elm.children) for (let i = 0; i < elm.children.length; i++) hmrInlineStylesTraverse(elm.children[i], versionId, trackers);
530
+ };
531
+ /**
532
+ * Update or remove a style element based on the HMR update.
533
+ * Returns true if this element matched and was processed.
534
+ */
535
+ const hmrStyleElement = (elm, versionId, stylesUpdated) => {
536
+ if (elm.getAttribute(STYLE_ID_ATTR) === stylesUpdated.styleId) {
537
+ if (stylesUpdated.styleText) {
538
+ elm.innerHTML = stylesUpdated.styleText.replace(/\\n/g, "\n");
539
+ elm.setAttribute("data-hmr", versionId);
540
+ } else elm.remove();
541
+ return true;
542
+ }
543
+ return false;
544
+ };
545
+ /**
546
+ * Find all component instances with the matching tag name and create style elements.
547
+ * Handles both shadow DOM components (style in shadow root) and scoped components (style in head).
548
+ */
549
+ const createStyleElementsForComponent = (rootElm, versionId, styleUpdate) => {
550
+ const { styleTag, styleId, styleText } = styleUpdate;
551
+ const doc = rootElm.ownerDocument;
552
+ const componentInstances = findComponentInstances(rootElm, styleTag);
553
+ if (componentInstances.length === 0) {
554
+ createStyleElement(doc.head, styleId, styleText, versionId);
555
+ return;
556
+ }
557
+ const processedShadowRoots = /* @__PURE__ */ new Set();
558
+ let addedToHead = false;
559
+ for (const instance of componentInstances) if (instance.shadowRoot) {
560
+ if (!processedShadowRoots.has(instance.shadowRoot)) {
561
+ processedShadowRoots.add(instance.shadowRoot);
562
+ createStyleElement(instance.shadowRoot, styleId, styleText, versionId);
563
+ }
564
+ } else if (!addedToHead) {
565
+ addedToHead = true;
566
+ createStyleElement(doc.head, styleId, styleText, versionId);
567
+ }
568
+ };
569
+ /**
570
+ * Find all instances of a component by tag name, including in shadow roots.
571
+ */
572
+ const findComponentInstances = (elm, tagName) => {
573
+ const instances = [];
574
+ findComponentInstancesTraverse(elm, tagName.toLowerCase(), instances);
575
+ return instances;
576
+ };
577
+ const findComponentInstancesTraverse = (elm, tagName, instances) => {
578
+ if (elm.nodeName.toLowerCase() === tagName) instances.push(elm);
579
+ if (hasShadowRoot(elm)) findComponentInstancesTraverse(elm.shadowRoot, tagName, instances);
580
+ if (elm.children) for (let i = 0; i < elm.children.length; i++) findComponentInstancesTraverse(elm.children[i], tagName, instances);
581
+ };
582
+ /**
583
+ * Create a new style element with the given content.
584
+ */
585
+ const createStyleElement = (container, styleId, styleText, versionId) => {
586
+ const styleElm = ("ownerDocument" in container ? container.ownerDocument : container.ownerDocument).createElement("style");
587
+ styleElm.innerHTML = styleText.replace(/\\n/g, "\n");
588
+ styleElm.setAttribute(STYLE_ID_ATTR, styleId);
589
+ styleElm.setAttribute("data-hmr", versionId);
590
+ if (container.firstChild) container.insertBefore(styleElm, container.firstChild);
591
+ else container.appendChild(styleElm);
592
+ };
593
+
594
+ //#endregion
595
+ //#region src/client/hmr/window.ts
596
+ const hmrWindow = (data) => {
597
+ const results = {
598
+ updatedComponents: [],
599
+ updatedExternalStyles: [],
600
+ updatedInlineStyles: [],
601
+ updatedImages: [],
602
+ versionId: ""
603
+ };
604
+ try {
605
+ if (!data || !data.window || !data.window.document.documentElement || !data.hmr || typeof data.hmr.versionId !== "string") return results;
606
+ const win = data.window;
607
+ const doc = win.document;
608
+ const hmr = data.hmr;
609
+ const documentElement = doc.documentElement;
610
+ const versionId = hmr.versionId;
611
+ results.versionId = versionId;
612
+ if (hmr.componentsUpdated) results.updatedComponents = hmrComponents(documentElement, versionId, hmr.componentsUpdated);
613
+ if (hmr.inlineStylesUpdated) results.updatedInlineStyles = hmrInlineStyles(documentElement, versionId, hmr.inlineStylesUpdated);
614
+ if (hmr.externalStylesUpdated) results.updatedExternalStyles = hmrExternalStyles(documentElement, versionId, hmr.externalStylesUpdated);
615
+ if (hmr.imagesUpdated) results.updatedImages = hmrImages(win, doc, versionId, hmr.imagesUpdated);
616
+ setHmrAttr(documentElement, versionId);
617
+ } catch (e) {
618
+ console.error(e);
619
+ }
620
+ return results;
621
+ };
622
+
623
+ //#endregion
624
+ //#region src/client/logger.ts
625
+ const YELLOW = "#f39c12";
626
+ const RED = "#c0392b";
627
+ const BLUE = "#3498db";
628
+ const GRAY = "#717171";
629
+ const log = (color, prefix, msg) => {
630
+ console.log("%c" + prefix, `background: ${color}; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;`, msg);
631
+ };
632
+ const logBuild = (msg) => log(BLUE, "Build", msg);
633
+ const logReload = (msg) => logWarn("Reload", msg);
634
+ const logWarn = (prefix, msg) => log(YELLOW, prefix, msg);
635
+ const logDisabled = (prefix, msg) => log(GRAY, prefix, msg);
636
+ const logDiagnostic = (diag) => {
637
+ let color = RED;
638
+ let prefix = "Error";
639
+ if (diag.level === "warn") {
640
+ color = YELLOW;
641
+ prefix = "Warning";
642
+ }
643
+ if (diag.header) prefix = diag.header;
644
+ let msg = "";
645
+ if (diag.relFilePath) {
646
+ msg += diag.relFilePath;
647
+ if (typeof diag.lineNumber === "number" && diag.lineNumber > 0) {
648
+ msg += ", line " + diag.lineNumber;
649
+ if (typeof diag.columnNumber === "number" && diag.columnNumber > 0) msg += ", column " + diag.columnNumber;
650
+ }
651
+ msg += "\n";
652
+ }
653
+ msg += diag.messageText;
654
+ log(color, prefix, msg);
655
+ };
656
+
657
+ //#endregion
658
+ //#region src/client/status.ts
659
+ /**
660
+ * Build status and favicon utilities for dev server client.
661
+ */
662
+ const ICON_DEFAULT = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAnFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD4jUzeAAAAM3RSTlMAsGDs4wML8QEbBvr2FMhAM7+ILCUPnNzXrX04otO6j3RiT0ggzLSTcmtWUUWoZlknghZc2mZzAAACrklEQVR42u3dWXLiUAyFYWEwg40x8wxhSIAwJtH+99ZVeeinfriXVpWk5Hyr+C2VrgkAAAAAAAAAAAw5sZQ7aUhYypw07FjKC2ko2yxk2SQFgwYLOWSkYFhlIZ06KWhNWMhqRApGKxYyaZGCeoeFVIekIDuwkEaXFDSXLKRdkoYjS9mRhjlLSUjDO0s5kYYzS+mThn3OQsYqAbQQC7hZSgoGYgHUy0jBa42FvKkEUDERC6CCFIzeWEjtlRRkPbGAG5CCtCIWQAtS0ByzkHxPGvos5UEaNizlnTRsWconhbM4wTpSFHMTrFtKCroNFrLGBOsJLbGAWxWkoFiJBRAmWE/I1r4nWOmNheTeJ1gX0vDJUrYUweAEa04aHs5XePvc9wpPboJ1SCmOsRVkr04aromUEQEAgB9lxaZ++ATFpNDv6Y8qm1QdBk9QTAr9ni6mbFK7DJ6g2LQLXoHZlFCQdMY2nYJXYDb1g1dgNo2boSswm2Zp6ArMptCFyIVtCl2IlDmbNC0QcPEQcD8l4HLvAXdxHnBb5wG3QcDFQ8D9mIDrIeCiIeDiA25oNeA+EHDREHDxAbdmmxBwT0HARQbciW0KDbiEbQoNuB3bFBxwbTYJAfcUBFxkwFG/YlNJAADgxzCRcqUY9m7KGgNSUEx9H3XXO76Puv/OY5wedX/flHk+6j46v2maO79purPvm6Yz+75puua+b5q6Dd/PEsrNMyZfFM5gAMW+ymPtWciYV3ksBpBOwKUH3wHXXLKUM2l4cR5wG+cBlzgPuJ3zgJNb6FRwlP4Ln1X8wrOKeFbxP6Qz3wEn+KzilWLYe5UnMuDwY5BvD+cBt899B9zC+49Bqr4DrlXzHXDF1HfA1Tu+Ay5b+w649OY74OjoO+Bo7jzg7s4DDgAAAAAAAAAA/u0POrfnVIaqz/QAAAAASUVORK5CYII=";
663
+ const ICON_PENDING = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAjVBMVEUAAAD8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjL8kjLn7xn3AAAALnRSTlMAsFBgAaDxfPpAdTMcD/fs47kDBhVXJQpvLNbInIiBRvSqIb+TZ2OOONxdzUxpgKSpAAAAA69JREFUeNrt3FtvskAQxvERFQXFioqnCkqth572+3+8947dN00TliF5ZpP53ZOAveg/OzCklFJKKaWUUkoppQTZm77cCGFo+jIhhG/TlwchJAvTk/GIAA6x6Um+JoDti+nJ644A5h+mJ8eMALKj6cnHnAB2r80NLJ4jf3Vz+cuWANZ5cwPTM/l7by6PZwQwGptGQf4q++dLCOHdNIbkb2IvjwjAvYEf8pe6j4/wYxopr/9SQih4BXa3l5eEcJ7a++c9/gkSQE8bcCWvXwcrAjjYADrxHv8KCbi3JasgD5fm8i9IAG1swMXzDv0X2wDaEED21dzA5UDeVoPm8uUbAayvvAI42YA7EIDzA5pv8lc6/UoAoxMv4CZuvyKUpnHn9VNBAG6B7XkBtCeEO6/AbvbyihAiXsB92svfCcA9wap4j19DAmgWs37AZCrnBKvu8vgX9AmWE3BZh/6L7QkWJIA2RxtwHQpml9sAQp9gXWbkbxz4CdYDfIK1qk1j3IV9fPgJFlNECJXhYfSfsBHkhBCKwEd452nYI7wncwQJP8GKTU+uO0I4D/uSkVJKqXAkA5nK9icoIi3nrU9QRHrZtj5BESmetT5BEantPCh7NTJFrUdgMg1bj8BkSv1HYJ8RmjMQKf1HYDdC+/R/IyQFzbD4AxH+CIyPPxCJoEdQ/IFIMgXNEPkDkd8jMLQs5wRcTXA1J+By/BGO+0ovYwQGU3kPRLJfIzCkCSfgpgmhpc5AxD/gIkLb8wKO0DTgoNyaGQQecNfQAy7TgGtHA04DLtyA24UecHngAVdrwIkJuAitU8DJ1Dbghkam9gEnU+uAWxiRjhsdoXagI1TPgKNyIBO+ZpRSSrW3HfblTAA9/juPDwTAfiMK9VG3PY/hwX7Ubc9j+AoCWNWGp+NSH4HflE2IgXUEGPI3TTfmN4ndv2kSsRUJvpUn4W1FShbYb5rc84ySAtzKs3W3IgW4lWfO24q0zsFbebIjaysSjbtt5RHzUf0DHHCrAW8gVYEDzl0LGYW4lefB24uYQgOOfwN7dMANeW/k3DkBJ2CrUNE54GRsFYIHnPNR+iPEgHPWKo5DDDhnrWKeBRhwzlrFeNtlq5CgtYqzAAPODaBzgAH331rFAAOOqsDXKjL3IqboN7ILJ4BCDDh3r3SIAfd0AijEgHP3So/8wQNuvjRBbxVij5A6Bpy8EZJnwIkbIfkFnLwRkm/ASRshXbwDTtYICRRwt7BHqEoppZRSSimllFLqD/8AOXJZHefotiIAAAAASUVORK5CYII=";
664
+ const ICON_ERROR = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAkFBMVEUAAAD5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0H5Q0HYvLBZAAAAL3RSTlMAsGDjA/rsC/ElHRUBBssz9pFCvoh0UEcsD9ec3K19OLiiaNLEYlmoVeiCbmE+GuMl4I8AAAKQSURBVHja7d1njupQDIZhAimEUIZQQu9taN7/7q50pfl/TmTJtvQ9q3hzLDsEAAAAAAAAAACGzFjKiTS0WcqONMxZypg0fH5YyLFPChZdFnIYkILil4VcclLw3bCQ85KULM8sZPMlBfmFhfwWpGBwYCHdESnoH1nIz4c0jFnKnDTsWEqbNJxYyow03FjKlDTUKQtZqwTQXizgtgkpWGQsZKIScL0OCxmqBFC5EQugkhQshyyk0yMFgwkLyRakIGmJBdCeFPTXLCStScOUpdwogsEXrBdpuLKUJ4XDC9afKmUh94QUjLy/YGViAZRTOIMBtypJQXn2HUC5WMBleMFqILmzkLSicBZfsB6k4clSrqTh5XyEd3MeQHXqe4Qn94LVSiicwRHkJScNdVvKkgAAwI+qZdM0/AXFpE4v+AXFpKwIfkExKfR7ulyxSWkV/IJi0zx4BGbTm4IkW7ZpFjwCs2kaPAKzad0PHYHZtE1CR2A2TQahIzCbhnnwCMykVYmAi4aAQ8BZ4T3grgi4BhBwCDgbEHCNIOAQcCYg4BpCwCHgLEDAaYgPuDfbhIBrBAGHgDMhNOBo2rKpIgAA8KNoS6kplq2dsu6CFJQr30vd+dD3Uvf/nTLHS93J3flZwrHznaad852mE/veaXqw752mKvW90zTq+j5LWGS+r/J8xQKoU1AUa2chm1zlsXQWUifgkoPvgOsffQccjZ0H3Mx5wL2dB9zcecB9sJTePOBM3cU+46wiziq6C7hk6zvg3J9VfDK7vir0ch5wN+cBV6e+A27v/ccgme+AkxshTXKKYW6EFH0X29gIKTLgzI2QYgPO2ggpLuDsvaDEBZy9EVJcwBkcIT0IAAAAAAAAAADs+AdjeyF69/r87QAAAABJRU5ErkJggg==";
665
+ const ICON_DISABLED = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAMAAABlApw1AAAAeFBMVEUAAAC4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7+4t7/uGGySAAAAJ3RSTlMAsGAE7OMcAQvxJRX69kHWyL8zq5GIdEcsD5zcfVg4uKLNa1JPZoK/xdPIAAACiklEQVR42u3dW5KqUAyF4QgCCggqIt7t9pb5z/Ccvjz2w95UqpJ0r28Uf2WTQAAAAAAAAAAAYMiWpTxJQ8JSTqThwVI2pKFZsJC3ghTs5izkmpKCcspCljNSkB9ZSLsnBfuWhRxzUjBbspBpSQrSKwuZr0lB8cZCFg1p2LCUB2k4sZSENNxYypY0nFlKTxqGmoUcClJwEQu4SUoKdmIBtEpJQZ6xkHeVAKqOYgFUkYL9OwvJclKQrsQCbkcK0olYAF1IQXFgIfVAGnqWcqZwFidYN4phb4L1onCYYMlPsLqUFKwxwRozwTIYcG1FCqrWdwBhgqU7wUo7FlJ7n2DdScPL+RPezfkT3tl5AA217yc89xMssYBbzUjDkEjZEwAA+NFMbOrDJygmZXnwBMWkaRk8QTFpvg6eoJi0aIInKDY9gp/AbEqCJyg2bYOfwGzqKUzPNh2K0Ccwm0IfRBK2KfSLkDvbFPog0tRsUlsh4EZAwP2SgKu9B9wdATcOAg4BZwACbgQEHALOCATcCAg4BJwVCLhREHB/LOAebFNwwC3YJATcKAi4yICjfmJTQwAA4EeZSBkojrWdsvmO4hjbKYtd6ra2Uxa71G1tp0xnqbvo+IPfpe4Nf3K703Ridr3T9OQPfnea7szseaepqX3vNH3NM/xe5fmeZ7i9yiMXQFlJEeydhYy4ymMygCICzmQAxQactbOQMQFnMoBiAs7iVaHIgDN3VSgq4AxeFYoOOGNXhbCUPkaJs4o4q/iXzyp2vgPO/VnFl/OAu/F/jq8KnZ0H3FD7DriL9x+DTH0HXJ75Driq9R1ws6XvgEuvvgOu6HwHHG18BxydnAfc03nAAQAAAAAAAADAz/4BoL2Us9XM2zMAAAAASUVORK5CYII=";
666
+ const ICON_TYPE = "image/x-icon";
667
+ const initBuildStatus = (data) => {
668
+ const win = data.window;
669
+ const doc = win.document;
670
+ getFavIcons(doc).forEach((iconElm) => {
671
+ if (iconElm.href) {
672
+ iconElm.dataset.href = iconElm.href;
673
+ iconElm.dataset.type = iconElm.type;
674
+ }
675
+ });
676
+ onBuildStatus(win, (buildStatus) => {
677
+ updateBuildStatus(doc, buildStatus);
678
+ });
679
+ };
680
+ const updateBuildStatus = (doc, status) => {
681
+ getFavIcons(doc).forEach((iconElm) => {
682
+ updateFavIcon(iconElm, status);
683
+ });
684
+ };
685
+ const updateFavIcon = (linkElm, status) => {
686
+ if (status === "pending") {
687
+ linkElm.href = ICON_PENDING;
688
+ linkElm.type = ICON_TYPE;
689
+ linkElm.setAttribute("data-status", status);
690
+ } else if (status === "error") {
691
+ linkElm.href = ICON_ERROR;
692
+ linkElm.type = ICON_TYPE;
693
+ linkElm.setAttribute("data-status", status);
694
+ } else if (status === "disabled") {
695
+ linkElm.href = ICON_DISABLED;
696
+ linkElm.type = ICON_TYPE;
697
+ linkElm.setAttribute("data-status", status);
698
+ } else {
699
+ linkElm.removeAttribute("data-status");
700
+ if (linkElm.dataset.href) {
701
+ linkElm.href = linkElm.dataset.href;
702
+ linkElm.type = linkElm.dataset.type || ICON_TYPE;
703
+ } else {
704
+ linkElm.href = ICON_DEFAULT;
705
+ linkElm.type = ICON_TYPE;
706
+ }
707
+ }
708
+ };
709
+ const getFavIcons = (doc) => {
710
+ const iconElms = [];
711
+ const linkElms = doc.querySelectorAll("link");
712
+ for (let i = 0; i < linkElms.length; i++) if (linkElms[i].href && linkElms[i].rel && (linkElms[i].rel.indexOf("shortcut") > -1 || linkElms[i].rel.indexOf("icon") > -1)) iconElms.push(linkElms[i]);
713
+ if (iconElms.length === 0) {
714
+ const linkElm = doc.createElement("link");
715
+ linkElm.rel = "shortcut icon";
716
+ doc.head.appendChild(linkElm);
717
+ iconElms.push(linkElm);
718
+ }
719
+ return iconElms;
720
+ };
721
+ const PROGRESS_BAR_ID = `dev-server-progress-bar`;
722
+ const initBuildProgress = (data) => {
723
+ const win = data.window;
724
+ const doc = win.document;
725
+ const barColor = `#5851ff`;
726
+ const errorColor = `#b70c19`;
727
+ let addBarTimerId;
728
+ let removeBarTimerId;
729
+ let opacityTimerId;
730
+ let incIntervalId;
731
+ let progressIncrease;
732
+ let currentProgress = 0;
733
+ function update() {
734
+ clearTimeout(opacityTimerId);
735
+ clearTimeout(removeBarTimerId);
736
+ const progressBar = getProgressBar();
737
+ if (!progressBar) {
738
+ createProgressBar();
739
+ addBarTimerId = setTimeout(update, 16);
740
+ return;
741
+ }
742
+ progressBar.style.background = barColor;
743
+ progressBar.style.opacity = `1`;
744
+ progressBar.style.transform = `scaleX(${Math.min(1, displayProgress())})`;
745
+ if (incIntervalId == null) incIntervalId = setInterval(() => {
746
+ progressIncrease += Math.random() * .05 + .01;
747
+ if (displayProgress() < .9) update();
748
+ else clearInterval(incIntervalId);
749
+ }, 800);
750
+ }
751
+ function reset() {
752
+ clearInterval(incIntervalId);
753
+ progressIncrease = .05;
754
+ incIntervalId = null;
755
+ clearTimeout(opacityTimerId);
756
+ clearTimeout(addBarTimerId);
757
+ clearTimeout(removeBarTimerId);
758
+ const progressBar = getProgressBar();
759
+ if (progressBar) {
760
+ if (currentProgress >= 1) progressBar.style.transform = `scaleX(1)`;
761
+ opacityTimerId = setTimeout(() => {
762
+ try {
763
+ const progressBar = getProgressBar();
764
+ if (progressBar) progressBar.style.opacity = `0`;
765
+ } catch (e) {}
766
+ }, 150);
767
+ removeBarTimerId = setTimeout(() => {
768
+ try {
769
+ const progressBar = getProgressBar();
770
+ if (progressBar?.parentNode) progressBar.parentNode.removeChild(progressBar);
771
+ } catch (e) {}
772
+ }, 1e3);
773
+ }
774
+ }
775
+ function displayProgress() {
776
+ const p = currentProgress + progressIncrease;
777
+ return Math.max(0, Math.min(1, p));
778
+ }
779
+ reset();
780
+ onBuildLog(win, (buildLog) => {
781
+ currentProgress = buildLog.progress;
782
+ if (currentProgress >= 0 && currentProgress < 1) update();
783
+ else reset();
784
+ });
785
+ onBuildResults(win, (buildResults) => {
786
+ if (buildResults.hasError) {
787
+ const progressBar = getProgressBar();
788
+ if (progressBar) {
789
+ progressBar.style.transform = `scaleX(1)`;
790
+ progressBar.style.background = errorColor;
791
+ }
792
+ }
793
+ reset();
794
+ });
795
+ onBuildStatus(win, (buildStatus) => {
796
+ if (buildStatus === "disabled") reset();
797
+ });
798
+ if (doc.head.dataset.tmpl === "tmpl-initial-load") update();
799
+ function getProgressBar() {
800
+ return doc.getElementById(PROGRESS_BAR_ID);
801
+ }
802
+ function createProgressBar() {
803
+ const progressBar = doc.createElement("div");
804
+ progressBar.id = PROGRESS_BAR_ID;
805
+ progressBar.style.position = `absolute`;
806
+ progressBar.style.top = `0`;
807
+ progressBar.style.left = `0`;
808
+ progressBar.style.zIndex = `100001`;
809
+ progressBar.style.width = `100%`;
810
+ progressBar.style.height = `2px`;
811
+ progressBar.style.transform = `scaleX(0)`;
812
+ progressBar.style.opacity = `1`;
813
+ progressBar.style.background = barColor;
814
+ progressBar.style.transformOrigin = `left center`;
815
+ progressBar.style.transition = `transform .1s ease-in-out, opacity .5s ease-in`;
816
+ progressBar.style.contain = `strict`;
817
+ doc.body.appendChild(progressBar);
818
+ }
819
+ };
820
+
821
+ //#endregion
822
+ //#region src/client/websocket.ts
823
+ /**
824
+ * WebSocket client for dev server communication.
825
+ */
826
+ const initClientWebSocket = (win, config) => {
827
+ let clientWs = null;
828
+ let reconnectTmrId = null;
829
+ let reconnectAttempts = 0;
830
+ let requestBuildResultsTmrId = null;
831
+ let hasGottenBuildResults = false;
832
+ let buildResultsRequests = 0;
833
+ function onOpen() {
834
+ if (reconnectAttempts > 0) emitBuildStatus(win, "pending");
835
+ if (!hasGottenBuildResults) requestBuildResultsTmrId = setInterval(() => {
836
+ buildResultsRequests++;
837
+ if (!hasGottenBuildResults && this.readyState === WebSocket.OPEN && buildResultsRequests < 500) this.send(JSON.stringify({ requestBuildResults: true }));
838
+ else if (requestBuildResultsTmrId) clearInterval(requestBuildResultsTmrId);
839
+ }, REQUEST_BUILD_RESULTS_INTERVAL_MS);
840
+ if (reconnectTmrId) clearTimeout(reconnectTmrId);
841
+ }
842
+ function onError() {
843
+ queueReconnect();
844
+ }
845
+ function onClose(event) {
846
+ emitBuildStatus(win, "disabled");
847
+ if (event.code > NORMAL_CLOSURE_CODE) logWarn("Dev Server", `web socket closed: ${event.code} ${event.reason}`);
848
+ else logDisabled("Dev Server", "Disconnected, attempting to reconnect...");
849
+ queueReconnect();
850
+ }
851
+ function onMessage(event) {
852
+ const msg = JSON.parse(event.data);
853
+ if (reconnectAttempts > 0) {
854
+ if (msg.isActivelyBuilding) return;
855
+ if (msg.buildResults) {
856
+ logReload("Reconnected to dev server");
857
+ hasGottenBuildResults = true;
858
+ buildResultsRequests = 0;
859
+ if (requestBuildResultsTmrId) clearInterval(requestBuildResultsTmrId);
860
+ if (win["s-build-id"] !== msg.buildResults.buildId) win.location.reload();
861
+ win["s-build-id"] = msg.buildResults.buildId;
862
+ return;
863
+ }
864
+ }
865
+ if (msg.buildLog) {
866
+ if (msg.buildLog.progress < 1) emitBuildStatus(win, "pending");
867
+ emitBuildLog(win, msg.buildLog);
868
+ return;
869
+ }
870
+ if (msg.buildResults) {
871
+ hasGottenBuildResults = true;
872
+ buildResultsRequests = 0;
873
+ if (requestBuildResultsTmrId) clearInterval(requestBuildResultsTmrId);
874
+ emitBuildStatus(win, "default");
875
+ emitBuildResults(win, msg.buildResults);
876
+ }
877
+ }
878
+ function connect() {
879
+ if (reconnectTmrId) clearTimeout(reconnectTmrId);
880
+ clientWs = new win.WebSocket(config.socketUrl, ["xmpp"]);
881
+ clientWs.addEventListener("open", onOpen);
882
+ clientWs.addEventListener("error", onError);
883
+ clientWs.addEventListener("close", onClose);
884
+ clientWs.addEventListener("message", onMessage);
885
+ }
886
+ function queueReconnect() {
887
+ hasGottenBuildResults = false;
888
+ if (clientWs) {
889
+ if (clientWs.readyState === WebSocket.OPEN || clientWs.readyState === WebSocket.CONNECTING) clientWs.close(NORMAL_CLOSURE_CODE);
890
+ clientWs.removeEventListener("open", onOpen);
891
+ clientWs.removeEventListener("error", onError);
892
+ clientWs.removeEventListener("close", onClose);
893
+ clientWs.removeEventListener("message", onMessage);
894
+ clientWs = null;
895
+ }
896
+ if (reconnectTmrId) clearTimeout(reconnectTmrId);
897
+ if (reconnectAttempts >= RECONNECT_ATTEMPTS) logWarn("Dev Server", "Canceling reconnect attempts");
898
+ else {
899
+ reconnectAttempts++;
900
+ reconnectTmrId = setTimeout(connect, RECONNECT_RETRY_MS);
901
+ emitBuildStatus(win, "disabled");
902
+ }
903
+ }
904
+ connect();
905
+ };
906
+
907
+ //#endregion
908
+ //#region src/client/index.ts
909
+ /**
910
+ * @stencil/dev-server Client
911
+ *
912
+ * Browser-side HMR (Hot Module Replacement) client for Stencil dev server.
913
+ * Handles WebSocket communication, component updates, style updates, and image updates.
914
+ *
915
+ * This module runs in the browser and is injected into pages during development.
916
+ */
917
+ const initAppUpdate = (win, config) => {
918
+ onBuildResults(win, (buildResults) => {
919
+ appUpdate(win, config, buildResults);
920
+ });
921
+ };
922
+ const appUpdate = (win, config, buildResults) => {
923
+ try {
924
+ if (buildResults.buildId === win["s-build-id"]) return;
925
+ win["s-build-id"] = buildResults.buildId;
926
+ clearAppErrorModal({ window: win });
927
+ if (buildResults.hasError) {
928
+ const errorResults = appError({
929
+ window: win,
930
+ buildResults,
931
+ openInEditor: Array.isArray(config.editors) && config.editors.length > 0 ? (data) => {
932
+ const url = `${OPEN_IN_EDITOR_URL}?${new URLSearchParams({
933
+ file: data.file,
934
+ line: String(data.line),
935
+ column: String(data.column)
936
+ }).toString()}`;
937
+ win.fetch(url).catch((err) => {
938
+ console.error("Failed to open in editor:", err);
939
+ });
940
+ } : void 0
941
+ });
942
+ errorResults.diagnostics.forEach(logDiagnostic);
943
+ if (errorResults.status) emitBuildStatus(win, errorResults.status);
944
+ if (win["s-initial-load"]) appReset(win, config, () => {
945
+ logReload("Initial load (with errors)");
946
+ win.location.reload();
947
+ });
948
+ return;
949
+ }
950
+ if (win["s-initial-load"]) {
951
+ appReset(win, config, () => {
952
+ logReload("Initial load");
953
+ win.location.reload();
954
+ });
955
+ return;
956
+ }
957
+ if (buildResults.hmr) appHmr(win, buildResults.hmr);
958
+ } catch (e) {
959
+ console.error(e);
960
+ }
961
+ };
962
+ const appHmr = (win, hmr) => {
963
+ let shouldWindowReload = false;
964
+ if (hmr.reloadStrategy === "pageReload") shouldWindowReload = true;
965
+ if (hmr.indexHtmlUpdated) {
966
+ logReload("Updated index.html");
967
+ shouldWindowReload = true;
968
+ }
969
+ if (hmr.serviceWorkerUpdated) {
970
+ logReload("Updated Service Worker: sw");
971
+ shouldWindowReload = true;
972
+ }
973
+ if (hmr.scriptsAdded && hmr.scriptsAdded.length > 0) {
974
+ logReload(`Added scripts: ${hmr.scriptsAdded.join(", ")}`);
975
+ shouldWindowReload = true;
976
+ }
977
+ if (hmr.scriptsDeleted && hmr.scriptsDeleted.length > 0) {
978
+ logReload(`Deleted scripts: ${hmr.scriptsDeleted.join(", ")}`);
979
+ shouldWindowReload = true;
980
+ }
981
+ if (hmr.excludeHmr && hmr.excludeHmr.length > 0) {
982
+ logReload(`Excluded From Hmr: ${hmr.excludeHmr.join(", ")}`);
983
+ shouldWindowReload = true;
984
+ }
985
+ if (shouldWindowReload) {
986
+ win.location.reload();
987
+ return;
988
+ }
989
+ const results = hmrWindow({
990
+ window: win,
991
+ hmr
992
+ });
993
+ if (results.updatedComponents.length > 0) logBuild(`Updated component${results.updatedComponents.length > 1 ? "s" : ""}: ${results.updatedComponents.join(", ")}`);
994
+ if (results.updatedInlineStyles.length > 0) logBuild(`Updated styles: ${results.updatedInlineStyles.join(", ")}`);
995
+ if (results.updatedExternalStyles.length > 0) logBuild(`Updated stylesheets: ${results.updatedExternalStyles.join(", ")}`);
996
+ if (results.updatedImages.length > 0) logBuild(`Updated images: ${results.updatedImages.join(", ")}`);
997
+ };
998
+ const appReset = (win, config, cb) => {
999
+ win.history.replaceState({}, "App", config.basePath);
1000
+ if (!win.navigator.serviceWorker?.getRegistration) cb();
1001
+ else win.navigator.serviceWorker.getRegistration().then((swRegistration) => {
1002
+ if (swRegistration) swRegistration.unregister().then((hasUnregistered) => {
1003
+ if (hasUnregistered) logBuild("unregistered service worker");
1004
+ cb();
1005
+ });
1006
+ else cb();
1007
+ }).catch((err) => {
1008
+ logWarn("Service Worker", err);
1009
+ cb();
1010
+ });
1011
+ };
1012
+ const initDevClient = (win, config) => {
1013
+ try {
1014
+ if (win["s-dev-server"]) return;
1015
+ win["s-dev-server"] = true;
1016
+ win.devServerConfig = config;
1017
+ initBuildStatus({ window: win });
1018
+ initBuildProgress({ window: win });
1019
+ initAppUpdate(win, config);
1020
+ if (isInitialDevServerLoad(win, config)) {
1021
+ win["s-initial-load"] = true;
1022
+ appReset(win, config, () => {
1023
+ initClientWebSocket(win, config);
1024
+ });
1025
+ } else initClientWebSocket(win, config);
1026
+ } catch (e) {
1027
+ console.error(e);
1028
+ }
1029
+ };
1030
+ const isInitialDevServerLoad = (win, config) => {
1031
+ let pathname = win.location.pathname;
1032
+ pathname = "/" + pathname.substring(config.basePath.length);
1033
+ return pathname === DEV_SERVER_INIT_URL;
1034
+ };
1035
+ if (typeof appWindow !== "undefined" && typeof config !== "undefined") {
1036
+ const defaultConfig = {
1037
+ basePath: appWindow.location.pathname,
1038
+ editors: [],
1039
+ reloadStrategy: "hmr",
1040
+ socketUrl: `${location.protocol === "https:" ? "wss:" : "ws:"}//${location.hostname}${location.port !== "" ? ":" + location.port : ""}/`
1041
+ };
1042
+ initDevClient(appWindow, {
1043
+ ...defaultConfig,
1044
+ ...appWindow.devServerConfig,
1045
+ ...config
1046
+ });
1047
+ }
1048
+
1049
+ //#endregion
1050
+ export { BUILD_LOG, BUILD_RESULTS, BUILD_STATUS, DEV_SERVER_INIT_URL, DEV_SERVER_URL, NODE_TYPE_DOCUMENT_FRAGMENT, NODE_TYPE_ELEMENT, NORMAL_CLOSURE_CODE, OPEN_IN_EDITOR_URL, RECONNECT_ATTEMPTS, RECONNECT_RETRY_MS, REQUEST_BUILD_RESULTS_INTERVAL_MS, appError, clearAppErrorModal, emitBuildLog, emitBuildResults, emitBuildStatus, hmrWindow, initBuildProgress, initBuildStatus, initClientWebSocket, initDevClient, logBuild, logDiagnostic, logDisabled, logReload, logWarn, onBuildLog, onBuildResults, onBuildStatus, updateFavIcon };