@picked/vite-plugin-picked 0.0.1-dev.1778467244607 → 0.0.1-dev.1778468342672

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,15 +1,15 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`@picked/client/plugins/dynamic-experiences`);function t(e,t){return t||=e.slice(0),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}var n;function r(e){let r=JSON.stringify(e),o=e.length>0?e.map(e=>`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`node:fs`),t=require(`@picked/client/plugins/dynamic-experiences`),n=require(`node:fs/promises`),r=require(`node:path`);function i(e,t){return t||=e.slice(0),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}var a;function o(e){let t=JSON.stringify(e),n=e.length>0?e.map(e=>`
2
2
  <div class="feature-row">
3
3
  <label>
4
- <input type="checkbox" data-feature-id="${a(e.id)}" checked>
5
- <span class="feature-name">${i(e.name)}</span>
6
- <span class="feature-id">${i(e.id)}</span>
4
+ <input type="checkbox" data-feature-id="${c(e.id)}" checked>
5
+ <span class="feature-name">${s(e.name)}</span>
6
+ <span class="feature-id">${s(e.id)}</span>
7
7
  </label>
8
- <select data-value-for="${a(e.id)}">
8
+ <select data-value-for="${c(e.id)}">
9
9
  <option value="true" selected>true</option>
10
10
  <option value="false">false</option>
11
11
  </select>
12
- </div>`).join(``):`<p class="text no-features">No features configured for this project.</p>`;return String.raw(n||=t([`<!DOCTYPE html>
12
+ </div>`).join(``):`<p class="text no-features">No features configured for this project.</p>`;return String.raw(a||=i([`<!DOCTYPE html>
13
13
  <html lang="en">
14
14
  <head>
15
15
  <meta charset="UTF-8">
@@ -855,7 +855,52 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require
855
855
  <\/script>
856
856
  </main>
857
857
  </body>
858
- </html>`]),o,r)}function i(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replaceAll(`"`,`&quot;`)}function a(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`"`,`&quot;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`)}var o=`picked`,s=`\x1B[0m`;function c(){let e=process.env.NO_COLOR;return e===`1`||e===`true`}function l(e){return t=>c()?t:`${e}${t}${s}`}var u=[`debug`,`info`,`warn`,`error`,`silent`],d={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 f(e,t){return`${new Date().toLocaleTimeString()} [${t?`${o}:${t}`:o}] ${e}`}function p(e,t,n,r){if(!e.enabled)return;let i=f(t,r);e.log(e.color?e.color(i):i),n!==void 0&&e.log(n)}function m(e){let t=d[e],n=new Set;return Object.assign((e,n,r)=>{p(t,e,n,r)},{once(e,r,i){!t.enabled||n.has(e)||(n.add(e),p(t,e,r,i))}})}function h(e){let t=u.indexOf(e);if(t===-1){p(d.error,`invalid log level: ${e}`);return}for(let[e,n]of u.entries())d[n].enabled=e>=t}var g=l(`\x1B[34m`),_=l(`\x1B[36m`);function v(){let e=[` ${g(`_`)} ${_(`_`)} _ _ _`,`${g(`(_)`)} ${_(`(_)`)} _ __(_)__| |_____ __| |`,` ${g(`_`)} ${g(`_`)} | '_ \\ / _| / / -_) _\` |`,`${g(`(_)`)} ${g(`(_)`)} | .__/_\\__|_\\_\\___\\__,_|`,` |_|
858
+ </html>`]),n,t)}function s(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`).replaceAll(`"`,`&quot;`)}function c(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`"`,`&quot;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`)}var l=`picked`,u=`\x1B[0m`;function d(){let e=process.env.NO_COLOR;return e===`1`||e===`true`}function f(e){return t=>d()?t:`${e}${t}${u}`}var p=[`debug`,`info`,`warn`,`error`,`silent`],m={debug:{color:f(`\x1B[2m`),log:console.debug,enabled:!1},info:{color:f(`\x1B[36m`),log:console.log,enabled:!0},warn:{color:f(`\x1B[33m`),log:console.warn,enabled:!0},error:{color:f(`\x1B[31m`),log:console.error,enabled:!0},silent:{log:()=>{},enabled:!1}};function ee(e,t){return`${new Date().toLocaleTimeString()} [${t?`${l}:${t}`:l}] ${e}`}function h(e,t,n,r){if(!e.enabled)return;let i=ee(t,r);e.log(e.color?e.color(i):i),n!==void 0&&e.log(n)}function g(e){let t=m[e],n=new Set;return Object.assign((e,n,r)=>{h(t,e,n,r)},{once(e,r,i){!t.enabled||n.has(e)||(n.add(e),h(t,e,r,i))}})}function _(e){let t=p.indexOf(e);if(t===-1){h(m.error,`invalid log level: ${e}`);return}for(let[e,n]of p.entries())m[n].enabled=e>=t}var v=f(`\x1B[34m`),y=f(`\x1B[36m`);function b(){let e=[` ${v(`_`)} ${y(`_`)} _ _ _`,`${v(`(_)`)} ${y(`(_)`)} _ __(_)__| |_____ __| |`,` ${v(`_`)} ${v(`_`)} | '_ \\ / _| / / -_) _\` |`,`${v(`(_)`)} ${v(`(_)`)} | .__/_\\__|_\\_\\___\\__,_|`,` |_|
859
859
  `];console.log(e.join(`
860
- `))}var y={banner:v,debug:m(`debug`),info:m(`info`),warn:m(`warn`),error:m(`error`),setLevel:h};function b(e){return(t,n,r)=>{if(t.method!==`GET`){r();return}let i=(t.url??``).split(`?`)[0];if(i!==`/`&&i!==`/index.html`){r();return}let a=e();n.setHeader(`Content-Type`,`text/html`),n.statusCode=200,n.end(a)}}var x=5;function S(e){return Array.isArray(e)?e:[]}function C(e,t,n){if(t.length===0)return;if(t.length>x){console.log(`\n ${e}: ${t.length.toString()} loaded\n`);return}let r=n.map(e=>Math.max(e.header.length,...t.map(t=>e.value(t).length))),i=(e,t)=>e.padEnd(r[t]??e.length),a=` ${n.map((e,t)=>i(e.header,t)).join(` `)}`,o=` ${r.map(e=>`─`.repeat(e)).join(` `)}`,s=t.map(e=>` ${n.map((t,n)=>i(t.value(e),n)).join(` `)}`);console.log([``,` ${e}:`,``,a,o,...s,``].join(`
861
- `))}function w(e,t){t.length!==0&&console.log(`\n ${e}: ${t.length.toString()} loaded\n`)}var T=[{header:`Name`,value:e=>e.name},{header:`ID`,value:e=>e.id},{header:`Status`,value:e=>e.enabled?`\x1B[32m enabled\x1B[0m`:`\x1B[2mdisabled\x1B[0m`},{header:`Weight`,value:e=>`${e.weight.toString()}%`.padStart(6)},{header:`Ver`,value:e=>`v${e.version.toString()}`}],E=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key},{header:`Component`,value:e=>e.componentName},{header:`Nodes`,value:e=>e.nodes.length.toString()},{header:`Targets`,value:e=>e.targets.length.toString()}],D=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key},{header:`Fields`,value:e=>(e.fieldIds?.length??0).toString()}],O=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key},{header:`Type`,value:e=>e.type},{header:`Required`,value:e=>e.required?`yes`:`no`}],k=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key}];function A(e){try{let t=new URL(e).hostname;return t===`localhost`||t===`127.0.0.1`||t===`::1`}catch{return!1}}function j(e){return new Promise(t=>{setTimeout(t,e)})}async function M(t,n,r){let i=await(0,e.fetchProject)(t,n,{headers:r});if(i||!A(t))return i;for(let i=1;i<=I;i++){y.info(`local API not ready, retrying in ${(L/1e3).toString()}s (${i.toString()}/${I.toString()})`),await j(L);let a=await(0,e.fetchProject)(t,n,{headers:r});if(a)return a}return null}function N(){return`0.0.1-dev.1778467244607`}var P=`https://api.picked.app`,F=`__PICKED_PROJECT_CONFIG__`,I=5,L=2e3;function R(t){let n=t.apiUrl??P,i=[],a,o=!1;return{name:`picked`,config:async()=>{if(o)return a;o=!0,y.banner(),y.info(`fetching project config for "${t.projectId}"`),n!==P&&y.warn(`using custom API URL: ${n}`);let r=(0,e.createClientHeaders)(`vite-plugin`,N()),s=performance.now(),c=await M(n,t.projectId,r),l=(performance.now()-s).toFixed(0);if(!c)return y.warn(`failed to fetch project config for "${t.projectId}" (${l}ms)`),a=void 0,a;i=S(c.features);let u=S(c.experiences),d=S(c.steps),f=S(c.fields),p=S(c.conditions),m=S(c.actions),h=JSON.stringify(c).length,g=[`${i.length.toString()} features`,`${u.length.toString()} experiences`,`${d.length.toString()} steps`,`${f.length.toString()} fields`,`${p.length.toString()} conditions`,`${m.length.toString()} actions`].join(`, `);return y.info(`fetched config for "${t.projectId}" in ${l}ms (${g})`),C(`Features`,i,T),C(`Experiences`,u,E),C(`Steps`,d,D),C(`Fields`,f,O),C(`Conditions`,p,k),w(`Actions`,m),y.debug(`config size: ${h.toString()} bytes`),a={define:{[F]:JSON.stringify(c)}},a},configureServer(e){if(t.disableLauncher)return;e.middlewares.use(b(()=>r(i)));let n=e.printUrls.bind(e);e.printUrls=()=>{let t=e.resolvedUrls?.local[0];if(t){let e=t.replace(/:(?<port>\d+)\//,(e,t)=>`:\x1b[1m${t}\x1b[22m/`);console.log(` \x1b[32m➜\x1b[0m \x1b[1mPicked\x1b[22m: \x1b[36m${e}\x1b[0m`)}n()}},generateBundle(){t.disableLauncher||this.emitFile({type:`asset`,fileName:`index.html`,source:r(i)})}}}exports.picked=R;
860
+ `))}var x={banner:b,debug:g(`debug`),info:g(`info`),warn:g(`warn`),error:g(`error`),setLevel:_};function S(e){return(t,n,r)=>{if(t.method!==`GET`){r();return}let i=(t.url??``).split(`?`)[0];if(i!==`/`&&i!==`/index.html`){r();return}let a=e();n.setHeader(`Content-Type`,`text/html`),n.statusCode=200,n.end(a)}}var C=`.picked/`;async function w(t,i){if(i)return;let a=(0,r.join)(t,`.gitignore`);if(!(0,e.existsSync)(a)){await(0,n.writeFile)(a,`${C}
861
+ `);return}let o=await(0,n.readFile)(a,`utf8`);T(o)||await(0,n.appendFile)(a,`${o.length>0&&!o.endsWith(`
862
+ `)?`
863
+ `:``}${C}
864
+ `)}function T(e){return e.split(/\r?\n/).map(e=>e.trim()).some(e=>e===C||e===`.picked`)}function E(e){return Array.isArray(e)?e:[]}var D=1;function O(e){let t=(0,r.join)(e,`.picked`);return{pickedDir:t,manifestPath:(0,r.join)(t,`manifest.json`),projectConfigPath:(0,r.join)(t,`project-config.json`),experiencesDir:(0,r.join)(t,`experiences`)}}async function te(t){if(!(0,e.existsSync)(t))return null;try{let e=await(0,n.readFile)(t,`utf8`),r=JSON.parse(e);return ne(r)?r:null}catch{return null}}function ne(e){return!(typeof e!=`object`||!e||!(`version`in e)||typeof e.version!=`number`||!(`projectVersionId`in e)||typeof e.projectVersionId!=`string`||!(`workspaceId`in e)||typeof e.workspaceId!=`string`||!(`experiences`in e)||!Array.isArray(e.experiences))}function re(e){let t=new Set;for(let n of E(e.steps))n.layoutContentId&&t.add(n.id);if(t.size===0)return[];let n=[];for(let r of E(e.experiences))E(r.nodes).some(e=>e.type===`step`&&t.has(e.stepId))&&n.push(r.id);return n}async function k(e){let{apiUrl:t,projectId:i,projectRoot:a,headers:o,reuseWhenUnchanged:s=!0}=e,c=O(a),l=await j(t,i,o),u=re(l);if(s){let e=await te(c.manifestPath);if(e&&e.projectVersionId===l.versionId&&e.workspaceId===l.workspaceId)return{config:l,manifest:e,experienceContentPaths:A(c,u)}}await(0,n.mkdir)(c.experiencesDir,{recursive:!0}),await(0,n.writeFile)(c.projectConfigPath,JSON.stringify(l,null,2));let d=new Date().toISOString(),f=[];for(let e of u){let a=await M(t,i,e,o);await(0,n.writeFile)((0,r.join)(c.experiencesDir,`${e}.json`),JSON.stringify(a,null,2)),f.push({id:e,fetchedAt:d})}let p={version:D,fetchedAt:d,projectVersionId:l.versionId,workspaceId:l.workspaceId,projectId:l.id,experiences:f};return await(0,n.writeFile)(c.manifestPath,JSON.stringify(p,null,2)),{config:l,manifest:p,experienceContentPaths:A(c,u)}}function A(e,t){let n={};for(let i of t)n[i]=(0,r.join)(e.experiencesDir,`${i}.json`);return n}async function j(e,n,r){let i;try{i=await(0,t.fetchProject)(e,n,{headers:r})}catch(t){throw Error(`[picked] Build-time fetch of project config failed for "${n}" at ${e}: ${N(t)}`)}if(!i)throw Error(`[picked] Build-time fetch of project config returned no usable response for "${n}" at ${e}. Confirm the API is reachable and the project ID is correct.`);return i}async function M(e,n,r,i){let a;try{a=await(0,t.fetchExperienceContent)(e,n,r,{headers:i})}catch(t){throw Error(`[picked] Build-time fetch of content for experience "${r}" failed at ${e}: ${N(t)}`)}if(!a)throw Error(`[picked] Build-time fetch of content for experience "${r}" returned no usable response. Confirm the experience id exists and the API is reachable.`);return a}function N(e){if(e instanceof Error)return e.message;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return`unknown error`}}function P(e){let{projectConfigPath:t,experienceContentPaths:n,manifestMetadata:r}=e,i=e=>JSON.stringify(e),a=Object.entries(n).map(([e,t])=>` ${JSON.stringify(e)}: () => import(${i(t)}).then((m) => m.default ?? m),`).join(`
865
+ `);return`import projectConfigJson from ${i(t)}
866
+
867
+ const experienceImporters = {
868
+ ${a}
869
+ }
870
+
871
+ export const projectConfig = projectConfigJson
872
+
873
+ export async function experienceContent(experience, _options) {
874
+ const id = typeof experience === 'string' ? experience : experience?.id
875
+ if (!id) return null
876
+ const importer = experienceImporters[id]
877
+ if (!importer) return null
878
+ try {
879
+ return await importer()
880
+ } catch {
881
+ return null
882
+ }
883
+ }
884
+
885
+ export const manifestMetadata = ${JSON.stringify(r)}
886
+ `}function F(e){let{apiUrl:t,projectId:n}=e;return`import { fetchProject, fetchExperienceContent } from '@picked/client/plugins/dynamic-experiences'
887
+
888
+ const apiUrl = ${JSON.stringify(t)}
889
+ const projectId = ${JSON.stringify(n)}
890
+
891
+ export const projectConfig = await fetchProject(apiUrl, projectId)
892
+
893
+ export async function experienceContent(experience, options) {
894
+ const id = typeof experience === 'string' ? experience : experience?.id
895
+ if (!id) return null
896
+ return await fetchExperienceContent(apiUrl, projectId, id, options)
897
+ }
898
+
899
+ export const manifestMetadata = {
900
+ mode: 'dev',
901
+ fetchedAt: null,
902
+ projectVersionId: projectConfig?.versionId ?? null,
903
+ workspaceId: projectConfig?.workspaceId ?? null,
904
+ }
905
+ `}var I=5;function L(e,t,n){if(t.length===0)return;if(t.length>I){console.log(`\n ${e}: ${t.length.toString()} loaded\n`);return}let r=n.map(e=>Math.max(e.header.length,...t.map(t=>e.value(t).length))),i=(e,t)=>e.padEnd(r[t]??e.length),a=` ${n.map((e,t)=>i(e.header,t)).join(` `)}`,o=` ${r.map(e=>`─`.repeat(e)).join(` `)}`,s=t.map(e=>` ${n.map((t,n)=>i(t.value(e),n)).join(` `)}`);console.log([``,` ${e}:`,``,a,o,...s,``].join(`
906
+ `))}function R(e,t){t.length!==0&&console.log(`\n ${e}: ${t.length.toString()} loaded\n`)}var z=[{header:`Name`,value:e=>e.name},{header:`ID`,value:e=>e.id},{header:`Status`,value:e=>e.enabled?`\x1B[32m enabled\x1B[0m`:`\x1B[2mdisabled\x1B[0m`},{header:`Weight`,value:e=>`${e.weight.toString()}%`.padStart(6)},{header:`Ver`,value:e=>`v${e.version.toString()}`}],B=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key},{header:`Component`,value:e=>e.componentName},{header:`Nodes`,value:e=>e.nodes.length.toString()},{header:`Targets`,value:e=>e.targets.length.toString()}],V=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key},{header:`Fields`,value:e=>(e.fieldIds?.length??0).toString()}],H=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key},{header:`Type`,value:e=>e.type},{header:`Required`,value:e=>e.required?`yes`:`no`}],U=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key}];function W(e){try{let t=new URL(e).hostname;return t===`localhost`||t===`127.0.0.1`||t===`::1`}catch{return!1}}function G(e){return new Promise(t=>{setTimeout(t,e)})}async function K(e,n,r){let i=await(0,t.fetchProject)(e,n,{headers:r});if(i||!W(e))return i;for(let i=1;i<=Z;i++){x.info(`local API not ready, retrying in ${(Q/1e3).toString()}s (${i.toString()}/${Z.toString()})`),await G(Q);let a=await(0,t.fetchProject)(e,n,{headers:r});if(a)return a}return null}function q(){return`0.0.1-dev.1778468342672`}var J=`https://api.picked.app`,Y=`virtual:picked/data`,X=`\0${Y}`,Z=5,Q=2e3;function ie(n){let r=n.apiUrl??J,i=[],a=process.cwd(),s=`serve`,c,l=!1;return{name:`picked`,config:async(o,u)=>{s=u.command,a=process.cwd(),x.banner(),r!==J&&x.warn(`using custom API URL: ${r}`);let d=(0,t.createClientHeaders)(`vite-plugin`,q());if(u.command===`build`){if(l)return;l=!0,x.info(`prefetching project config + content for "${n.projectId}"`);let t=O(a),o=(0,e.existsSync)(t.pickedDir),s=performance.now(),u=await k({apiUrl:r,projectId:n.projectId,projectRoot:a,headers:d}),f=(performance.now()-s).toFixed(0);await w(a,o);let p=u.config;i=E(p.features),$(p,f),c=P({projectConfigPath:t.projectConfigPath,experienceContentPaths:u.experienceContentPaths,manifestMetadata:{mode:`build`,fetchedAt:u.manifest.fetchedAt,projectVersionId:u.manifest.projectVersionId,workspaceId:u.manifest.workspaceId}})}else{x.info(`fetching project config for "${n.projectId}" (dev)`);let e=performance.now(),t=await K(r,n.projectId,d),a=(performance.now()-e).toFixed(0);t?(i=E(t.features),$(t,a)):x.warn(`failed to fetch project config for "${n.projectId}" (${a}ms)`)}},resolveId(e){if(e===Y)return X},load(e){if(e===X)return s===`build`?c:F({apiUrl:r,projectId:n.projectId})},configureServer(e){if(n.disableLauncher)return;e.middlewares.use(S(()=>o(i)));let t=e.printUrls.bind(e);e.printUrls=()=>{let n=e.resolvedUrls?.local[0];if(n){let e=n.replace(/:(?<port>\d+)\//,(e,t)=>`:\x1b[1m${t}\x1b[22m/`);console.log(` \x1b[32m➜\x1b[0m \x1b[1mPicked\x1b[22m: \x1b[36m${e}\x1b[0m`)}t()}},generateBundle(){n.disableLauncher||this.emitFile({type:`asset`,fileName:`index.html`,source:o(i)})}}}function $(e,t){let n=E(e.features),r=E(e.experiences),i=E(e.steps),a=E(e.fields),o=E(e.conditions),s=E(e.actions),c=JSON.stringify(e).length,l=[`${n.length.toString()} features`,`${r.length.toString()} experiences`,`${i.length.toString()} steps`,`${a.length.toString()} fields`,`${o.length.toString()} conditions`,`${s.length.toString()} actions`].join(`, `);x.info(`fetched config in ${t}ms (${l})`),L(`Features`,n,z),L(`Experiences`,r,B),L(`Steps`,i,V),L(`Fields`,a,H),L(`Conditions`,o,U),R(`Actions`,s),x.debug(`config size: ${c.toString()} bytes`)}exports.picked=ie;
package/dist/esm/index.js CHANGED
@@ -1,25 +1,28 @@
1
- import { createClientHeaders as e, fetchProject as t } from "@picked/client/plugins/dynamic-experiences";
1
+ import { existsSync as e } from "node:fs";
2
+ import { createClientHeaders as t, fetchExperienceContent as n, fetchProject as r } from "@picked/client/plugins/dynamic-experiences";
3
+ import { appendFile as i, mkdir as a, readFile as o, writeFile as s } from "node:fs/promises";
4
+ import { join as c } from "node:path";
2
5
  //#region \0@oxc-project+runtime@0.124.0/helpers/taggedTemplateLiteral.js
3
- function n(e, t) {
6
+ function l(e, t) {
4
7
  return t ||= e.slice(0), Object.freeze(Object.defineProperties(e, { raw: { value: Object.freeze(t) } }));
5
8
  }
6
9
  //#endregion
7
10
  //#region src/launcher.ts
8
- var r;
9
- function i(e) {
10
- let t = JSON.stringify(e), i = e.length > 0 ? e.map((e) => `
11
+ var u;
12
+ function d(e) {
13
+ let t = JSON.stringify(e), n = e.length > 0 ? e.map((e) => `
11
14
  <div class="feature-row">
12
15
  <label>
13
- <input type="checkbox" data-feature-id="${o(e.id)}" checked>
14
- <span class="feature-name">${a(e.name)}</span>
15
- <span class="feature-id">${a(e.id)}</span>
16
+ <input type="checkbox" data-feature-id="${p(e.id)}" checked>
17
+ <span class="feature-name">${f(e.name)}</span>
18
+ <span class="feature-id">${f(e.id)}</span>
16
19
  </label>
17
- <select data-value-for="${o(e.id)}">
20
+ <select data-value-for="${p(e.id)}">
18
21
  <option value="true" selected>true</option>
19
22
  <option value="false">false</option>
20
23
  </select>
21
24
  </div>`).join("") : "<p class=\"text no-features\">No features configured for this project.</p>";
22
- return String.raw(r ||= n([
25
+ return String.raw(u ||= l([
23
26
  "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"robots\" content=\"noindex, nofollow\">\n <title>Picked</title>\n <style>\n main {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n display: grid;\n align-items: center;\n justify-content: center;\n font-family: monospace;\n color: #4A4A4A\n }\n\n .wrap {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n max-width: 480px;\n width: 100%;\n }\n\n .title {\n font-size: 1.125rem;\n font-weight: 700;\n margin-bottom: 0;\n }\n\n .text {\n margin-top: .5rem;\n font-size: .875rem\n }\n\n .text a {\n color: #4A4A4A;\n text-decoration: none;\n }\n\n .text a:hover {\n cursor: pointer;\n text-decoration: underline\n }\n\n .preview-form {\n margin-top: 2rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n\n .preview-input {\n padding: 0.5rem;\n border: 1px solid #4A4A4A;\n border-radius: 0;\n font-family: monospace;\n }\n\n .preview-button {\n padding: 0.5rem;\n background: #4A4A4A;\n color: white;\n border: none;\n border-radius: 0;\n cursor: pointer;\n font-family: monospace;\n }\n\n .preview-button:hover {\n opacity: 0.9;\n }\n\n .buttons {\n display: grid;\n gap: 0.5em;\n grid-template-columns: 1fr 1fr;\n }\n\n #copy-status {\n font-size: 1em;\n text-align: right;\n margin-top: 0.5em;\n }\n\n .features-section {\n margin-top: 1.5rem;\n }\n\n .features-label {\n font-weight: 700;\n font-size: .875rem;\n margin-bottom: 0.5rem;\n }\n\n .feature-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.25rem 0;\n }\n\n .feature-row label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n min-width: 0;\n flex: 1;\n }\n\n .feature-name {\n font-size: .875rem;\n }\n\n .feature-id {\n font-size: .75rem;\n color: #888;\n }\n\n .feature-row select {\n font-family: monospace;\n font-size: .75rem;\n padding: 0.125rem 0.25rem;\n border: 1px solid #4A4A4A;\n border-radius: 0;\n background: white;\n flex-shrink: 0;\n }\n\n .no-features {\n color: #888;\n font-style: italic;\n }\n\n .url-history {\n margin-top: 0.5rem;\n font-size: .75rem;\n }\n\n .url-history-item {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0;\n }\n\n .url-history-item button {\n background: none;\n border: none;\n cursor: pointer;\n font-family: monospace;\n font-size: .75rem;\n color: #888;\n padding: 0;\n }\n\n .url-history-item button.url-link {\n color: #4A4A4A;\n text-decoration: none;\n text-align: left;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n min-width: 0;\n }\n\n .url-history-item button.url-link:hover {\n text-decoration: underline;\n }\n\n .url-history-item button.url-delete:hover {\n color: #b71c1c;\n }\n\n @media (min-width: 640px) {\n .title {\n font-size: 1.25rem\n }\n\n .text {\n font-size: 1rem\n }\n }\n </style>\n</head>\n<body>\n\n<main>\n <div class=\"wrap\">\n <p class=\"title\">Picked</p>\n <p class=\"text\">\n Learn more at\n <a href=\"https://picked.app\">\n https://picked.app\n </a>\n </p>\n <div class=\"preview-form\">\n <input type=\"text\" id=\"url-input\" pattern=\"^(https?://)?.+\" placeholder=\"Enter preview URL\" required\n class=\"preview-input\">\n <div id=\"url-history\" class=\"url-history\"></div>\n <div class=\"features-section\">\n <p class=\"features-label\">Features</p>\n ",
24
27
  "\n </div>\n <div class=\"buttons\">\n <button type=\"button\" class=\"preview-button\" id=\"copy-btn\">Copy</button>\n <button type=\"button\" class=\"preview-button\" id=\"preview-btn\">Preview</button>\n </div>\n <p class=\"text\" id=\"copy-status\" aria-live=\"polite\" style=\"visibility:hidden;\">\n &nbsp;\n </p>\n </div>\n </div>\n\n <script>\n var FEATURES = ",
25
28
  ";\n var STORAGE_KEY_URL = 'picked-launcher-url';\n var STORAGE_KEY_HISTORY = 'picked-launcher-history';\n var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';\n\n function getUrlInput() {\n return document.getElementById('url-input');\n }\n\n // URL history\n function getHistory() {\n try {\n var raw = localStorage.getItem(STORAGE_KEY_HISTORY);\n if (!raw) return [];\n var parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed : [];\n } catch (e) {\n return [];\n }\n }\n\n function saveHistory(history) {\n localStorage.setItem(STORAGE_KEY_HISTORY, JSON.stringify(history));\n }\n\n function addToHistory(url) {\n var history = getHistory().filter(function(h) { return h !== url; });\n history.unshift(url);\n if (history.length > 10) history = history.slice(0, 10);\n saveHistory(history);\n renderHistory();\n }\n\n function removeFromHistory(url) {\n var history = getHistory().filter(function(h) { return h !== url; });\n saveHistory(history);\n renderHistory();\n }\n\n function renderHistory() {\n var container = document.getElementById('url-history');\n if (!container) return;\n var history = getHistory();\n if (history.length === 0) {\n container.innerHTML = '';\n return;\n }\n container.innerHTML = history.map(function(url) {\n return '<div class=\"url-history-item\">' +\n '<button type=\"button\" class=\"url-link\" data-history-url=\"' + escapeAttr(url) + '\">' + escapeHtml(url) + '</button>' +\n '<button type=\"button\" class=\"url-delete\" data-history-delete=\"' + escapeAttr(url) + '\">x</button>' +\n '</div>';\n }).join('');\n }\n\n // Feature selection persistence\n function getSelections() {\n try {\n var raw = localStorage.getItem(STORAGE_KEY_SELECTIONS);\n if (!raw) return {};\n var parsed = JSON.parse(raw);\n return typeof parsed === 'object' && parsed !== null ? parsed : {};\n } catch (e) {\n return {};\n }\n }\n\n function saveSelections() {\n var selections = {};\n FEATURES.forEach(function(f) {\n var checkbox = document.querySelector('input[data-feature-id=\"' + f.id + '\"]');\n var select = document.querySelector('select[data-value-for=\"' + f.id + '\"]');\n if (checkbox && select) {\n selections[f.id] = { checked: checkbox.checked, value: select.value };\n }\n });\n localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));\n }\n\n function restoreSelections() {\n var selections = getSelections();\n FEATURES.forEach(function(f) {\n var saved = selections[f.id];\n if (!saved) return;\n var checkbox = document.querySelector('input[data-feature-id=\"' + f.id + '\"]');\n var select = document.querySelector('select[data-value-for=\"' + f.id + '\"]');\n if (checkbox) checkbox.checked = saved.checked;\n if (select) select.value = saved.value;\n });\n }\n\n function escapeHtml(str) {\n var div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n }\n\n function escapeAttr(str) {\n return str.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n }\n\n function buildTargetUrl(inputValue) {\n var value = inputValue;\n if (!value.startsWith('http://') && !value.startsWith('https://')) {\n value = 'https://' + value;\n }\n var hostname = window.location.hostname;\n var subdomain = hostname.split('.').length > 2 ? hostname.split('.')[0] : '';\n var target = value;\n var sep = target.includes('?') ? '&' : '?';\n if (subdomain) {\n target = target + sep + 'cvly_env=' + encodeURIComponent(subdomain);\n sep = '&';\n }\n FEATURES.forEach(function(f) {\n var checkbox = document.querySelector('input[data-feature-id=\"' + f.id + '\"]');\n var select = document.querySelector('select[data-value-for=\"' + f.id + '\"]');\n if (checkbox && checkbox.checked && select) {\n target = target + sep + 'picked-feature=' + encodeURIComponent(f.id + ':' + select.value);\n sep = '&';\n }\n });\n return target;\n }\n\n function showCopyStatus(message, success) {\n var el = document.getElementById('copy-status');\n if (!el) return;\n el.textContent = message;\n el.style.visibility = 'visible';\n el.style.color = success ? '#2e7d32' : '#b71c1c';\n setTimeout(function() {\n el.style.visibility = 'hidden';\n }, 2000);\n }\n\n // Init\n window.addEventListener('load', function() {\n var input = getUrlInput();\n var savedUrl = localStorage.getItem(STORAGE_KEY_URL);\n if (savedUrl && input) {\n input.value = savedUrl;\n }\n renderHistory();\n restoreSelections();\n });\n\n // Delegate click events\n document.addEventListener('click', function(e) {\n var target = e.target;\n\n // History URL click\n var historyUrl = target.getAttribute('data-history-url');\n if (historyUrl) {\n var input = getUrlInput();\n if (input) input.value = historyUrl;\n return;\n }\n\n // History delete click\n var deleteUrl = target.getAttribute('data-history-delete');\n if (deleteUrl) {\n removeFromHistory(deleteUrl);\n return;\n }\n });\n\n // Feature change persistence\n document.addEventListener('change', function(e) {\n var target = e.target;\n if (target.getAttribute('data-feature-id') || target.getAttribute('data-value-for')) {\n saveSelections();\n }\n });\n\n // Copy button\n document.getElementById('copy-btn').addEventListener('click', function() {\n var input = getUrlInput();\n if (!input || !input.value) return;\n localStorage.setItem(STORAGE_KEY_URL, input.value);\n addToHistory(input.value);\n saveSelections();\n var target = buildTargetUrl(input.value);\n navigator.clipboard.writeText(target).then(function() {\n showCopyStatus('Preview URL copied to clipboard', true);\n });\n });\n\n // Preview button\n document.getElementById('preview-btn').addEventListener('click', function() {\n var input = getUrlInput();\n if (!input || !input.value) return;\n localStorage.setItem(STORAGE_KEY_URL, input.value);\n addToHistory(input.value);\n saveSelections();\n var target = buildTargetUrl(input.value);\n window.location.href = target;\n });\n <\/script>\n</main>\n</body>\n</html>"
@@ -27,48 +30,48 @@ function i(e) {
27
30
  "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <meta name=\"robots\" content=\"noindex, nofollow\">\n <title>Picked</title>\n <style>\n main {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n display: grid;\n align-items: center;\n justify-content: center;\n font-family: monospace;\n color: #4A4A4A\n }\n\n .wrap {\n padding-left: 1.5rem;\n padding-right: 1.5rem;\n max-width: 480px;\n width: 100%;\n }\n\n .title {\n font-size: 1.125rem;\n font-weight: 700;\n margin-bottom: 0;\n }\n\n .text {\n margin-top: .5rem;\n font-size: .875rem\n }\n\n .text a {\n color: #4A4A4A;\n text-decoration: none;\n }\n\n .text a:hover {\n cursor: pointer;\n text-decoration: underline\n }\n\n .preview-form {\n margin-top: 2rem;\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n }\n\n .preview-input {\n padding: 0.5rem;\n border: 1px solid #4A4A4A;\n border-radius: 0;\n font-family: monospace;\n }\n\n .preview-button {\n padding: 0.5rem;\n background: #4A4A4A;\n color: white;\n border: none;\n border-radius: 0;\n cursor: pointer;\n font-family: monospace;\n }\n\n .preview-button:hover {\n opacity: 0.9;\n }\n\n .buttons {\n display: grid;\n gap: 0.5em;\n grid-template-columns: 1fr 1fr;\n }\n\n #copy-status {\n font-size: 1em;\n text-align: right;\n margin-top: 0.5em;\n }\n\n .features-section {\n margin-top: 1.5rem;\n }\n\n .features-label {\n font-weight: 700;\n font-size: .875rem;\n margin-bottom: 0.5rem;\n }\n\n .feature-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n padding: 0.25rem 0;\n }\n\n .feature-row label {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n cursor: pointer;\n min-width: 0;\n flex: 1;\n }\n\n .feature-name {\n font-size: .875rem;\n }\n\n .feature-id {\n font-size: .75rem;\n color: #888;\n }\n\n .feature-row select {\n font-family: monospace;\n font-size: .75rem;\n padding: 0.125rem 0.25rem;\n border: 1px solid #4A4A4A;\n border-radius: 0;\n background: white;\n flex-shrink: 0;\n }\n\n .no-features {\n color: #888;\n font-style: italic;\n }\n\n .url-history {\n margin-top: 0.5rem;\n font-size: .75rem;\n }\n\n .url-history-item {\n display: flex;\n align-items: center;\n gap: 0.25rem;\n padding: 0.125rem 0;\n }\n\n .url-history-item button {\n background: none;\n border: none;\n cursor: pointer;\n font-family: monospace;\n font-size: .75rem;\n color: #888;\n padding: 0;\n }\n\n .url-history-item button.url-link {\n color: #4A4A4A;\n text-decoration: none;\n text-align: left;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n flex: 1;\n min-width: 0;\n }\n\n .url-history-item button.url-link:hover {\n text-decoration: underline;\n }\n\n .url-history-item button.url-delete:hover {\n color: #b71c1c;\n }\n\n @media (min-width: 640px) {\n .title {\n font-size: 1.25rem\n }\n\n .text {\n font-size: 1rem\n }\n }\n </style>\n</head>\n<body>\n\n<main>\n <div class=\"wrap\">\n <p class=\"title\">Picked</p>\n <p class=\"text\">\n Learn more at\n <a href=\"https://picked.app\">\n https://picked.app\n </a>\n </p>\n <div class=\"preview-form\">\n <input type=\"text\" id=\"url-input\" pattern=\"^(https?:\\/\\/)?.+\" placeholder=\"Enter preview URL\" required\n class=\"preview-input\">\n <div id=\"url-history\" class=\"url-history\"></div>\n <div class=\"features-section\">\n <p class=\"features-label\">Features</p>\n ",
28
31
  "\n </div>\n <div class=\"buttons\">\n <button type=\"button\" class=\"preview-button\" id=\"copy-btn\">Copy</button>\n <button type=\"button\" class=\"preview-button\" id=\"preview-btn\">Preview</button>\n </div>\n <p class=\"text\" id=\"copy-status\" aria-live=\"polite\" style=\"visibility:hidden;\">\n &nbsp;\n </p>\n </div>\n </div>\n\n <script>\n var FEATURES = ",
29
32
  ";\n var STORAGE_KEY_URL = 'picked-launcher-url';\n var STORAGE_KEY_HISTORY = 'picked-launcher-history';\n var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';\n\n function getUrlInput() {\n return document.getElementById('url-input');\n }\n\n // URL history\n function getHistory() {\n try {\n var raw = localStorage.getItem(STORAGE_KEY_HISTORY);\n if (!raw) return [];\n var parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed : [];\n } catch (e) {\n return [];\n }\n }\n\n function saveHistory(history) {\n localStorage.setItem(STORAGE_KEY_HISTORY, JSON.stringify(history));\n }\n\n function addToHistory(url) {\n var history = getHistory().filter(function(h) { return h !== url; });\n history.unshift(url);\n if (history.length > 10) history = history.slice(0, 10);\n saveHistory(history);\n renderHistory();\n }\n\n function removeFromHistory(url) {\n var history = getHistory().filter(function(h) { return h !== url; });\n saveHistory(history);\n renderHistory();\n }\n\n function renderHistory() {\n var container = document.getElementById('url-history');\n if (!container) return;\n var history = getHistory();\n if (history.length === 0) {\n container.innerHTML = '';\n return;\n }\n container.innerHTML = history.map(function(url) {\n return '<div class=\"url-history-item\">' +\n '<button type=\"button\" class=\"url-link\" data-history-url=\"' + escapeAttr(url) + '\">' + escapeHtml(url) + '</button>' +\n '<button type=\"button\" class=\"url-delete\" data-history-delete=\"' + escapeAttr(url) + '\">x</button>' +\n '</div>';\n }).join('');\n }\n\n // Feature selection persistence\n function getSelections() {\n try {\n var raw = localStorage.getItem(STORAGE_KEY_SELECTIONS);\n if (!raw) return {};\n var parsed = JSON.parse(raw);\n return typeof parsed === 'object' && parsed !== null ? parsed : {};\n } catch (e) {\n return {};\n }\n }\n\n function saveSelections() {\n var selections = {};\n FEATURES.forEach(function(f) {\n var checkbox = document.querySelector('input[data-feature-id=\"' + f.id + '\"]');\n var select = document.querySelector('select[data-value-for=\"' + f.id + '\"]');\n if (checkbox && select) {\n selections[f.id] = { checked: checkbox.checked, value: select.value };\n }\n });\n localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));\n }\n\n function restoreSelections() {\n var selections = getSelections();\n FEATURES.forEach(function(f) {\n var saved = selections[f.id];\n if (!saved) return;\n var checkbox = document.querySelector('input[data-feature-id=\"' + f.id + '\"]');\n var select = document.querySelector('select[data-value-for=\"' + f.id + '\"]');\n if (checkbox) checkbox.checked = saved.checked;\n if (select) select.value = saved.value;\n });\n }\n\n function escapeHtml(str) {\n var div = document.createElement('div');\n div.textContent = str;\n return div.innerHTML;\n }\n\n function escapeAttr(str) {\n return str.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n }\n\n function buildTargetUrl(inputValue) {\n var value = inputValue;\n if (!value.startsWith('http://') && !value.startsWith('https://')) {\n value = 'https://' + value;\n }\n var hostname = window.location.hostname;\n var subdomain = hostname.split('.').length > 2 ? hostname.split('.')[0] : '';\n var target = value;\n var sep = target.includes('?') ? '&' : '?';\n if (subdomain) {\n target = target + sep + 'cvly_env=' + encodeURIComponent(subdomain);\n sep = '&';\n }\n FEATURES.forEach(function(f) {\n var checkbox = document.querySelector('input[data-feature-id=\"' + f.id + '\"]');\n var select = document.querySelector('select[data-value-for=\"' + f.id + '\"]');\n if (checkbox && checkbox.checked && select) {\n target = target + sep + 'picked-feature=' + encodeURIComponent(f.id + ':' + select.value);\n sep = '&';\n }\n });\n return target;\n }\n\n function showCopyStatus(message, success) {\n var el = document.getElementById('copy-status');\n if (!el) return;\n el.textContent = message;\n el.style.visibility = 'visible';\n el.style.color = success ? '#2e7d32' : '#b71c1c';\n setTimeout(function() {\n el.style.visibility = 'hidden';\n }, 2000);\n }\n\n // Init\n window.addEventListener('load', function() {\n var input = getUrlInput();\n var savedUrl = localStorage.getItem(STORAGE_KEY_URL);\n if (savedUrl && input) {\n input.value = savedUrl;\n }\n renderHistory();\n restoreSelections();\n });\n\n // Delegate click events\n document.addEventListener('click', function(e) {\n var target = e.target;\n\n // History URL click\n var historyUrl = target.getAttribute('data-history-url');\n if (historyUrl) {\n var input = getUrlInput();\n if (input) input.value = historyUrl;\n return;\n }\n\n // History delete click\n var deleteUrl = target.getAttribute('data-history-delete');\n if (deleteUrl) {\n removeFromHistory(deleteUrl);\n return;\n }\n });\n\n // Feature change persistence\n document.addEventListener('change', function(e) {\n var target = e.target;\n if (target.getAttribute('data-feature-id') || target.getAttribute('data-value-for')) {\n saveSelections();\n }\n });\n\n // Copy button\n document.getElementById('copy-btn').addEventListener('click', function() {\n var input = getUrlInput();\n if (!input || !input.value) return;\n localStorage.setItem(STORAGE_KEY_URL, input.value);\n addToHistory(input.value);\n saveSelections();\n var target = buildTargetUrl(input.value);\n navigator.clipboard.writeText(target).then(function() {\n showCopyStatus('Preview URL copied to clipboard', true);\n });\n });\n\n // Preview button\n document.getElementById('preview-btn').addEventListener('click', function() {\n var input = getUrlInput();\n if (!input || !input.value) return;\n localStorage.setItem(STORAGE_KEY_URL, input.value);\n addToHistory(input.value);\n saveSelections();\n var target = buildTargetUrl(input.value);\n window.location.href = target;\n });\n <\/script>\n</main>\n</body>\n</html>"
30
- ]), i, t);
33
+ ]), n, t);
31
34
  }
32
- function a(e) {
35
+ function f(e) {
33
36
  return e.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
34
37
  }
35
- function o(e) {
38
+ function p(e) {
36
39
  return e.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
37
40
  }
38
41
  //#endregion
39
42
  //#region src/log.ts
40
- var s = "picked", c = "\x1B[0m";
41
- function l() {
43
+ var m = "picked", h = "\x1B[0m";
44
+ function ee() {
42
45
  let e = process.env.NO_COLOR;
43
46
  return e === "1" || e === "true";
44
47
  }
45
- function u(e) {
46
- return (t) => l() ? t : `${e}${t}${c}`;
48
+ function g(e) {
49
+ return (t) => ee() ? t : `${e}${t}${h}`;
47
50
  }
48
- var d = [
51
+ var _ = [
49
52
  "debug",
50
53
  "info",
51
54
  "warn",
52
55
  "error",
53
56
  "silent"
54
- ], f = {
57
+ ], v = {
55
58
  debug: {
56
- color: u("\x1B[2m"),
59
+ color: g("\x1B[2m"),
57
60
  log: console.debug,
58
61
  enabled: !1
59
62
  },
60
63
  info: {
61
- color: u("\x1B[36m"),
64
+ color: g("\x1B[36m"),
62
65
  log: console.log,
63
66
  enabled: !0
64
67
  },
65
68
  warn: {
66
- color: u("\x1B[33m"),
69
+ color: g("\x1B[33m"),
67
70
  log: console.warn,
68
71
  enabled: !0
69
72
  },
70
73
  error: {
71
- color: u("\x1B[31m"),
74
+ color: g("\x1B[31m"),
72
75
  log: console.error,
73
76
  enabled: !0
74
77
  },
@@ -77,52 +80,52 @@ var d = [
77
80
  enabled: !1
78
81
  }
79
82
  };
80
- function p(e, t) {
81
- return `${(/* @__PURE__ */ new Date()).toLocaleTimeString()} [${t ? `${s}:${t}` : s}] ${e}`;
83
+ function te(e, t) {
84
+ return `${(/* @__PURE__ */ new Date()).toLocaleTimeString()} [${t ? `${m}:${t}` : m}] ${e}`;
82
85
  }
83
- function m(e, t, n, r) {
86
+ function y(e, t, n, r) {
84
87
  if (!e.enabled) return;
85
- let i = p(t, r);
88
+ let i = te(t, r);
86
89
  e.log(e.color ? e.color(i) : i), n !== void 0 && e.log(n);
87
90
  }
88
- function h(e) {
89
- let t = f[e], n = /* @__PURE__ */ new Set();
91
+ function b(e) {
92
+ let t = v[e], n = /* @__PURE__ */ new Set();
90
93
  return Object.assign((e, n, r) => {
91
- m(t, e, n, r);
94
+ y(t, e, n, r);
92
95
  }, { once(e, r, i) {
93
- !t.enabled || n.has(e) || (n.add(e), m(t, e, r, i));
96
+ !t.enabled || n.has(e) || (n.add(e), y(t, e, r, i));
94
97
  } });
95
98
  }
96
- function g(e) {
97
- let t = d.indexOf(e);
99
+ function x(e) {
100
+ let t = _.indexOf(e);
98
101
  if (t === -1) {
99
- m(f.error, `invalid log level: ${e}`);
102
+ y(v.error, `invalid log level: ${e}`);
100
103
  return;
101
104
  }
102
- for (let [e, n] of d.entries()) f[n].enabled = e >= t;
105
+ for (let [e, n] of _.entries()) v[n].enabled = e >= t;
103
106
  }
104
- var _ = u("\x1B[34m"), v = u("\x1B[36m");
105
- function y() {
107
+ var S = g("\x1B[34m"), C = g("\x1B[36m");
108
+ function w() {
106
109
  let e = [
107
- ` ${_("_")} ${v("_")} _ _ _`,
108
- `${_("(_)")} ${v("(_)")} _ __(_)__| |_____ __| |`,
109
- ` ${_("_")} ${_("_")} | '_ \\ / _| / / -_) _\` |`,
110
- `${_("(_)")} ${_("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,
110
+ ` ${S("_")} ${C("_")} _ _ _`,
111
+ `${S("(_)")} ${C("(_)")} _ __(_)__| |_____ __| |`,
112
+ ` ${S("_")} ${S("_")} | '_ \\ / _| / / -_) _\` |`,
113
+ `${S("(_)")} ${S("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,
111
114
  " |_|\n "
112
115
  ];
113
116
  console.log(e.join("\n"));
114
117
  }
115
- var b = {
116
- banner: y,
117
- debug: h("debug"),
118
- info: h("info"),
119
- warn: h("warn"),
120
- error: h("error"),
121
- setLevel: g
118
+ var T = {
119
+ banner: w,
120
+ debug: b("debug"),
121
+ info: b("info"),
122
+ warn: b("warn"),
123
+ error: b("error"),
124
+ setLevel: x
122
125
  };
123
126
  //#endregion
124
127
  //#region src/middleware.ts
125
- function x(e) {
128
+ function ne(e) {
126
129
  return (t, n, r) => {
127
130
  if (t.method !== "GET") {
128
131
  r();
@@ -138,14 +141,185 @@ function x(e) {
138
141
  };
139
142
  }
140
143
  //#endregion
141
- //#region src/index.ts
142
- var S = 5;
143
- function C(e) {
144
+ //#region src/gitignore.ts
145
+ var E = ".picked/";
146
+ async function D(t, n) {
147
+ if (n) return;
148
+ let r = c(t, ".gitignore");
149
+ if (!e(r)) {
150
+ await s(r, `${E}
151
+ `);
152
+ return;
153
+ }
154
+ let a = await o(r, "utf8");
155
+ O(a) || await i(r, `${a.length > 0 && !a.endsWith("\n") ? "\n" : ""}${E}
156
+ `);
157
+ }
158
+ function O(e) {
159
+ return e.split(/\r?\n/).map((e) => e.trim()).some((e) => e === E || e === ".picked");
160
+ }
161
+ //#endregion
162
+ //#region src/util.ts
163
+ function k(e) {
144
164
  return Array.isArray(e) ? e : [];
145
165
  }
146
- function w(e, t, n) {
166
+ //#endregion
167
+ //#region src/prefetch.ts
168
+ var re = 1;
169
+ function A(e) {
170
+ let t = c(e, ".picked");
171
+ return {
172
+ pickedDir: t,
173
+ manifestPath: c(t, "manifest.json"),
174
+ projectConfigPath: c(t, "project-config.json"),
175
+ experiencesDir: c(t, "experiences")
176
+ };
177
+ }
178
+ async function ie(t) {
179
+ if (!e(t)) return null;
180
+ try {
181
+ let e = await o(t, "utf8"), n = JSON.parse(e);
182
+ return ae(n) ? n : null;
183
+ } catch {
184
+ return null;
185
+ }
186
+ }
187
+ function ae(e) {
188
+ return !(typeof e != "object" || !e || !("version" in e) || typeof e.version != "number" || !("projectVersionId" in e) || typeof e.projectVersionId != "string" || !("workspaceId" in e) || typeof e.workspaceId != "string" || !("experiences" in e) || !Array.isArray(e.experiences));
189
+ }
190
+ function j(e) {
191
+ let t = /* @__PURE__ */ new Set();
192
+ for (let n of k(e.steps)) n.layoutContentId && t.add(n.id);
193
+ if (t.size === 0) return [];
194
+ let n = [];
195
+ for (let r of k(e.experiences)) k(r.nodes).some((e) => e.type === "step" && t.has(e.stepId)) && n.push(r.id);
196
+ return n;
197
+ }
198
+ async function M(e) {
199
+ let { apiUrl: t, projectId: n, projectRoot: r, headers: i, reuseWhenUnchanged: o = !0 } = e, l = A(r), u = await P(t, n, i), d = j(u);
200
+ if (o) {
201
+ let e = await ie(l.manifestPath);
202
+ if (e && e.projectVersionId === u.versionId && e.workspaceId === u.workspaceId) return {
203
+ config: u,
204
+ manifest: e,
205
+ experienceContentPaths: N(l, d)
206
+ };
207
+ }
208
+ await a(l.experiencesDir, { recursive: !0 }), await s(l.projectConfigPath, JSON.stringify(u, null, 2));
209
+ let f = (/* @__PURE__ */ new Date()).toISOString(), p = [];
210
+ for (let e of d) {
211
+ let r = await F(t, n, e, i);
212
+ await s(c(l.experiencesDir, `${e}.json`), JSON.stringify(r, null, 2)), p.push({
213
+ id: e,
214
+ fetchedAt: f
215
+ });
216
+ }
217
+ let m = {
218
+ version: re,
219
+ fetchedAt: f,
220
+ projectVersionId: u.versionId,
221
+ workspaceId: u.workspaceId,
222
+ projectId: u.id,
223
+ experiences: p
224
+ };
225
+ return await s(l.manifestPath, JSON.stringify(m, null, 2)), {
226
+ config: u,
227
+ manifest: m,
228
+ experienceContentPaths: N(l, d)
229
+ };
230
+ }
231
+ function N(e, t) {
232
+ let n = {};
233
+ for (let r of t) n[r] = c(e.experiencesDir, `${r}.json`);
234
+ return n;
235
+ }
236
+ async function P(e, t, n) {
237
+ let i;
238
+ try {
239
+ i = await r(e, t, { headers: n });
240
+ } catch (n) {
241
+ throw Error(`[picked] Build-time fetch of project config failed for "${t}" at ${e}: ${I(n)}`);
242
+ }
243
+ if (!i) throw Error(`[picked] Build-time fetch of project config returned no usable response for "${t}" at ${e}. Confirm the API is reachable and the project ID is correct.`);
244
+ return i;
245
+ }
246
+ async function F(e, t, r, i) {
247
+ let a;
248
+ try {
249
+ a = await n(e, t, r, { headers: i });
250
+ } catch (t) {
251
+ throw Error(`[picked] Build-time fetch of content for experience "${r}" failed at ${e}: ${I(t)}`);
252
+ }
253
+ if (!a) throw Error(`[picked] Build-time fetch of content for experience "${r}" returned no usable response. Confirm the experience id exists and the API is reachable.`);
254
+ return a;
255
+ }
256
+ function I(e) {
257
+ if (e instanceof Error) return e.message;
258
+ if (typeof e == "string") return e;
259
+ try {
260
+ return JSON.stringify(e);
261
+ } catch {
262
+ return "unknown error";
263
+ }
264
+ }
265
+ //#endregion
266
+ //#region src/virtual-module/build.ts
267
+ function L(e) {
268
+ let { projectConfigPath: t, experienceContentPaths: n, manifestMetadata: r } = e, i = (e) => JSON.stringify(e), a = Object.entries(n).map(([e, t]) => ` ${JSON.stringify(e)}: () => import(${i(t)}).then((m) => m.default ?? m),`).join("\n");
269
+ return `import projectConfigJson from ${i(t)}
270
+
271
+ const experienceImporters = {
272
+ ${a}
273
+ }
274
+
275
+ export const projectConfig = projectConfigJson
276
+
277
+ export async function experienceContent(experience, _options) {
278
+ const id = typeof experience === 'string' ? experience : experience?.id
279
+ if (!id) return null
280
+ const importer = experienceImporters[id]
281
+ if (!importer) return null
282
+ try {
283
+ return await importer()
284
+ } catch {
285
+ return null
286
+ }
287
+ }
288
+
289
+ export const manifestMetadata = ${JSON.stringify(r)}
290
+ `;
291
+ }
292
+ //#endregion
293
+ //#region src/virtual-module/dev.ts
294
+ function R(e) {
295
+ let { apiUrl: t, projectId: n } = e;
296
+ return `import { fetchProject, fetchExperienceContent } from '@picked/client/plugins/dynamic-experiences'
297
+
298
+ const apiUrl = ${JSON.stringify(t)}
299
+ const projectId = ${JSON.stringify(n)}
300
+
301
+ export const projectConfig = await fetchProject(apiUrl, projectId)
302
+
303
+ export async function experienceContent(experience, options) {
304
+ const id = typeof experience === 'string' ? experience : experience?.id
305
+ if (!id) return null
306
+ return await fetchExperienceContent(apiUrl, projectId, id, options)
307
+ }
308
+
309
+ export const manifestMetadata = {
310
+ mode: 'dev',
311
+ fetchedAt: null,
312
+ projectVersionId: projectConfig?.versionId ?? null,
313
+ workspaceId: projectConfig?.workspaceId ?? null,
314
+ }
315
+ `;
316
+ }
317
+ //#endregion
318
+ //#region src/index.ts
319
+ var z = 5;
320
+ function B(e, t, n) {
147
321
  if (t.length === 0) return;
148
- if (t.length > S) {
322
+ if (t.length > z) {
149
323
  console.log(`\n ${e}: ${t.length.toString()} loaded\n`);
150
324
  return;
151
325
  }
@@ -160,10 +334,10 @@ function w(e, t, n) {
160
334
  ""
161
335
  ].join("\n"));
162
336
  }
163
- function T(e, t) {
337
+ function V(e, t) {
164
338
  t.length !== 0 && console.log(`\n ${e}: ${t.length.toString()} loaded\n`);
165
339
  }
166
- var E = [
340
+ var H = [
167
341
  {
168
342
  header: "Name",
169
343
  value: (e) => e.name
@@ -184,7 +358,7 @@ var E = [
184
358
  header: "Ver",
185
359
  value: (e) => `v${e.version.toString()}`
186
360
  }
187
- ], D = [
361
+ ], U = [
188
362
  {
189
363
  header: "Name",
190
364
  value: (e) => e.name
@@ -205,7 +379,7 @@ var E = [
205
379
  header: "Targets",
206
380
  value: (e) => e.targets.length.toString()
207
381
  }
208
- ], O = [
382
+ ], W = [
209
383
  {
210
384
  header: "Name",
211
385
  value: (e) => e.name
@@ -218,7 +392,7 @@ var E = [
218
392
  header: "Fields",
219
393
  value: (e) => (e.fieldIds?.length ?? 0).toString()
220
394
  }
221
- ], k = [
395
+ ], G = [
222
396
  {
223
397
  header: "Name",
224
398
  value: (e) => e.name
@@ -235,14 +409,14 @@ var E = [
235
409
  header: "Required",
236
410
  value: (e) => e.required ? "yes" : "no"
237
411
  }
238
- ], A = [{
412
+ ], K = [{
239
413
  header: "Name",
240
414
  value: (e) => e.name
241
415
  }, {
242
416
  header: "Key",
243
417
  value: (e) => e.key
244
418
  }];
245
- function j(e) {
419
+ function q(e) {
246
420
  try {
247
421
  let t = new URL(e).hostname;
248
422
  return t === "localhost" || t === "127.0.0.1" || t === "::1";
@@ -250,66 +424,100 @@ function j(e) {
250
424
  return !1;
251
425
  }
252
426
  }
253
- function M(e) {
427
+ function oe(e) {
254
428
  return new Promise((t) => {
255
429
  setTimeout(t, e);
256
430
  });
257
431
  }
258
- async function N(e, n, r) {
259
- let i = await t(e, n, { headers: r });
260
- if (i || !j(e)) return i;
261
- for (let i = 1; i <= L; i++) {
262
- b.info(`local API not ready, retrying in ${(R / 1e3).toString()}s (${i.toString()}/${L.toString()})`), await M(R);
263
- let a = await t(e, n, { headers: r });
432
+ async function se(e, t, n) {
433
+ let i = await r(e, t, { headers: n });
434
+ if (i || !q(e)) return i;
435
+ for (let i = 1; i <= Z; i++) {
436
+ T.info(`local API not ready, retrying in ${(Q / 1e3).toString()}s (${i.toString()}/${Z.toString()})`), await oe(Q);
437
+ let a = await r(e, t, { headers: n });
264
438
  if (a) return a;
265
439
  }
266
440
  return null;
267
441
  }
268
- function P() {
269
- return "0.0.1-dev.1778467244607";
442
+ function ce() {
443
+ return "0.0.1-dev.1778468342672";
270
444
  }
271
- var F = "https://api.picked.app", I = "__PICKED_PROJECT_CONFIG__", L = 5, R = 2e3;
272
- function z(t) {
273
- let n = t.apiUrl ?? F, r = [], a, o = !1;
445
+ var J = "https://api.picked.app", Y = "virtual:picked/data", X = `\0${Y}`, Z = 5, Q = 2e3;
446
+ function le(n) {
447
+ let r = n.apiUrl ?? J, i = [], a = process.cwd(), o = "serve", s, c = !1;
274
448
  return {
275
449
  name: "picked",
276
- config: async () => {
277
- if (o) return a;
278
- o = !0, b.banner(), b.info(`fetching project config for "${t.projectId}"`), n !== F && b.warn(`using custom API URL: ${n}`);
279
- let i = e("vite-plugin", P()), s = performance.now(), c = await N(n, t.projectId, i), l = (performance.now() - s).toFixed(0);
280
- if (!c) return b.warn(`failed to fetch project config for "${t.projectId}" (${l}ms)`), a = void 0, a;
281
- r = C(c.features);
282
- let u = C(c.experiences), d = C(c.steps), f = C(c.fields), p = C(c.conditions), m = C(c.actions), h = JSON.stringify(c).length, g = [
283
- `${r.length.toString()} features`,
284
- `${u.length.toString()} experiences`,
285
- `${d.length.toString()} steps`,
286
- `${f.length.toString()} fields`,
287
- `${p.length.toString()} conditions`,
288
- `${m.length.toString()} actions`
289
- ].join(", ");
290
- return b.info(`fetched config for "${t.projectId}" in ${l}ms (${g})`), w("Features", r, E), w("Experiences", u, D), w("Steps", d, O), w("Fields", f, k), w("Conditions", p, A), T("Actions", m), b.debug(`config size: ${h.toString()} bytes`), a = { define: { [I]: JSON.stringify(c) } }, a;
450
+ config: async (l, u) => {
451
+ o = u.command, a = process.cwd(), T.banner(), r !== J && T.warn(`using custom API URL: ${r}`);
452
+ let d = t("vite-plugin", ce());
453
+ if (u.command === "build") {
454
+ if (c) return;
455
+ c = !0, T.info(`prefetching project config + content for "${n.projectId}"`);
456
+ let t = A(a), o = e(t.pickedDir), l = performance.now(), u = await M({
457
+ apiUrl: r,
458
+ projectId: n.projectId,
459
+ projectRoot: a,
460
+ headers: d
461
+ }), f = (performance.now() - l).toFixed(0);
462
+ await D(a, o);
463
+ let p = u.config;
464
+ i = k(p.features), $(p, f), s = L({
465
+ projectConfigPath: t.projectConfigPath,
466
+ experienceContentPaths: u.experienceContentPaths,
467
+ manifestMetadata: {
468
+ mode: "build",
469
+ fetchedAt: u.manifest.fetchedAt,
470
+ projectVersionId: u.manifest.projectVersionId,
471
+ workspaceId: u.manifest.workspaceId
472
+ }
473
+ });
474
+ } else {
475
+ T.info(`fetching project config for "${n.projectId}" (dev)`);
476
+ let e = performance.now(), t = await se(r, n.projectId, d), a = (performance.now() - e).toFixed(0);
477
+ t ? (i = k(t.features), $(t, a)) : T.warn(`failed to fetch project config for "${n.projectId}" (${a}ms)`);
478
+ }
479
+ },
480
+ resolveId(e) {
481
+ if (e === Y) return X;
482
+ },
483
+ load(e) {
484
+ if (e === X) return o === "build" ? s : R({
485
+ apiUrl: r,
486
+ projectId: n.projectId
487
+ });
291
488
  },
292
489
  configureServer(e) {
293
- if (t.disableLauncher) return;
294
- e.middlewares.use(x(() => i(r)));
295
- let n = e.printUrls.bind(e);
490
+ if (n.disableLauncher) return;
491
+ e.middlewares.use(ne(() => d(i)));
492
+ let t = e.printUrls.bind(e);
296
493
  e.printUrls = () => {
297
- let t = e.resolvedUrls?.local[0];
298
- if (t) {
299
- let e = t.replace(/:(?<port>\d+)\//, (e, t) => `:\x1b[1m${t}\x1b[22m/`);
494
+ let n = e.resolvedUrls?.local[0];
495
+ if (n) {
496
+ let e = n.replace(/:(?<port>\d+)\//, (e, t) => `:\x1b[1m${t}\x1b[22m/`);
300
497
  console.log(` \x1b[32m➜\x1b[0m \x1b[1mPicked\x1b[22m: \x1b[36m${e}\x1b[0m`);
301
498
  }
302
- n();
499
+ t();
303
500
  };
304
501
  },
305
502
  generateBundle() {
306
- t.disableLauncher || this.emitFile({
503
+ n.disableLauncher || this.emitFile({
307
504
  type: "asset",
308
505
  fileName: "index.html",
309
- source: i(r)
506
+ source: d(i)
310
507
  });
311
508
  }
312
509
  };
313
510
  }
511
+ function $(e, t) {
512
+ let n = k(e.features), r = k(e.experiences), i = k(e.steps), a = k(e.fields), o = k(e.conditions), s = k(e.actions), c = JSON.stringify(e).length, l = [
513
+ `${n.length.toString()} features`,
514
+ `${r.length.toString()} experiences`,
515
+ `${i.length.toString()} steps`,
516
+ `${a.length.toString()} fields`,
517
+ `${o.length.toString()} conditions`,
518
+ `${s.length.toString()} actions`
519
+ ].join(", ");
520
+ T.info(`fetched config in ${t}ms (${l})`), B("Features", n, H), B("Experiences", r, U), B("Steps", i, W), B("Fields", a, G), B("Conditions", o, K), V("Actions", s), T.debug(`config size: ${c.toString()} bytes`);
521
+ }
314
522
  //#endregion
315
- export { z as picked };
523
+ export { le as picked };
@@ -0,0 +1,16 @@
1
+ /**
2
+ * If `<root>/.picked/` did not exist before this build, append `.picked/` to the
3
+ * project's `.gitignore` (creating the file if absent and not already containing the
4
+ * line). On subsequent runs, leaves the gitignore alone.
5
+ *
6
+ * @param {string} projectRoot - Absolute path to the Vite project root.
7
+ * @param {boolean} pickedDirAlreadyExists - Whether `<root>/.picked/` existed before the prefetch
8
+ * ran. Pass the result of `existsSync(pickedDir)` evaluated BEFORE any writes.
9
+ * @returns {Promise<void>} Resolves once the gitignore has been updated (or skipped).
10
+ * @example
11
+ * ```typescript
12
+ * await appendGitignoreOnFirstRun(process.cwd(), existsSync(pickedDir))
13
+ * ```
14
+ */
15
+ export declare function appendGitignoreOnFirstRun(projectRoot: string, pickedDirAlreadyExists: boolean): Promise<void>;
16
+ //# sourceMappingURL=gitignore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gitignore.d.ts","sourceRoot":"","sources":["../../src/gitignore.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;GAaG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,sBAAsB,EAAE,OAAO,GAC9B,OAAO,CAAC,IAAI,CAAC,CAqBf"}
@@ -8,11 +8,15 @@ export interface PickedPluginOptions {
8
8
  disableLauncher?: boolean;
9
9
  }
10
10
  /**
11
- * Vite plugin that fetches Picked project config at build time
12
- * and injects it via `define`, eliminating the runtime API request.
11
+ * Vite plugin that fetches Picked project config + per-experience CMS content at build time
12
+ * and exposes both via the `virtual:picked/data` virtual module.
13
13
  *
14
- * When a preview token is present at runtime, the SDK will still
15
- * fetch fresh config from the API, ignoring the build-time value.
14
+ * Build mode (`vite build`) prefetches every CMS-using experience, writes JSON artefacts
15
+ * to `<root>/.picked/`, and synthesises a virtual module that statically imports the
16
+ * project config (so it's bundled) and lazily imports each experience's content on demand.
17
+ *
18
+ * Dev mode (`vite serve`) writes nothing to disk; the synthesised virtual module performs
19
+ * runtime API fetches via top-level `await` for project config and per-call for content.
16
20
  *
17
21
  * @param {PickedPluginOptions} options - Plugin configuration.
18
22
  * @returns {Plugin} A Vite plugin instance.
@@ -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;AAmNlC,MAAM,WAAW,mBAAmB;IAClC,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAwG3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AA2MlC,MAAM,WAAW,mBAAmB;IAClC,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAA;IACjB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,qFAAqF;IACrF,eAAe,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAmI3D"}
@@ -0,0 +1,72 @@
1
+ import { ProjectConfig } from '@picked/client/plugins/dynamic-experiences';
2
+ interface ManifestExperienceEntry {
3
+ id: string;
4
+ fetchedAt: string;
5
+ }
6
+ interface PickedManifest {
7
+ version: number;
8
+ fetchedAt: string;
9
+ projectVersionId: string;
10
+ workspaceId: string;
11
+ projectId: string;
12
+ experiences: ManifestExperienceEntry[];
13
+ }
14
+ interface PrefetchPaths {
15
+ /** Absolute path to `<root>/.picked/`. */
16
+ pickedDir: string;
17
+ /** Absolute path to `<root>/.picked/manifest.json`. */
18
+ manifestPath: string;
19
+ /** Absolute path to `<root>/.picked/project-config.json`. */
20
+ projectConfigPath: string;
21
+ /** Absolute path to `<root>/.picked/experiences/`. */
22
+ experiencesDir: string;
23
+ }
24
+ interface PrefetchResult {
25
+ config: ProjectConfig;
26
+ manifest: PickedManifest;
27
+ /** Map of experience id → absolute path to its `<id>.json`. */
28
+ experienceContentPaths: Record<string, string>;
29
+ }
30
+ /**
31
+ * Resolves the artefact paths under `<root>/.picked/`.
32
+ *
33
+ * @param {string} projectRoot - Vite project root (typically `process.cwd()`).
34
+ * @returns {PrefetchPaths} Absolute paths under `.picked/`.
35
+ * @example
36
+ * ```typescript
37
+ * const paths = resolvePrefetchPaths(process.cwd())
38
+ * ```
39
+ */
40
+ export declare function resolvePrefetchPaths(projectRoot: string): PrefetchPaths;
41
+ interface RunPrefetchOptions {
42
+ apiUrl: string;
43
+ projectId: string;
44
+ projectRoot: string;
45
+ /** HTTP headers to forward with every fetch (e.g. `Picked-Client`, `Picked-Version`). */
46
+ headers: Record<string, string>;
47
+ /** When the existing manifest matches the API's versionId+workspaceId, skip per-experience fetches. */
48
+ reuseWhenUnchanged?: boolean;
49
+ }
50
+ /**
51
+ * Runs the full build-mode prefetch: fetches project config, walks CMS-using experiences,
52
+ * fetches each one's content, writes all artefacts under `<root>/.picked/`, and replaces
53
+ * `manifest.json` in full so stale entries cannot accumulate.
54
+ *
55
+ * Hard-fails on any API failure (non-2xx response or network error). Customers shipping
56
+ * with the Vite plugin must ship from a known-good snapshot or not at all.
57
+ *
58
+ * When `reuseWhenUnchanged` is true and the existing manifest's `versionId` + `workspaceId`
59
+ * match the freshly-fetched project config, per-experience fetches are skipped and the
60
+ * existing JSON files are left in place. The manifest is left unchanged.
61
+ *
62
+ * @param {RunPrefetchOptions} options - Prefetch configuration.
63
+ * @returns {Promise<PrefetchResult>} The fetched config, manifest, and content-path map.
64
+ * @throws {Error} When any API request fails or returns malformed data.
65
+ * @example
66
+ * ```typescript
67
+ * const result = await runPrefetch({ apiUrl, projectId, projectRoot: cwd, headers })
68
+ * ```
69
+ */
70
+ export declare function runPrefetch(options: RunPrefetchOptions): Promise<PrefetchResult>;
71
+ export {};
72
+ //# sourceMappingURL=prefetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefetch.d.ts","sourceRoot":"","sources":["../../src/prefetch.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,aAAa,EACd,MAAM,4CAA4C,CAAA;AAMnD,UAAU,uBAAuB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,cAAc;IACtB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,MAAM,CAAA;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,uBAAuB,EAAE,CAAA;CACvC;AAED,UAAU,aAAa;IACrB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAA;IACjB,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,iBAAiB,EAAE,MAAM,CAAA;IACzB,sDAAsD;IACtD,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,UAAU,cAAc;IACtB,MAAM,EAAE,aAAa,CAAA;IACrB,QAAQ,EAAE,cAAc,CAAA;IACxB,+DAA+D;IAC/D,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC/C;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,CAQvE;AAsFD,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,yFAAyF;IACzF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,uGAAuG;IACvG,kBAAkB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAiDtF"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @file Shared utilities for the Picked Vite plugin. Currently exposes a single
3
+ * defensive helper for handling API entity arrays that may be omitted at runtime
4
+ * despite being typed as required.
5
+ */
6
+ /**
7
+ * Safely coerce a value to an array, returning an empty array for nullish inputs.
8
+ * Needed because the API response may omit entity arrays at runtime even though
9
+ * the TypeScript type marks them as required.
10
+ *
11
+ * @template T - The element type of the array.
12
+ * @param {ReadonlyArray<T> | null | undefined} value - The value to coerce.
13
+ * @returns {ReadonlyArray<T>} The original array, or an empty array if the input is nullish.
14
+ * @example
15
+ * toArray(undefined) // []
16
+ */
17
+ export declare function toArray<T>(value: ReadonlyArray<T> | null | undefined): ReadonlyArray<T>;
18
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,CAEvF"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @file Build-mode synthesis for `virtual:picked/data`.
3
+ *
4
+ * Generates a JavaScript module that statically imports the prefetched project config
5
+ * (so it's bundled into the customer's main chunk) and lazily imports each experience's
6
+ * content JSON on demand.
7
+ */
8
+ interface BuildVirtualModuleOptions {
9
+ /** Absolute path to `<root>/.picked/project-config.json`. */
10
+ projectConfigPath: string;
11
+ /** Map of experience id → absolute path to its content JSON file. */
12
+ experienceContentPaths: Record<string, string>;
13
+ /** Manifest metadata that the synthesised module re-exports as `manifestMetadata`. */
14
+ manifestMetadata: {
15
+ mode: 'build';
16
+ fetchedAt: string | null;
17
+ projectVersionId: string | null;
18
+ workspaceId: string | null;
19
+ };
20
+ }
21
+ /**
22
+ * Synthesises the source code for the build-mode `virtual:picked/data` module.
23
+ *
24
+ * @param {BuildVirtualModuleOptions} options - Build-mode synthesis inputs.
25
+ * @returns {string} JavaScript source as a string for Vite's `load` hook.
26
+ * @example
27
+ * ```typescript
28
+ * const src = buildVirtualModuleSource({ projectConfigPath, experienceContentPaths, manifestMetadata })
29
+ * ```
30
+ */
31
+ export declare function buildVirtualModuleSource(options: BuildVirtualModuleOptions): string;
32
+ export {};
33
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../../src/virtual-module/build.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,UAAU,yBAAyB;IACjC,6DAA6D;IAC7D,iBAAiB,EAAE,MAAM,CAAA;IACzB,qEAAqE;IACrE,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9C,sFAAsF;IACtF,gBAAgB,EAAE;QAChB,IAAI,EAAE,OAAO,CAAA;QACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;QACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;QAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAC3B,CAAA;CACF;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,MAAM,CAiCnF"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file Dev-mode synthesis for `virtual:picked/data`.
3
+ *
4
+ * Generates a JavaScript module that fetches the project config at module-evaluation time
5
+ * via top-level `await`, and resolves per-experience content with per-call API requests.
6
+ * No filesystem writes; matches the customer's runtime API behaviour.
7
+ */
8
+ interface DevVirtualModuleOptions {
9
+ /** Absolute API base URL (e.g. `https://api.picked.app`). */
10
+ apiUrl: string;
11
+ /** Picked project ID to fetch. */
12
+ projectId: string;
13
+ }
14
+ /**
15
+ * Synthesises the source code for the dev-mode `virtual:picked/data` module.
16
+ *
17
+ * @param {DevVirtualModuleOptions} options - Dev-mode synthesis inputs.
18
+ * @returns {string} JavaScript source as a string for Vite's `load` hook.
19
+ * @example
20
+ * ```typescript
21
+ * const src = devVirtualModuleSource({ apiUrl: 'https://api.picked.app', projectId: 'p_1' })
22
+ * ```
23
+ */
24
+ export declare function devVirtualModuleSource(options: DevVirtualModuleOptions): string;
25
+ export {};
26
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../../src/virtual-module/dev.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,UAAU,uBAAuB;IAC/B,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAA;IACd,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAuB/E"}
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.1778467244607",
4
+ "version": "0.0.1-dev.1778468342672",
5
5
  "dependencies": {
6
- "@picked/client": "0.0.1-dev.1778467244607"
6
+ "@picked/client": "0.0.1-dev.1778468342672"
7
7
  },
8
8
  "devDependencies": {
9
9
  "@repo/eslint-config": "workspace:*",