@coreframe/preview 0.1.16 → 0.1.18

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.
Files changed (2) hide show
  1. package/dist/index.js +1 -1
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{preparePreviewTunnel as e}from"./cloudflare.js";import{chmod as t,copyFile as n,glob as r,mkdir as i,mkdtemp as a,open as o,readFile as s,stat as c}from"node:fs/promises";import{tmpdir as l}from"node:os";import u from"node:path";import d from"node:process";import{parseEnv as f}from"node:util";import{coreframeLocalWorkerVariables as p,readProjectConfig as m}from"@coreframe/config";import{migrateLocalDb as h,runProjectSeed as g,startProjectPostgres as _,startProjectTurso as v}from"@coreframe/db";import y from"nano-spawn";import{supervise as b}from"procband";const x=[`DATABASE_URL`,`PGDATABASE`,`PGHOST`,`PGPASSWORD`,`PGPORT`,`PGUSER`,`TURSO_AUTH_TOKEN`,`TURSO_DATABASE_URL`],S=[`POSTHOG_`,`VITE_POSTHOG_`,`VITE_GA_`],C=[`CI`,`COLORTERM`,`COMSPEC`,`ComSpec`,`FORCE_COLOR`,`HOME`,`LANG`,`NODE_EXTRA_CA_CERTS`,`NODE_OPTIONS`,`NO_COLOR`,`PATH`,`PATHEXT`,`PNPM_HOME`,`SHELL`,`SSL_CERT_DIR`,`SSL_CERT_FILE`,`SYSTEMROOT`,`SystemRoot`,`TEMP`,`TERM`,`TMP`,`TMPDIR`,`USERPROFILE`],w=d.platform===`win32`?`pnpm.cmd`:`pnpm`;async function T({cwd:e=d.cwd(),env:t=d.env,host:n,port:r},i={}){let a=await m({cwd:e}),o=E(a,{host:n,port:r}),s=await P(e),c=O({appOrigin:o.appOrigin,config:a,env:t,environmentFiles:s}),l=o.access?{CLOUDFLARE_API_TOKEN:t.CLOUDFLARE_API_TOKEN??s.CLOUDFLARE_API_TOKEN}:void 0,u=N({config:a,cwd:e,env:c}),f=await j();console.log(`Preview output: ${f.path}`);let p,h,g=new Set,_=!1,v,y=()=>{if(!_){_=!0;for(let e of g)e.nodeChildProcess.then(e=>e.kill(`SIGTERM`)).catch(()=>void 0);p?.kill(`SIGTERM`),u.stop()}},b=[`SIGINT`,`SIGTERM`].map(e=>{let t=()=>{v??=e,y()};return d.on(e,t),{handler:t,signal:e}});try{await u.start();let n=k({config:o,cwd:e,database:u,env:c,accessEnvironment:l,output:f,processEnvironment:t,commands:g,onServe(e){p=e.server,h=e.disposeTunnel},isStopping:()=>_,onStop:y});await n.database.migrate(),await n.database.seed(),await i.beforeBuild?.(n),await n.build(),await i.afterBuild?.(n),await A(e),await n.serve()}finally{let e=[...g];y();try{await u.dispose()}finally{try{await Promise.allSettled([...e,p?.wait()].filter(Boolean)),await h?.()}finally{try{await f.close()}finally{for(let{handler:e,signal:t}of b)d.off(t,e)}}v&&(d.exitCode??=v===`SIGINT`?130:143)}}}function E(e,t={}){let n=e.preview??{},r=t.host??n.host??`127.0.0.1`,i=t.port??n.port??4173,a=n.strictPort??!0,o=n.appOrigin;if(!Number.isInteger(i)||i<1||i>65535)throw Error(`Preview port must be an integer between 1 and 65535.`);if(!r.trim())throw Error(`Preview host must not be empty.`);return o&&R(o),n.tunnel&&I(n.tunnel,o,a),n.access&&L(n.access,n.tunnel,o),{access:n.access,appOrigin:o,host:r,port:i,strictPort:a,tunnel:n.tunnel}}async function D({appOrigin:e,config:t,cwd:n,env:r}){return O({appOrigin:e,config:t,env:r,environmentFiles:await P(n)})}function O({appOrigin:e,config:t,env:n,environmentFiles:r}){let i=Object.keys(t.worker?.environment??{}).filter(e=>!S.some(t=>e.startsWith(t))),a=new Set([...p,...x,...i]),o={},s=new Set([...Object.keys(n),...Object.keys(r)].filter(e=>e.startsWith(`VITE_`)&&!S.some(t=>e.startsWith(t))));for(let e of[...C,...Object.keys(n).filter(e=>e.startsWith(`LC_`))])n[e]!==void 0&&(o[e]=n[e]);for(let e of a){let t=n[e]??r[e];t!==void 0&&(o[e]=t)}for(let e of s){let t=n[e]??r[e];t!==void 0&&(o[e]=t)}return e!==void 0&&(a.add(`APP_ORIGIN`),o.APP_ORIGIN=e),o.CLOUDFLARE_ENV=`preview`,o.COREFRAME_ENV=`preview`,o.COREFRAME_PLATFORM=`web`,o.COREFRAME_PREVIEW_WORKER_VARIABLES=JSON.stringify([...a].filter(e=>!S.some(t=>e.startsWith(t)))),o}function k({accessEnvironment:t,config:a,cwd:o,database:s,env:l,output:f,processEnvironment:p,commands:m,onServe:h,isStopping:g,onStop:_}){let v=!1,x={cwd:o,database:s,env:l,host:a.host,origin:a.appOrigin??z(a.host,a.port),port:a.port,async build(){await x.runScript(`build`,[`--mode`,`preview`])},report(e,t){console.log(t===void 0?e:`${e}: ${t}`)},async run(e,t=[]){let n=y(e,t,{cwd:o,env:l,stdin:`inherit`,stderr:f.fd,stdout:f.fd});m.add(n);try{await n}finally{m.delete(n)}},async runScript(e,t=[]){await x.run(w,[`run`,e,...t])},async serve(){if(v)throw Error(`Preview serving can only be started once.`);v=!0;let n,r,i;try{if(n=a.tunnel?await e({appOrigin:a.appOrigin,access:a.access,accessEnv:t,config:a.tunnel,cwd:o,env:p}):void 0,g()){await n?.dispose();return}r=b({name:`preview`,command:w,args:[`exec`,`vite`,`preview`,`--mode`,`preview`,`--outDir`,`dist/client`,`--host`,a.host,`--port`,String(a.port),...a.strictPort?[`--strictPort`]:[]],cwd:o,env:l,prefix:!1,stdin:d.stdin}),i=n?y(d.platform===`win32`?`cloudflared.exe`:`cloudflared`,[`tunnel`,`run`,`--url`,`http://${V(B(a.host))}:${a.port}`,`--credentials-file`,n.credentialsFile,n.tunnel.tunnelId],{cwd:o,env:l,stdin:`ignore`,stderr:f.fd,stdout:f.fd}):void 0,i&&m.add(i)}catch(e){throw r?.kill(`SIGTERM`),await r?.wait(),await n?.dispose(),e}try{h({disposeTunnel:n?.dispose,server:r}),x.report(`Preview`,x.url(`/`)),n&&(x.report(`Cloudflare tunnel`,`${n.tunnel.name} (${n.tunnel.tunnelId})`),n.access&&x.report(`Cloudflare Access bypass`,n.access.policyName)),await Promise.race(i?[r.expectSuccess(),i]:[r.expectSuccess()])}catch(e){if(g()||_(),await n?.dispose(),g())return;throw e}},async stageArtifact({label:e,pathname:t,source:a}){let s=M(o,t),l=[];for await(let e of r(a,{cwd:o}))(await c(u.resolve(o,e))).isFile()&&l.push(e);if(l.length===0)throw Error(`Preview artifact source ${JSON.stringify(a)} did not match a file.`);if(l.length>1)throw Error(`Preview artifact source ${JSON.stringify(a)} matched multiple files: ${l.sort().join(`, `)}.`);await i(u.dirname(s),{recursive:!0}),await n(u.resolve(o,l[0]),s);let d=x.url(t);return x.report(e,d),d},url(e=`/`){return new URL(e,`${x.origin.replace(/\/$/u,``)}/`).toString()}};return x}async function A(e){for await(let n of r(`dist/**/.dev.vars`,{cwd:e})){let r=u.resolve(e,n);(await c(r)).isFile()&&await t(r,384)}}async function j(){let e=await a(u.join(l(),`coreframe-preview-`)),t=u.join(e,`preview.log`),n=await o(t,`wx`,384);return{close:()=>n.close(),fd:n.fd,path:t}}function M(e,t){let n=new URL(t,`https://coreframe.invalid`);if(!t.startsWith(`/`)||t===`/`||t.includes(`\\`)||t.includes(`?`)||t.includes(`#`)||n.origin!==`https://coreframe.invalid`||n.pathname!==t||u.posix.normalize(t)!==t)throw Error(`Preview artifact pathname must be a normalized absolute URL path.`);return u.resolve(e,`dist/client`,`.${t}`)}function N({config:e,cwd:t,env:n}){let r=e.database?.dialect??`postgres`,i,a,o,s,c=!1,l=n,u=()=>a?(s??=a[Symbol.asyncDispose](),s):Promise.resolve(),d=()=>{c||(c=!0,u().catch(()=>void 0))};return{dialect:r,get env(){return l},async migrate(){await h({config:e,cwd:t,env:l})},async seed(){await g(`default`,{cwd:t,env:l,seedEntryPoint:e.database?.seed})},async start(){if(r===`sqlite`){a=await v({config:e,cwd:t,env:l,useSupervisorLease:!0}),Object.assign(l,a.env);return}i=await _({config:e,cwd:t,env:l,failIfRunning:!0,postgresOutput:`on-error`,useSupervisorLease:!0}),Object.assign(l,i.env)},stop:d,async dispose(){o??=(async()=>{d(),await Promise.allSettled([i?.[Symbol.asyncDispose](),u()]),i=void 0,a=void 0})(),await o}}}async function P(e){let t={};for(let n of[`.env`,`.env.local`,`.env.preview`,`.env.preview.local`]){let r=await F(u.resolve(e,n));r&&(t={...t,...r})}let n=await F(u.resolve(e,`.dev.vars`));n&&(t={...t,...n});let r=await F(u.resolve(e,`.dev.vars.preview`));return r&&(t={...t,...r}),t}async function F(e){try{return Object.fromEntries(Object.entries(f(await s(e,`utf8`))).filter(e=>e[1]!==void 0))}catch(e){if(e.code===`ENOENT`)return;throw e}}function I(e,t,n){if(!t)throw Error(`preview.appOrigin is required when preview.tunnel is configured.`);if(!n)throw Error(`preview.strictPort must be true when preview.tunnel is configured.`);let r=[`credentialsFile`,`tokenEnv`,`tokenFile`],i=e,a=r.find(e=>e in i);if(a)throw Error(`preview.tunnel.${a} is no longer supported. Coreframe preview now provisions Cloudflare credentials through the operating system credential store.`);if(!e.name.trim())throw Error(`preview.tunnel.name must not be empty.`);if(!/^[a-z0-9][a-z0-9._-]*$/u.test(e.profile))throw Error(`preview.tunnel.profile must start with a lowercase letter or number and contain only lowercase letters, numbers, dots, underscores, or hyphens.`);if(e.dns!==`managed`&&e.dns!==`external`)throw Error(`preview.tunnel.dns must be either "managed" or "external".`)}function L(e,t,n){if(!t)throw Error(`preview.tunnel is required when preview.access is configured.`);if(!n)throw Error(`preview.appOrigin is required when preview.access is configured.`);if(e.applicationId!==void 0&&!e.applicationId.trim())throw Error(`preview.access.applicationId must not be empty.`);if(!e.bypass||typeof e.bypass!=`object`)throw Error(`preview.access.bypass must be configured.`);if(e.bypass.policyName!==void 0&&!e.bypass.policyName.trim())throw Error(`preview.access.bypass.policyName must not be empty.`);let{ips:r}=e.bypass;if(typeof r!=`string`&&!Array.isArray(r)&&typeof r!=`function`)throw Error(`preview.access.bypass.ips must be an IP, an array of IPs, or a resolver.`);if(Array.isArray(r)&&r.length===0)throw Error(`preview.access.bypass.ips must contain at least one IP.`)}function R(e){let t;try{t=new URL(e)}catch{throw Error(`preview.appOrigin must be an exact HTTPS browser origin.`)}if(t.protocol!==`https:`||t.origin!==e||t.pathname!==`/`||t.search||t.hash||t.username||t.password)throw Error(`preview.appOrigin must be an exact HTTPS browser origin.`);return t}function z(e,t){return`http://${V(B(e))}:${t}`}function B(e){return e===`0.0.0.0`||e===`::`?`127.0.0.1`:e}function V(e){return e.includes(`:`)&&!e.startsWith(`[`)?`[${e}]`:e}export{D as createPreviewEnvironment,E as resolvePreviewConfig,T as runPreview};
1
+ import{preparePreviewTunnel as e}from"./cloudflare.js";import{chmod as t,copyFile as n,glob as r,mkdir as i,mkdtemp as a,open as o,readFile as s,stat as c,writeFile as l}from"node:fs/promises";import{tmpdir as u}from"node:os";import d from"node:path";import f from"node:process";import{parseEnv as p}from"node:util";import{coreframeLocalWorkerVariables as m,readProjectConfig as h}from"@coreframe/config";import{migrateLocalDb as g,runProjectSeed as _,startProjectPostgres as v,startProjectTurso as y}from"@coreframe/db";import b from"nano-spawn";import{supervise as x}from"procband";const S=[`DATABASE_URL`,`PGDATABASE`,`PGHOST`,`PGPASSWORD`,`PGPORT`,`PGUSER`,`TURSO_AUTH_TOKEN`,`TURSO_DATABASE_URL`],C=[`POSTHOG_`,`VITE_POSTHOG_`,`VITE_GA_`],w=[`CI`,`COLORTERM`,`COMSPEC`,`ComSpec`,`FORCE_COLOR`,`HOME`,`LANG`,`NODE_EXTRA_CA_CERTS`,`NODE_OPTIONS`,`NO_COLOR`,`PATH`,`PATHEXT`,`PNPM_HOME`,`SHELL`,`SSL_CERT_DIR`,`SSL_CERT_FILE`,`SYSTEMROOT`,`SystemRoot`,`TEMP`,`TERM`,`TMP`,`TMPDIR`,`USERPROFILE`],T=f.platform===`win32`?`pnpm.cmd`:`pnpm`;async function E({cwd:e=f.cwd(),env:t=f.env,host:n,port:r},i={}){let a=await h({cwd:e}),o=D(a,{host:n,port:r}),s=await I(e),c=k({appOrigin:o.appOrigin,config:a,env:t,environmentFiles:s}),l=o.access?{CLOUDFLARE_API_TOKEN:t.CLOUDFLARE_API_TOKEN??s.CLOUDFLARE_API_TOKEN}:void 0,u=F({config:a,cwd:e,env:c}),d=await N();console.log(`Preview output: ${d.path}`);let p,m,g=new Set,_=!1,v,y=()=>{if(!_){_=!0;for(let e of g)e.nodeChildProcess.then(e=>e.kill(`SIGTERM`)).catch(()=>void 0);p?.kill(`SIGTERM`),u.stop()}},b=[`SIGINT`,`SIGTERM`].map(e=>{let t=()=>{v??=e,y()};return f.on(e,t),{handler:t,signal:e}});try{await u.start();let n=A({config:o,cwd:e,database:u,env:c,accessEnvironment:l,output:d,processEnvironment:t,commands:g,onServe(e){p=e.server,m=e.disposeTunnel},isStopping:()=>_,onStop:y});await n.database.migrate(),await n.database.seed(),await i.beforeBuild?.(n),await n.build(),await i.afterBuild?.(n),await j(e,c),await n.serve()}finally{let e=[...g];y();try{await u.dispose()}finally{try{await Promise.allSettled([...e,p?.wait()].filter(Boolean)),await m?.()}finally{try{await d.close()}finally{for(let{handler:e,signal:t}of b)f.off(t,e)}}v&&(f.exitCode??=v===`SIGINT`?130:143)}}}function D(e,t={}){let n=e.preview??{},r=t.host??n.host??`127.0.0.1`,i=t.port??n.port??4173,a=n.strictPort??!0,o=n.appOrigin;if(!Number.isInteger(i)||i<1||i>65535)throw Error(`Preview port must be an integer between 1 and 65535.`);if(!r.trim())throw Error(`Preview host must not be empty.`);return o&&B(o),n.tunnel&&R(n.tunnel,o,a),n.access&&z(n.access,n.tunnel,o),{access:n.access,appOrigin:o,host:r,port:i,strictPort:a,tunnel:n.tunnel}}async function O({appOrigin:e,config:t,cwd:n,env:r}){return k({appOrigin:e,config:t,env:r,environmentFiles:await I(n)})}function k({appOrigin:e,config:t,env:n,environmentFiles:r}){let i=Object.keys(t.worker?.environment??{}).filter(e=>!C.some(t=>e.startsWith(t))),a=new Set([...m,...S,...i]),o={},s=new Set([...Object.keys(n),...Object.keys(r)].filter(e=>e.startsWith(`VITE_`)&&!C.some(t=>e.startsWith(t))));for(let e of[...w,...Object.keys(n).filter(e=>e.startsWith(`LC_`))])n[e]!==void 0&&(o[e]=n[e]);for(let e of a){let t=n[e]??r[e];t!==void 0&&(o[e]=t)}for(let e of s){let t=n[e]??r[e];t!==void 0&&(o[e]=t)}return e!==void 0&&(a.add(`APP_ORIGIN`),o.APP_ORIGIN=e),o.CLOUDFLARE_ENV=`preview`,o.COREFRAME_ENV=`preview`,o.COREFRAME_PLATFORM=`web`,o.COREFRAME_PREVIEW_WORKER_VARIABLES=JSON.stringify([...a].filter(e=>!C.some(t=>e.startsWith(t)))),o}function A({accessEnvironment:t,config:a,cwd:o,database:s,env:l,output:u,processEnvironment:p,commands:m,onServe:h,isStopping:g,onStop:_}){let v=!1,y={cwd:o,database:s,env:l,host:a.host,origin:a.appOrigin??V(a.host,a.port),port:a.port,async build(){await y.runScript(`build`,[`--mode`,`preview`])},report(e,t){console.log(t===void 0?e:`${e}: ${t}`)},async run(e,t=[]){let n=b(e,t,{cwd:o,env:l,stdin:`inherit`,stderr:u.fd,stdout:u.fd});m.add(n);try{await n}finally{m.delete(n)}},async runScript(e,t=[]){await y.run(T,[`run`,e,...t])},async serve(){if(v)throw Error(`Preview serving can only be started once.`);v=!0;let n,r,i;try{if(n=a.tunnel?await e({appOrigin:a.appOrigin,access:a.access,accessEnv:t,config:a.tunnel,cwd:o,env:p}):void 0,g()){await n?.dispose();return}r=x({name:`preview`,command:T,args:[`exec`,`vite`,`preview`,`--mode`,`preview`,`--outDir`,`dist/client`,`--host`,a.host,`--port`,String(a.port),...a.strictPort?[`--strictPort`]:[]],cwd:o,env:l,prefix:!1,stdin:f.stdin}),i=n?b(f.platform===`win32`?`cloudflared.exe`:`cloudflared`,[`tunnel`,`run`,`--url`,`http://${U(H(a.host))}:${a.port}`,`--credentials-file`,n.credentialsFile,n.tunnel.tunnelId],{cwd:o,env:l,stdin:`ignore`,stderr:u.fd,stdout:u.fd}):void 0,i&&m.add(i)}catch(e){throw r?.kill(`SIGTERM`),await r?.wait(),await n?.dispose(),e}try{h({disposeTunnel:n?.dispose,server:r}),y.report(`Preview`,y.url(`/`)),n&&(y.report(`Cloudflare tunnel`,`${n.tunnel.name} (${n.tunnel.tunnelId})`),n.access&&y.report(`Cloudflare Access bypass`,n.access.policyName)),await Promise.race(i?[r.expectSuccess(),i]:[r.expectSuccess()])}catch(e){if(g()||_(),await n?.dispose(),g())return;throw e}},async stageArtifact({label:e,pathname:t,source:a}){let s=P(o,t),l=[];for await(let e of r(a,{cwd:o}))(await c(d.resolve(o,e))).isFile()&&l.push(e);if(l.length===0)throw Error(`Preview artifact source ${JSON.stringify(a)} did not match a file.`);if(l.length>1)throw Error(`Preview artifact source ${JSON.stringify(a)} matched multiple files: ${l.sort().join(`, `)}.`);await i(d.dirname(s),{recursive:!0}),await n(d.resolve(o,l[0]),s);let u=y.url(t);return y.report(e,u),u},url(e=`/`){return new URL(e,`${y.origin.replace(/\/$/u,``)}/`).toString()}};return y}async function j(e,n){for await(let i of r(`dist/**/.dev.vars`,{cwd:e})){let r=d.resolve(e,i);if((await c(r)).isFile()){let e=p(await s(r,`utf8`));for(let t of S){let r=n[t];r===void 0?delete e[t]:e[t]=r}await l(r,Object.entries(e).flatMap(([e,t])=>t===void 0?[]:[`${e}=${M(t)}\n`]).join(``)),await t(r,384)}}}function M(e){if(!e.includes(`'`))return`'${e}'`;if(!e.includes("`"))return`\`${e}\``;if(!e.includes(`"`)&&!/[\\\n\r]/u.test(e))return`"${e}"`;throw Error(`Unable to serialize preview Worker variable to .dev.vars.`)}async function N(){let e=await a(d.join(u(),`coreframe-preview-`)),t=d.join(e,`preview.log`),n=await o(t,`wx`,384);return{close:()=>n.close(),fd:n.fd,path:t}}function P(e,t){let n=new URL(t,`https://coreframe.invalid`);if(!t.startsWith(`/`)||t===`/`||t.includes(`\\`)||t.includes(`?`)||t.includes(`#`)||n.origin!==`https://coreframe.invalid`||n.pathname!==t||d.posix.normalize(t)!==t)throw Error(`Preview artifact pathname must be a normalized absolute URL path.`);return d.resolve(e,`dist/client`,`.${t}`)}function F({config:e,cwd:t,env:n}){let r=e.database?.dialect??`postgres`,i,a,o,s,c=!1,l=n,u=()=>a?(s??=a[Symbol.asyncDispose](),s):Promise.resolve(),d=()=>{c||(c=!0,u().catch(()=>void 0))};return{dialect:r,get env(){return l},async migrate(){await g({config:e,cwd:t,env:l})},async seed(){await _(`default`,{cwd:t,env:l,seedEntryPoint:e.database?.seed})},async start(){if(r===`sqlite`){a=await y({config:e,cwd:t,env:l,useSupervisorLease:!0}),Object.assign(l,a.env);return}i=await v({config:e,cwd:t,env:l,failIfRunning:!0,postgresOutput:`on-error`,useSupervisorLease:!0}),Object.assign(l,i.env)},stop:d,async dispose(){o??=(async()=>{d(),await Promise.allSettled([i?.[Symbol.asyncDispose](),u()]),i=void 0,a=void 0})(),await o}}}async function I(e){let t={};for(let n of[`.env`,`.env.local`,`.env.preview`,`.env.preview.local`]){let r=await L(d.resolve(e,n));r&&(t={...t,...r})}let n=await L(d.resolve(e,`.dev.vars`));n&&(t={...t,...n});let r=await L(d.resolve(e,`.dev.vars.preview`));return r&&(t={...t,...r}),t}async function L(e){try{return Object.fromEntries(Object.entries(p(await s(e,`utf8`))).filter(e=>e[1]!==void 0))}catch(e){if(e.code===`ENOENT`)return;throw e}}function R(e,t,n){if(!t)throw Error(`preview.appOrigin is required when preview.tunnel is configured.`);if(!n)throw Error(`preview.strictPort must be true when preview.tunnel is configured.`);let r=[`credentialsFile`,`tokenEnv`,`tokenFile`],i=e,a=r.find(e=>e in i);if(a)throw Error(`preview.tunnel.${a} is no longer supported. Coreframe preview now provisions Cloudflare credentials through the operating system credential store.`);if(!e.name.trim())throw Error(`preview.tunnel.name must not be empty.`);if(!/^[a-z0-9][a-z0-9._-]*$/u.test(e.profile))throw Error(`preview.tunnel.profile must start with a lowercase letter or number and contain only lowercase letters, numbers, dots, underscores, or hyphens.`);if(e.dns!==`managed`&&e.dns!==`external`)throw Error(`preview.tunnel.dns must be either "managed" or "external".`)}function z(e,t,n){if(!t)throw Error(`preview.tunnel is required when preview.access is configured.`);if(!n)throw Error(`preview.appOrigin is required when preview.access is configured.`);if(e.applicationId!==void 0&&!e.applicationId.trim())throw Error(`preview.access.applicationId must not be empty.`);if(!e.bypass||typeof e.bypass!=`object`)throw Error(`preview.access.bypass must be configured.`);if(e.bypass.policyName!==void 0&&!e.bypass.policyName.trim())throw Error(`preview.access.bypass.policyName must not be empty.`);let{ips:r}=e.bypass;if(typeof r!=`string`&&!Array.isArray(r)&&typeof r!=`function`)throw Error(`preview.access.bypass.ips must be an IP, an array of IPs, or a resolver.`);if(Array.isArray(r)&&r.length===0)throw Error(`preview.access.bypass.ips must contain at least one IP.`)}function B(e){let t;try{t=new URL(e)}catch{throw Error(`preview.appOrigin must be an exact HTTPS browser origin.`)}if(t.protocol!==`https:`||t.origin!==e||t.pathname!==`/`||t.search||t.hash||t.username||t.password)throw Error(`preview.appOrigin must be an exact HTTPS browser origin.`);return t}function V(e,t){return`http://${U(H(e))}:${t}`}function H(e){return e===`0.0.0.0`||e===`::`?`127.0.0.1`:e}function U(e){return e.includes(`:`)&&!e.startsWith(`[`)?`[${e}]`:e}export{O as createPreviewEnvironment,D as resolvePreviewConfig,E as runPreview};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreframe/preview",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Production-like local preview lifecycle utilities for Coreframe apps",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,9 +20,9 @@
20
20
  "dependencies": {
21
21
  "@napi-rs/keyring": "1.3.0",
22
22
  "nano-spawn": "^2.1.0",
23
- "procband": "^0.3.8",
24
- "@coreframe/db": "^0.1.17",
25
- "@coreframe/config": "^0.1.13"
23
+ "procband": "^0.3.9",
24
+ "@coreframe/config": "^0.1.13",
25
+ "@coreframe/db": "^0.1.18"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^26.1.0",