@picked/vite-plugin-picked 0.0.62-next.12 → 0.0.62-next.2

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(`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=>`
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=>`
2
2
  <div class="feature-row">
3
3
  <label>
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>
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>
7
7
  </label>
8
- <select data-value-for="${c(e.id)}">
8
+ <select data-value-for="${a(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(a||=i([`<!DOCTYPE html>
12
+ </div>`).join(``):`<p class="text no-features">No features configured for this project.</p>`;return String.raw(n||=t([`<!DOCTYPE html>
13
13
  <html lang="en">
14
14
  <head>
15
15
  <meta charset="UTF-8">
@@ -855,52 +855,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require
855
855
  <\/script>
856
856
  </main>
857
857
  </body>
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 h(e,t){return`${new Date().toLocaleTimeString()} [${t?`${l}:${t}`:l}] ${e}`}function g(e,t,n,r){if(!e.enabled)return;let i=h(t,r);e.log(e.color?e.color(i):i),n!==void 0&&e.log(n)}function _(e){let t=m[e],n=new Set;return Object.assign((e,n,r)=>{g(t,e,n,r)},{once(e,r,i){!t.enabled||n.has(e)||(n.add(e),g(t,e,r,i))}})}function ee(e){let t=p.indexOf(e);if(t===-1){g(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(`(_)`)} | .__/_\\__|_\\_\\___\\__,_|`,` |_|
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(`(_)`)} | .__/_\\__|_\\_\\___\\__,_|`,` |_|
859
859
  `];console.log(e.join(`
860
- `))}var x={banner:b,debug:_(`debug`),info:_(`info`),warn:_(`warn`),error:_(`error`),setLevel:ee};function te(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 S=`.picked/`;async function C(t,i){if(i)return;let a=(0,r.join)(t,`.gitignore`);if(!(0,e.existsSync)(a)){await(0,n.writeFile)(a,`${S}
861
- `);return}let o=await(0,n.readFile)(a,`utf8`);w(o)||await(0,n.appendFile)(a,`${o.length>0&&!o.endsWith(`
862
- `)?`
863
- `:``}${S}
864
- `)}function w(e){return e.split(/\r?\n/).map(e=>e.trim()).some(e=>e===S||e===`.picked`)}var T=6,E=5e3;function D(e){let t;try{t=new URL(e).hostname}catch{return!1}return t===`localhost`||t===`127.0.0.1`||t===`::1`||t===`[::1]`?!0:t===`api.picked.app`?!1:t.endsWith(`.picked.app`)}function ne(e){return new Promise(t=>{setTimeout(t,e)})}async function O(e,t){let n=null,r=null;try{n=await e()}catch(e){r=e}if(n!==null)return n;for(let i=1;i<=T;i++){let a=E*2**(i-1);t(i,T,a),await ne(a),r=null;try{n=await e()}catch(e){r=e}if(n!==null)return n}if(r!==null)throw r;return null}function k(e){return Array.isArray(e)?e:[]}var re=1;function A(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 j(t){if(!(0,e.existsSync)(t))return null;try{let e=await(0,n.readFile)(t,`utf8`),r=JSON.parse(e);return M(r)?r:null}catch{return null}}function M(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 N(e){let t=new Set;for(let n of k(e.steps))n.layoutContentId&&t.add(n.id);if(t.size===0)return[];let n=[];for(let r of k(e.experiences))k(r.nodes).some(e=>e.type===`step`&&t.has(e.stepId))&&n.push(r.id);return n}async function P(e){let{apiUrl:t,projectId:i,projectRoot:a,headers:o,reuseWhenUnchanged:s=!0}=e,c=A(a),l=await I(t,i,o),u=N(l);if(s){let e=await j(c.manifestPath);if(e&&e.projectVersionId===l.versionId&&e.workspaceId===l.workspaceId)return{config:l,manifest:e,experienceContentPaths:F(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 L(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:re,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:F(c,u)}}function F(e,t){let n={};for(let i of t)n[i]=(0,r.join)(e.experiencesDir,`${i}.json`);return n}async function I(e,n,r){let i=()=>(0,t.fetchProject)(e,n,{headers:r}),a;try{a=D(e)?await O(i,(e,t,n)=>{x.info(`project config not ready, retrying in ${(n/1e3).toString()}s (${e.toString()}/${t.toString()})`)}):await i()}catch(t){throw Error(`[picked] Build-time fetch of project config failed for "${n}" at ${e}: ${R(t)}`)}if(!a)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 a}async function L(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}: ${R(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 R(e){if(e instanceof Error)return e.message;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return`unknown error`}}function z(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 B(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 V=5;function H(e,t,n){if(t.length===0)return;if(t.length>V){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 U(e,t){t.length!==0&&console.log(`\n ${e}: ${t.length.toString()} loaded\n`)}var W=[{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()}`}],G=[{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()}],K=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key},{header:`Fields`,value:e=>(e.fieldIds?.length??0).toString()}],q=[{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`}],J=[{header:`Name`,value:e=>e.name},{header:`Key`,value:e=>e.key}];function Y(){return`0.0.62-next.12`}var X=`https://api.picked.app`,Z=`virtual:picked/data`,Q=`\0${Z}`;function ie(n){let r=n.apiUrl??X,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!==X&&x.warn(`using custom API URL: ${r}`);let d=(0,t.createClientHeaders)(`vite-plugin`,Y());if(u.command===`build`){if(l)return;l=!0,x.info(`prefetching project config + content for "${n.projectId}"`);let t=A(a),o=(0,e.existsSync)(t.pickedDir),s=performance.now(),u=await P({apiUrl:r,projectId:n.projectId,projectRoot:a,headers:d}),f=(performance.now()-s).toFixed(0);await C(a,o);let p=u.config;i=k(p.features),$(p,f),c=z({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(),a=()=>(0,t.fetchProject)(r,n.projectId,{headers:d}),o=D(r)?await O(a,(e,t,n)=>{x.info(`local API not ready, retrying in ${(n/1e3).toString()}s (${e.toString()}/${t.toString()})`)}):await a(),s=(performance.now()-e).toFixed(0);o?(i=k(o.features),$(o,s)):x.warn(`failed to fetch project config for "${n.projectId}" (${s}ms)`)}},resolveId(e){if(e===Z)return Q},load(e){if(e===Q)return s===`build`?c:B({apiUrl:r,projectId:n.projectId})},configureServer(e){if(n.disableLauncher)return;e.middlewares.use(te(()=>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=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=[`${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})`),H(`Features`,n,W),H(`Experiences`,r,G),H(`Steps`,i,K),H(`Fields`,a,q),H(`Conditions`,o,J),U(`Actions`,s),x.debug(`config size: ${c.toString()} bytes`)}exports.picked=ie;
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.62-next.2`}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;
package/dist/esm/index.js CHANGED
@@ -1,28 +1,25 @@
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";
1
+ import { createClientHeaders as e, fetchProject as t } from "@picked/client/plugins/dynamic-experiences";
5
2
  //#region \0@oxc-project+runtime@0.124.0/helpers/taggedTemplateLiteral.js
6
- function l(e, t) {
3
+ function n(e, t) {
7
4
  return t ||= e.slice(0), Object.freeze(Object.defineProperties(e, { raw: { value: Object.freeze(t) } }));
8
5
  }
9
6
  //#endregion
10
7
  //#region src/launcher.ts
11
- var u;
12
- function d(e) {
13
- let t = JSON.stringify(e), n = e.length > 0 ? e.map((e) => `
8
+ var r;
9
+ function i(e) {
10
+ let t = JSON.stringify(e), i = e.length > 0 ? e.map((e) => `
14
11
  <div class="feature-row">
15
12
  <label>
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>
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>
19
16
  </label>
20
- <select data-value-for="${p(e.id)}">
17
+ <select data-value-for="${o(e.id)}">
21
18
  <option value="true" selected>true</option>
22
19
  <option value="false">false</option>
23
20
  </select>
24
21
  </div>`).join("") : "<p class=\"text no-features\">No features configured for this project.</p>";
25
- return String.raw(u ||= l([
22
+ return String.raw(r ||= n([
26
23
  "<!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 ",
27
24
  "\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 = ",
28
25
  ";\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,48 +27,48 @@ function d(e) {
30
27
  "<!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 ",
31
28
  "\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 = ",
32
29
  ";\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>"
33
- ]), n, t);
30
+ ]), i, t);
34
31
  }
35
- function f(e) {
32
+ function a(e) {
36
33
  return e.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
37
34
  }
38
- function p(e) {
35
+ function o(e) {
39
36
  return e.replaceAll("&", "&amp;").replaceAll("\"", "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
40
37
  }
41
38
  //#endregion
42
39
  //#region src/log.ts
43
- var m = "picked", ee = "\x1B[0m";
44
- function te() {
40
+ var s = "picked", c = "\x1B[0m";
41
+ function l() {
45
42
  let e = process.env.NO_COLOR;
46
43
  return e === "1" || e === "true";
47
44
  }
48
- function h(e) {
49
- return (t) => te() ? t : `${e}${t}${ee}`;
45
+ function u(e) {
46
+ return (t) => l() ? t : `${e}${t}${c}`;
50
47
  }
51
- var g = [
48
+ var d = [
52
49
  "debug",
53
50
  "info",
54
51
  "warn",
55
52
  "error",
56
53
  "silent"
57
- ], _ = {
54
+ ], f = {
58
55
  debug: {
59
- color: h("\x1B[2m"),
56
+ color: u("\x1B[2m"),
60
57
  log: console.debug,
61
58
  enabled: !1
62
59
  },
63
60
  info: {
64
- color: h("\x1B[36m"),
61
+ color: u("\x1B[36m"),
65
62
  log: console.log,
66
63
  enabled: !0
67
64
  },
68
65
  warn: {
69
- color: h("\x1B[33m"),
66
+ color: u("\x1B[33m"),
70
67
  log: console.warn,
71
68
  enabled: !0
72
69
  },
73
70
  error: {
74
- color: h("\x1B[31m"),
71
+ color: u("\x1B[31m"),
75
72
  log: console.error,
76
73
  enabled: !0
77
74
  },
@@ -80,52 +77,52 @@ var g = [
80
77
  enabled: !1
81
78
  }
82
79
  };
83
- function v(e, t) {
84
- return `${(/* @__PURE__ */ new Date()).toLocaleTimeString()} [${t ? `${m}:${t}` : m}] ${e}`;
80
+ function p(e, t) {
81
+ return `${(/* @__PURE__ */ new Date()).toLocaleTimeString()} [${t ? `${s}:${t}` : s}] ${e}`;
85
82
  }
86
- function y(e, t, n, r) {
83
+ function m(e, t, n, r) {
87
84
  if (!e.enabled) return;
88
- let i = v(t, r);
85
+ let i = p(t, r);
89
86
  e.log(e.color ? e.color(i) : i), n !== void 0 && e.log(n);
90
87
  }
91
- function b(e) {
92
- let t = _[e], n = /* @__PURE__ */ new Set();
88
+ function h(e) {
89
+ let t = f[e], n = /* @__PURE__ */ new Set();
93
90
  return Object.assign((e, n, r) => {
94
- y(t, e, n, r);
91
+ m(t, e, n, r);
95
92
  }, { once(e, r, i) {
96
- !t.enabled || n.has(e) || (n.add(e), y(t, e, r, i));
93
+ !t.enabled || n.has(e) || (n.add(e), m(t, e, r, i));
97
94
  } });
98
95
  }
99
- function x(e) {
100
- let t = g.indexOf(e);
96
+ function g(e) {
97
+ let t = d.indexOf(e);
101
98
  if (t === -1) {
102
- y(_.error, `invalid log level: ${e}`);
99
+ m(f.error, `invalid log level: ${e}`);
103
100
  return;
104
101
  }
105
- for (let [e, n] of g.entries()) _[n].enabled = e >= t;
102
+ for (let [e, n] of d.entries()) f[n].enabled = e >= t;
106
103
  }
107
- var S = h("\x1B[34m"), C = h("\x1B[36m");
108
- function w() {
104
+ var _ = u("\x1B[34m"), v = u("\x1B[36m");
105
+ function y() {
109
106
  let e = [
110
- ` ${S("_")} ${C("_")} _ _ _`,
111
- `${S("(_)")} ${C("(_)")} _ __(_)__| |_____ __| |`,
112
- ` ${S("_")} ${S("_")} | '_ \\ / _| / / -_) _\` |`,
113
- `${S("(_)")} ${S("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,
107
+ ` ${_("_")} ${v("_")} _ _ _`,
108
+ `${_("(_)")} ${v("(_)")} _ __(_)__| |_____ __| |`,
109
+ ` ${_("_")} ${_("_")} | '_ \\ / _| / / -_) _\` |`,
110
+ `${_("(_)")} ${_("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,
114
111
  " |_|\n "
115
112
  ];
116
113
  console.log(e.join("\n"));
117
114
  }
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
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
125
122
  };
126
123
  //#endregion
127
124
  //#region src/middleware.ts
128
- function E(e) {
125
+ function x(e) {
129
126
  return (t, n, r) => {
130
127
  if (t.method !== "GET") {
131
128
  r();
@@ -141,225 +138,14 @@ function E(e) {
141
138
  };
142
139
  }
143
140
  //#endregion
144
- //#region src/gitignore.ts
145
- var D = ".picked/";
146
- async function ne(t, n) {
147
- if (n) return;
148
- let r = c(t, ".gitignore");
149
- if (!e(r)) {
150
- await s(r, `${D}
151
- `);
152
- return;
153
- }
154
- let a = await o(r, "utf8");
155
- O(a) || await i(r, `${a.length > 0 && !a.endsWith("\n") ? "\n" : ""}${D}
156
- `);
157
- }
158
- function O(e) {
159
- return e.split(/\r?\n/).map((e) => e.trim()).some((e) => e === D || e === ".picked");
160
- }
161
- //#endregion
162
- //#region src/retry.ts
163
- var k = 6, A = 5e3;
164
- function j(e) {
165
- let t;
166
- try {
167
- t = new URL(e).hostname;
168
- } catch {
169
- return !1;
170
- }
171
- return t === "localhost" || t === "127.0.0.1" || t === "::1" || t === "[::1]" ? !0 : t === "api.picked.app" ? !1 : t.endsWith(".picked.app");
172
- }
173
- function re(e) {
174
- return new Promise((t) => {
175
- setTimeout(t, e);
176
- });
177
- }
178
- async function M(e, t) {
179
- let n = null, r = null;
180
- try {
181
- n = await e();
182
- } catch (e) {
183
- r = e;
184
- }
185
- if (n !== null) return n;
186
- for (let i = 1; i <= k; i++) {
187
- let a = A * 2 ** (i - 1);
188
- t(i, k, a), await re(a), r = null;
189
- try {
190
- n = await e();
191
- } catch (e) {
192
- r = e;
193
- }
194
- if (n !== null) return n;
195
- }
196
- if (r !== null) throw r;
197
- return null;
198
- }
199
- //#endregion
200
- //#region src/util.ts
201
- function N(e) {
141
+ //#region src/index.ts
142
+ var S = 5;
143
+ function C(e) {
202
144
  return Array.isArray(e) ? e : [];
203
145
  }
204
- //#endregion
205
- //#region src/prefetch.ts
206
- var P = 1;
207
- function F(e) {
208
- let t = c(e, ".picked");
209
- return {
210
- pickedDir: t,
211
- manifestPath: c(t, "manifest.json"),
212
- projectConfigPath: c(t, "project-config.json"),
213
- experiencesDir: c(t, "experiences")
214
- };
215
- }
216
- async function I(t) {
217
- if (!e(t)) return null;
218
- try {
219
- let e = await o(t, "utf8"), n = JSON.parse(e);
220
- return L(n) ? n : null;
221
- } catch {
222
- return null;
223
- }
224
- }
225
- function L(e) {
226
- 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));
227
- }
228
- function R(e) {
229
- let t = /* @__PURE__ */ new Set();
230
- for (let n of N(e.steps)) n.layoutContentId && t.add(n.id);
231
- if (t.size === 0) return [];
232
- let n = [];
233
- for (let r of N(e.experiences)) N(r.nodes).some((e) => e.type === "step" && t.has(e.stepId)) && n.push(r.id);
234
- return n;
235
- }
236
- async function z(e) {
237
- let { apiUrl: t, projectId: n, projectRoot: r, headers: i, reuseWhenUnchanged: o = !0 } = e, l = F(r), u = await V(t, n, i), d = R(u);
238
- if (o) {
239
- let e = await I(l.manifestPath);
240
- if (e && e.projectVersionId === u.versionId && e.workspaceId === u.workspaceId) return {
241
- config: u,
242
- manifest: e,
243
- experienceContentPaths: B(l, d)
244
- };
245
- }
246
- await a(l.experiencesDir, { recursive: !0 }), await s(l.projectConfigPath, JSON.stringify(u, null, 2));
247
- let f = (/* @__PURE__ */ new Date()).toISOString(), p = [];
248
- for (let e of d) {
249
- let r = await H(t, n, e, i);
250
- await s(c(l.experiencesDir, `${e}.json`), JSON.stringify(r, null, 2)), p.push({
251
- id: e,
252
- fetchedAt: f
253
- });
254
- }
255
- let m = {
256
- version: P,
257
- fetchedAt: f,
258
- projectVersionId: u.versionId,
259
- workspaceId: u.workspaceId,
260
- projectId: u.id,
261
- experiences: p
262
- };
263
- return await s(l.manifestPath, JSON.stringify(m, null, 2)), {
264
- config: u,
265
- manifest: m,
266
- experienceContentPaths: B(l, d)
267
- };
268
- }
269
- function B(e, t) {
270
- let n = {};
271
- for (let r of t) n[r] = c(e.experiencesDir, `${r}.json`);
272
- return n;
273
- }
274
- async function V(e, t, n) {
275
- let i = () => r(e, t, { headers: n }), a;
276
- try {
277
- a = j(e) ? await M(i, (e, t, n) => {
278
- T.info(`project config not ready, retrying in ${(n / 1e3).toString()}s (${e.toString()}/${t.toString()})`);
279
- }) : await i();
280
- } catch (n) {
281
- throw Error(`[picked] Build-time fetch of project config failed for "${t}" at ${e}: ${U(n)}`);
282
- }
283
- if (!a) 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.`);
284
- return a;
285
- }
286
- async function H(e, t, r, i) {
287
- let a;
288
- try {
289
- a = await n(e, t, r, { headers: i });
290
- } catch (t) {
291
- throw Error(`[picked] Build-time fetch of content for experience "${r}" failed at ${e}: ${U(t)}`);
292
- }
293
- 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.`);
294
- return a;
295
- }
296
- function U(e) {
297
- if (e instanceof Error) return e.message;
298
- if (typeof e == "string") return e;
299
- try {
300
- return JSON.stringify(e);
301
- } catch {
302
- return "unknown error";
303
- }
304
- }
305
- //#endregion
306
- //#region src/virtual-module/build.ts
307
- function W(e) {
308
- 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");
309
- return `import projectConfigJson from ${i(t)}
310
-
311
- const experienceImporters = {
312
- ${a}
313
- }
314
-
315
- export const projectConfig = projectConfigJson
316
-
317
- export async function experienceContent(experience, _options) {
318
- const id = typeof experience === 'string' ? experience : experience?.id
319
- if (!id) return null
320
- const importer = experienceImporters[id]
321
- if (!importer) return null
322
- try {
323
- return await importer()
324
- } catch {
325
- return null
326
- }
327
- }
328
-
329
- export const manifestMetadata = ${JSON.stringify(r)}
330
- `;
331
- }
332
- //#endregion
333
- //#region src/virtual-module/dev.ts
334
- function G(e) {
335
- let { apiUrl: t, projectId: n } = e;
336
- return `import { fetchProject, fetchExperienceContent } from '@picked/client/plugins/dynamic-experiences'
337
-
338
- const apiUrl = ${JSON.stringify(t)}
339
- const projectId = ${JSON.stringify(n)}
340
-
341
- export const projectConfig = await fetchProject(apiUrl, projectId)
342
-
343
- export async function experienceContent(experience, options) {
344
- const id = typeof experience === 'string' ? experience : experience?.id
345
- if (!id) return null
346
- return await fetchExperienceContent(apiUrl, projectId, id, options)
347
- }
348
-
349
- export const manifestMetadata = {
350
- mode: 'dev',
351
- fetchedAt: null,
352
- projectVersionId: projectConfig?.versionId ?? null,
353
- workspaceId: projectConfig?.workspaceId ?? null,
354
- }
355
- `;
356
- }
357
- //#endregion
358
- //#region src/index.ts
359
- var K = 5;
360
- function q(e, t, n) {
146
+ function w(e, t, n) {
361
147
  if (t.length === 0) return;
362
- if (t.length > K) {
148
+ if (t.length > S) {
363
149
  console.log(`\n ${e}: ${t.length.toString()} loaded\n`);
364
150
  return;
365
151
  }
@@ -374,10 +160,10 @@ function q(e, t, n) {
374
160
  ""
375
161
  ].join("\n"));
376
162
  }
377
- function J(e, t) {
163
+ function T(e, t) {
378
164
  t.length !== 0 && console.log(`\n ${e}: ${t.length.toString()} loaded\n`);
379
165
  }
380
- var Y = [
166
+ var E = [
381
167
  {
382
168
  header: "Name",
383
169
  value: (e) => e.name
@@ -398,7 +184,7 @@ var Y = [
398
184
  header: "Ver",
399
185
  value: (e) => `v${e.version.toString()}`
400
186
  }
401
- ], ie = [
187
+ ], D = [
402
188
  {
403
189
  header: "Name",
404
190
  value: (e) => e.name
@@ -419,7 +205,7 @@ var Y = [
419
205
  header: "Targets",
420
206
  value: (e) => e.targets.length.toString()
421
207
  }
422
- ], ae = [
208
+ ], O = [
423
209
  {
424
210
  header: "Name",
425
211
  value: (e) => e.name
@@ -432,7 +218,7 @@ var Y = [
432
218
  header: "Fields",
433
219
  value: (e) => (e.fieldIds?.length ?? 0).toString()
434
220
  }
435
- ], oe = [
221
+ ], k = [
436
222
  {
437
223
  header: "Name",
438
224
  value: (e) => e.name
@@ -449,94 +235,81 @@ var Y = [
449
235
  header: "Required",
450
236
  value: (e) => e.required ? "yes" : "no"
451
237
  }
452
- ], se = [{
238
+ ], A = [{
453
239
  header: "Name",
454
240
  value: (e) => e.name
455
241
  }, {
456
242
  header: "Key",
457
243
  value: (e) => e.key
458
244
  }];
459
- function ce() {
460
- return "0.0.62-next.12";
245
+ function j(e) {
246
+ try {
247
+ let t = new URL(e).hostname;
248
+ return t === "localhost" || t === "127.0.0.1" || t === "::1";
249
+ } catch {
250
+ return !1;
251
+ }
252
+ }
253
+ function M(e) {
254
+ return new Promise((t) => {
255
+ setTimeout(t, e);
256
+ });
257
+ }
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 });
264
+ if (a) return a;
265
+ }
266
+ return null;
461
267
  }
462
- var X = "https://api.picked.app", Z = "virtual:picked/data", Q = `\0${Z}`;
463
- function le(n) {
464
- let i = n.apiUrl ?? X, a = [], o = process.cwd(), s = "serve", c, l = !1;
268
+ function P() {
269
+ return "0.0.62-next.2";
270
+ }
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;
465
274
  return {
466
275
  name: "picked",
467
- config: async (u, d) => {
468
- s = d.command, o = process.cwd(), T.banner(), i !== X && T.warn(`using custom API URL: ${i}`);
469
- let f = t("vite-plugin", ce());
470
- if (d.command === "build") {
471
- if (l) return;
472
- l = !0, T.info(`prefetching project config + content for "${n.projectId}"`);
473
- let t = F(o), r = e(t.pickedDir), s = performance.now(), u = await z({
474
- apiUrl: i,
475
- projectId: n.projectId,
476
- projectRoot: o,
477
- headers: f
478
- }), d = (performance.now() - s).toFixed(0);
479
- await ne(o, r);
480
- let p = u.config;
481
- a = N(p.features), $(p, d), c = W({
482
- projectConfigPath: t.projectConfigPath,
483
- experienceContentPaths: u.experienceContentPaths,
484
- manifestMetadata: {
485
- mode: "build",
486
- fetchedAt: u.manifest.fetchedAt,
487
- projectVersionId: u.manifest.projectVersionId,
488
- workspaceId: u.manifest.workspaceId
489
- }
490
- });
491
- } else {
492
- T.info(`fetching project config for "${n.projectId}" (dev)`);
493
- let e = performance.now(), t = () => r(i, n.projectId, { headers: f }), o = j(i) ? await M(t, (e, t, n) => {
494
- T.info(`local API not ready, retrying in ${(n / 1e3).toString()}s (${e.toString()}/${t.toString()})`);
495
- }) : await t(), s = (performance.now() - e).toFixed(0);
496
- o ? (a = N(o.features), $(o, s)) : T.warn(`failed to fetch project config for "${n.projectId}" (${s}ms)`);
497
- }
498
- },
499
- resolveId(e) {
500
- if (e === Z) return Q;
501
- },
502
- load(e) {
503
- if (e === Q) return s === "build" ? c : G({
504
- apiUrl: i,
505
- projectId: n.projectId
506
- });
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;
507
291
  },
508
292
  configureServer(e) {
509
- if (n.disableLauncher) return;
510
- e.middlewares.use(E(() => d(a)));
511
- let t = e.printUrls.bind(e);
293
+ if (t.disableLauncher) return;
294
+ e.middlewares.use(x(() => i(r)));
295
+ let n = e.printUrls.bind(e);
512
296
  e.printUrls = () => {
513
- let n = e.resolvedUrls?.local[0];
514
- if (n) {
515
- let e = n.replace(/:(?<port>\d+)\//, (e, t) => `:\x1b[1m${t}\x1b[22m/`);
297
+ let t = e.resolvedUrls?.local[0];
298
+ if (t) {
299
+ let e = t.replace(/:(?<port>\d+)\//, (e, t) => `:\x1b[1m${t}\x1b[22m/`);
516
300
  console.log(` \x1b[32m➜\x1b[0m \x1b[1mPicked\x1b[22m: \x1b[36m${e}\x1b[0m`);
517
301
  }
518
- t();
302
+ n();
519
303
  };
520
304
  },
521
305
  generateBundle() {
522
- n.disableLauncher || this.emitFile({
306
+ t.disableLauncher || this.emitFile({
523
307
  type: "asset",
524
308
  fileName: "index.html",
525
- source: d(a)
309
+ source: i(r)
526
310
  });
527
311
  }
528
312
  };
529
313
  }
530
- function $(e, t) {
531
- let n = N(e.features), r = N(e.experiences), i = N(e.steps), a = N(e.fields), o = N(e.conditions), s = N(e.actions), c = JSON.stringify(e).length, l = [
532
- `${n.length.toString()} features`,
533
- `${r.length.toString()} experiences`,
534
- `${i.length.toString()} steps`,
535
- `${a.length.toString()} fields`,
536
- `${o.length.toString()} conditions`,
537
- `${s.length.toString()} actions`
538
- ].join(", ");
539
- T.info(`fetched config in ${t}ms (${l})`), q("Features", n, Y), q("Experiences", r, ie), q("Steps", i, ae), q("Fields", a, oe), q("Conditions", o, se), J("Actions", s), T.debug(`config size: ${c.toString()} bytes`);
540
- }
541
314
  //#endregion
542
- export { le as picked };
315
+ export { z as picked };
@@ -8,15 +8,11 @@ export interface PickedPluginOptions {
8
8
  disableLauncher?: boolean;
9
9
  }
10
10
  /**
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.
11
+ * Vite plugin that fetches Picked project config at build time
12
+ * and injects it via `define`, eliminating the runtime API request.
13
13
  *
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.
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.
20
16
  *
21
17
  * @param {PickedPluginOptions} options - Plugin configuration.
22
18
  * @returns {Plugin} A Vite plugin instance.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAsIlC,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,CA2I3D"}
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"}
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.62-next.12",
4
+ "version": "0.0.62-next.2",
5
5
  "dependencies": {
6
- "@picked/client": "0.0.62-next.12"
6
+ "@picked/client": "0.0.62-next.2"
7
7
  },
8
8
  "devDependencies": {
9
9
  "@repo/eslint-config": "workspace:*",
@@ -1,16 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,72 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"prefetch.d.ts","sourceRoot":"","sources":["../../src/prefetch.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,aAAa,EACd,MAAM,4CAA4C,CAAA;AAQnD,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"}
@@ -1,56 +0,0 @@
1
- /**
2
- * @file URL-driven retry helper for the build- and dev-mode project-config fetch.
3
- *
4
- * Retries are auto-enabled when the configured `apiUrl` points at a host where
5
- * deploys can race ahead of the API: `localhost`/`127.0.0.1`/`::1` for local
6
- * development, or any `*.picked.app` host EXCEPT the canonical production host
7
- * `api.picked.app`. Production and external customer hosts continue to fail fast.
8
- *
9
- * The retry schedule is hardcoded — there is no public option. The behavior is
10
- * an internal deploy-ordering workaround for the Picked monorepo and is not
11
- * intended for tuning by external SDK consumers.
12
- */
13
- /**
14
- * Whether build- and dev-mode project-config fetches against `apiUrl` should be
15
- * retried with exponential backoff. True for hosts where the API may briefly
16
- * be unreachable while a deploy is propagating; false for the canonical
17
- * production host and every external host.
18
- *
19
- * @param {string} apiUrl - The configured API base URL.
20
- * @returns {boolean} `true` when retries should be attempted, `false` otherwise.
21
- * @example
22
- * shouldRetryUrl('http://localhost:54321') // true
23
- * shouldRetryUrl('https://picked-api-git-foo.picked.app') // true
24
- * shouldRetryUrl('https://api.picked.app') // false
25
- */
26
- export declare function shouldRetryUrl(apiUrl: string): boolean;
27
- /**
28
- * Run `fetchFn` once. If it returns `null` OR throws, retry up to 6 times with
29
- * exponential backoff (5s → 10s → 20s → 40s → 80s → 160s, ~315 s worst-case wall time).
30
- *
31
- * Both thrown errors AND `null` returns are eligible for retry — the SDK's
32
- * `fetchProject` and `fetchExperienceContent` swallow network errors and return
33
- * `null`, so retrying only on throws would do nothing useful for the typical
34
- * "API not yet up" failure mode. If every attempt fails, the most recent thrown
35
- * error is rethrown; if every attempt simply returned `null`, `null` is returned
36
- * so the caller can produce its own diagnostic.
37
- *
38
- * `onRetry` is invoked once per retry, before the corresponding backoff sleep,
39
- * with the 1-indexed attempt number, the total retry budget, and the upcoming
40
- * delay in ms. The callback is the only place log lines are produced — callers
41
- * own the phrasing and any contextual prefix.
42
- *
43
- * @template T - Type of the value resolved by the fetch operation.
44
- * @param {() => Promise<T | null>} fetchFn - The async fetch operation to run.
45
- * @param {(attempt: number, totalAttempts: number, nextDelayMs: number) => void} onRetry -
46
- * Hook invoked before each backoff sleep.
47
- * @returns {Promise<T | null>} The first non-null result, or `null` after all retries are exhausted.
48
- * @throws {Error} The last thrown error when every attempt threw.
49
- * @example
50
- * const config = await withRetry(
51
- * () => fetchProject(apiUrl, projectId, { headers }),
52
- * (attempt, total, ms) => log.info(`retrying in ${ms}ms (${attempt}/${total})`),
53
- * )
54
- */
55
- export declare function withRetry<T>(fetchFn: () => Promise<T | null>, onRetry: (attempt: number, totalAttempts: number, nextDelayMs: number) => void): Promise<T | null>;
56
- //# sourceMappingURL=retry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAsBtD;AAgBD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,EAChC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,GAC7E,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CA+BnB"}
@@ -1,18 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,33 +0,0 @@
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
@@ -1 +0,0 @@
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"}
@@ -1,26 +0,0 @@
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
@@ -1 +0,0 @@
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"}