webserial-core 2.0.0-dev.1 → 2.0.1

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,255 @@
1
+ /* Shared styles for all webserial-core demos.
2
+ * Each demo HTML sets its own CSS custom properties in an inline <style> block:
3
+ * --accent, --accent-dark, --accent-badge, --log-event
4
+ * --notice-bg, --notice-border, --notice-text, --notice-code-bg (optional)
5
+ */
6
+
7
+ *,
8
+ *::before,
9
+ *::after {
10
+ box-sizing: border-box;
11
+ margin: 0;
12
+ padding: 0;
13
+ }
14
+
15
+ body {
16
+ font-family:
17
+ "Segoe UI",
18
+ system-ui,
19
+ -apple-system,
20
+ sans-serif;
21
+ background: #0f0f12;
22
+ color: #e4e4e7;
23
+ min-height: 100vh;
24
+ display: flex;
25
+ align-items: center;
26
+ justify-content: center;
27
+ }
28
+
29
+ #app {
30
+ width: min(640px, 94vw);
31
+ background: #18181b;
32
+ border: 1px solid #27272a;
33
+ border-radius: 16px;
34
+ overflow: hidden;
35
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45);
36
+ }
37
+
38
+ header {
39
+ padding: 20px 24px;
40
+ border-bottom: 1px solid #27272a;
41
+ display: flex;
42
+ align-items: center;
43
+ gap: 12px;
44
+ }
45
+
46
+ header h1 {
47
+ font-size: 1.15rem;
48
+ font-weight: 600;
49
+ color: var(--accent);
50
+ }
51
+
52
+ header span {
53
+ font-size: 0.8rem;
54
+ color: #71717a;
55
+ }
56
+
57
+ .badge {
58
+ background: var(--accent);
59
+ color: var(--accent-badge);
60
+ font-size: 0.65rem;
61
+ font-weight: 700;
62
+ padding: 2px 8px;
63
+ border-radius: 999px;
64
+ text-transform: uppercase;
65
+ letter-spacing: 0.05em;
66
+ }
67
+
68
+ .controls {
69
+ display: flex;
70
+ gap: 8px;
71
+ padding: 16px 24px;
72
+ border-bottom: 1px solid #27272a;
73
+ flex-wrap: wrap;
74
+ }
75
+
76
+ button {
77
+ padding: 8px 18px;
78
+ border: none;
79
+ border-radius: 8px;
80
+ cursor: pointer;
81
+ font-size: 0.85rem;
82
+ font-weight: 500;
83
+ transition:
84
+ background 0.2s,
85
+ opacity 0.2s;
86
+ }
87
+
88
+ button:disabled {
89
+ opacity: 0.4;
90
+ cursor: not-allowed;
91
+ }
92
+
93
+ #btn-connect {
94
+ background: var(--accent);
95
+ color: var(--accent-badge);
96
+ }
97
+
98
+ #btn-connect:hover:not(:disabled) {
99
+ background: var(--accent-dark);
100
+ }
101
+
102
+ #btn-disconnect {
103
+ background: #ef4444;
104
+ color: #fff;
105
+ }
106
+
107
+ #btn-disconnect:hover:not(:disabled) {
108
+ background: #dc2626;
109
+ }
110
+
111
+ .notice {
112
+ margin: 0 24px 16px;
113
+ padding: 14px 16px;
114
+ background: var(--notice-bg, #161616);
115
+ border: 1px solid var(--notice-border, #3f3f46);
116
+ border-left: 3px solid var(--accent);
117
+ border-radius: 8px;
118
+ font-size: 0.78rem;
119
+ line-height: 1.6;
120
+ color: var(--notice-text, #e4e4e7);
121
+ }
122
+
123
+ .notice code {
124
+ background: var(--notice-code-bg, #0f0f0f);
125
+ padding: 1px 5px;
126
+ border-radius: 4px;
127
+ font-family: monospace;
128
+ }
129
+
130
+ .info-text {
131
+ margin: 0 24px 4px;
132
+ padding: 10px 0;
133
+ font-size: 0.8rem;
134
+ line-height: 1.6;
135
+ color: #a1a1aa;
136
+ border-bottom: 1px solid #27272a;
137
+ }
138
+
139
+ .info-text code {
140
+ background: #09090b;
141
+ color: #e4e4e7;
142
+ padding: 1px 5px;
143
+ border-radius: 4px;
144
+ font-family: monospace;
145
+ font-size: 0.78rem;
146
+ }
147
+
148
+ .send-row {
149
+ display: flex;
150
+ gap: 8px;
151
+ padding: 0 24px 16px;
152
+ }
153
+
154
+ .send-row input {
155
+ flex: 1;
156
+ padding: 8px 12px;
157
+ border-radius: 8px;
158
+ border: 1px solid #3f3f46;
159
+ background: #09090b;
160
+ color: #e4e4e7;
161
+ font-size: 0.85rem;
162
+ outline: none;
163
+ transition: border-color 0.2s;
164
+ }
165
+
166
+ .send-row input:focus {
167
+ border-color: var(--accent);
168
+ }
169
+
170
+ .send-row input:disabled {
171
+ opacity: 0.4;
172
+ }
173
+
174
+ #btn-send {
175
+ background: #6366f1;
176
+ color: #fff;
177
+ }
178
+
179
+ #btn-send:hover:not(:disabled) {
180
+ background: #4f46e5;
181
+ }
182
+
183
+ #mode-toggle {
184
+ background: var(--accent);
185
+ color: var(--accent-badge);
186
+ font-weight: 700;
187
+ min-width: 54px;
188
+ }
189
+
190
+ #mode-toggle:hover {
191
+ background: var(--accent-dark);
192
+ }
193
+
194
+ #log {
195
+ height: 340px;
196
+ overflow-y: auto;
197
+ padding: 16px 24px;
198
+ font-family: "Fira Code", "Cascadia Code", monospace;
199
+ font-size: 0.8rem;
200
+ line-height: 1.7;
201
+ background: #09090b;
202
+ }
203
+
204
+ .log-line {
205
+ white-space: pre-wrap;
206
+ word-break: break-all;
207
+ }
208
+
209
+ .log-info {
210
+ color: #a1a1aa;
211
+ }
212
+
213
+ .log-event {
214
+ color: var(--log-event, #38bdf8);
215
+ }
216
+
217
+ .log-data {
218
+ color: #4ade80;
219
+ }
220
+
221
+ .log-error {
222
+ color: #f87171;
223
+ }
224
+
225
+ #log::-webkit-scrollbar {
226
+ width: 6px;
227
+ }
228
+
229
+ #log::-webkit-scrollbar-track {
230
+ background: transparent;
231
+ }
232
+
233
+ #log::-webkit-scrollbar-thumb {
234
+ background: #3f3f46;
235
+ border-radius: 3px;
236
+ }
237
+
238
+ .nav-link {
239
+ display: block;
240
+ text-align: center;
241
+ padding: 10px;
242
+ color: #71717a;
243
+ font-size: 0.78rem;
244
+ text-decoration: none;
245
+ border-top: 1px solid #27272a;
246
+ }
247
+
248
+ .nav-link:hover {
249
+ color: var(--accent);
250
+ }
251
+
252
+ .nav-link + .nav-link {
253
+ border-top: none;
254
+ padding-top: 0;
255
+ }
@@ -0,0 +1 @@
1
+ *,:before,:after{box-sizing:border-box;margin:0;padding:0}html,body{height:100%;overflow:hidden}:root{--bg:#f4f4f5;--surface:#fff;--surface-2:#f4f4f5;--surface-3:#e4e4e7;--border:#e4e4e7;--border-hi:#d1d5db;--text:#18181b;--text-muted:#71717a;--text-faint:#a1a1aa;--accent:#22c55e;--accent-dark:#16a34a;--accent-glow:#22c55e1f;--accent-badge:#fff;--sent-bg:var(--accent);--sent-text:#fff;--recv-bg:#e4e4e7;--recv-text:#18181b;--sys-bg:#fef9c3;--sys-text:#713f12;--sys-border:#fbbf24;--err-bg:#fee2e2;--err-text:#991b1b;--err-border:#f87171;--topbar-h:56px;--sidebar-w:320px;--code-w:370px;--code-bg:#1e1e1e;--code-text:#d4d4d4;--code-gutter:#858585;--code-hover:#ffffff0a;--code-border:#3f3f46;--scrollbar:#d1d5db}[data-theme=dark]{--bg:#0f0f12;--surface:#18181b;--surface-2:#1c1c1f;--surface-3:#27272a;--border:#27272a;--border-hi:#3f3f46;--text:#e4e4e7;--text-muted:#71717a;--text-faint:#52525b;--recv-bg:#27272a;--recv-text:#e4e4e7;--sys-bg:#1c1a07;--sys-text:#fcd34d;--sys-border:#854d0e;--err-bg:#1f0707;--err-text:#f87171;--err-border:#7f1d1d;--scrollbar:#3f3f46}body{background:var(--bg);color:var(--text);flex-direction:column;font-family:Segoe UI,system-ui,-apple-system,sans-serif;transition:background .2s,color .2s;display:flex}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:0 0}::-webkit-scrollbar-thumb{background:var(--scrollbar);border-radius:3px}.topbar{height:var(--topbar-h);background:var(--surface);border-bottom:1px solid var(--border);z-index:100;flex-shrink:0;align-items:center;gap:10px;padding:0 14px;display:flex}.topbar-brand{flex-shrink:0;align-items:center;gap:7px;text-decoration:none;display:flex}.brand-icon{font-size:1.1rem}.brand-name{color:var(--text);white-space:nowrap;font-size:.88rem;font-weight:700}.brand-ver{color:var(--text-faint);border:1px solid var(--border);border-radius:4px;padding:1px 6px;font-size:.6rem}.provider-pill{background:var(--accent);color:var(--accent-badge);text-transform:uppercase;letter-spacing:.05em;white-space:nowrap;border-radius:999px;padding:2px 8px;font-size:.6rem;font-weight:700}.topbar-sep{background:var(--border);flex-shrink:0;width:1px;height:22px}.flex-1{flex:1}.topbar-nav{scrollbar-width:none;flex-shrink:0;gap:2px;display:flex;overflow-x:auto}.topbar-nav::-webkit-scrollbar{display:none}.nav-item{color:var(--text-muted);white-space:nowrap;border-radius:7px;align-items:center;gap:5px;padding:5px 10px;font-size:.77rem;font-weight:500;text-decoration:none;transition:background .15s,color .15s;display:flex}.nav-item:hover{background:var(--surface-2);color:var(--text)}.nav-item.active{background:var(--accent-glow);color:var(--accent)}.topbar-actions{flex-shrink:0;align-items:center;gap:6px;display:flex}.status-pill{border:1px solid var(--border);color:var(--text-muted);white-space:nowrap;border-radius:999px;align-items:center;gap:5px;padding:4px 9px;font-size:.7rem;display:flex}.status-dot{background:var(--text-faint);border-radius:50%;flex-shrink:0;width:7px;height:7px;transition:background .2s,box-shadow .2s}.status-dot.connected{background:var(--accent);box-shadow:0 0 5px var(--accent)}.status-dot.connecting{background:#f59e0b;animation:1s infinite blink}.status-dot.error{background:#ef4444}@keyframes blink{0%,to{opacity:1}50%{opacity:.3}}.btn{cursor:pointer;white-space:nowrap;-webkit-user-select:none;user-select:none;border:1px solid #0000;border-radius:8px;justify-content:center;align-items:center;gap:5px;padding:6px 13px;font-size:.77rem;font-weight:500;line-height:1;transition:background .15s,opacity .15s,transform .1s,border-color .15s;display:inline-flex}.btn:active:not(:disabled){transform:scale(.97)}.btn:disabled{opacity:.4;cursor:not-allowed}.btn-connect{background:var(--accent);color:#fff}.btn-connect:hover:not(:disabled){background:var(--accent-dark)}.btn-disconnect{color:#fff;background:#ef4444}.btn-disconnect:hover:not(:disabled){background:#dc2626}.btn-send{color:#fff;background:#6366f1}.btn-send:hover:not(:disabled){background:#4f46e5}.btn-ghost{border-color:var(--border);color:var(--text-muted);background:0 0}.btn-ghost:hover:not(:disabled){background:var(--surface-2);color:var(--text)}.btn-mode{background:var(--accent);color:var(--accent-badge);border-color:#0000;min-width:46px;font-weight:700}.btn-mode:hover{background:var(--accent-dark)}.btn-dl{background:var(--surface);border-color:var(--border);color:var(--text)}.btn-dl:hover:not(:disabled){background:var(--surface-2)}.icon-btn{border:1px solid var(--border);cursor:pointer;width:32px;height:32px;color:var(--text-muted);background:0 0;border-radius:7px;flex-shrink:0;justify-content:center;align-items:center;font-size:.88rem;transition:background .15s,color .15s;display:flex}.icon-btn:hover{background:var(--surface-2);color:var(--text)}.app-layout{flex:1;display:flex;overflow:hidden}.sidebar{width:var(--sidebar-w);background:var(--surface);border-right:1px solid var(--border);flex-direction:column;flex-shrink:0;transition:width .22s;display:flex;overflow:hidden}.sidebar.collapsed{width:0}.sidebar-scroll{flex:1;overflow-y:auto}.sb-section{padding:12px 13px 9px}.sb-section+.sb-section{border-top:1px solid var(--border)}.sb-title{text-transform:uppercase;letter-spacing:.08em;color:var(--text-faint);margin-bottom:9px;font-size:.59rem;font-weight:700}.field{flex-direction:column;gap:3px;margin-bottom:8px;display:flex}.field:last-child{margin-bottom:0}.field-row{gap:7px;display:flex}.field-row .field{flex:1;min-width:0}.field label{color:var(--text-muted);font-size:.68rem;font-weight:500}.field select,.field input[type=text],.field input[type=number],.field input[type=url]{border:1px solid var(--border-hi);background:var(--surface-2);width:100%;color:var(--text);appearance:textfield;border-radius:6px;outline:none;padding:5px 8px;font-size:.75rem;transition:border-color .15s}.field input::-webkit-inner-spin-button{-webkit-appearance:none}.field select:focus,.field input:focus{border-color:var(--accent)}.field-toggle{justify-content:space-between;align-items:center;margin-bottom:8px;padding:1px 0;display:flex}.field-toggle label{color:var(--text-muted);cursor:pointer;font-size:.74rem}.sw{width:34px;height:18px;display:inline-block;position:relative}.sw input{opacity:0;width:0;height:0}.sw-knob{background:var(--surface-3);cursor:pointer;border-radius:999px;transition:background .2s;position:absolute;inset:0}.sw-knob:before{content:"";background:#fff;border-radius:50%;width:12px;height:12px;transition:transform .2s;position:absolute;bottom:3px;left:3px;box-shadow:0 1px 3px #00000040}.sw input:checked+.sw-knob{background:var(--accent)}.sw input:checked+.sw-knob:before{transform:translate(16px)}.dl-lang-row,.dl-type-row{flex-wrap:wrap;gap:5px;margin-bottom:7px;display:flex}.dl-opt{border:1px solid var(--border);background:var(--surface-2);color:var(--text-muted);cursor:pointer;border-radius:6px;align-items:center;gap:4px;padding:3px 9px;font-size:.71rem;transition:all .15s;display:inline-flex}.dl-opt:has(input:checked){border-color:var(--accent);color:var(--accent);background:var(--accent-glow)}.dl-opt:hover{background:var(--surface-3)}.dl-opt input{accent-color:var(--accent)}.dl-btns{flex-wrap:wrap;gap:5px;margin-top:7px;display:flex}.dl-btns .btn{flex:1;font-size:.72rem}.console-area{flex-direction:column;flex:1;min-width:0;display:flex;overflow:hidden}.console-hdr{background:var(--surface);border-bottom:1px solid var(--border);flex-shrink:0;align-items:center;gap:8px;padding:7px 13px;display:flex}.console-hdr .status-pill{font-size:.7rem}.messages{flex-direction:column;flex:1;gap:3px;padding:12px 13px;display:flex;position:relative;overflow-y:auto}.msg{flex-direction:column;max-width:78%;animation:.15s both msgIn;display:flex}@keyframes msgIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.msg.sent{align-self:flex-end;align-items:flex-end}.msg.received{align-self:flex-start;align-items:flex-start}.msg.system,.msg.error{align-self:center;max-width:88%}.msg-label{text-transform:uppercase;letter-spacing:.04em;color:var(--text-faint);margin-bottom:2px;padding:0 4px;font-size:.59rem;font-weight:700}.msg-bubble{word-break:break-word;white-space:pre-wrap;border-radius:14px;padding:7px 12px;font-family:Cascadia Code,Fira Code,monospace;font-size:.79rem;line-height:1.5}.msg.sent .msg-bubble{background:var(--sent-bg);color:var(--sent-text);border-bottom-right-radius:3px}.msg.received .msg-bubble{background:var(--recv-bg);color:var(--recv-text);border-bottom-left-radius:3px}.msg.system .msg-bubble{background:var(--sys-bg);color:var(--sys-text);border-left:3px solid var(--sys-border);border-radius:8px;font-family:inherit;font-size:.73rem}.msg.error .msg-bubble{background:var(--err-bg);color:var(--err-text);border-left:3px solid var(--err-border);border-radius:8px;font-family:inherit;font-size:.73rem}.msg-time{color:var(--text-faint);margin-top:2px;padding:0 4px;font-size:.59rem}.empty-state{color:var(--text-faint);-webkit-user-select:none;user-select:none;pointer-events:none;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;font-size:.78rem;display:flex}.empty-icon{opacity:.3;font-size:2.4rem}.input-bar{background:var(--surface);border-top:1px solid var(--border);flex-shrink:0;align-items:center;gap:7px;padding:10px 12px;display:flex}.msg-input{border:1px solid var(--border-hi);background:var(--surface-2);color:var(--text);border-radius:22px;outline:none;flex:1;padding:8px 14px;font-size:.82rem;transition:border-color .15s}.msg-input:focus{border-color:var(--accent)}.msg-input:disabled{opacity:.4}.code-panel{width:var(--code-w);background:var(--code-bg);border-left:1px solid var(--code-border);flex-direction:column;flex-shrink:0;transition:width .22s;display:flex;overflow:hidden}.code-panel.collapsed{width:0}.cp-hdr{border-bottom:1px solid var(--code-border);background:#252526;flex-shrink:0;justify-content:space-between;align-items:center;gap:8px;padding:7px 11px;display:flex}.cp-title{color:#ccc;align-items:center;gap:6px;font-size:.68rem;font-weight:600;display:flex}.cp-tab{color:#bbb;cursor:default;background:#37373d;border:none;border-radius:4px;padding:2px 8px;font-size:.67rem}.cp-actions{gap:4px;display:flex}.cp-btn{color:#888;cursor:pointer;background:#37373d;border:none;border-radius:4px;padding:3px 8px;font-size:.67rem;transition:all .15s}.cp-btn:hover{color:#ccc;background:#4a4a4f}.cp-btn.copied{color:#4ade80;background:#1e4d2b}.code-view{background:var(--code-bg);flex:1;padding:6px 0;font-family:Cascadia Code,Fira Code,Consolas,monospace;font-size:.72rem;line-height:1.65;overflow:auto}.code-line{min-height:1.65em;display:flex}.code-line:hover{background:var(--code-hover)}.cl-num{text-align:right;width:42px;color:var(--code-gutter);-webkit-user-select:none;user-select:none;flex-shrink:0;padding-right:14px;font-size:.67rem;line-height:1.65}.cl-txt{color:var(--code-text);white-space:pre;flex:1;padding:0 14px}.t-kw{color:#569cd6}.t-str{color:#ce9178}.t-num{color:#b5cea8}.t-cmt{color:#6a9955;font-style:italic}.t-fn{color:#dcdcaa}.t-cls{color:#4ec9b0}.t-var{color:#9cdcfe}.t-typ{color:#4ec9b0}.notice{background:var(--surface-2);border:1px solid var(--border);border-left:3px solid var(--accent);color:var(--text-muted);border-radius:7px;margin-bottom:3px;padding:8px 11px;font-size:.71rem;line-height:1.6}.notice code{background:var(--surface-3);border-radius:3px;padding:1px 5px;font-family:monospace;font-size:.69rem}.mob-toggle{display:none!important}.mob-nav-drawer{top:var(--topbar-h);background:var(--surface);border-bottom:1px solid var(--border);z-index:85;max-height:0;transition:max-height .26s,box-shadow .26s;position:fixed;left:0;right:0;overflow:hidden;box-shadow:0 6px 28px #00000038}.mob-nav-drawer.open{max-height:340px;box-shadow:0 6px 28px #0000004d}.mob-nav-inner{flex-direction:column;gap:9px;padding:10px 12px 12px;display:flex}.mob-nav-links{flex-wrap:wrap;gap:6px;display:flex}.mob-nav-links .nav-item{border:1px solid var(--border);background:var(--surface-2);border-radius:8px;flex:1;justify-content:center;min-width:72px;padding:8px 10px;font-size:.78rem}.mob-nav-links .nav-lbl{display:inline!important}.mob-nav-sep{background:var(--border);height:1px}.mob-nav-actions{flex-wrap:wrap;align-items:center;gap:8px;display:flex}.mob-nav-actions .btn{flex:1;min-width:90px}@media (width<=1200px){:root{--code-w:320px}.mob-toggle{display:flex!important}.topbar-nav{display:none!important}.topbar-sep{display:none}}@media (width<=960px){:root{--sidebar-w:290px}.code-panel{right:0;top:var(--topbar-h);z-index:70;width:min(90vw,400px);transition:transform .28s;position:fixed;bottom:0;transform:translate(calc(100% + 1px));box-shadow:-4px 0 24px #0006}.code-panel:not(.collapsed){transform:translate(0)}.code-toggle{display:flex!important}.resize-handle{display:none!important}}@media (width<=720px){.brand-ver,.topbar-brand{display:none}}@media (width<=640px){.topbar-actions .btn-connect,.topbar-actions .btn-disconnect{display:none}.sidebar{top:var(--topbar-h);z-index:50;position:fixed;bottom:0;left:0;box-shadow:4px 0 24px #0000004d}.sidebar.collapsed{box-shadow:none}}.resize-handle,.sidebar-resize-handle{cursor:col-resize;z-index:10;background:0 0;flex-shrink:0;width:4px;transition:background .15s}.resize-handle:hover,.resize-handle.dragging,.sidebar-resize-handle:hover,.sidebar-resize-handle.dragging{background:var(--accent)}.chip-list{flex-direction:column;gap:5px;margin-top:5px;display:flex}.chip{background:var(--surface-2);border:1px solid var(--border);border-radius:8px;align-items:center;gap:5px;min-width:0;padding:5px 8px;font-size:.71rem;display:flex}.chip-badge{background:var(--accent-glow);color:var(--accent);text-transform:uppercase;letter-spacing:.03em;border-radius:4px;flex-shrink:0;padding:1px 5px;font-size:.57rem;font-weight:700}.chip-name{color:var(--text);text-overflow:ellipsis;white-space:nowrap;flex-shrink:0;max-width:72px;font-weight:600;overflow:hidden}.chip-val{color:var(--text-muted);text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;font-family:Cascadia Code,Fira Code,monospace;font-size:.68rem;overflow:hidden}.chip-send,.chip-del{cursor:pointer;background:var(--surface-3);width:20px;height:20px;color:var(--text-muted);border:none;border-radius:5px;flex-shrink:0;justify-content:center;align-items:center;padding:0;font-size:.68rem;line-height:1;transition:background .15s,color .15s;display:flex}.chip-send:hover{background:var(--accent-glow);color:var(--accent)}.chip-del:hover{color:#dc2626;background:#fee2e2}[data-theme=dark] .chip-del:hover{color:#f87171;background:#3f0707}[data-lucide]{stroke-width:2px;vertical-align:-2px;flex-shrink:0;width:14px;height:14px;display:inline-block}.icon-btn [data-lucide]{width:16px;height:16px}.app-footer{color:var(--text-faint);text-align:center;border-top:1px solid var(--border);background:var(--surface);letter-spacing:.02em;flex-shrink:0;padding:5px 16px;font-size:.63rem}
@@ -0,0 +1,272 @@
1
+ (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=class{listeners={};on(e,t){return this.listeners[e]||(this.listeners[e]=new Set),this.listeners[e].add(t),this}off(e,t){return this.listeners[e]&&this.listeners[e].delete(t),this}emit(e,...t){let n=this.listeners[e];if(!n||n.size===0)return!1;for(let e of n)e(...t);return!0}},t=class{static instances=new Set;static portInstanceMap=new WeakMap;static getInstances(){return Array.from(this.instances)}static register(e){this.instances.add(e)}static unregister(e){this.instances.delete(e)}static isPortInUse(e,t){let n=this.portInstanceMap.get(e);return n!==void 0&&n!==t}static lockPort(e,t){this.portInstanceMap.set(e,t)}static unlockPort(e){this.portInstanceMap.delete(e)}},n=class{queue=[];isProcessing=!1;isPaused=!0;timeoutId=null;commandTimeout;onSend;onTimeout;constructor(e){this.commandTimeout=e.commandTimeout,this.onSend=e.onSend,this.onTimeout=e.onTimeout}get queueSize(){return this.queue.length}enqueue(e){this.queue.push(e),this.tryProcessNext()}advance(){this.clearCommandTimeout(),this.isProcessing=!1,this.tryProcessNext()}pause(){this.isPaused=!0,this.clearCommandTimeout(),this.isProcessing=!1}resume(){this.isPaused=!1,this.tryProcessNext()}clear(){this.queue=[],this.clearCommandTimeout(),this.isProcessing=!1}snapshot(){return[...this.queue]}restore(e){this.queue=[...e,...this.queue]}tryProcessNext(){if(this.isPaused||this.isProcessing||this.queue.length===0)return;this.isProcessing=!0;let e=this.queue.shift();this.commandTimeout>0&&(this.timeoutId=setTimeout(()=>{this.timeoutId=null,this.onTimeout(e),this.advance()},this.commandTimeout)),this.onSend(e).catch(()=>{this.advance()})}clearCommandTimeout(){this.timeoutId!==null&&(clearTimeout(this.timeoutId),this.timeoutId=null)}},r=class e extends Error{constructor(t){super(t),this.name=`SerialPermissionError`,Object.setPrototypeOf(this,e.prototype)}},i=class e extends Error{constructor(t){super(t),this.name=`SerialReadError`,Object.setPrototypeOf(this,e.prototype)}},a=class e extends Error{constructor(t){super(t),this.name=`SerialWriteError`,Object.setPrototypeOf(this,e.prototype)}},o=class o extends e{port=null;reader=null;writer=null;queue;options;isConnecting=!1;abortController=null;userInitiatedDisconnect=!1;reconnectTimerId=null;isHandshaking=!1;static customProvider=null;static polyfillOptions;constructor(e){super(),this.options={baudRate:e.baudRate,dataBits:e.dataBits??8,stopBits:e.stopBits??1,parity:e.parity??`none`,bufferSize:e.bufferSize??255,flowControl:e.flowControl??`none`,filters:e.filters??[],commandTimeout:e.commandTimeout??0,parser:e.parser,autoReconnect:e.autoReconnect??!1,autoReconnectInterval:e.autoReconnectInterval??1500,handshakeTimeout:e.handshakeTimeout??2e3,provider:e.provider,polyfillOptions:e.polyfillOptions},this.queue=new n({commandTimeout:this.options.commandTimeout,onSend:async e=>{await this.writeToPort(e),this.emit(`serial:sent`,e,this)},onTimeout:e=>{this.emit(`serial:timeout`,e,this)}}),this.on(`serial:data`,()=>{this.queue.advance()}),t.register(this)}async handshake(){return!0}async connect(){if(!this.isConnecting&&!this.port){this.isConnecting=!0,this.emit(`serial:connecting`,this);try{let e=this.getSerial();if(!e)throw Error(`Web Serial API is not supported in this browser. Use AbstractSerialDevice.setProvider() to set a WebUSB polyfill.`);if(this.port=await this.findAndValidatePort(),!this.port){let t;try{t=await e.requestPort({filters:this.options.filters},this.options.polyfillOptions??o.polyfillOptions)}catch(e){throw e instanceof DOMException&&(e.name===`NotFoundError`||e.name===`SecurityError`||e.name===`AbortError`)?new r(e instanceof Error?e.message:String(e)):e instanceof Error?e:Error(String(e))}if(!await this.openAndHandshake(t))throw Error(`Handshake failed: the selected device did not respond correctly.`);this.port=t}this.abortController=new AbortController,this.queue.resume(),this.emit(`serial:connected`,this)}catch(e){if(e instanceof r?this.emit(`serial:need-permission`,this):this.emit(`serial:error`,e instanceof Error?e:Error(String(e)),this),this.port){t.unlockPort(this.port);try{await this.port.close()}catch{}this.port=null}throw e}finally{this.isConnecting=!1}}}async disconnect(){this.port&&(this.userInitiatedDisconnect=!0,this.stopReconnecting(),await this.cleanupPort())}async cleanupPort(){if(this.port){this.queue.pause(),this.abortController?.abort(),this.abortController=null;try{let e=this.reader,t=this.writer;if(this.reader=null,this.writer=null,e){try{await e.cancel()}catch{}try{e.releaseLock()}catch{}}if(t){try{await t.close()}catch{}try{t.releaseLock()}catch{}}try{await this.port.close()}catch{}}catch(e){this.emit(`serial:error`,e instanceof Error?e:Error(String(e)),this)}finally{this.port&&t.unlockPort(this.port),this.port=null,this.options.parser?.reset?.(),this.emit(`serial:disconnected`,this),!this.userInitiatedDisconnect&&this.options.autoReconnect&&this.startReconnecting(),this.userInitiatedDisconnect=!1}}}async forget(){await this.disconnect(),this.port&&typeof this.port.forget==`function`&&await this.port.forget(),t.unregister(this)}async send(e){let t;t=typeof e==`string`?new TextEncoder().encode(e):e,t.length>0&&this.queue.enqueue(t)}clearQueue(){this.queue.clear(),this.emit(`serial:queue-empty`,this)}async writeToPort(e){if(!this.port||!this.port.writable)throw new a(`Port not writable.`);this.writer=this.port.writable.getWriter();try{await this.writer.write(e)}catch(e){throw new a(e instanceof Error?e.message:String(e))}finally{this.writer.releaseLock(),this.writer=null}}async readLoop(){if(!(!this.port||!this.port.readable)&&!this.reader){this.reader=this.port.readable.getReader();try{for(;;){let{value:e,done:t}=await this.reader.read();if(t)break;e&&(this.options.parser?this.options.parser.parse(e,e=>{this.emit(`serial:data`,e,this)}):this.emit(`serial:data`,e,this))}}catch(e){if(this.port)throw new i(e instanceof Error?e.message:String(e))}finally{if(this.reader){try{this.reader.releaseLock()}catch{}this.reader=null}}}}async openAndHandshake(e){let n=this;if(t.isPortInUse(e,n))return!1;t.lockPort(e,n);try{await e.open({baudRate:this.options.baudRate,dataBits:this.options.dataBits,stopBits:this.options.stopBits,parity:this.options.parity,bufferSize:this.options.bufferSize,flowControl:this.options.flowControl})}catch(n){throw t.unlockPort(e),n instanceof Error?n:Error(String(n))}this.port=e,this.abortController=new AbortController;let r=this.queue.snapshot();this.isHandshaking=!0,this.readLoop().catch(e=>{!this.isHandshaking&&this.port&&(this.emit(`serial:error`,e,this),this.cleanupPort())}),this.queue.resume();try{let t=await this.runHandshakeWithTimeout();return this.isHandshaking=!1,t?(this.queue.pause(),this.queue.clear(),this.queue.restore(r),this.options.parser?.reset?.(),!0):(await this.teardownHandshake(e,r),!1)}catch{return this.isHandshaking=!1,await this.teardownHandshake(e,r),!1}}async teardownHandshake(e,n){this.queue.pause(),this.queue.clear(),this.queue.restore(n),await this.stopReader(),this.port=null,this.abortController=null,this.options.parser?.reset?.();try{await e.close()}catch{}t.unlockPort(e)}async stopReader(){let e=this.reader;if(this.reader=null,e){try{await e.cancel()}catch{}try{e.releaseLock()}catch{}}}async runHandshakeWithTimeout(){let e=this.options.handshakeTimeout??2e3;return Promise.race([this.handshake(),new Promise(t=>setTimeout(()=>t(!1),e))])}async findAndValidatePort(){let e=this.getSerial();if(!e)return null;let n=await e.getPorts(this.options.polyfillOptions??o.polyfillOptions);if(n.length===0)return null;let r=this.options.filters??[],i=this;for(let e of n)if(!t.isPortInUse(e,i)){if(r.length>0){let t=e.getInfo();if(!r.some(e=>{let n=e.usbVendorId===void 0||e.usbVendorId===t.usbVendorId,r=e.usbProductId===void 0||e.usbProductId===t.usbProductId;return n&&r}))continue}try{if(await this.openAndHandshake(e))return e}catch{}}return null}startReconnecting(){this.reconnectTimerId||=(this.emit(`serial:reconnecting`,this),setInterval(async()=>{if(this.port||this.isConnecting){this.stopReconnecting();return}try{let e=await this.findAndValidatePort();e&&(this.stopReconnecting(),await this.reconnect(e))}catch{}},this.options.autoReconnectInterval))}stopReconnecting(){this.reconnectTimerId&&=(clearInterval(this.reconnectTimerId),null)}async reconnect(e){if(!(this.isConnecting||this.port)){this.isConnecting=!0,this.emit(`serial:connecting`,this);try{this.port=e,this.abortController=new AbortController,this.queue.resume(),this.emit(`serial:connected`,this)}catch(e){this.emit(`serial:error`,e instanceof Error?e:Error(String(e)),this),this.port&&=(t.unlockPort(this.port),null),this.options.autoReconnect&&this.startReconnecting()}finally{this.isConnecting=!1}}}static getInstances(){return t.getInstances()}static async connectAll(){let e=t.getInstances();for(let t of e)try{await t.connect()}catch{}}static setProvider(e,t){o.customProvider=e,o.polyfillOptions=t}getSerial(){return this.options.provider?this.options.provider:o.customProvider?o.customProvider:typeof navigator<`u`&&navigator.serial?navigator.serial:null}};function s(e){let t=``,n=new TextDecoder;return{parse(r,i){t+=n.decode(r,{stream:!0});let a;for(;(a=t.indexOf(e))!==-1;)i(t.slice(0,a)),t=t.slice(a+e.length)},reset(){t=``,n=new TextDecoder}}}var c=`wsc-demo-theme`;function l(){return window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`}function u(){let e=localStorage.getItem(c)??l();return document.documentElement.setAttribute(`data-theme`,e),window.matchMedia(`(prefers-color-scheme: dark)`).addEventListener(`change`,e=>{localStorage.getItem(c)||document.documentElement.setAttribute(`data-theme`,e.matches?`dark`:`light`)}),e}function d(){let e=(document.documentElement.getAttribute(`data-theme`)??l())===`dark`?`light`:`dark`;return localStorage.setItem(c,e),document.documentElement.setAttribute(`data-theme`,e),e}function f(e,t,n){let r=e.querySelector(`.empty-state`);r&&r.remove();let{kind:i,label:a,time:o=new Date}=n,s=document.createElement(`div`);if(s.className=`msg ${i}`,a&&(i===`sent`||i===`received`)){let e=document.createElement(`div`);e.className=`msg-label`,e.textContent=a,s.appendChild(e)}let c=document.createElement(`div`);c.className=`msg-bubble`,c.textContent=t,s.appendChild(c);let l=document.createElement(`div`);l.className=`msg-time`,l.textContent=o.toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`,second:`2-digit`}),s.appendChild(l),e.appendChild(s),e.scrollTop=e.scrollHeight}function p(e){e.innerHTML=`
2
+ <div class="empty-state">
3
+ <div class="empty-icon">💬</div>
4
+ <span>Messages cleared</span>
5
+ </div>`}var m=new Set(`import.export.from.default.as.class.extends.implements.constructor.super.new.this.return.const.let.var.async.await.function.protected.public.private.static.abstract.interface.type.enum.namespace.declare.readonly.true.false.null.undefined.void.never.any.unknown.if.else.for.while.do.switch.case.break.continue.try.catch.finally.throw.typeof.instanceof.in.of.keyof.infer.string.number.boolean.object.symbol.bigint.Promise.Array.Set.Map`.split(`.`));function h(e){return e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`)}function g(e){let t=``,n=0,r=e.length;for(;n<r;){if(e[n]===`/`&&e[n+1]===`/`){t+=`<span class="t-cmt">${h(e.slice(n))}</span>`;break}let i=e[n];if(i===`'`||i===`"`||i==="`"){let a=n+1;for(;a<r;){if(e[a]===`\\`&&a+1<r){a+=2;continue}if(e[a]===i){a++;break}a++}t+=`<span class="t-str">${h(e.slice(n,a))}</span>`,n=a;continue}if(/\d/.test(e[n])&&(n===0||!/\w/.test(e[n-1]))){let i=n;for(;i<r&&/[\d.xXa-fA-F_n]/.test(e[i]);)i++;t+=`<span class="t-num">${h(e.slice(n,i))}</span>`,n=i;continue}if(/[a-zA-Z_$]/.test(e[n])){let i=n;for(;i<r&&/[\w$]/.test(e[i]);)i++;let a=e.slice(n,i);m.has(a)?t+=`<span class="t-kw">${h(a)}</span>`:i<r&&e[i]===`(`?t+=`<span class="t-fn">${h(a)}</span>`:/^[A-Z]/.test(a)?t+=`<span class="t-cls">${h(a)}</span>`:t+=`<span class="t-var">${h(a)}</span>`,n=i;continue}t+=h(e[n]),n++}return t}function _(e,t){let n=t.split(`
6
+ `);e.innerHTML=``,n.forEach((t,n)=>{let r=document.createElement(`div`);r.className=`code-line`;let i=document.createElement(`span`);i.className=`cl-num`,i.textContent=String(n+1);let a=document.createElement(`span`);a.className=`cl-txt`,a.innerHTML=g(t)||` `,r.appendChild(i),r.appendChild(a),e.appendChild(r)})}function v(e){return`'${e.replace(/\\(?![nrt0\\'])/g,`\\\\`).replace(/'/g,`\\'`)}'`}function y(e){return e.replace(/\\n/g,`
7
+ `).replace(/\\r/g,`\r`).replace(/\\t/g,` `).replace(/\\0/g,`\0`)}function b(e){return!e||e.length===0?`[]`:`[${e.map(e=>{let t=[];return e.usbVendorId!==void 0&&t.push(`usbVendorId: 0x${e.usbVendorId.toString(16).padStart(4,`0`)}`),e.usbProductId!==void 0&&t.push(`usbProductId: 0x${e.usbProductId.toString(16).padStart(4,`0`)}`),`{ ${t.join(`, `)} }`}).join(`, `)}]`}function x(e){return e.trim().split(/\s+/).filter(Boolean).map(e=>parseInt(e,16)).filter(e=>!isNaN(e))}function S(e){let t=x(e);return t.length===0?`new Uint8Array([])`:`new Uint8Array([${t.map(e=>`0x${e.toString(16).padStart(2,`0`)}`).join(`, `)}])`}function C(e){return e.replace(/[^a-zA-Z0-9 _-]/g,``).split(/[\s_-]+/).filter(Boolean).map((e,t)=>t===0?e.charAt(0).toLowerCase()+e.slice(1).toLowerCase():e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(``)||`cmd`}function w(e,t){if(e.length===0)return``;let n=t.charAt(0).toLowerCase()+t.slice(1);return`
8
+ declare module 'webserial-core' {
9
+ interface SerialEventMap<T> {
10
+ `+e.map(e=>` '${n}:${C(e.name||`listener`)}': (data: string) => void;`).join(`
11
+ `)+`
12
+ }
13
+ }
14
+ `}function T(e,t){if(e.length===0)return``;let n=t?`: Promise<void>`:``,r=t?`public `:``;return`
15
+ `+e.map(e=>{let t=C(e.name),i=`send`+t.charAt(0).toUpperCase()+t.slice(1);return e.mode===`hex`?` ${r}${i}()${n} { return this.send(${S(e.value)}); } // ${e.name}`:` ${r}${i}()${n} { return this.send('${e.value.replace(/'/g,`\\'`)}'); } // ${e.name}`}).join(`
16
+ `)+`
17
+ `}function E(e,t,n){if(e.length===0)return``;let r=t.charAt(0).toLowerCase()+t.slice(1),i=n?`(data: string)`:`(data)`,a=n?`: void`:``,o=e.map(e=>{let t=e.name||`listener`,n=`${r}:${C(t)}`,i;switch(e.match){case`contains`:i=`String(data).includes('${e.pattern.replace(/'/g,`\\'`)}')`;break;case`startsWith`:i=`String(data).startsWith('${e.pattern.replace(/'/g,`\\'`)}')`;break;case`hex`:i=`(() => { const enc = new TextEncoder().encode(String(data)); const ex = ${`[${x(e.pattern).map(e=>`0x${e.toString(16).padStart(2,`0`)}`).join(`, `)}]`}; return enc.length === ex.length && enc.every((b, i) => b === ex[i]); })()`;break;default:i=`String(data).trim() === '${e.pattern.replace(/'/g,`\\'`)}' `}return` // ${t}\n if (${i}) {\n this.emit('${n}', data);\n }`}).join(`
18
+ `);return`\n ${n?`private `:``}startListening()${a} {\n this.on('serial:data', ${i} => {\n${o}\n });\n }\n`}function D(e,t,n,r,i){if(!e)return` // No handshake configured — accept any device.
19
+ return true;`;let a;if(a=t===`hex`?` await this.send(${S(e)});`:` await this.send('${e.replace(/'/g,`\\'`)}');`,!n)return`${a}\n return true;`;let o=i?`(data: string)`:`(data)`,s;return s=r===`hex`?`(() => { const enc = new TextEncoder().encode(String(data)); const ex = ${`[${x(n).map(e=>`0x${e.toString(16).padStart(2,`0`)}`).join(`, `)}]`}; return enc.length === ex.length && enc.every((b, i) => b === ex[i]); })()`:`String(data).trim() === '${n.replace(/'/g,`\\'`)}'`,`${a}\n return new Promise((resolve) => {\n const _h = ${o} => {\n this.off('serial:data', _h);\n resolve(${s});\n };\n this.on('serial:data', _h);\n });`}function O(e,t,n,r=[],i=[]){let a=n?`ts`:`js`,o=v(e.delimiter||`\\n`),s=n?`: Promise<boolean>`:``,c=n?`: SerialPortFilter[]`:``,l=n?`
20
+ import type { SerialPortFilter } from 'webserial-core';`:``,u=b(e.filters);return`// device.${a} — Generated by webserial-core demo
21
+ import { AbstractSerialDevice, delimiter } from 'webserial-core';${l}
22
+ ${n?w(i,t):``}
23
+ export class ${t} extends AbstractSerialDevice${n?`<string>`:``} {
24
+ constructor(filters${n?`${c}`:` = []`}) {
25
+ super({
26
+ baudRate: ${e.baudRate},
27
+ dataBits: ${e.dataBits},
28
+ stopBits: ${e.stopBits},
29
+ parity: '${e.parity}',
30
+ flowControl: '${e.flowControl}',
31
+ bufferSize: ${e.bufferSize},
32
+ commandTimeout: ${e.commandTimeout},
33
+ parser: delimiter(${o}),
34
+ autoReconnect: ${e.autoReconnect},
35
+ autoReconnectInterval: ${e.autoReconnectInterval},
36
+ handshakeTimeout: ${e.handshakeTimeout},
37
+ filters,
38
+ });${i.length>0?`
39
+ this.startListening();`:``}
40
+ }
41
+
42
+ ${n?`protected `:``}async handshake()${s} {
43
+ ${D(e.hsCmd,e.hsCmdMode,e.hsExpect,e.hsExpectMode,n)}
44
+ }
45
+ ${T(r,n)}${E(i,t,n)}}
46
+
47
+ // ── Usage ────────────────────────────────────────────────────────
48
+ const device = new ${t}(${u});
49
+
50
+ device.on('serial:connected', () => console.log('Connected!'));
51
+ device.on('serial:disconnected', () => console.log('Disconnected.'));
52
+ device.on('serial:data', (data) => console.log('← ', data));
53
+ device.on('serial:error', (err) => console.error(err.message));
54
+
55
+ // Must be called from a user-gesture (click handler):
56
+ // await device.connect();
57
+
58
+ // Send a message (prepend/append applied in your UI layer):
59
+ // await device.send('${e.prepend}COMMAND${e.append}');
60
+
61
+ // Disconnect:
62
+ // await device.disconnect();
63
+ `}function k(e,t,n,r=[],i=[]){let a=n?`ts`:`js`,o=v(e.delimiter||`\\n`),s=n?`: Promise<boolean>`:``;return`// device.${a} — Generated by webserial-core demo
64
+ import { AbstractSerialDevice, delimiter, createBluetoothProvider } from 'webserial-core';
65
+
66
+ // Inject the BLE provider before creating any device instance.
67
+ AbstractSerialDevice.setProvider(createBluetoothProvider());
68
+ ${n?w(i,t):``}
69
+ export class ${t} extends AbstractSerialDevice${n?`<string>`:``} {
70
+ constructor() {
71
+ super({
72
+ baudRate: 9600, // Nominal — not used over BLE GATT
73
+ bufferSize: ${e.bufferSize},
74
+ commandTimeout: ${e.commandTimeout},
75
+ parser: delimiter(${o}),
76
+ autoReconnect: false, // BLE requires user gesture to reconnect
77
+ handshakeTimeout: ${e.handshakeTimeout},
78
+ });${i.length>0?`
79
+ this.startListening();`:``}
80
+ }
81
+
82
+ ${n?`protected `:``}async handshake()${s} {
83
+ ${D(e.hsCmd,e.hsCmdMode,e.hsExpect,e.hsExpectMode,n)}
84
+ }
85
+ ${T(r,n)}${E(i,t,n)}}
86
+
87
+ // ── Usage ────────────────────────────────────────────────────────
88
+ const device = new ${t}();
89
+
90
+ device.on('serial:connected', () => console.log('BLE connected!'));
91
+ device.on('serial:disconnected', () => console.log('Disconnected.'));
92
+ device.on('serial:data', (data) => console.log('← ', data));
93
+ device.on('serial:error', (err) => console.error(err.message));
94
+
95
+ // Must be called from a user-gesture:
96
+ // await device.connect();
97
+ // await device.send('${e.prepend}COMMAND${e.append}');
98
+ // await device.disconnect();
99
+ `}function A(e,t,n,r=[],i=[]){let a=n?`ts`:`js`,o=v(e.delimiter||`\\n`),s=n?`: Promise<boolean>`:``,c=n?`: SerialPortFilter[]`:``,l=n?`
100
+ import type { SerialPortFilter } from 'webserial-core';`:``,u=b(e.filters);return`// device.${a} — Generated by webserial-core demo
101
+ import { AbstractSerialDevice, delimiter, WebUsbProvider } from 'webserial-core';${l}
102
+
103
+ // Inject the WebUSB polyfill provider.
104
+ AbstractSerialDevice.setProvider(
105
+ new WebUsbProvider({
106
+ usbControlInterfaceClass: ${e.usbControlInterfaceClass},
107
+ usbTransferInterfaceClass: ${e.usbTransferInterfaceClass},
108
+ })
109
+ );
110
+ ${n?w(i,t):``}
111
+ export class ${t} extends AbstractSerialDevice${n?`<string>`:``} {
112
+ constructor(filters${n?`${c}`:` = []`}) {
113
+ super({
114
+ baudRate: ${e.baudRate},
115
+ dataBits: ${e.dataBits},
116
+ stopBits: ${e.stopBits},
117
+ parity: '${e.parity}',
118
+ flowControl: '${e.flowControl}',
119
+ bufferSize: ${e.bufferSize},
120
+ commandTimeout: ${e.commandTimeout},
121
+ parser: delimiter(${o}),
122
+ autoReconnect: ${e.autoReconnect},
123
+ autoReconnectInterval: ${e.autoReconnectInterval},
124
+ handshakeTimeout: ${e.handshakeTimeout},
125
+ filters,
126
+ });${i.length>0?`
127
+ this.startListening();`:``}
128
+ }
129
+
130
+ ${n?`protected `:``}async handshake()${s} {
131
+ ${D(e.hsCmd,e.hsCmdMode,e.hsExpect,e.hsExpectMode,n)}
132
+ }
133
+ ${T(r,n)}${E(i,t,n)}}
134
+
135
+ // ── Usage ────────────────────────────────────────────────────────
136
+ // CP2102/ESP32: { usbVendorId: 0x10c4, usbProductId: 0xea60 }
137
+ // CH340/Arduino: { usbVendorId: 0x1a86, usbProductId: 0x7523 }
138
+ const device = new ${t}(${u});
139
+
140
+ device.on('serial:connected', () => console.log('USB connected!'));
141
+ device.on('serial:disconnected', () => console.log('Disconnected.'));
142
+ device.on('serial:data', (data) => console.log('← ', data));
143
+ device.on('serial:error', (err) => console.error(err.message));
144
+
145
+ // await device.connect();
146
+ // await device.send('${e.prepend}COMMAND${e.append}');
147
+ // await device.disconnect();
148
+ `}function j(e,t,n,r=[],i=[]){let a=n?`ts`:`js`,o=v(e.delimiter||`\\n`),s=n?`: Promise<boolean>`:``;return`// device.${a} — Generated by webserial-core demo
149
+ import { AbstractSerialDevice, delimiter, createWebSocketProvider } from 'webserial-core';
150
+
151
+ // Inject the WebSocket bridge provider.
152
+ // Start the Node.js bridge first: cd demos/websocket && node server.js
153
+ const wsProvider = createWebSocketProvider('${e.wsUrl}');
154
+ AbstractSerialDevice.setProvider(wsProvider);
155
+ ${n?w(i,t):``}
156
+ export class ${t} extends AbstractSerialDevice${n?`<string>`:``} {
157
+ constructor() {
158
+ super({
159
+ baudRate: ${e.baudRate},
160
+ dataBits: ${e.dataBits},
161
+ stopBits: ${e.stopBits},
162
+ parity: '${e.parity}',
163
+ flowControl: '${e.flowControl}',
164
+ bufferSize: ${e.bufferSize},
165
+ commandTimeout: ${e.commandTimeout},
166
+ parser: delimiter(${o}),
167
+ autoReconnect: ${e.autoReconnect},
168
+ autoReconnectInterval: ${e.autoReconnectInterval},
169
+ handshakeTimeout: ${e.handshakeTimeout},
170
+ });${i.length>0?`
171
+ this.startListening();`:``}
172
+ }
173
+
174
+ ${n?`protected `:``}async handshake()${s} {
175
+ ${D(e.hsCmd,e.hsCmdMode,e.hsExpect,e.hsExpectMode,n)}
176
+ }
177
+ ${T(r,n)}${E(i,t,n)}}
178
+
179
+ // ── Usage ────────────────────────────────────────────────────────
180
+ const device = new ${t}();
181
+
182
+ device.on('serial:connected', () => console.log('WS connected!'));
183
+ device.on('serial:disconnected', () => console.log('Disconnected.'));
184
+ device.on('serial:data', (data) => console.log('← ', data));
185
+ device.on('serial:error', (err) => console.error(err.message));
186
+
187
+ // await device.connect();
188
+ // await device.send('${e.prepend}COMMAND${e.append}');
189
+ // await device.disconnect();
190
+ `}function M(e,t,n){let r=n===`ws`?{ws:`^8.0.0`}:{},i={vite:`^8.0.0`,...t?{typescript:`~5.9.3`}:{}};return JSON.stringify({name:e.toLowerCase().replace(/\s+/g,`-`).replace(/[^a-z0-9-]/g,``),version:`1.0.0`,type:`module`,scripts:{dev:`vite`,build:`vite build`,preview:`vite preview`},dependencies:{"webserial-core":`^2.0.0`,...r},devDependencies:i},null,2)}function N(){return JSON.stringify({compilerOptions:{target:`ES2022`,useDefineForClassFields:!0,lib:[`ES2022`,`DOM`,`DOM.Iterable`],module:`ESNext`,skipLibCheck:!0,moduleResolution:`bundler`,allowImportingTsExtensions:!0,strict:!0,noEmit:!0},include:[`**/*.ts`]},null,2)}function P(e,t,n){return`<!doctype html>
191
+ <html lang="en">
192
+ <head>
193
+ <meta charset="UTF-8" />
194
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
195
+ <title>${e} — ${n}</title>
196
+ <style>
197
+ body { font-family: system-ui, sans-serif; max-width: 600px; margin: 40px auto; padding: 0 16px; }
198
+ pre { background: #0f0f0f; color: #4ade80; padding: 12px; border-radius: 8px; font-size: 0.82rem; min-height: 120px; overflow-y: auto; }
199
+ .controls { display: flex; gap: 8px; margin-bottom: 12px; }
200
+ button { padding: 8px 16px; border-radius: 6px; border: none; cursor: pointer; }
201
+ #btn-connect { background: #22c55e; color: #fff; }
202
+ #btn-disconnect { background: #ef4444; color: #fff; }
203
+ #btn-send { background: #6366f1; color: #fff; }
204
+ input { flex: 1; padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; }
205
+ </style>
206
+ </head>
207
+ <body>
208
+ <h2>${e}</h2>
209
+ <div class="controls">
210
+ <button id="btn-connect">Connect</button>
211
+ <button id="btn-disconnect" disabled>Disconnect</button>
212
+ </div>
213
+ <div class="controls">
214
+ <input id="input-send" type="text" placeholder="Command, e.g. LED_ON" disabled />
215
+ <button id="btn-send" disabled>Send</button>
216
+ </div>
217
+ <pre id="log">Waiting for connection...</pre>
218
+
219
+ <script type="module">
220
+ import { ${e} } from './device.${t}';
221
+ const device = new ${e}();
222
+ const log = (msg) => {
223
+ document.getElementById('log').textContent += msg + '\\n';
224
+ };
225
+ device.on('serial:connected', () => { log('✓ Connected'); document.getElementById('btn-disconnect').disabled = false; document.getElementById('btn-send').disabled = false; document.getElementById('input-send').disabled = false; });
226
+ device.on('serial:disconnected', () => { log('✗ Disconnected'); document.getElementById('btn-disconnect').disabled = true; document.getElementById('btn-send').disabled = true; document.getElementById('input-send').disabled = true; });
227
+ device.on('serial:data', (data) => log('← ' + data));
228
+ device.on('serial:error', (err) => log('⚠ ' + err.message));
229
+ document.getElementById('btn-connect').onclick = () => device.connect();
230
+ document.getElementById('btn-disconnect').onclick = () => device.disconnect();
231
+ document.getElementById('btn-send').onclick = () => {
232
+ const v = document.getElementById('input-send').value.trim();
233
+ if (v) { device.send(v + '\\n'); document.getElementById('input-send').value = ''; }
234
+ };
235
+ document.getElementById('input-send').onkeydown = (e) => { if (e.key === 'Enter') document.getElementById('btn-send').click(); };
236
+ <\/script>
237
+ </body>
238
+ </html>
239
+ `}function F(e,t,n,r){return`# ${e}
240
+
241
+ A ${n} device using [webserial-core](https://github.com/danidoble/webserial-core).
242
+
243
+ ${r}
244
+
245
+ ## Setup
246
+
247
+ \`\`\`bash
248
+ npm install
249
+ npm run dev
250
+ \`\`\`
251
+
252
+ ## Usage
253
+
254
+ \`\`\`typescript
255
+ import { ${e} } from './device.${t}';
256
+
257
+ const device = new ${e}();
258
+
259
+ device.on('serial:data', (data) => {
260
+ console.log('Received:', data);
261
+ });
262
+
263
+ // Must be called from a user-gesture (button click):
264
+ await device.connect();
265
+
266
+ // Send data:
267
+ await device.send('LED_ON\\n');
268
+
269
+ // Disconnect:
270
+ await device.disconnect();
271
+ \`\`\`
272
+ `}function I(e,t){let n=new Blob([t],{type:`text/plain;charset=utf-8`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=e,document.body.appendChild(i),i.click(),document.body.removeChild(i),URL.revokeObjectURL(r)}function L(e,t){let n=JSON.stringify(e,null,2),r=new Blob([n],{type:`application/json;charset=utf-8`}),i=URL.createObjectURL(r),a=document.createElement(`a`);a.href=i,a.download=t.endsWith(`.json`)?t:t+`.json`,document.body.appendChild(a),a.click(),document.body.removeChild(a),URL.revokeObjectURL(i)}function R(e,t){let n=new TextEncoder,r=W(e.map(e=>({name:e.name,data:n.encode(e.content)}))),i=new Blob([r.buffer],{type:`application/zip`}),a=URL.createObjectURL(i),o=document.createElement(`a`);o.href=a,o.download=t.endsWith(`.zip`)?t:t+`.zip`,document.body.appendChild(o),o.click(),document.body.removeChild(o),URL.revokeObjectURL(a)}var z=null;function B(){if(z)return z;z=new Uint32Array(256);for(let e=0;e<256;e++){let t=e;for(let e=0;e<8;e++)t=t&1?3988292384^t>>>1:t>>>1;z[e]=t>>>0}return z}function V(e){let t=B(),n=4294967295;for(let r=0;r<e.length;r++)n=n>>>8^t[(n^e[r])&255];return(n^4294967295)>>>0}function H(e,t,n){new DataView(e.buffer,e.byteOffset+t).setUint16(0,n,!0)}function U(e,t,n){new DataView(e.buffer,e.byteOffset+t).setUint32(0,n,!0)}function W(e){let t=new TextEncoder,n=[],r=0;for(let i of e){let e=t.encode(i.name),a=V(i.data),o=new Uint8Array(30+e.length);U(o,0,67324752),H(o,4,20),H(o,6,0),H(o,8,0),H(o,10,0),H(o,12,0),U(o,14,a),U(o,18,i.data.length),U(o,22,i.data.length),H(o,26,e.length),H(o,28,0),o.set(e,30);let s=new Uint8Array(46+e.length);U(s,0,33639248),H(s,4,20),H(s,6,20),H(s,8,0),H(s,10,0),H(s,12,0),H(s,14,0),U(s,16,a),U(s,20,i.data.length),U(s,24,i.data.length),H(s,28,e.length),H(s,30,0),H(s,32,0),H(s,34,0),H(s,36,0),U(s,38,0),U(s,42,r),s.set(e,46),n.push({localHdr:o,data:i.data,cdHdr:s,offset:r}),r+=o.length+i.data.length}let i=n.reduce((e,t)=>e+t.cdHdr.length,0),a=new Uint8Array(22);U(a,0,101010256),H(a,4,0),H(a,6,0),H(a,8,n.length),H(a,10,n.length),U(a,12,i),U(a,16,r),H(a,20,0);let o=new Uint8Array(r+i+a.length),s=0;for(let e of n)o.set(e.localHdr,s),s+=e.localHdr.length,o.set(e.data,s),s+=e.data.length;for(let e of n)o.set(e.cdHdr,s),s+=e.cdHdr.length;return o.set(a,s),o}function G(e){let t=document.createElement(`canvas`);t.style.cssText=`position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:0;opacity:0.55;`,e.insertBefore(t,e.firstChild);let n=t.getContext(`2d`),r=window.devicePixelRatio||1,i=[],a=[],o=[],s=0,c=0;function l(){let l=e.getBoundingClientRect();s=Math.max(l.width,1),c=Math.max(l.height,1),t.width=Math.round(s*r),t.height=Math.round(c*r),t.style.width=`${s}px`,t.style.height=`${c}px`,n.setTransform(r,0,0,r,0,0);let u=Math.ceil(s/52),d=Math.ceil(c/52);i=[];let f=new Map,p=(e,t)=>{f.set(`${e},${t}`,(f.get(`${e},${t}`)??0)+1)};for(let e=0;e<=d;e++)for(let t=0;t<=u;t++){let n=t*52,r=e*52;t<u&&Math.random()>.22&&(i.push({x1:n,y1:r,x2:n+52,y2:r}),p(n,r),p(n+52,r)),e<d&&Math.random()>.22&&(i.push({x1:n,y1:r,x2:n,y2:r+52}),p(n,r),p(n,r+52))}a=Array.from(f.keys()).map(e=>{let[t,n]=e.split(`,`).map(Number);return[t,n]});let m=Math.max(10,Math.min(35,Math.floor(s*c/11e3)));o=Array.from({length:m},()=>({seg:Math.floor(Math.random()*Math.max(1,i.length)),t:Math.random(),speed:.004+Math.random()*.009,sz:1.5+Math.random()*2}))}function u(){let e=getComputedStyle(document.documentElement).getPropertyValue(`--accent`).trim();if(e.startsWith(`#`)){let t=e.length===4?e.slice(1).split(``).map(e=>e+e).join(``):e.slice(1);return[0,2,4].map(e=>parseInt(t.slice(e,e+2),16)).join(`,`)}return`34,197,94`}let d=0;function f(){n.clearRect(0,0,s,c);let e=u();n.strokeStyle=`rgba(${e},0.07)`,n.lineWidth=.8;for(let e of i)n.beginPath(),n.moveTo(e.x1,e.y1),n.lineTo(e.x2,e.y2),n.stroke();for(let[t,r]of a)n.beginPath(),n.arc(t,r,3.8,0,Math.PI*2),n.fillStyle=`rgba(${e},0.05)`,n.fill(),n.strokeStyle=`rgba(${e},0.2)`,n.lineWidth=.7,n.stroke(),n.beginPath(),n.arc(t,r,1.4,0,Math.PI*2),n.fillStyle=`rgba(${e},0.25)`,n.fill();for(let t of o){let r=i[t.seg];if(!r)continue;let a=r.x1+(r.x2-r.x1)*t.t,o=r.y1+(r.y2-r.y1)*t.t,s=Math.max(0,t.t-.24),c=r.x1+(r.x2-r.x1)*s,l=r.y1+(r.y2-r.y1)*s,u=n.createLinearGradient(c,l,a,o);u.addColorStop(0,`rgba(${e},0)`),u.addColorStop(1,`rgba(${e},0.42)`),n.strokeStyle=u,n.lineWidth=2,n.beginPath(),n.moveTo(c,l),n.lineTo(a,o),n.stroke();let d=n.createRadialGradient(a,o,0,a,o,t.sz*7);d.addColorStop(0,`rgba(${e},0.5)`),d.addColorStop(.4,`rgba(${e},0.15)`),d.addColorStop(1,`rgba(${e},0)`),n.fillStyle=d,n.beginPath(),n.arc(a,o,t.sz*7,0,Math.PI*2),n.fill(),n.fillStyle=`rgba(${e},1)`,n.beginPath(),n.arc(a,o,t.sz,0,Math.PI*2),n.fill(),n.fillStyle=`rgba(255,255,255,0.75)`,n.beginPath(),n.arc(a,o,t.sz*.4,0,Math.PI*2),n.fill(),t.t+=t.speed,t.t>=1&&(t.t=0,t.seg=Math.floor(Math.random()*i.length))}d=requestAnimationFrame(f)}l(),f(),new ResizeObserver(()=>{cancelAnimationFrame(d),l(),f()}).observe(e)}function K(){let e=document.querySelector(`.topbar`);if(!e)return;let t=document.createElement(`button`);t.className=`icon-btn mob-toggle`,t.title=`Navigation menu`,t.innerHTML=`<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2.2" fill="none" stroke-linecap="round"><circle cx="12" cy="5" r="1.3"/><circle cx="12" cy="12" r="1.3"/><circle cx="12" cy="19" r="1.3"/></svg>`,e.appendChild(t);let n=document.createElement(`div`);n.className=`mob-nav-drawer`;let r=document.createElement(`div`);r.className=`mob-nav-inner`;let i=e.querySelector(`.topbar-nav`);if(i){let e=document.createElement(`div`);e.className=`mob-nav-links`,i.querySelectorAll(`.nav-item`).forEach(t=>{e.appendChild(t.cloneNode(!0))}),r.appendChild(e)}let a=document.createElement(`div`);a.className=`mob-nav-sep`,r.appendChild(a);let o=document.createElement(`div`);o.className=`mob-nav-actions`;let s=document.getElementById(`btn-connect`),c=document.getElementById(`btn-disconnect`),l=(e,t,r)=>{let i=document.createElement(`button`);return i.className=`btn ${t}`,i.textContent=r,e&&(i.disabled=e.disabled,new MutationObserver(()=>{i.disabled=e.disabled}).observe(e,{attributes:!0,attributeFilter:[`disabled`]}),i.addEventListener(`click`,()=>{e.click(),n.classList.remove(`open`)})),i};o.appendChild(l(s,`btn-connect`,`Connect`)),o.appendChild(l(c,`btn-disconnect`,`Disconnect`)),r.appendChild(o),n.appendChild(r),document.body.appendChild(n),t.addEventListener(`click`,e=>{e.stopPropagation(),n.classList.toggle(`open`)}),document.addEventListener(`click`,()=>n.classList.remove(`open`)),n.addEventListener(`click`,e=>e.stopPropagation())}export{N as _,I as a,s as b,O as c,G as d,K as f,F as g,M as h,L as i,A as l,P as m,p as n,R as o,u as p,y as r,k as s,f as t,j as u,_ as v,o as x,d as y};
@@ -0,0 +1 @@
1
+ import{_ as e,a as t,b as n,d as r,f as i,g as a,h as o,i as s,m as ee,n as c,o as te,p as l,r as u,s as ne,t as d,v as re,x as f,y as ie}from"./demo-shared-DnvFynUr.js";var p=`6e400001-b5a3-f393-e0a9-e50e24dcca9e`,ae=`6e400003-b5a3-f393-e0a9-e50e24dcca9e`,oe=`6e400002-b5a3-f393-e0a9-e50e24dcca9e`,m=20,se=10;function ce(e){let t=null,n=null,r=null;return{get readable(){return t},get writable(){return n},getInfo(){return{}},async open(){if(!e.gatt)throw Error(`GATT not available on this Bluetooth device.`);r=await e.gatt.connect();let i=await r.getPrimaryService(p),a=await i.getCharacteristic(ae),o=await i.getCharacteristic(oe);await a.startNotifications(),t=new ReadableStream({start(e){a.addEventListener(`characteristicvaluechanged`,t=>{let n=t.target.value.buffer;e.enqueue(new Uint8Array(n))})}}),n=new WritableStream({async write(e){for(let t=0;t<e.length;t+=m){let n=e.slice(t,t+m);await o.writeValueWithoutResponse(n),t+m<e.length&&await new Promise(e=>setTimeout(e,se))}}})},async close(){r?.connected&&r.disconnect(),t=null,n=null}}}function le(){return{async requestPort(){if(!navigator.bluetooth)throw Error(`Web Bluetooth API is not supported in this browser. Use Chrome on Android, macOS, or ChromeOS.`);return ce(await navigator.bluetooth.requestDevice({filters:[{services:[p]}]}))},async getPorts(){return[]}}}f.setProvider(le());var h=[],g=[],ue=class extends f{_hsCmd;_hsCmdMode;_hsExpect;_hsExpectMode;constructor(e,t,n,r,i){super(e),this._hsCmd=t,this._hsCmdMode=n,this._hsExpect=r,this._hsExpectMode=i}async handshake(){if(!this._hsCmd||(this._hsCmdMode===`hex`?await this.send(I(this._hsCmd)):await this.send(u(this._hsCmd)),!this._hsExpect))return!0;let e=this._hsExpect.trim();return new Promise(t=>{let n=r=>{if(this.off(`serial:data`,n),this._hsExpectMode===`hex`){let e=new TextEncoder().encode(String(r)),n=I(this._hsExpect);t(e.length===n.length&&e.every((e,t)=>e===n[t]))}else t(String(r).trim()===e)};this.on(`serial:data`,n)})}},_=e=>document.getElementById(e),v=_(`messages`),y=_(`btn-connect`),b=_(`btn-disconnect`),x=_(`btn-send`),S=_(`input-send`),C=_(`mode-toggle`),de=_(`status-dot`),w=_(`status-text`),fe=_(`console-dot`),T=_(`console-text`),E=_(`sidebar`),D=_(`code-panel`),O=_(`code-view`),k=_(`code-tab`),pe=_(`menu-btn`),me=_(`code-toggle-btn`),A=_(`theme-btn`),he=_(`clear-btn`),j=_(`copy-btn`),ge=_(`dl-btn`),_e=_(`cfg-export-btn`),M=_(`cfg-import-input`);function N(){let e=e=>(_(e)?.value??``).trim(),t=(t,n)=>parseInt(e(t))||n,n=e=>_(e)?.value??``;return{bufferSize:t(`cfg-bufsize`,255),commandTimeout:t(`cfg-timeout`,3e3),handshakeTimeout:t(`cfg-handshake`,2e3),delimiter:e(`cfg-delim`)||`\\n`,prepend:e(`cfg-prepend`),append:e(`cfg-append`),hsCmd:e(`cfg-hs-cmd`),hsCmdMode:n(`cfg-hs-cmd-mode`)||`text`,hsExpect:e(`cfg-hs-expect`),hsExpectMode:n(`cfg-hs-expect-mode`)||`text`}}function ve(e){let t=(e,t)=>{let n=document.getElementById(e);n&&(n instanceof HTMLInputElement&&n.type===`checkbox`?n.checked=!!t:(n instanceof HTMLInputElement||n instanceof HTMLSelectElement)&&(n.value=String(t??``)))};t(`cfg-bufsize`,e.bufferSize??255),t(`cfg-timeout`,e.commandTimeout??3e3),t(`cfg-handshake`,e.handshakeTimeout??2e3),t(`cfg-delim`,e.delimiter??`\\n`),t(`cfg-prepend`,e.prepend??``),t(`cfg-append`,e.append??``),t(`cfg-hs-cmd`,e.hsCmd??``),t(`cfg-hs-cmd-mode`,e.hsCmdMode??`text`),t(`cfg-hs-expect`,e.hsExpect??``),t(`cfg-hs-expect-mode`,e.hsExpectMode??`text`)}function P(e){let t=e.replace(/[^a-zA-Z0-9_$]/g,``).replace(/^[^a-zA-Z_$]/,`C`);return t.charAt(0).toUpperCase()+t.slice(1)||`MyDevice`}function F(e){return Array.from(e).map(e=>e.toString(16).toUpperCase().padStart(2,`0`)).join(` `)}function I(e){let t=e.replace(/\s+/g,``);if(t.length%2!=0)throw Error(`Odd number of hex characters.`);let n=new Uint8Array(t.length/2);for(let e=0;e<t.length;e+=2)n[e/2]=parseInt(t.substring(e,e+2),16);return n}function L(e,t){[de,fe].forEach(t=>{t&&(t.className=`status-dot`,e!==`disconnected`&&t.classList.add(e))}),w&&(w.textContent=t),T&&(T.textContent=t)}var R=null;function z(){R&&clearTimeout(R),R=setTimeout(()=>{let e=N(),t=P((_(`dl-name`)?.value??`MyBleDevice`).trim()),n=(document.querySelector(`input[name='dl-lang']:checked`)?.value??`ts`)===`ts`,r=n?`ts`:`js`;re(O,ne(e,t,n,h,g)),k&&(k.textContent=`${t.substring(0,10).toLowerCase()}.${r}`)},180)}var ye=l();A&&(A.textContent=ye===`dark`?`☀️`:`🌙`),pe?.addEventListener(`click`,()=>E.classList.toggle(`collapsed`)),me?.addEventListener(`click`,()=>D.classList.toggle(`collapsed`));var B=_(`resize-handle`);if(B){let e=0,t=0,n=n=>{let r=Math.max(180,Math.min(700,t+(e-n.clientX)));document.documentElement.style.setProperty(`--code-w`,`${r}px`)},r=()=>{B.classList.remove(`dragging`),document.removeEventListener(`pointermove`,n)};B.addEventListener(`pointerdown`,i=>{e=i.clientX,t=D.getBoundingClientRect().width,B.classList.add(`dragging`),document.addEventListener(`pointermove`,n),document.addEventListener(`pointerup`,r,{once:!0}),i.preventDefault()})}var V=_(`sidebar-resize-handle`);if(V){let e=0,t=0,n=n=>{let r=Math.max(200,Math.min(600,t+(n.clientX-e)));document.documentElement.style.setProperty(`--sidebar-w`,`${r}px`)},r=()=>{V.classList.remove(`dragging`),document.removeEventListener(`pointermove`,n)};V.addEventListener(`pointerdown`,i=>{e=i.clientX,t=E.getBoundingClientRect().width,V.classList.add(`dragging`),document.addEventListener(`pointermove`,n),document.addEventListener(`pointerup`,r,{once:!0}),i.preventDefault()})}window.innerWidth<=960&&D.classList.add(`collapsed`),window.innerWidth<=640&&E.classList.add(`collapsed`),A?.addEventListener(`click`,()=>{let e=ie();A&&(A.textContent=e===`dark`?`☀️`:`🌙`)}),he?.addEventListener(`click`,()=>c(v)),j?.addEventListener(`click`,async()=>{let e=O?.textContent??``;try{await navigator.clipboard.writeText(e),j&&(j.textContent=`Copied!`,j.classList.add(`copied`),setTimeout(()=>{j.textContent=`Copy`,j.classList.remove(`copied`)},1500))}catch{}}),ge?.addEventListener(`click`,()=>{let n=N(),r=(_(`dl-name`)?.value??`my-ble-device`).trim(),i=P(r),s=(document.querySelector(`input[name='dl-lang']:checked`)?.value??`ts`)===`ts`,c=document.querySelector(`input[name='dl-type']:checked`)?.value??`file`,l=s?`ts`:`js`,u=ne(n,i,s,h,g);c===`project`?te([{name:`device.${l}`,content:u},{name:`package.json`,content:o(r,s,`ble`)},{name:`index.html`,content:ee(i,l,`Web Bluetooth`)},{name:`README.md`,content:a(i,l,`Web Bluetooth`,`Requires a Chromium browser. The device must expose a Nordic UART Service (NUS) via BLE GATT.`)},...s?[{name:`tsconfig.json`,content:e()}]:[]],`${r}-project`):t(`${r}.${l}`,u)}),_e?.addEventListener(`click`,()=>{let e=(_(`dl-name`)?.value??`my-ble-device`).trim(),t=P(e);s({$version:1,provider:`ble`,className:e,language:document.querySelector(`input[name='dl-lang']:checked`)?.value??`ts`,dlType:document.querySelector(`input[name='dl-type']:checked`)?.value??`file`,cfg:N(),commands:h,listeners:g},t+`-config`)}),M?.addEventListener(`change`,()=>{let e=M.files?.[0];if(!e)return;let t=new FileReader;t.onload=e=>{try{let t=JSON.parse(e.target?.result);if(t.$version!==1||t.provider!==`ble`)return;let n=_(`dl-name`);n&&(n.value=t.className),document.querySelectorAll(`input[name='dl-lang']`).forEach(e=>{e.checked=e.value===t.language}),document.querySelectorAll(`input[name='dl-type']`).forEach(e=>{e.checked=e.value===t.dlType}),ve(t.cfg),h=t.commands.map(e=>({...e,id:crypto.randomUUID()})),g=t.listeners.map(e=>({...e,id:crypto.randomUUID()})),Q(),$(),z()}catch{}M.value=``},t.readAsText(e)}),[`cfg-bufsize`,`cfg-timeout`,`cfg-handshake`,`cfg-delim`,`cfg-prepend`,`cfg-append`,`cfg-hs-cmd`,`cfg-hs-cmd-mode`,`cfg-hs-expect`,`cfg-hs-expect-mode`,`dl-name`].forEach(e=>{let t=document.getElementById(e);t?.addEventListener(`change`,z),t?.addEventListener(`input`,z)}),document.querySelectorAll(`input[name='dl-lang']`).forEach(e=>e.addEventListener(`change`,z)),z();var H=`text`;C?.addEventListener(`click`,()=>{H=H===`text`?`hex`:`text`,C.textContent=H===`text`?`TXT`:`HEX`,S.placeholder=H===`text`?`Type a command, e.g. LED_ON`:`Hex bytes, e.g. FF 01 A3`});var U=null;function W(e){x.disabled=!e,S.disabled=!e,b.disabled=!e,y.disabled=e}y?.addEventListener(`click`,async()=>{if(U){try{await U.disconnect()}catch{}U=null}let e=N(),t=u(e.delimiter);U=new ue({baudRate:9600,bufferSize:e.bufferSize,commandTimeout:e.commandTimeout,parser:n(t),autoReconnect:!1,handshakeTimeout:e.handshakeTimeout},e.hsCmd,e.hsCmdMode,e.hsExpect,e.hsExpectMode),U.on(`serial:connecting`,()=>{L(`connecting`,`Connecting…`),y.disabled=!0,d(v,`Initiating Web Bluetooth connection…`,{kind:`system`})}),U.on(`serial:connected`,()=>{L(`connected`,`Connected`),W(!0),d(v,`Connected via Web Bluetooth!`,{kind:`system`})}),U.on(`serial:disconnected`,()=>{L(`disconnected`,`Disconnected`),W(!1),d(v,`Disconnected.`,{kind:`system`}),U=null}),U.on(`serial:data`,e=>{d(v,String(e),{kind:`received`,label:`Device`})}),U.on(`serial:error`,e=>{L(`error`,`Error`),d(v,`Error: ${e.message}`,{kind:`error`}),y.disabled=!1}),U.on(`serial:need-permission`,()=>{L(`error`,`Permission denied`),d(v,`Permission denied — select a valid BLE device and allow access.`,{kind:`error`}),y.disabled=!1}),U.on(`serial:timeout`,e=>{d(v,`Timeout: ${F(e)}`,{kind:`error`})});try{await U.connect()}catch{}}),b?.addEventListener(`click`,async()=>{await U?.disconnect()});async function G(){let e=S.value.trim();if(!e||!U)return;let t=N(),n=t.append?u(t.append):u(t.delimiter);try{if(H===`hex`){let t=I(e);d(v,`HEX: ${F(t)}`,{kind:`sent`,label:`You`}),await U.send(t)}else{let r=t.prepend+e+n;d(v,e,{kind:`sent`,label:`You`}),await U.send(r)}S.value=``,S.focus()}catch(e){d(v,`Send error: ${e instanceof Error?e.message:String(e)}`,{kind:`error`})}}x?.addEventListener(`click`,G),S?.addEventListener(`keydown`,e=>{e.key===`Enter`&&G()});var K=_(`cmd-name`),q=_(`cmd-value`),be=_(`cmd-mode`),xe=_(`cmd-add`),J=_(`cmd-list`),Y=_(`lst-name`),X=_(`lst-pattern`),Se=_(`lst-match`),Ce=_(`lst-add`),Z=_(`lst-list`);function Q(){if(J){J.innerHTML=``;for(let e of h){let t=document.createElement(`div`);t.className=`chip`;let n=document.createElement(`span`);n.className=`chip-badge`,n.textContent=e.mode.toUpperCase();let r=document.createElement(`span`);r.className=`chip-name`,r.textContent=e.name;let i=document.createElement(`span`);i.className=`chip-val`,i.textContent=e.value;let a=document.createElement(`button`);a.className=`chip-send`,a.title=`Send now`,a.textContent=`▶`,a.addEventListener(`click`,()=>{if(U)if(e.mode===`hex`){let t=I(e.value);U.send(t).catch(()=>{}),d(v,`HEX: ${F(t)}`,{kind:`sent`,label:`You`})}else{let t=N(),n=t.append?u(t.append):u(t.delimiter);U.send(t.prepend+e.value+n).catch(()=>{}),d(v,e.name,{kind:`sent`,label:`You`})}});let o=document.createElement(`button`);o.className=`chip-del`,o.title=`Remove`,o.textContent=`×`,o.addEventListener(`click`,()=>{h=h.filter(t=>t.id!==e.id),Q(),z()}),t.append(n,r,i,a,o),J.appendChild(t)}}}function $(){if(Z){Z.innerHTML=``;for(let e of g){let t=document.createElement(`div`);t.className=`chip`;let n=document.createElement(`span`);n.className=`chip-badge`,n.textContent=e.match;let r=document.createElement(`span`);r.className=`chip-name`,r.textContent=e.name;let i=document.createElement(`span`);i.className=`chip-val`,i.textContent=e.pattern;let a=document.createElement(`button`);a.className=`chip-del`,a.title=`Remove`,a.textContent=`×`,a.addEventListener(`click`,()=>{g=g.filter(t=>t.id!==e.id),$(),z()}),t.append(n,r,i,a),Z.appendChild(t)}}}xe?.addEventListener(`click`,()=>{let e=K?.value.trim(),t=q?.value.trim();if(!e||!t)return;let n=be?.value??`text`;h.push({id:crypto.randomUUID(),name:e,value:t,mode:n}),K&&(K.value=``),q&&(q.value=``),Q(),z()}),Ce?.addEventListener(`click`,()=>{let e=Y?.value.trim(),t=X?.value.trim();if(!e||!t)return;let n=Se?.value??`exact`;g.push({id:crypto.randomUUID(),name:e,pattern:t,match:n}),Y&&(Y.value=``),X&&(X.value=``),$(),z()}),navigator.bluetooth?d(v,`Web Bluetooth demo ready — configure settings and click Connect.`,{kind:`system`}):(d(v,`Web Bluetooth is NOT supported in this browser or OS.`,{kind:`error`}),y.disabled=!0),r(v),i();
@@ -0,0 +1 @@
1
+ import{_ as e,a as t,b as n,c as r,d as i,f as a,g as o,h as ee,i as s,m as te,n as c,o as ne,p as l,r as u,t as d,v as f,x as re,y as ie}from"./demo-shared-DnvFynUr.js";var p=[],m=[],h=class extends re{_hsCmd;_hsCmdMode;_hsExpect;_hsExpectMode;constructor(e,t,n,r,i){super(e),this._hsCmd=t,this._hsCmdMode=n,this._hsExpect=r,this._hsExpectMode=i}async handshake(){if(!this._hsCmd||(this._hsCmdMode===`hex`?await this.send(F(this._hsCmd)):await this.send(u(this._hsCmd)),!this._hsExpect))return!0;let e=this._hsExpect.trim();return new Promise(t=>{let n=r=>{if(this.off(`serial:data`,n),this._hsExpectMode===`hex`){let e=new TextEncoder().encode(String(r)),n=F(this._hsExpect);t(e.length===n.length&&e.every((e,t)=>e===n[t]))}else t(String(r).trim()===e)};this.on(`serial:data`,n)})}},g=e=>document.getElementById(e),_=g(`messages`),v=g(`btn-connect`),y=g(`btn-disconnect`),b=g(`btn-send`),x=g(`input-send`),S=g(`mode-toggle`),ae=g(`status-dot`),C=g(`status-text`),oe=g(`console-dot`),w=g(`console-text`),T=g(`sidebar`),E=g(`code-panel`),D=g(`code-view`),O=g(`code-tab`),se=g(`menu-btn`),ce=g(`code-toggle-btn`),k=g(`theme-btn`),le=g(`clear-btn`),A=g(`copy-btn`),ue=g(`dl-btn`),de=g(`cfg-export-btn`),j=g(`cfg-import-input`);function M(){let e=e=>(g(e)?.value??``).trim(),t=(t,n)=>parseInt(e(t))||n,n=e=>g(e)?.value??``,r=e=>g(e)?.checked??!1,i=e(`cfg-vendor`),a=e(`cfg-product`),o=[];if(i||a){let e={};i&&(e.usbVendorId=parseInt(i,16)),a&&(e.usbProductId=parseInt(a,16)),o.push(e)}return{baudRate:t(`cfg-baud`,9600),dataBits:t(`cfg-databits`,8),stopBits:t(`cfg-stopbits`,1),parity:n(`cfg-parity`)||`none`,flowControl:n(`cfg-flow`)||`none`,bufferSize:t(`cfg-bufsize`,255),commandTimeout:t(`cfg-timeout`,3e3),autoReconnect:r(`cfg-autoreconnect`),autoReconnectInterval:t(`cfg-reconnect-ms`,1500),handshakeTimeout:t(`cfg-handshake`,2e3),delimiter:e(`cfg-delim`)||`\\n`,prepend:e(`cfg-prepend`),append:e(`cfg-append`),hsCmd:e(`cfg-hs-cmd`),hsCmdMode:n(`cfg-hs-cmd-mode`)||`text`,hsExpect:e(`cfg-hs-expect`),hsExpectMode:n(`cfg-hs-expect-mode`)||`text`,filters:o}}function fe(e){let t=(e,t)=>{let n=document.getElementById(e);n&&(n instanceof HTMLInputElement&&n.type===`checkbox`?n.checked=!!t:(n instanceof HTMLInputElement||n instanceof HTMLSelectElement)&&(n.value=String(t??``)))};t(`cfg-baud`,e.baudRate??9600),t(`cfg-databits`,e.dataBits??8),t(`cfg-stopbits`,e.stopBits??1),t(`cfg-parity`,e.parity??`none`),t(`cfg-flow`,e.flowControl??`none`),t(`cfg-bufsize`,e.bufferSize??255),t(`cfg-timeout`,e.commandTimeout??3e3),t(`cfg-handshake`,e.handshakeTimeout??2e3),t(`cfg-reconnect-ms`,e.autoReconnectInterval??1500),t(`cfg-autoreconnect`,e.autoReconnect??!1),t(`cfg-vendor`,e.filters?.[0]?.usbVendorId==null?``:e.filters[0].usbVendorId.toString(16)),t(`cfg-product`,e.filters?.[0]?.usbProductId==null?``:e.filters[0].usbProductId.toString(16)),t(`cfg-delim`,e.delimiter??`\\n`),t(`cfg-prepend`,e.prepend??``),t(`cfg-append`,e.append??``),t(`cfg-hs-cmd`,e.hsCmd??``),t(`cfg-hs-cmd-mode`,e.hsCmdMode??`text`),t(`cfg-hs-expect`,e.hsExpect??``),t(`cfg-hs-expect-mode`,e.hsExpectMode??`text`)}function N(e){let t=e.replace(/[^a-zA-Z0-9_$]/g,``).replace(/^[^a-zA-Z_$]/,`C`);return t.charAt(0).toUpperCase()+t.slice(1)||`MyDevice`}function P(e){return Array.from(e).map(e=>e.toString(16).toUpperCase().padStart(2,`0`)).join(` `)}function F(e){let t=e.replace(/\s+/g,``);if(t.length%2!=0)throw Error(`Odd number of hex characters.`);let n=new Uint8Array(t.length/2);for(let e=0;e<t.length;e+=2)n[e/2]=parseInt(t.substring(e,e+2),16);return n}function I(e,t){[ae,oe].forEach(t=>{t&&(t.className=`status-dot`,e!==`disconnected`&&t.classList.add(e))}),C&&(C.textContent=t),w&&(w.textContent=t)}var L=null;function R(){L&&clearTimeout(L),L=setTimeout(()=>{let e=M(),t=N((g(`dl-name`)?.value??`MySerialDevice`).trim()),n=(document.querySelector(`input[name='dl-lang']:checked`)?.value??`ts`)===`ts`,i=n?`ts`:`js`;f(D,r(e,t,n,p,m)),O&&(O.textContent=`${t.substring(0,10).toLowerCase()}.${i}`)},180)}var z=l();k&&(k.textContent=z===`dark`?`☀️`:`🌙`),se?.addEventListener(`click`,()=>T.classList.toggle(`collapsed`)),ce?.addEventListener(`click`,()=>E.classList.toggle(`collapsed`));var B=g(`resize-handle`);if(B){let e=0,t=0,n=n=>{let r=Math.max(180,Math.min(700,t+(e-n.clientX)));document.documentElement.style.setProperty(`--code-w`,`${r}px`)},r=()=>{B.classList.remove(`dragging`),document.removeEventListener(`pointermove`,n)};B.addEventListener(`pointerdown`,i=>{e=i.clientX,t=E.getBoundingClientRect().width,B.classList.add(`dragging`),document.addEventListener(`pointermove`,n),document.addEventListener(`pointerup`,r,{once:!0}),i.preventDefault()})}var V=g(`sidebar-resize-handle`);if(V){let e=0,t=0,n=n=>{let r=Math.max(200,Math.min(600,t+(n.clientX-e)));document.documentElement.style.setProperty(`--sidebar-w`,`${r}px`)},r=()=>{V.classList.remove(`dragging`),document.removeEventListener(`pointermove`,n)};V.addEventListener(`pointerdown`,i=>{e=i.clientX,t=T.getBoundingClientRect().width,V.classList.add(`dragging`),document.addEventListener(`pointermove`,n),document.addEventListener(`pointerup`,r,{once:!0}),i.preventDefault()})}window.innerWidth<=960&&E.classList.add(`collapsed`),window.innerWidth<=640&&T.classList.add(`collapsed`),k?.addEventListener(`click`,()=>{let e=ie();k&&(k.textContent=e===`dark`?`☀️`:`🌙`)}),le?.addEventListener(`click`,()=>c(_)),A?.addEventListener(`click`,async()=>{let e=D?.textContent??``;try{await navigator.clipboard.writeText(e),A&&(A.textContent=`Copied!`,A.classList.add(`copied`),setTimeout(()=>{A.textContent=`Copy`,A.classList.remove(`copied`)},1500))}catch{}}),ue?.addEventListener(`click`,()=>{let n=M(),i=(g(`dl-name`)?.value??`my-device`).trim(),a=N(i),s=(document.querySelector(`input[name='dl-lang']:checked`)?.value??`ts`)===`ts`,c=document.querySelector(`input[name='dl-type']:checked`)?.value??`file`,l=s?`ts`:`js`,u=r(n,a,s,p,m);c===`project`?ne([{name:`device.${l}`,content:u},{name:`package.json`,content:ee(i,s,`serial`)},{name:`index.html`,content:te(a,l,`Web Serial`)},{name:`README.md`,content:o(a,l,`Web Serial`,`Requires a Chromium browser with Web Serial API support.`)},...s?[{name:`tsconfig.json`,content:e()}]:[]],`${i}-project`):t(`${i}.${l}`,u)}),de?.addEventListener(`click`,()=>{let e=(g(`dl-name`)?.value??`my-device`).trim(),t=N(e);s({$version:1,provider:`serial`,className:e,language:document.querySelector(`input[name='dl-lang']:checked`)?.value??`ts`,dlType:document.querySelector(`input[name='dl-type']:checked`)?.value??`file`,cfg:M(),commands:p,listeners:m},t+`-config`)}),j?.addEventListener(`change`,()=>{let e=j.files?.[0];if(!e)return;let t=new FileReader;t.onload=e=>{try{let t=JSON.parse(e.target?.result);if(t.$version!==1||t.provider!==`serial`)return;let n=g(`dl-name`);n&&(n.value=t.className),document.querySelectorAll(`input[name='dl-lang']`).forEach(e=>{e.checked=e.value===t.language}),document.querySelectorAll(`input[name='dl-type']`).forEach(e=>{e.checked=e.value===t.dlType}),fe(t.cfg),p=t.commands.map(e=>({...e,id:crypto.randomUUID()})),m=t.listeners.map(e=>({...e,id:crypto.randomUUID()})),Q(),$(),R()}catch{}j.value=``},t.readAsText(e)}),[`cfg-baud`,`cfg-databits`,`cfg-stopbits`,`cfg-parity`,`cfg-flow`,`cfg-bufsize`,`cfg-timeout`,`cfg-handshake`,`cfg-reconnect-ms`,`cfg-autoreconnect`,`cfg-vendor`,`cfg-product`,`cfg-delim`,`cfg-prepend`,`cfg-append`,`cfg-hs-cmd`,`cfg-hs-cmd-mode`,`cfg-hs-expect`,`cfg-hs-expect-mode`,`dl-name`].forEach(e=>{let t=document.getElementById(e);t?.addEventListener(`change`,R),t?.addEventListener(`input`,R)}),document.querySelectorAll(`input[name='dl-lang']`).forEach(e=>e.addEventListener(`change`,R)),R();var H=`text`;S?.addEventListener(`click`,()=>{H=H===`text`?`hex`:`text`,S.textContent=H===`text`?`TXT`:`HEX`,x.placeholder=H===`text`?`Type a command, e.g. LED_ON`:`Hex bytes, e.g. FF 01 A3`});var U=null;function W(e){b.disabled=!e,x.disabled=!e,y.disabled=!e,v.disabled=e}v?.addEventListener(`click`,async()=>{if(U){try{await U.disconnect()}catch{}U=null}let e=M(),t=u(e.delimiter);U=new h({baudRate:e.baudRate,dataBits:e.dataBits,stopBits:e.stopBits,parity:e.parity,flowControl:e.flowControl,bufferSize:e.bufferSize,commandTimeout:e.commandTimeout,parser:n(t),autoReconnect:e.autoReconnect,autoReconnectInterval:e.autoReconnectInterval,handshakeTimeout:e.handshakeTimeout,filters:e.filters??[]},e.hsCmd,e.hsCmdMode,e.hsExpect,e.hsExpectMode),U.on(`serial:connecting`,()=>{I(`connecting`,`Connecting…`),v.disabled=!0,d(_,`Connecting to serial device…`,{kind:`system`})}),U.on(`serial:connected`,()=>{I(`connected`,`Connected`),W(!0),d(_,`Connected via Web Serial!`,{kind:`system`})}),U.on(`serial:disconnected`,()=>{I(`disconnected`,`Disconnected`),W(!1),d(_,`Disconnected.`,{kind:`system`}),U=null}),U.on(`serial:data`,e=>{d(_,String(e),{kind:`received`,label:`Device`})}),U.on(`serial:error`,e=>{I(`error`,`Error`),d(_,`Error: ${e.message}`,{kind:`error`}),v.disabled=!1}),U.on(`serial:need-permission`,()=>{I(`error`,`Permission denied`),d(_,`Permission denied — select a port and allow access.`,{kind:`error`}),v.disabled=!1}),U.on(`serial:timeout`,e=>{d(_,`Timeout: ${P(e)}`,{kind:`error`})}),U.on(`serial:reconnecting`,()=>{I(`connecting`,`Reconnecting…`),d(_,`Auto-reconnecting…`,{kind:`system`})});try{await U.connect()}catch{}}),y?.addEventListener(`click`,async()=>{await U?.disconnect()});async function G(){let e=x.value.trim();if(!e||!U)return;let t=M(),n=t.append?u(t.append):u(t.delimiter);try{if(H===`hex`){let t=F(e);d(_,`HEX: ${P(t)}`,{kind:`sent`,label:`You`}),await U.send(t)}else{let r=t.prepend+e+n;d(_,e,{kind:`sent`,label:`You`}),await U.send(r)}x.value=``,x.focus()}catch(e){d(_,`Send error: ${e instanceof Error?e.message:String(e)}`,{kind:`error`})}}b?.addEventListener(`click`,G),x?.addEventListener(`keydown`,e=>{e.key===`Enter`&&G()});var K=g(`cmd-name`),q=g(`cmd-value`),pe=g(`cmd-mode`),me=g(`cmd-add`),J=g(`cmd-list`),Y=g(`lst-name`),X=g(`lst-pattern`),he=g(`lst-match`),ge=g(`lst-add`),Z=g(`lst-list`);function Q(){if(J){J.innerHTML=``;for(let e of p){let t=document.createElement(`div`);t.className=`chip`;let n=document.createElement(`span`);n.className=`chip-badge`,n.textContent=e.mode.toUpperCase();let r=document.createElement(`span`);r.className=`chip-name`,r.textContent=e.name;let i=document.createElement(`span`);i.className=`chip-val`,i.textContent=e.value;let a=document.createElement(`button`);a.className=`chip-send`,a.title=`Send now`,a.textContent=`▶`,a.addEventListener(`click`,()=>{if(U)if(e.mode===`hex`){let t=F(e.value);U.send(t).catch(()=>{}),d(_,`HEX: ${P(t)}`,{kind:`sent`,label:`You`})}else{let t=M(),n=t.append?u(t.append):u(t.delimiter);U.send(t.prepend+e.value+n).catch(()=>{}),d(_,e.name,{kind:`sent`,label:`You`})}});let o=document.createElement(`button`);o.className=`chip-del`,o.title=`Remove`,o.textContent=`×`,o.addEventListener(`click`,()=>{p=p.filter(t=>t.id!==e.id),Q(),R()}),t.append(n,r,i,a,o),J.appendChild(t)}}}function $(){if(Z){Z.innerHTML=``;for(let e of m){let t=document.createElement(`div`);t.className=`chip`;let n=document.createElement(`span`);n.className=`chip-badge`,n.textContent=e.match;let r=document.createElement(`span`);r.className=`chip-name`,r.textContent=e.name;let i=document.createElement(`span`);i.className=`chip-val`,i.textContent=e.pattern;let a=document.createElement(`button`);a.className=`chip-del`,a.title=`Remove`,a.textContent=`×`,a.addEventListener(`click`,()=>{m=m.filter(t=>t.id!==e.id),$(),R()}),t.append(n,r,i,a),Z.appendChild(t)}}}me?.addEventListener(`click`,()=>{let e=K?.value.trim(),t=q?.value.trim();if(!e||!t)return;let n=pe?.value??`text`;p.push({id:crypto.randomUUID(),name:e,value:t,mode:n}),K&&(K.value=``),q&&(q.value=``),Q(),R()}),ge?.addEventListener(`click`,()=>{let e=Y?.value.trim(),t=X?.value.trim();if(!e||!t)return;let n=he?.value??`exact`;m.push({id:crypto.randomUUID(),name:e,pattern:t,match:n}),Y&&(Y.value=``),X&&(X.value=``),$(),R()}),d(_,`Web Serial demo ready — configure settings and click Connect.`,{kind:`system`}),i(_),a();