@picked/vite-plugin-picked 0.0.48-next.1 → 0.0.49-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -1,4 +1,861 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("@picked/client/plugins/dynamic-experiences"),m="picked",x="\x1B[0m";function L(){const n=process.env.NO_COLOR;return n==="1"||n==="true"}function l(n){return e=>L()?e:`${n}${e}${x}`}const b=["debug","info","warn","error","silent"],_={debug:{color:l("\x1B[2m"),log:console.debug,enabled:!1},info:{color:l("\x1B[36m"),log:console.log,enabled:!0},warn:{color:l("\x1B[33m"),log:console.warn,enabled:!0},error:{color:l("\x1B[31m"),log:console.error,enabled:!0},silent:{log:()=>{},enabled:!1}};function y(n,e){const o=new Date().toLocaleTimeString(),t=e?`${m}:${e}`:m;return`${o} [${t}] ${n}`}function g(n,e,o,t){if(!n.enabled)return;const r=y(e,t);n.log(n.color?n.color(r):r),o!==void 0&&n.log(o)}function d(n){const e=_[n],o=new Set;return Object.assign((t,r,i)=>{g(e,t,r,i)},{once(t,r,i){!e.enabled||o.has(t)||(o.add(t),g(e,t,r,i))}})}function I(n){const e=b.indexOf(n);if(e===-1){g(_.error,`invalid log level: ${n}`);return}for(const[o,t]of b.entries())_[t].enabled=o>=e}const s=l("\x1B[34m"),h=l("\x1B[36m");function O(){const n=[` ${s("_")} ${h("_")} _ _ _`,`${s("(_)")} ${h("(_)")} _ __(_)__| |_____ __| |`,` ${s("_")} ${s("_")} | '_ \\ / _| / / -_) _\` |`,`${s("(_)")} ${s("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,` |_|
2
- `];console.log(n.join(`
3
- `))}const a={banner:O,debug:d("debug"),info:d("info"),warn:d("warn"),error:d("error"),setLevel:I};function R(n){if(n.length===0)return;const e=Math.max(4,...n.map(c=>c.name.length)),o=Math.max(2,...n.map(c=>c.id.length)),t=` ${"Name".padEnd(e)} ${"ID".padEnd(o)} Status Weight Ver`,r=` ${"─".repeat(e)} ${"─".repeat(o)} ──────── ────── ───`,i=n.map(c=>{const f=c.enabled?"\x1B[32m enabled\x1B[0m":"\x1B[2mdisabled\x1B[0m",u=`${c.weight.toString()}%`.padStart(6),E=`v${c.version.toString()}`;return` ${c.name.padEnd(e)} ${c.id.padEnd(o)} ${f} ${u} ${E}`});console.log([""," Features:","",t,r,...i,""].join(`
4
- `))}function T(n){try{const e=new URL(n).hostname;return e==="localhost"||e==="127.0.0.1"||e==="::1"}catch{return!1}}function j(n){return new Promise(e=>{setTimeout(e,n)})}async function v(n,e){const o=await $.fetchProject(n,e);if(o||!T(n))return o;for(let t=1;t<=S;t++){a.info(`local API not ready, retrying in ${(w/1e3).toString()}s (${t.toString()}/${S.toString()})`),await j(w);const r=await $.fetchProject(n,e);if(r)return r}return null}const p="https://api.picked.app",B="__PICKED_PROJECT_CONFIG__",S=5,w=2e3;function P(n){const e=n.apiUrl??p;return{name:"picked",config:async()=>{a.banner(),a.info(`fetching project config for "${n.projectId}"`),e!==p&&a.warn(`using custom API URL: ${e}`);const o=performance.now(),t=await v(e,n.projectId),r=(performance.now()-o).toFixed(0);if(!t){a.warn(`failed to fetch project config for "${n.projectId}" (${r}ms)`);return}const i=t.features.length,c=t.features.filter(u=>u.enabled).length,f=JSON.stringify(t).length;return a.info(`fetched ${i.toString()} features (${c.toString()} enabled) for "${n.projectId}" in ${r}ms`),R(t.features),a.debug(`config size: ${f.toString()} bytes`),{define:{[B]:JSON.stringify(t)}}}}}exports.picked=P;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("@picked/client/plugins/dynamic-experiences");var h=Object.freeze,R=Object.defineProperty,I=(e,t)=>h(R(e,"raw",{value:h(t||e.slice())})),y;function b(e){const t=JSON.stringify(e),r=e.length>0?e.map(n=>`
2
+ <div class="feature-row">
3
+ <label>
4
+ <input type="checkbox" data-feature-id="${S(n.id)}" checked>
5
+ <span class="feature-name">${w(n.name)}</span>
6
+ <span class="feature-id">${w(n.id)}</span>
7
+ </label>
8
+ <select data-value-for="${S(n.id)}">
9
+ <option value="true" selected>true</option>
10
+ <option value="false">false</option>
11
+ </select>
12
+ </div>`).join(""):'<p class="text no-features">No features configured for this project.</p>';return String.raw(y||(y=I([`<!DOCTYPE html>
13
+ <html lang="en">
14
+ <head>
15
+ <meta charset="UTF-8">
16
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
17
+ <meta name="robots" content="noindex, nofollow">
18
+ <title>Picked</title>
19
+ <style>
20
+ main {
21
+ position: fixed;
22
+ top: 0;
23
+ right: 0;
24
+ bottom: 0;
25
+ left: 0;
26
+ display: grid;
27
+ align-items: center;
28
+ justify-content: center;
29
+ font-family: monospace;
30
+ color: #4A4A4A
31
+ }
32
+
33
+ .wrap {
34
+ padding-left: 1.5rem;
35
+ padding-right: 1.5rem;
36
+ max-width: 480px;
37
+ width: 100%;
38
+ }
39
+
40
+ .title {
41
+ font-size: 1.125rem;
42
+ font-weight: 700;
43
+ margin-bottom: 0;
44
+ }
45
+
46
+ .text {
47
+ margin-top: .5rem;
48
+ font-size: .875rem
49
+ }
50
+
51
+ .text a {
52
+ color: #4A4A4A;
53
+ text-decoration: none;
54
+ }
55
+
56
+ .text a:hover {
57
+ cursor: pointer;
58
+ text-decoration: underline
59
+ }
60
+
61
+ .preview-form {
62
+ margin-top: 2rem;
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: 0.5rem;
66
+ }
67
+
68
+ .preview-input {
69
+ padding: 0.5rem;
70
+ border: 1px solid #4A4A4A;
71
+ border-radius: 0;
72
+ font-family: monospace;
73
+ }
74
+
75
+ .preview-button {
76
+ padding: 0.5rem;
77
+ background: #4A4A4A;
78
+ color: white;
79
+ border: none;
80
+ border-radius: 0;
81
+ cursor: pointer;
82
+ font-family: monospace;
83
+ }
84
+
85
+ .preview-button:hover {
86
+ opacity: 0.9;
87
+ }
88
+
89
+ .buttons {
90
+ display: grid;
91
+ gap: 0.5em;
92
+ grid-template-columns: 1fr 1fr;
93
+ }
94
+
95
+ #copy-status {
96
+ font-size: 1em;
97
+ text-align: right;
98
+ margin-top: 0.5em;
99
+ }
100
+
101
+ .features-section {
102
+ margin-top: 1.5rem;
103
+ }
104
+
105
+ .features-label {
106
+ font-weight: 700;
107
+ font-size: .875rem;
108
+ margin-bottom: 0.5rem;
109
+ }
110
+
111
+ .feature-row {
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: space-between;
115
+ gap: 0.5rem;
116
+ padding: 0.25rem 0;
117
+ }
118
+
119
+ .feature-row label {
120
+ display: flex;
121
+ align-items: center;
122
+ gap: 0.5rem;
123
+ cursor: pointer;
124
+ min-width: 0;
125
+ flex: 1;
126
+ }
127
+
128
+ .feature-name {
129
+ font-size: .875rem;
130
+ }
131
+
132
+ .feature-id {
133
+ font-size: .75rem;
134
+ color: #888;
135
+ }
136
+
137
+ .feature-row select {
138
+ font-family: monospace;
139
+ font-size: .75rem;
140
+ padding: 0.125rem 0.25rem;
141
+ border: 1px solid #4A4A4A;
142
+ border-radius: 0;
143
+ background: white;
144
+ flex-shrink: 0;
145
+ }
146
+
147
+ .no-features {
148
+ color: #888;
149
+ font-style: italic;
150
+ }
151
+
152
+ .url-history {
153
+ margin-top: 0.5rem;
154
+ font-size: .75rem;
155
+ }
156
+
157
+ .url-history-item {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 0.25rem;
161
+ padding: 0.125rem 0;
162
+ }
163
+
164
+ .url-history-item button {
165
+ background: none;
166
+ border: none;
167
+ cursor: pointer;
168
+ font-family: monospace;
169
+ font-size: .75rem;
170
+ color: #888;
171
+ padding: 0;
172
+ }
173
+
174
+ .url-history-item button.url-link {
175
+ color: #4A4A4A;
176
+ text-decoration: none;
177
+ text-align: left;
178
+ overflow: hidden;
179
+ text-overflow: ellipsis;
180
+ white-space: nowrap;
181
+ flex: 1;
182
+ min-width: 0;
183
+ }
184
+
185
+ .url-history-item button.url-link:hover {
186
+ text-decoration: underline;
187
+ }
188
+
189
+ .url-history-item button.url-delete:hover {
190
+ color: #b71c1c;
191
+ }
192
+
193
+ @media (min-width: 640px) {
194
+ .title {
195
+ font-size: 1.25rem
196
+ }
197
+
198
+ .text {
199
+ font-size: 1rem
200
+ }
201
+ }
202
+ </style>
203
+ </head>
204
+ <body>
205
+
206
+ <main>
207
+ <div class="wrap">
208
+ <p class="title">Picked</p>
209
+ <p class="text">
210
+ Learn more at
211
+ <a href="https://picked.app">
212
+ https://picked.app
213
+ </a>
214
+ </p>
215
+ <div class="preview-form">
216
+ <input type="text" id="url-input" pattern="^(https?://)?.+" placeholder="Enter preview URL" required
217
+ class="preview-input">
218
+ <div id="url-history" class="url-history"></div>
219
+ <div class="features-section">
220
+ <p class="features-label">Features</p>
221
+ `,`
222
+ </div>
223
+ <div class="buttons">
224
+ <button type="button" class="preview-button" id="copy-btn">Copy</button>
225
+ <button type="button" class="preview-button" id="preview-btn">Preview</button>
226
+ </div>
227
+ <p class="text" id="copy-status" aria-live="polite" style="visibility:hidden;">
228
+ &nbsp;
229
+ </p>
230
+ </div>
231
+ </div>
232
+
233
+ <script>
234
+ var FEATURES = `,`;
235
+ var STORAGE_KEY_URL = 'picked-launcher-url';
236
+ var STORAGE_KEY_HISTORY = 'picked-launcher-history';
237
+ var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';
238
+
239
+ function getUrlInput() {
240
+ return document.getElementById('url-input');
241
+ }
242
+
243
+ // URL history
244
+ function getHistory() {
245
+ try {
246
+ var raw = localStorage.getItem(STORAGE_KEY_HISTORY);
247
+ if (!raw) return [];
248
+ var parsed = JSON.parse(raw);
249
+ return Array.isArray(parsed) ? parsed : [];
250
+ } catch (e) {
251
+ return [];
252
+ }
253
+ }
254
+
255
+ function saveHistory(history) {
256
+ localStorage.setItem(STORAGE_KEY_HISTORY, JSON.stringify(history));
257
+ }
258
+
259
+ function addToHistory(url) {
260
+ var history = getHistory().filter(function(h) { return h !== url; });
261
+ history.unshift(url);
262
+ if (history.length > 10) history = history.slice(0, 10);
263
+ saveHistory(history);
264
+ renderHistory();
265
+ }
266
+
267
+ function removeFromHistory(url) {
268
+ var history = getHistory().filter(function(h) { return h !== url; });
269
+ saveHistory(history);
270
+ renderHistory();
271
+ }
272
+
273
+ function renderHistory() {
274
+ var container = document.getElementById('url-history');
275
+ if (!container) return;
276
+ var history = getHistory();
277
+ if (history.length === 0) {
278
+ container.innerHTML = '';
279
+ return;
280
+ }
281
+ container.innerHTML = history.map(function(url) {
282
+ return '<div class="url-history-item">' +
283
+ '<button type="button" class="url-link" data-history-url="' + escapeAttr(url) + '">' + escapeHtml(url) + '</button>' +
284
+ '<button type="button" class="url-delete" data-history-delete="' + escapeAttr(url) + '">x</button>' +
285
+ '</div>';
286
+ }).join('');
287
+ }
288
+
289
+ // Feature selection persistence
290
+ function getSelections() {
291
+ try {
292
+ var raw = localStorage.getItem(STORAGE_KEY_SELECTIONS);
293
+ if (!raw) return {};
294
+ var parsed = JSON.parse(raw);
295
+ return typeof parsed === 'object' && parsed !== null ? parsed : {};
296
+ } catch (e) {
297
+ return {};
298
+ }
299
+ }
300
+
301
+ function saveSelections() {
302
+ var selections = {};
303
+ FEATURES.forEach(function(f) {
304
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
305
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
306
+ if (checkbox && select) {
307
+ selections[f.id] = { checked: checkbox.checked, value: select.value };
308
+ }
309
+ });
310
+ localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));
311
+ }
312
+
313
+ function restoreSelections() {
314
+ var selections = getSelections();
315
+ FEATURES.forEach(function(f) {
316
+ var saved = selections[f.id];
317
+ if (!saved) return;
318
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
319
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
320
+ if (checkbox) checkbox.checked = saved.checked;
321
+ if (select) select.value = saved.value;
322
+ });
323
+ }
324
+
325
+ function escapeHtml(str) {
326
+ var div = document.createElement('div');
327
+ div.textContent = str;
328
+ return div.innerHTML;
329
+ }
330
+
331
+ function escapeAttr(str) {
332
+ return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
333
+ }
334
+
335
+ function buildTargetUrl(inputValue) {
336
+ var value = inputValue;
337
+ if (!value.startsWith('http://') && !value.startsWith('https://')) {
338
+ value = 'https://' + value;
339
+ }
340
+ var hostname = window.location.hostname;
341
+ var subdomain = hostname.split('.').length > 2 ? hostname.split('.')[0] : '';
342
+ var target = value;
343
+ var sep = target.includes('?') ? '&' : '?';
344
+ if (subdomain) {
345
+ target = target + sep + 'cvly_env=' + encodeURIComponent(subdomain);
346
+ sep = '&';
347
+ }
348
+ FEATURES.forEach(function(f) {
349
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
350
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
351
+ if (checkbox && checkbox.checked && select) {
352
+ target = target + sep + 'picked-feature=' + encodeURIComponent(f.id + ':' + select.value);
353
+ sep = '&';
354
+ }
355
+ });
356
+ return target;
357
+ }
358
+
359
+ function showCopyStatus(message, success) {
360
+ var el = document.getElementById('copy-status');
361
+ if (!el) return;
362
+ el.textContent = message;
363
+ el.style.visibility = 'visible';
364
+ el.style.color = success ? '#2e7d32' : '#b71c1c';
365
+ setTimeout(function() {
366
+ el.style.visibility = 'hidden';
367
+ }, 2000);
368
+ }
369
+
370
+ // Init
371
+ window.addEventListener('load', function() {
372
+ var input = getUrlInput();
373
+ var savedUrl = localStorage.getItem(STORAGE_KEY_URL);
374
+ if (savedUrl && input) {
375
+ input.value = savedUrl;
376
+ }
377
+ renderHistory();
378
+ restoreSelections();
379
+ });
380
+
381
+ // Delegate click events
382
+ document.addEventListener('click', function(e) {
383
+ var target = e.target;
384
+
385
+ // History URL click
386
+ var historyUrl = target.getAttribute('data-history-url');
387
+ if (historyUrl) {
388
+ var input = getUrlInput();
389
+ if (input) input.value = historyUrl;
390
+ return;
391
+ }
392
+
393
+ // History delete click
394
+ var deleteUrl = target.getAttribute('data-history-delete');
395
+ if (deleteUrl) {
396
+ removeFromHistory(deleteUrl);
397
+ return;
398
+ }
399
+ });
400
+
401
+ // Feature change persistence
402
+ document.addEventListener('change', function(e) {
403
+ var target = e.target;
404
+ if (target.getAttribute('data-feature-id') || target.getAttribute('data-value-for')) {
405
+ saveSelections();
406
+ }
407
+ });
408
+
409
+ // Copy button
410
+ document.getElementById('copy-btn').addEventListener('click', function() {
411
+ var input = getUrlInput();
412
+ if (!input || !input.value) return;
413
+ localStorage.setItem(STORAGE_KEY_URL, input.value);
414
+ addToHistory(input.value);
415
+ saveSelections();
416
+ var target = buildTargetUrl(input.value);
417
+ navigator.clipboard.writeText(target).then(function() {
418
+ showCopyStatus('Preview URL copied to clipboard', true);
419
+ });
420
+ });
421
+
422
+ // Preview button
423
+ document.getElementById('preview-btn').addEventListener('click', function() {
424
+ var input = getUrlInput();
425
+ if (!input || !input.value) return;
426
+ localStorage.setItem(STORAGE_KEY_URL, input.value);
427
+ addToHistory(input.value);
428
+ saveSelections();
429
+ var target = buildTargetUrl(input.value);
430
+ window.location.href = target;
431
+ });
432
+ <\/script>
433
+ </main>
434
+ </body>
435
+ </html>`],[`<!DOCTYPE html>
436
+ <html lang="en">
437
+ <head>
438
+ <meta charset="UTF-8">
439
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
440
+ <meta name="robots" content="noindex, nofollow">
441
+ <title>Picked</title>
442
+ <style>
443
+ main {
444
+ position: fixed;
445
+ top: 0;
446
+ right: 0;
447
+ bottom: 0;
448
+ left: 0;
449
+ display: grid;
450
+ align-items: center;
451
+ justify-content: center;
452
+ font-family: monospace;
453
+ color: #4A4A4A
454
+ }
455
+
456
+ .wrap {
457
+ padding-left: 1.5rem;
458
+ padding-right: 1.5rem;
459
+ max-width: 480px;
460
+ width: 100%;
461
+ }
462
+
463
+ .title {
464
+ font-size: 1.125rem;
465
+ font-weight: 700;
466
+ margin-bottom: 0;
467
+ }
468
+
469
+ .text {
470
+ margin-top: .5rem;
471
+ font-size: .875rem
472
+ }
473
+
474
+ .text a {
475
+ color: #4A4A4A;
476
+ text-decoration: none;
477
+ }
478
+
479
+ .text a:hover {
480
+ cursor: pointer;
481
+ text-decoration: underline
482
+ }
483
+
484
+ .preview-form {
485
+ margin-top: 2rem;
486
+ display: flex;
487
+ flex-direction: column;
488
+ gap: 0.5rem;
489
+ }
490
+
491
+ .preview-input {
492
+ padding: 0.5rem;
493
+ border: 1px solid #4A4A4A;
494
+ border-radius: 0;
495
+ font-family: monospace;
496
+ }
497
+
498
+ .preview-button {
499
+ padding: 0.5rem;
500
+ background: #4A4A4A;
501
+ color: white;
502
+ border: none;
503
+ border-radius: 0;
504
+ cursor: pointer;
505
+ font-family: monospace;
506
+ }
507
+
508
+ .preview-button:hover {
509
+ opacity: 0.9;
510
+ }
511
+
512
+ .buttons {
513
+ display: grid;
514
+ gap: 0.5em;
515
+ grid-template-columns: 1fr 1fr;
516
+ }
517
+
518
+ #copy-status {
519
+ font-size: 1em;
520
+ text-align: right;
521
+ margin-top: 0.5em;
522
+ }
523
+
524
+ .features-section {
525
+ margin-top: 1.5rem;
526
+ }
527
+
528
+ .features-label {
529
+ font-weight: 700;
530
+ font-size: .875rem;
531
+ margin-bottom: 0.5rem;
532
+ }
533
+
534
+ .feature-row {
535
+ display: flex;
536
+ align-items: center;
537
+ justify-content: space-between;
538
+ gap: 0.5rem;
539
+ padding: 0.25rem 0;
540
+ }
541
+
542
+ .feature-row label {
543
+ display: flex;
544
+ align-items: center;
545
+ gap: 0.5rem;
546
+ cursor: pointer;
547
+ min-width: 0;
548
+ flex: 1;
549
+ }
550
+
551
+ .feature-name {
552
+ font-size: .875rem;
553
+ }
554
+
555
+ .feature-id {
556
+ font-size: .75rem;
557
+ color: #888;
558
+ }
559
+
560
+ .feature-row select {
561
+ font-family: monospace;
562
+ font-size: .75rem;
563
+ padding: 0.125rem 0.25rem;
564
+ border: 1px solid #4A4A4A;
565
+ border-radius: 0;
566
+ background: white;
567
+ flex-shrink: 0;
568
+ }
569
+
570
+ .no-features {
571
+ color: #888;
572
+ font-style: italic;
573
+ }
574
+
575
+ .url-history {
576
+ margin-top: 0.5rem;
577
+ font-size: .75rem;
578
+ }
579
+
580
+ .url-history-item {
581
+ display: flex;
582
+ align-items: center;
583
+ gap: 0.25rem;
584
+ padding: 0.125rem 0;
585
+ }
586
+
587
+ .url-history-item button {
588
+ background: none;
589
+ border: none;
590
+ cursor: pointer;
591
+ font-family: monospace;
592
+ font-size: .75rem;
593
+ color: #888;
594
+ padding: 0;
595
+ }
596
+
597
+ .url-history-item button.url-link {
598
+ color: #4A4A4A;
599
+ text-decoration: none;
600
+ text-align: left;
601
+ overflow: hidden;
602
+ text-overflow: ellipsis;
603
+ white-space: nowrap;
604
+ flex: 1;
605
+ min-width: 0;
606
+ }
607
+
608
+ .url-history-item button.url-link:hover {
609
+ text-decoration: underline;
610
+ }
611
+
612
+ .url-history-item button.url-delete:hover {
613
+ color: #b71c1c;
614
+ }
615
+
616
+ @media (min-width: 640px) {
617
+ .title {
618
+ font-size: 1.25rem
619
+ }
620
+
621
+ .text {
622
+ font-size: 1rem
623
+ }
624
+ }
625
+ </style>
626
+ </head>
627
+ <body>
628
+
629
+ <main>
630
+ <div class="wrap">
631
+ <p class="title">Picked</p>
632
+ <p class="text">
633
+ Learn more at
634
+ <a href="https://picked.app">
635
+ https://picked.app
636
+ </a>
637
+ </p>
638
+ <div class="preview-form">
639
+ <input type="text" id="url-input" pattern="^(https?:\\/\\/)?.+" placeholder="Enter preview URL" required
640
+ class="preview-input">
641
+ <div id="url-history" class="url-history"></div>
642
+ <div class="features-section">
643
+ <p class="features-label">Features</p>
644
+ `,`
645
+ </div>
646
+ <div class="buttons">
647
+ <button type="button" class="preview-button" id="copy-btn">Copy</button>
648
+ <button type="button" class="preview-button" id="preview-btn">Preview</button>
649
+ </div>
650
+ <p class="text" id="copy-status" aria-live="polite" style="visibility:hidden;">
651
+ &nbsp;
652
+ </p>
653
+ </div>
654
+ </div>
655
+
656
+ <script>
657
+ var FEATURES = `,`;
658
+ var STORAGE_KEY_URL = 'picked-launcher-url';
659
+ var STORAGE_KEY_HISTORY = 'picked-launcher-history';
660
+ var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';
661
+
662
+ function getUrlInput() {
663
+ return document.getElementById('url-input');
664
+ }
665
+
666
+ // URL history
667
+ function getHistory() {
668
+ try {
669
+ var raw = localStorage.getItem(STORAGE_KEY_HISTORY);
670
+ if (!raw) return [];
671
+ var parsed = JSON.parse(raw);
672
+ return Array.isArray(parsed) ? parsed : [];
673
+ } catch (e) {
674
+ return [];
675
+ }
676
+ }
677
+
678
+ function saveHistory(history) {
679
+ localStorage.setItem(STORAGE_KEY_HISTORY, JSON.stringify(history));
680
+ }
681
+
682
+ function addToHistory(url) {
683
+ var history = getHistory().filter(function(h) { return h !== url; });
684
+ history.unshift(url);
685
+ if (history.length > 10) history = history.slice(0, 10);
686
+ saveHistory(history);
687
+ renderHistory();
688
+ }
689
+
690
+ function removeFromHistory(url) {
691
+ var history = getHistory().filter(function(h) { return h !== url; });
692
+ saveHistory(history);
693
+ renderHistory();
694
+ }
695
+
696
+ function renderHistory() {
697
+ var container = document.getElementById('url-history');
698
+ if (!container) return;
699
+ var history = getHistory();
700
+ if (history.length === 0) {
701
+ container.innerHTML = '';
702
+ return;
703
+ }
704
+ container.innerHTML = history.map(function(url) {
705
+ return '<div class="url-history-item">' +
706
+ '<button type="button" class="url-link" data-history-url="' + escapeAttr(url) + '">' + escapeHtml(url) + '</button>' +
707
+ '<button type="button" class="url-delete" data-history-delete="' + escapeAttr(url) + '">x</button>' +
708
+ '</div>';
709
+ }).join('');
710
+ }
711
+
712
+ // Feature selection persistence
713
+ function getSelections() {
714
+ try {
715
+ var raw = localStorage.getItem(STORAGE_KEY_SELECTIONS);
716
+ if (!raw) return {};
717
+ var parsed = JSON.parse(raw);
718
+ return typeof parsed === 'object' && parsed !== null ? parsed : {};
719
+ } catch (e) {
720
+ return {};
721
+ }
722
+ }
723
+
724
+ function saveSelections() {
725
+ var selections = {};
726
+ FEATURES.forEach(function(f) {
727
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
728
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
729
+ if (checkbox && select) {
730
+ selections[f.id] = { checked: checkbox.checked, value: select.value };
731
+ }
732
+ });
733
+ localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));
734
+ }
735
+
736
+ function restoreSelections() {
737
+ var selections = getSelections();
738
+ FEATURES.forEach(function(f) {
739
+ var saved = selections[f.id];
740
+ if (!saved) return;
741
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
742
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
743
+ if (checkbox) checkbox.checked = saved.checked;
744
+ if (select) select.value = saved.value;
745
+ });
746
+ }
747
+
748
+ function escapeHtml(str) {
749
+ var div = document.createElement('div');
750
+ div.textContent = str;
751
+ return div.innerHTML;
752
+ }
753
+
754
+ function escapeAttr(str) {
755
+ return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
756
+ }
757
+
758
+ function buildTargetUrl(inputValue) {
759
+ var value = inputValue;
760
+ if (!value.startsWith('http://') && !value.startsWith('https://')) {
761
+ value = 'https://' + value;
762
+ }
763
+ var hostname = window.location.hostname;
764
+ var subdomain = hostname.split('.').length > 2 ? hostname.split('.')[0] : '';
765
+ var target = value;
766
+ var sep = target.includes('?') ? '&' : '?';
767
+ if (subdomain) {
768
+ target = target + sep + 'cvly_env=' + encodeURIComponent(subdomain);
769
+ sep = '&';
770
+ }
771
+ FEATURES.forEach(function(f) {
772
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
773
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
774
+ if (checkbox && checkbox.checked && select) {
775
+ target = target + sep + 'picked-feature=' + encodeURIComponent(f.id + ':' + select.value);
776
+ sep = '&';
777
+ }
778
+ });
779
+ return target;
780
+ }
781
+
782
+ function showCopyStatus(message, success) {
783
+ var el = document.getElementById('copy-status');
784
+ if (!el) return;
785
+ el.textContent = message;
786
+ el.style.visibility = 'visible';
787
+ el.style.color = success ? '#2e7d32' : '#b71c1c';
788
+ setTimeout(function() {
789
+ el.style.visibility = 'hidden';
790
+ }, 2000);
791
+ }
792
+
793
+ // Init
794
+ window.addEventListener('load', function() {
795
+ var input = getUrlInput();
796
+ var savedUrl = localStorage.getItem(STORAGE_KEY_URL);
797
+ if (savedUrl && input) {
798
+ input.value = savedUrl;
799
+ }
800
+ renderHistory();
801
+ restoreSelections();
802
+ });
803
+
804
+ // Delegate click events
805
+ document.addEventListener('click', function(e) {
806
+ var target = e.target;
807
+
808
+ // History URL click
809
+ var historyUrl = target.getAttribute('data-history-url');
810
+ if (historyUrl) {
811
+ var input = getUrlInput();
812
+ if (input) input.value = historyUrl;
813
+ return;
814
+ }
815
+
816
+ // History delete click
817
+ var deleteUrl = target.getAttribute('data-history-delete');
818
+ if (deleteUrl) {
819
+ removeFromHistory(deleteUrl);
820
+ return;
821
+ }
822
+ });
823
+
824
+ // Feature change persistence
825
+ document.addEventListener('change', function(e) {
826
+ var target = e.target;
827
+ if (target.getAttribute('data-feature-id') || target.getAttribute('data-value-for')) {
828
+ saveSelections();
829
+ }
830
+ });
831
+
832
+ // Copy button
833
+ document.getElementById('copy-btn').addEventListener('click', function() {
834
+ var input = getUrlInput();
835
+ if (!input || !input.value) return;
836
+ localStorage.setItem(STORAGE_KEY_URL, input.value);
837
+ addToHistory(input.value);
838
+ saveSelections();
839
+ var target = buildTargetUrl(input.value);
840
+ navigator.clipboard.writeText(target).then(function() {
841
+ showCopyStatus('Preview URL copied to clipboard', true);
842
+ });
843
+ });
844
+
845
+ // Preview button
846
+ document.getElementById('preview-btn').addEventListener('click', function() {
847
+ var input = getUrlInput();
848
+ if (!input || !input.value) return;
849
+ localStorage.setItem(STORAGE_KEY_URL, input.value);
850
+ addToHistory(input.value);
851
+ saveSelections();
852
+ var target = buildTargetUrl(input.value);
853
+ window.location.href = target;
854
+ });
855
+ <\/script>
856
+ </main>
857
+ </body>
858
+ </html>`])),r,t)}function w(e){return e.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;")}function S(e){return e.replaceAll("&","&amp;").replaceAll('"',"&quot;").replaceAll("<","&lt;").replaceAll(">","&gt;")}const E="picked",L="\x1B[0m";function O(){const e=process.env.NO_COLOR;return e==="1"||e==="true"}function c(e){return t=>O()?t:`${e}${t}${L}`}const x=["debug","info","warn","error","silent"],v={debug:{color:c("\x1B[2m"),log:console.debug,enabled:!1},info:{color:c("\x1B[36m"),log:console.log,enabled:!0},warn:{color:c("\x1B[33m"),log:console.warn,enabled:!0},error:{color:c("\x1B[31m"),log:console.error,enabled:!0},silent:{log:()=>{},enabled:!1}};function H(e,t){const r=new Date().toLocaleTimeString(),n=t?`${E}:${t}`:E;return`${r} [${n}] ${e}`}function g(e,t,r,n){if(!e.enabled)return;const o=H(t,n);e.log(e.color?e.color(o):o),r!==void 0&&e.log(r)}function p(e){const t=v[e],r=new Set;return Object.assign((n,o,i)=>{g(t,n,o,i)},{once(n,o,i){!t.enabled||r.has(n)||(r.add(n),g(t,n,o,i))}})}function $(e){const t=x.indexOf(e);if(t===-1){g(v.error,`invalid log level: ${e}`);return}for(const[r,n]of x.entries())v[n].enabled=r>=t}const s=c("\x1B[34m"),_=c("\x1B[36m");function C(){const e=[` ${s("_")} ${_("_")} _ _ _`,`${s("(_)")} ${_("(_)")} _ __(_)__| |_____ __| |`,` ${s("_")} ${s("_")} | '_ \\ / _| / / -_) _\` |`,`${s("(_)")} ${s("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,` |_|
859
+ `];console.log(e.join(`
860
+ `))}const l={banner:C,debug:p("debug"),info:p("info"),warn:p("warn"),error:p("error"),setLevel:$};function Y(e){return(t,r,n)=>{if(t.method!=="GET"){n();return}const i=(t.url??"").split("?")[0];if(i!=="/"&&i!=="/index.html"){n();return}const a=e();r.setHeader("Content-Type","text/html"),r.statusCode=200,r.end(a)}}function B(e){if(e.length===0)return;const t=Math.max(4,...e.map(a=>a.name.length)),r=Math.max(2,...e.map(a=>a.id.length)),n=` ${"Name".padEnd(t)} ${"ID".padEnd(r)} Status Weight Ver`,o=` ${"─".repeat(t)} ${"─".repeat(r)} ──────── ────── ───`,i=e.map(a=>{const d=a.enabled?"\x1B[32m enabled\x1B[0m":"\x1B[2mdisabled\x1B[0m",u=`${a.weight.toString()}%`.padStart(6),f=`v${a.version.toString()}`;return` ${a.name.padEnd(t)} ${a.id.padEnd(r)} ${d} ${u} ${f}`});console.log([""," Features:","",n,o,...i,""].join(`
861
+ `))}function F(e){try{const t=new URL(e).hostname;return t==="localhost"||t==="127.0.0.1"||t==="::1"}catch{return!1}}function P(e){return new Promise(t=>{setTimeout(t,e)})}async function z(e,t,r){const n=await m.fetchProject(e,t,{headers:r});if(n||!F(e))return n;for(let o=1;o<=T;o++){l.info(`local API not ready, retrying in ${(k/1e3).toString()}s (${o.toString()}/${T.toString()})`),await P(k);const i=await m.fetchProject(e,t,{headers:r});if(i)return i}return null}function N(){return"0.0.49-next.1"}const A="https://api.picked.app",j="__PICKED_PROJECT_CONFIG__",T=5,k=2e3;function G(e){const t=e.apiUrl??A;let r=[];return{name:"picked",config:async()=>{l.banner(),l.info(`fetching project config for "${e.projectId}"`),t!==A&&l.warn(`using custom API URL: ${t}`);const n=m.createClientHeaders("vite-plugin",N()),o=performance.now(),i=await z(t,e.projectId,n),a=(performance.now()-o).toFixed(0);if(!i){l.warn(`failed to fetch project config for "${e.projectId}" (${a}ms)`);return}r=i.features;const d=i.features.length,u=i.features.filter(U=>U.enabled).length,f=JSON.stringify(i).length;return l.info(`fetched ${d.toString()} features (${u.toString()} enabled) for "${e.projectId}" in ${a}ms`),B(i.features),l.debug(`config size: ${f.toString()} bytes`),{define:{[j]:JSON.stringify(i)}}},configureServer(n){if(e.disableLauncher)return;n.middlewares.use(Y(()=>b(r)));const o=n.printUrls.bind(n);n.printUrls=()=>{const i=n.resolvedUrls?.local[0];if(i){const a=i.replace(/:(?<port>\d+)\//,(d,u)=>`:\x1B[1m${u}\x1B[22m/`);console.log(` \x1B[32m➜\x1B[0m \x1B[1mPicked\x1B[22m: \x1B[36m${a}\x1B[0m`)}o()}},generateBundle(){e.disableLauncher||this.emitFile({type:"asset",fileName:"index.html",source:b(r)})}}}exports.picked=G;