@picked/vite-plugin-picked 0.0.1-dev.1772412203098 → 0.0.1-dev.1772493269328

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,438 @@
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");function v(e){const t=JSON.stringify(e);return`<!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
+ <meta name="robots" content="noindex, nofollow">
7
+ <title>Picked</title>
8
+ <style>
9
+ main {
10
+ position: fixed;
11
+ top: 0;
12
+ right: 0;
13
+ bottom: 0;
14
+ left: 0;
15
+ display: grid;
16
+ align-items: center;
17
+ justify-content: center;
18
+ font-family: monospace;
19
+ color: #4A4A4A
20
+ }
21
+
22
+ .wrap {
23
+ padding-left: 1.5rem;
24
+ padding-right: 1.5rem;
25
+ max-width: 480px;
26
+ width: 100%;
27
+ }
28
+
29
+ .title {
30
+ font-size: 1.125rem;
31
+ font-weight: 700;
32
+ margin-bottom: 0;
33
+ }
34
+
35
+ .text {
36
+ margin-top: .5rem;
37
+ font-size: .875rem
38
+ }
39
+
40
+ .text a {
41
+ color: #4A4A4A;
42
+ text-decoration: none;
43
+ }
44
+
45
+ .text a:hover {
46
+ cursor: pointer;
47
+ text-decoration: underline
48
+ }
49
+
50
+ .preview-form {
51
+ margin-top: 2rem;
52
+ display: flex;
53
+ flex-direction: column;
54
+ gap: 0.5rem;
55
+ }
56
+
57
+ .preview-input {
58
+ padding: 0.5rem;
59
+ border: 1px solid #4A4A4A;
60
+ border-radius: 0;
61
+ font-family: monospace;
62
+ }
63
+
64
+ .preview-button {
65
+ padding: 0.5rem;
66
+ background: #4A4A4A;
67
+ color: white;
68
+ border: none;
69
+ border-radius: 0;
70
+ cursor: pointer;
71
+ font-family: monospace;
72
+ }
73
+
74
+ .preview-button:hover {
75
+ opacity: 0.9;
76
+ }
77
+
78
+ .buttons {
79
+ display: grid;
80
+ gap: 0.5em;
81
+ grid-template-columns: 1fr 1fr;
82
+ }
83
+
84
+ #copy-status {
85
+ font-size: 1em;
86
+ text-align: right;
87
+ margin-top: 0.5em;
88
+ }
89
+
90
+ .features-section {
91
+ margin-top: 1.5rem;
92
+ }
93
+
94
+ .features-label {
95
+ font-weight: 700;
96
+ font-size: .875rem;
97
+ margin-bottom: 0.5rem;
98
+ }
99
+
100
+ .feature-row {
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: space-between;
104
+ gap: 0.5rem;
105
+ padding: 0.25rem 0;
106
+ }
107
+
108
+ .feature-row label {
109
+ display: flex;
110
+ align-items: center;
111
+ gap: 0.5rem;
112
+ cursor: pointer;
113
+ min-width: 0;
114
+ flex: 1;
115
+ }
116
+
117
+ .feature-name {
118
+ font-size: .875rem;
119
+ }
120
+
121
+ .feature-id {
122
+ font-size: .75rem;
123
+ color: #888;
124
+ }
125
+
126
+ .feature-row select {
127
+ font-family: monospace;
128
+ font-size: .75rem;
129
+ padding: 0.125rem 0.25rem;
130
+ border: 1px solid #4A4A4A;
131
+ border-radius: 0;
132
+ background: white;
133
+ flex-shrink: 0;
134
+ }
135
+
136
+ .no-features {
137
+ color: #888;
138
+ font-style: italic;
139
+ }
140
+
141
+ .url-history {
142
+ margin-top: 0.5rem;
143
+ font-size: .75rem;
144
+ }
145
+
146
+ .url-history-item {
147
+ display: flex;
148
+ align-items: center;
149
+ gap: 0.25rem;
150
+ padding: 0.125rem 0;
151
+ }
152
+
153
+ .url-history-item button {
154
+ background: none;
155
+ border: none;
156
+ cursor: pointer;
157
+ font-family: monospace;
158
+ font-size: .75rem;
159
+ color: #888;
160
+ padding: 0;
161
+ }
162
+
163
+ .url-history-item button.url-link {
164
+ color: #4A4A4A;
165
+ text-decoration: none;
166
+ text-align: left;
167
+ overflow: hidden;
168
+ text-overflow: ellipsis;
169
+ white-space: nowrap;
170
+ flex: 1;
171
+ min-width: 0;
172
+ }
173
+
174
+ .url-history-item button.url-link:hover {
175
+ text-decoration: underline;
176
+ }
177
+
178
+ .url-history-item button.url-delete:hover {
179
+ color: #b71c1c;
180
+ }
181
+
182
+ @media (min-width: 640px) {
183
+ .title {
184
+ font-size: 1.25rem
185
+ }
186
+
187
+ .text {
188
+ font-size: 1rem
189
+ }
190
+ }
191
+ </style>
192
+ </head>
193
+ <body>
194
+
195
+ <main>
196
+ <div class="wrap">
197
+ <p class="title">Picked</p>
198
+ <p class="text">
199
+ Learn more at
200
+ <a href="https://picked.app">
201
+ https://picked.app
202
+ </a>
203
+ </p>
204
+ <div class="preview-form">
205
+ <input type="text" id="url-input" pattern="^(https?:\\/\\/)?.+" placeholder="Enter preview URL" required
206
+ class="preview-input">
207
+ <div id="url-history" class="url-history"></div>
208
+ <div class="features-section">
209
+ <p class="features-label">Features</p>
210
+ ${e.length>0?e.map(r=>`
211
+ <div class="feature-row">
212
+ <label>
213
+ <input type="checkbox" data-feature-id="${b(r.id)}" checked>
214
+ <span class="feature-name">${y(r.name)}</span>
215
+ <span class="feature-id">${y(r.id)}</span>
216
+ </label>
217
+ <select data-value-for="${b(r.id)}">
218
+ <option value="true" selected>true</option>
219
+ <option value="false">false</option>
220
+ </select>
221
+ </div>`).join(""):'<p class="text no-features">No features configured for this project.</p>'}
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 = ${t};
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>`}function y(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function b(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}const _="picked",T="\x1B[0m";function k(){const e=process.env.NO_COLOR;return e==="1"||e==="true"}function c(e){return t=>k()?t:`${e}${t}${T}`}const w=["debug","info","warn","error","silent"],g={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 U(e,t){const n=new Date().toLocaleTimeString(),r=t?`${_}:${t}`:_;return`${n} [${r}] ${e}`}function h(e,t,n,r){if(!e.enabled)return;const i=U(t,r);e.log(e.color?e.color(i):i),n!==void 0&&e.log(n)}function p(e){const t=g[e],n=new Set;return Object.assign((r,i,o)=>{h(t,r,i,o)},{once(r,i,o){!t.enabled||n.has(r)||(n.add(r),h(t,r,i,o))}})}function R(e){const t=w.indexOf(e);if(t===-1){h(g.error,`invalid log level: ${e}`);return}for(const[n,r]of w.entries())g[r].enabled=n>=t}const l=c("\x1B[34m"),S=c("\x1B[36m");function L(){const e=[` ${l("_")} ${S("_")} _ _ _`,`${l("(_)")} ${S("(_)")} _ __(_)__| |_____ __| |`,` ${l("_")} ${l("_")} | '_ \\ / _| / / -_) _\` |`,`${l("(_)")} ${l("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,` |_|
436
+ `];console.log(e.join(`
437
+ `))}const s={banner:L,debug:p("debug"),info:p("info"),warn:p("warn"),error:p("error"),setLevel:R};function I(e){return(t,n,r)=>{if(t.method!=="GET"){r();return}const o=(t.url??"").split("?")[0];if(o!=="/"&&o!=="/index.html"){r();return}const a=e();n.setHeader("Content-Type","text/html"),n.statusCode=200,n.end(a)}}function O(e){if(e.length===0)return;const t=Math.max(4,...e.map(a=>a.name.length)),n=Math.max(2,...e.map(a=>a.id.length)),r=` ${"Name".padEnd(t)} ${"ID".padEnd(n)} Status Weight Ver`,i=` ${"─".repeat(t)} ${"─".repeat(n)} ──────── ────── ───`,o=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(n)} ${d} ${u} ${f}`});console.log([""," Features:","",r,i,...o,""].join(`
438
+ `))}function H(e){try{const t=new URL(e).hostname;return t==="localhost"||t==="127.0.0.1"||t==="::1"}catch{return!1}}function B(e){return new Promise(t=>{setTimeout(t,e)})}async function C(e,t,n){const r=await m.fetchProject(e,t,{headers:n});if(r||!H(e))return r;for(let i=1;i<=x;i++){s.info(`local API not ready, retrying in ${(A/1e3).toString()}s (${i.toString()}/${x.toString()})`),await B(A);const o=await m.fetchProject(e,t,{headers:n});if(o)return o}return null}function P(){return"0.0.1-dev.1772493269328"}const E="https://api.picked.app",F="__PICKED_PROJECT_CONFIG__",x=5,A=2e3;function Y(e){const t=e.apiUrl??E;let n=[];return{name:"picked",config:async()=>{s.banner(),s.info(`fetching project config for "${e.projectId}"`),t!==E&&s.warn(`using custom API URL: ${t}`);const r=m.createClientHeaders("vite-plugin",P()),i=performance.now(),o=await C(t,e.projectId,r),a=(performance.now()-i).toFixed(0);if(!o){s.warn(`failed to fetch project config for "${e.projectId}" (${a}ms)`);return}n=o.features;const d=o.features.length,u=o.features.filter($=>$.enabled).length,f=JSON.stringify(o).length;return s.info(`fetched ${d.toString()} features (${u.toString()} enabled) for "${e.projectId}" in ${a}ms`),O(o.features),s.debug(`config size: ${f.toString()} bytes`),{define:{[F]:JSON.stringify(o)}}},configureServer(r){if(e.disableLauncher)return;r.middlewares.use(I(()=>v(n)));const i=r.printUrls.bind(r);r.printUrls=()=>{const o=r.resolvedUrls?.local[0];if(o){const a=o.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`)}i()}},generateBundle(){e.disableLauncher||this.emitFile({type:"asset",fileName:"index.html",source:v(n)})}}}exports.picked=Y;
package/dist/esm/index.js CHANGED
@@ -1,30 +1,476 @@
1
- import { fetchProject as $ } from "@picked/client/plugins/dynamic-experiences";
2
- const m = "picked", x = "\x1B[0m";
3
- function L() {
4
- const n = process.env.NO_COLOR;
5
- return n === "1" || n === "true";
1
+ import { createClientHeaders as T, fetchProject as h } from "@picked/client/plugins/dynamic-experiences";
2
+ function v(e) {
3
+ const t = JSON.stringify(e);
4
+ return `<!DOCTYPE html>
5
+ <html lang="en">
6
+ <head>
7
+ <meta charset="UTF-8">
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
9
+ <meta name="robots" content="noindex, nofollow">
10
+ <title>Picked</title>
11
+ <style>
12
+ main {
13
+ position: fixed;
14
+ top: 0;
15
+ right: 0;
16
+ bottom: 0;
17
+ left: 0;
18
+ display: grid;
19
+ align-items: center;
20
+ justify-content: center;
21
+ font-family: monospace;
22
+ color: #4A4A4A
23
+ }
24
+
25
+ .wrap {
26
+ padding-left: 1.5rem;
27
+ padding-right: 1.5rem;
28
+ max-width: 480px;
29
+ width: 100%;
30
+ }
31
+
32
+ .title {
33
+ font-size: 1.125rem;
34
+ font-weight: 700;
35
+ margin-bottom: 0;
36
+ }
37
+
38
+ .text {
39
+ margin-top: .5rem;
40
+ font-size: .875rem
41
+ }
42
+
43
+ .text a {
44
+ color: #4A4A4A;
45
+ text-decoration: none;
46
+ }
47
+
48
+ .text a:hover {
49
+ cursor: pointer;
50
+ text-decoration: underline
51
+ }
52
+
53
+ .preview-form {
54
+ margin-top: 2rem;
55
+ display: flex;
56
+ flex-direction: column;
57
+ gap: 0.5rem;
58
+ }
59
+
60
+ .preview-input {
61
+ padding: 0.5rem;
62
+ border: 1px solid #4A4A4A;
63
+ border-radius: 0;
64
+ font-family: monospace;
65
+ }
66
+
67
+ .preview-button {
68
+ padding: 0.5rem;
69
+ background: #4A4A4A;
70
+ color: white;
71
+ border: none;
72
+ border-radius: 0;
73
+ cursor: pointer;
74
+ font-family: monospace;
75
+ }
76
+
77
+ .preview-button:hover {
78
+ opacity: 0.9;
79
+ }
80
+
81
+ .buttons {
82
+ display: grid;
83
+ gap: 0.5em;
84
+ grid-template-columns: 1fr 1fr;
85
+ }
86
+
87
+ #copy-status {
88
+ font-size: 1em;
89
+ text-align: right;
90
+ margin-top: 0.5em;
91
+ }
92
+
93
+ .features-section {
94
+ margin-top: 1.5rem;
95
+ }
96
+
97
+ .features-label {
98
+ font-weight: 700;
99
+ font-size: .875rem;
100
+ margin-bottom: 0.5rem;
101
+ }
102
+
103
+ .feature-row {
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: space-between;
107
+ gap: 0.5rem;
108
+ padding: 0.25rem 0;
109
+ }
110
+
111
+ .feature-row label {
112
+ display: flex;
113
+ align-items: center;
114
+ gap: 0.5rem;
115
+ cursor: pointer;
116
+ min-width: 0;
117
+ flex: 1;
118
+ }
119
+
120
+ .feature-name {
121
+ font-size: .875rem;
122
+ }
123
+
124
+ .feature-id {
125
+ font-size: .75rem;
126
+ color: #888;
127
+ }
128
+
129
+ .feature-row select {
130
+ font-family: monospace;
131
+ font-size: .75rem;
132
+ padding: 0.125rem 0.25rem;
133
+ border: 1px solid #4A4A4A;
134
+ border-radius: 0;
135
+ background: white;
136
+ flex-shrink: 0;
137
+ }
138
+
139
+ .no-features {
140
+ color: #888;
141
+ font-style: italic;
142
+ }
143
+
144
+ .url-history {
145
+ margin-top: 0.5rem;
146
+ font-size: .75rem;
147
+ }
148
+
149
+ .url-history-item {
150
+ display: flex;
151
+ align-items: center;
152
+ gap: 0.25rem;
153
+ padding: 0.125rem 0;
154
+ }
155
+
156
+ .url-history-item button {
157
+ background: none;
158
+ border: none;
159
+ cursor: pointer;
160
+ font-family: monospace;
161
+ font-size: .75rem;
162
+ color: #888;
163
+ padding: 0;
164
+ }
165
+
166
+ .url-history-item button.url-link {
167
+ color: #4A4A4A;
168
+ text-decoration: none;
169
+ text-align: left;
170
+ overflow: hidden;
171
+ text-overflow: ellipsis;
172
+ white-space: nowrap;
173
+ flex: 1;
174
+ min-width: 0;
175
+ }
176
+
177
+ .url-history-item button.url-link:hover {
178
+ text-decoration: underline;
179
+ }
180
+
181
+ .url-history-item button.url-delete:hover {
182
+ color: #b71c1c;
183
+ }
184
+
185
+ @media (min-width: 640px) {
186
+ .title {
187
+ font-size: 1.25rem
188
+ }
189
+
190
+ .text {
191
+ font-size: 1rem
192
+ }
193
+ }
194
+ </style>
195
+ </head>
196
+ <body>
197
+
198
+ <main>
199
+ <div class="wrap">
200
+ <p class="title">Picked</p>
201
+ <p class="text">
202
+ Learn more at
203
+ <a href="https://picked.app">
204
+ https://picked.app
205
+ </a>
206
+ </p>
207
+ <div class="preview-form">
208
+ <input type="text" id="url-input" pattern="^(https?:\\/\\/)?.+" placeholder="Enter preview URL" required
209
+ class="preview-input">
210
+ <div id="url-history" class="url-history"></div>
211
+ <div class="features-section">
212
+ <p class="features-label">Features</p>
213
+ ${e.length > 0 ? e.map(
214
+ (r) => `
215
+ <div class="feature-row">
216
+ <label>
217
+ <input type="checkbox" data-feature-id="${b(r.id)}" checked>
218
+ <span class="feature-name">${y(r.name)}</span>
219
+ <span class="feature-id">${y(r.id)}</span>
220
+ </label>
221
+ <select data-value-for="${b(r.id)}">
222
+ <option value="true" selected>true</option>
223
+ <option value="false">false</option>
224
+ </select>
225
+ </div>`
226
+ ).join("") : '<p class="text no-features">No features configured for this project.</p>'}
227
+ </div>
228
+ <div class="buttons">
229
+ <button type="button" class="preview-button" id="copy-btn">Copy</button>
230
+ <button type="button" class="preview-button" id="preview-btn">Preview</button>
231
+ </div>
232
+ <p class="text" id="copy-status" aria-live="polite" style="visibility:hidden;">
233
+ &nbsp;
234
+ </p>
235
+ </div>
236
+ </div>
237
+
238
+ <script>
239
+ var FEATURES = ${t};
240
+ var STORAGE_KEY_URL = 'picked-launcher-url';
241
+ var STORAGE_KEY_HISTORY = 'picked-launcher-history';
242
+ var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';
243
+
244
+ function getUrlInput() {
245
+ return document.getElementById('url-input');
246
+ }
247
+
248
+ // URL history
249
+ function getHistory() {
250
+ try {
251
+ var raw = localStorage.getItem(STORAGE_KEY_HISTORY);
252
+ if (!raw) return [];
253
+ var parsed = JSON.parse(raw);
254
+ return Array.isArray(parsed) ? parsed : [];
255
+ } catch (e) {
256
+ return [];
257
+ }
258
+ }
259
+
260
+ function saveHistory(history) {
261
+ localStorage.setItem(STORAGE_KEY_HISTORY, JSON.stringify(history));
262
+ }
263
+
264
+ function addToHistory(url) {
265
+ var history = getHistory().filter(function(h) { return h !== url; });
266
+ history.unshift(url);
267
+ if (history.length > 10) history = history.slice(0, 10);
268
+ saveHistory(history);
269
+ renderHistory();
270
+ }
271
+
272
+ function removeFromHistory(url) {
273
+ var history = getHistory().filter(function(h) { return h !== url; });
274
+ saveHistory(history);
275
+ renderHistory();
276
+ }
277
+
278
+ function renderHistory() {
279
+ var container = document.getElementById('url-history');
280
+ if (!container) return;
281
+ var history = getHistory();
282
+ if (history.length === 0) {
283
+ container.innerHTML = '';
284
+ return;
285
+ }
286
+ container.innerHTML = history.map(function(url) {
287
+ return '<div class="url-history-item">' +
288
+ '<button type="button" class="url-link" data-history-url="' + escapeAttr(url) + '">' + escapeHtml(url) + '</button>' +
289
+ '<button type="button" class="url-delete" data-history-delete="' + escapeAttr(url) + '">x</button>' +
290
+ '</div>';
291
+ }).join('');
292
+ }
293
+
294
+ // Feature selection persistence
295
+ function getSelections() {
296
+ try {
297
+ var raw = localStorage.getItem(STORAGE_KEY_SELECTIONS);
298
+ if (!raw) return {};
299
+ var parsed = JSON.parse(raw);
300
+ return typeof parsed === 'object' && parsed !== null ? parsed : {};
301
+ } catch (e) {
302
+ return {};
303
+ }
304
+ }
305
+
306
+ function saveSelections() {
307
+ var selections = {};
308
+ FEATURES.forEach(function(f) {
309
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
310
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
311
+ if (checkbox && select) {
312
+ selections[f.id] = { checked: checkbox.checked, value: select.value };
313
+ }
314
+ });
315
+ localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));
316
+ }
317
+
318
+ function restoreSelections() {
319
+ var selections = getSelections();
320
+ FEATURES.forEach(function(f) {
321
+ var saved = selections[f.id];
322
+ if (!saved) return;
323
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
324
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
325
+ if (checkbox) checkbox.checked = saved.checked;
326
+ if (select) select.value = saved.value;
327
+ });
328
+ }
329
+
330
+ function escapeHtml(str) {
331
+ var div = document.createElement('div');
332
+ div.textContent = str;
333
+ return div.innerHTML;
334
+ }
335
+
336
+ function escapeAttr(str) {
337
+ return str.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
338
+ }
339
+
340
+ function buildTargetUrl(inputValue) {
341
+ var value = inputValue;
342
+ if (!value.startsWith('http://') && !value.startsWith('https://')) {
343
+ value = 'https://' + value;
344
+ }
345
+ var hostname = window.location.hostname;
346
+ var subdomain = hostname.split('.').length > 2 ? hostname.split('.')[0] : '';
347
+ var target = value;
348
+ var sep = target.includes('?') ? '&' : '?';
349
+ if (subdomain) {
350
+ target = target + sep + 'cvly_env=' + encodeURIComponent(subdomain);
351
+ sep = '&';
352
+ }
353
+ FEATURES.forEach(function(f) {
354
+ var checkbox = document.querySelector('input[data-feature-id="' + f.id + '"]');
355
+ var select = document.querySelector('select[data-value-for="' + f.id + '"]');
356
+ if (checkbox && checkbox.checked && select) {
357
+ target = target + sep + 'picked-feature=' + encodeURIComponent(f.id + ':' + select.value);
358
+ sep = '&';
359
+ }
360
+ });
361
+ return target;
362
+ }
363
+
364
+ function showCopyStatus(message, success) {
365
+ var el = document.getElementById('copy-status');
366
+ if (!el) return;
367
+ el.textContent = message;
368
+ el.style.visibility = 'visible';
369
+ el.style.color = success ? '#2e7d32' : '#b71c1c';
370
+ setTimeout(function() {
371
+ el.style.visibility = 'hidden';
372
+ }, 2000);
373
+ }
374
+
375
+ // Init
376
+ window.addEventListener('load', function() {
377
+ var input = getUrlInput();
378
+ var savedUrl = localStorage.getItem(STORAGE_KEY_URL);
379
+ if (savedUrl && input) {
380
+ input.value = savedUrl;
381
+ }
382
+ renderHistory();
383
+ restoreSelections();
384
+ });
385
+
386
+ // Delegate click events
387
+ document.addEventListener('click', function(e) {
388
+ var target = e.target;
389
+
390
+ // History URL click
391
+ var historyUrl = target.getAttribute('data-history-url');
392
+ if (historyUrl) {
393
+ var input = getUrlInput();
394
+ if (input) input.value = historyUrl;
395
+ return;
396
+ }
397
+
398
+ // History delete click
399
+ var deleteUrl = target.getAttribute('data-history-delete');
400
+ if (deleteUrl) {
401
+ removeFromHistory(deleteUrl);
402
+ return;
403
+ }
404
+ });
405
+
406
+ // Feature change persistence
407
+ document.addEventListener('change', function(e) {
408
+ var target = e.target;
409
+ if (target.getAttribute('data-feature-id') || target.getAttribute('data-value-for')) {
410
+ saveSelections();
411
+ }
412
+ });
413
+
414
+ // Copy button
415
+ document.getElementById('copy-btn').addEventListener('click', function() {
416
+ var input = getUrlInput();
417
+ if (!input || !input.value) return;
418
+ localStorage.setItem(STORAGE_KEY_URL, input.value);
419
+ addToHistory(input.value);
420
+ saveSelections();
421
+ var target = buildTargetUrl(input.value);
422
+ navigator.clipboard.writeText(target).then(function() {
423
+ showCopyStatus('Preview URL copied to clipboard', true);
424
+ });
425
+ });
426
+
427
+ // Preview button
428
+ document.getElementById('preview-btn').addEventListener('click', function() {
429
+ var input = getUrlInput();
430
+ if (!input || !input.value) return;
431
+ localStorage.setItem(STORAGE_KEY_URL, input.value);
432
+ addToHistory(input.value);
433
+ saveSelections();
434
+ var target = buildTargetUrl(input.value);
435
+ window.location.href = target;
436
+ });
437
+ <\/script>
438
+ </main>
439
+ </body>
440
+ </html>`;
441
+ }
442
+ function y(e) {
443
+ return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
6
444
  }
7
- function l(n) {
8
- return (e) => L() ? e : `${n}${e}${x}`;
445
+ function b(e) {
446
+ return e.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9
447
  }
10
- const b = ["debug", "info", "warn", "error", "silent"], u = {
448
+ const _ = "picked", k = "\x1B[0m";
449
+ function U() {
450
+ const e = process.env.NO_COLOR;
451
+ return e === "1" || e === "true";
452
+ }
453
+ function c(e) {
454
+ return (t) => U() ? t : `${e}${t}${k}`;
455
+ }
456
+ const w = ["debug", "info", "warn", "error", "silent"], m = {
11
457
  debug: {
12
- color: l("\x1B[2m"),
458
+ color: c("\x1B[2m"),
13
459
  log: console.debug,
14
460
  enabled: !1
15
461
  },
16
462
  info: {
17
- color: l("\x1B[36m"),
463
+ color: c("\x1B[36m"),
18
464
  log: console.log,
19
465
  enabled: !0
20
466
  },
21
467
  warn: {
22
- color: l("\x1B[33m"),
468
+ color: c("\x1B[33m"),
23
469
  log: console.warn,
24
470
  enabled: !0
25
471
  },
26
472
  error: {
27
- color: l("\x1B[31m"),
473
+ color: c("\x1B[31m"),
28
474
  log: console.error,
29
475
  enabled: !0
30
476
  },
@@ -34,119 +480,162 @@ const b = ["debug", "info", "warn", "error", "silent"], u = {
34
480
  enabled: !1
35
481
  }
36
482
  };
37
- function I(n, e) {
38
- const o = (/* @__PURE__ */ new Date()).toLocaleTimeString(), t = e ? `${m}:${e}` : m;
39
- return `${o} [${t}] ${n}`;
483
+ function R(e, t) {
484
+ const n = (/* @__PURE__ */ new Date()).toLocaleTimeString(), r = t ? `${_}:${t}` : _;
485
+ return `${n} [${r}] ${e}`;
40
486
  }
41
- function g(n, e, o, t) {
42
- if (!n.enabled)
487
+ function g(e, t, n, r) {
488
+ if (!e.enabled)
43
489
  return;
44
- const r = I(e, t);
45
- n.log(n.color ? n.color(r) : r), o !== void 0 && n.log(o);
490
+ const i = R(t, r);
491
+ e.log(e.color ? e.color(i) : i), n !== void 0 && e.log(n);
46
492
  }
47
- function d(n) {
48
- const e = u[n], o = /* @__PURE__ */ new Set();
493
+ function p(e) {
494
+ const t = m[e], n = /* @__PURE__ */ new Set();
49
495
  return Object.assign(
50
- (t, r, c) => {
51
- g(e, t, r, c);
496
+ (r, i, o) => {
497
+ g(t, r, i, o);
52
498
  },
53
499
  {
54
- once(t, r, c) {
55
- !e.enabled || o.has(t) || (o.add(t), g(e, t, r, c));
500
+ once(r, i, o) {
501
+ !t.enabled || n.has(r) || (n.add(r), g(t, r, i, o));
56
502
  }
57
503
  }
58
504
  );
59
505
  }
60
- function R(n) {
61
- const e = b.indexOf(n);
62
- if (e === -1) {
63
- g(u.error, `invalid log level: ${n}`);
506
+ function L(e) {
507
+ const t = w.indexOf(e);
508
+ if (t === -1) {
509
+ g(m.error, `invalid log level: ${e}`);
64
510
  return;
65
511
  }
66
- for (const [o, t] of b.entries())
67
- u[t].enabled = o >= e;
68
- }
69
- const s = l("\x1B[34m"), h = l("\x1B[36m");
70
- function y() {
71
- const n = [
72
- ` ${s("_")} ${h("_")} _ _ _`,
73
- `${s("(_)")} ${h("(_)")} _ __(_)__| |_____ __| |`,
512
+ for (const [n, r] of w.entries())
513
+ m[r].enabled = n >= t;
514
+ }
515
+ const s = c("\x1B[34m"), S = c("\x1B[36m");
516
+ function I() {
517
+ const e = [
518
+ ` ${s("_")} ${S("_")} _ _ _`,
519
+ `${s("(_)")} ${S("(_)")} _ __(_)__| |_____ __| |`,
74
520
  ` ${s("_")} ${s("_")} | '_ \\ / _| / / -_) _\` |`,
75
521
  `${s("(_)")} ${s("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,
76
522
  ` |_|
77
523
  `
78
524
  ];
79
- console.log(n.join(`
525
+ console.log(e.join(`
80
526
  `));
81
527
  }
82
- const a = {
83
- banner: y,
84
- debug: d("debug"),
85
- info: d("info"),
86
- warn: d("warn"),
87
- error: d("error"),
88
- setLevel: R
528
+ const l = {
529
+ banner: I,
530
+ debug: p("debug"),
531
+ info: p("info"),
532
+ warn: p("warn"),
533
+ error: p("error"),
534
+ setLevel: L
89
535
  };
90
- function B(n) {
91
- if (n.length === 0)
536
+ function O(e) {
537
+ return (t, n, r) => {
538
+ if (t.method !== "GET") {
539
+ r();
540
+ return;
541
+ }
542
+ const o = (t.url ?? "").split("?")[0];
543
+ if (o !== "/" && o !== "/index.html") {
544
+ r();
545
+ return;
546
+ }
547
+ const a = e();
548
+ n.setHeader("Content-Type", "text/html"), n.statusCode = 200, n.end(a);
549
+ };
550
+ }
551
+ function H(e) {
552
+ if (e.length === 0)
92
553
  return;
93
- const e = Math.max(4, ...n.map((i) => i.name.length)), o = Math.max(2, ...n.map((i) => i.id.length)), t = ` ${"Name".padEnd(e)} ${"ID".padEnd(o)} Status Weight Ver`, r = ` ${"─".repeat(e)} ${"─".repeat(o)} ──────── ────── ───`, c = n.map((i) => {
94
- const f = i.enabled ? "\x1B[32m enabled\x1B[0m" : "\x1B[2mdisabled\x1B[0m", _ = `${i.weight.toString()}%`.padStart(6), S = `v${i.version.toString()}`;
95
- return ` ${i.name.padEnd(e)} ${i.id.padEnd(o)} ${f} ${_} ${S}`;
554
+ const t = Math.max(4, ...e.map((a) => a.name.length)), n = Math.max(2, ...e.map((a) => a.id.length)), r = ` ${"Name".padEnd(t)} ${"ID".padEnd(n)} Status Weight Ver`, i = ` ${"─".repeat(t)} ${"─".repeat(n)} ──────── ────── ───`, o = e.map((a) => {
555
+ const d = a.enabled ? "\x1B[32m enabled\x1B[0m" : "\x1B[2mdisabled\x1B[0m", u = `${a.weight.toString()}%`.padStart(6), f = `v${a.version.toString()}`;
556
+ return ` ${a.name.padEnd(t)} ${a.id.padEnd(n)} ${d} ${u} ${f}`;
96
557
  });
97
- console.log(["", " Features:", "", t, r, ...c, ""].join(`
558
+ console.log(["", " Features:", "", r, i, ...o, ""].join(`
98
559
  `));
99
560
  }
100
- function O(n) {
561
+ function B(e) {
101
562
  try {
102
- const e = new URL(n).hostname;
103
- return e === "localhost" || e === "127.0.0.1" || e === "::1";
563
+ const t = new URL(e).hostname;
564
+ return t === "localhost" || t === "127.0.0.1" || t === "::1";
104
565
  } catch {
105
566
  return !1;
106
567
  }
107
568
  }
108
- function T(n) {
109
- return new Promise((e) => {
110
- setTimeout(e, n);
569
+ function C(e) {
570
+ return new Promise((t) => {
571
+ setTimeout(t, e);
111
572
  });
112
573
  }
113
- async function v(n, e) {
114
- const o = await $(n, e);
115
- if (o || !O(n))
116
- return o;
117
- for (let t = 1; t <= w; t++) {
118
- a.info(
119
- `local API not ready, retrying in ${(E / 1e3).toString()}s (${t.toString()}/${w.toString()})`
120
- ), await T(E);
121
- const r = await $(n, e);
122
- if (r)
123
- return r;
574
+ async function F(e, t, n) {
575
+ const r = await h(e, t, { headers: n });
576
+ if (r || !B(e))
577
+ return r;
578
+ for (let i = 1; i <= E; i++) {
579
+ l.info(
580
+ `local API not ready, retrying in ${(A / 1e3).toString()}s (${i.toString()}/${E.toString()})`
581
+ ), await C(A);
582
+ const o = await h(e, t, { headers: n });
583
+ if (o)
584
+ return o;
124
585
  }
125
586
  return null;
126
587
  }
127
- const p = "https://api.picked.app", C = "__PICKED_PROJECT_CONFIG__", w = 5, E = 2e3;
128
- function P(n) {
129
- const e = n.apiUrl ?? p;
588
+ function P() {
589
+ return "0.0.1-dev.1772493269328";
590
+ }
591
+ const x = "https://api.picked.app", Y = "__PICKED_PROJECT_CONFIG__", E = 5, A = 2e3;
592
+ function j(e) {
593
+ const t = e.apiUrl ?? x;
594
+ let n = [];
130
595
  return {
131
596
  name: "picked",
132
597
  config: async () => {
133
- a.banner(), a.info(`fetching project config for "${n.projectId}"`), e !== p && a.warn(`using custom API URL: ${e}`);
134
- const o = performance.now(), t = await v(e, n.projectId), r = (performance.now() - o).toFixed(0);
135
- if (!t) {
136
- a.warn(`failed to fetch project config for "${n.projectId}" (${r}ms)`);
598
+ l.banner(), l.info(`fetching project config for "${e.projectId}"`), t !== x && l.warn(`using custom API URL: ${t}`);
599
+ const r = T("vite-plugin", P()), i = performance.now(), o = await F(t, e.projectId, r), a = (performance.now() - i).toFixed(0);
600
+ if (!o) {
601
+ l.warn(`failed to fetch project config for "${e.projectId}" (${a}ms)`);
137
602
  return;
138
603
  }
139
- const c = t.features.length, i = t.features.filter((_) => _.enabled).length, f = JSON.stringify(t).length;
140
- return a.info(
141
- `fetched ${c.toString()} features (${i.toString()} enabled) for "${n.projectId}" in ${r}ms`
142
- ), B(t.features), a.debug(`config size: ${f.toString()} bytes`), {
604
+ n = o.features;
605
+ const d = o.features.length, u = o.features.filter(($) => $.enabled).length, f = JSON.stringify(o).length;
606
+ return l.info(
607
+ `fetched ${d.toString()} features (${u.toString()} enabled) for "${e.projectId}" in ${a}ms`
608
+ ), H(o.features), l.debug(`config size: ${f.toString()} bytes`), {
143
609
  define: {
144
- [C]: JSON.stringify(t)
610
+ [Y]: JSON.stringify(o)
145
611
  }
146
612
  };
613
+ },
614
+ configureServer(r) {
615
+ if (e.disableLauncher) return;
616
+ r.middlewares.use(O(() => v(n)));
617
+ const i = r.printUrls.bind(r);
618
+ r.printUrls = () => {
619
+ const o = r.resolvedUrls?.local[0];
620
+ if (o) {
621
+ const a = o.replace(
622
+ /:(?<port>\d+)\//,
623
+ (d, u) => `:\x1B[1m${u}\x1B[22m/`
624
+ );
625
+ console.log(` \x1B[32m➜\x1B[0m \x1B[1mPicked\x1B[22m: \x1B[36m${a}\x1B[0m`);
626
+ }
627
+ i();
628
+ };
629
+ },
630
+ generateBundle() {
631
+ e.disableLauncher || this.emitFile({
632
+ type: "asset",
633
+ fileName: "index.html",
634
+ source: v(n)
635
+ });
147
636
  }
148
637
  };
149
638
  }
150
639
  export {
151
- P as picked
640
+ j as picked
152
641
  };
@@ -4,6 +4,8 @@ export interface PickedPluginOptions {
4
4
  projectId: string;
5
5
  /** Custom API URL (defaults to https://api.picked.app) */
6
6
  apiUrl?: string;
7
+ /** Disable the launcher HTML page (dev server + build output). Defaults to false. */
8
+ disableLauncher?: boolean;
7
9
  }
8
10
  /**
9
11
  * Vite plugin that fetches Picked project config at build time
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAoElC,MAAM,WAAW,mBAAmB;IAClC,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAuC3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AA+ElC,MAAM,WAAW,mBAAmB;IAClC,4BAA4B;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAyE3D"}
@@ -0,0 +1,3 @@
1
+ import { ProjectConfigFeature } from '@picked/client/plugins/dynamic-experiences';
2
+ export declare function getLauncherHtml(features: ReadonlyArray<ProjectConfigFeature>): string;
3
+ //# sourceMappingURL=launcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.d.ts","sourceRoot":"","sources":["../../src/launcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4CAA4C,CAAA;AAEtF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,aAAa,CAAC,oBAAoB,CAAC,GAAG,MAAM,CA+brF"}
@@ -0,0 +1,3 @@
1
+ import { Connect } from 'vite';
2
+ export declare function createPickedMiddleware(getHtml: () => string): Connect.NextHandleFunction;
3
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAoBxF"}
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@picked/vite-plugin-picked",
3
3
  "description": "Vite plugin for build-time config injection",
4
- "version": "0.0.1-dev.1772412203098",
4
+ "version": "0.0.1-dev.1772493269328",
5
5
  "dependencies": {
6
- "@picked/client": "0.0.1-dev.1772412203098"
6
+ "@picked/client": "0.0.1-dev.1772493269328"
7
7
  },
8
8
  "devDependencies": {
9
9
  "@repo/eslint-config": "workspace:*",