everyapp 0.2.2 → 0.3.0-rc.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/LICENSE +21 -0
- package/README.md +6 -77
- package/bin/everyapp.js +235 -0
- package/dist/access-LGEN3ABJ.js +1 -0
- package/dist/activity-RSD4D66F.js +12 -0
- package/dist/apps-4RCFXT74.js +13 -0
- package/dist/chunk-23HJ5I2A.js +2 -0
- package/dist/chunk-2Y5Q6A5K.js +6 -0
- package/dist/chunk-4JRIS6S6.js +1 -0
- package/dist/chunk-5PTNYZK6.js +4 -0
- package/dist/chunk-6OGVO7QK.js +6 -0
- package/dist/chunk-6PGUCTJ6.js +11 -0
- package/dist/chunk-AGTCKFRB.js +22 -0
- package/dist/chunk-BHMRY53V.js +2 -0
- package/dist/chunk-CB4U7H2G.js +4 -0
- package/dist/chunk-CCWBPAKH.js +4 -0
- package/dist/chunk-CZTEDWZ2.js +22 -0
- package/dist/chunk-CZXHKPRZ.js +2 -0
- package/dist/chunk-E3EPK27P.js +10 -0
- package/dist/chunk-EGEWRFVY.js +1 -0
- package/dist/chunk-ELK7QZ2M.js +1 -0
- package/dist/chunk-FJJSSVET.js +33 -0
- package/dist/chunk-GKBPYVP3.js +25 -0
- package/dist/chunk-H6QQMY7B.js +18 -0
- package/dist/chunk-H7PDL3X5.js +1 -0
- package/dist/chunk-HOUHG236.js +20 -0
- package/dist/chunk-IFCPALVC.js +46 -0
- package/dist/chunk-IUOBIB5M.js +30 -0
- package/dist/chunk-J35DDCNU.js +1 -0
- package/dist/chunk-J455FAEN.js +7 -0
- package/dist/chunk-JYKRUS5C.js +1 -0
- package/dist/chunk-LXYMDZER.js +1 -0
- package/dist/chunk-LYNBZ7RV.js +57 -0
- package/dist/chunk-M2QQ2UD7.js +132 -0
- package/dist/chunk-N4E5YE4X.js +5 -0
- package/dist/chunk-N5GQLGEC.js +2 -0
- package/dist/chunk-NFU4YFXB.js +1 -0
- package/dist/chunk-OM2HDWVP.js +1 -0
- package/dist/chunk-ONLNJXVQ.js +32 -0
- package/dist/chunk-OP4DYXYI.js +2 -0
- package/dist/chunk-PNLU5U3P.js +1 -0
- package/dist/chunk-PS7S74DG.js +6 -0
- package/dist/chunk-RMF4YGD6.js +98 -0
- package/dist/chunk-T2GD7RHS.js +10 -0
- package/dist/chunk-TLRM3P7V.js +15 -0
- package/dist/chunk-W3JCQHHU.js +1 -0
- package/dist/chunk-WOVS3GV5.js +10 -0
- package/dist/chunk-YHJZMJYZ.js +1 -0
- package/dist/chunk-ZECBN24L.js +15 -0
- package/dist/chunk-ZEXVHB22.js +2 -0
- package/dist/chunk-ZFCUH5PK.js +7 -0
- package/dist/configure-F7UZCJUG.js +8 -0
- package/dist/create-2E5HVWYK.js +22 -0
- package/dist/db-HEQVTDTM.js +9 -0
- package/dist/delete-XCSIQIRS.js +3 -0
- package/dist/deploy-3QOZEZHC.js +1 -0
- package/dist/dev-JL3ZP5BT.js +86 -0
- package/dist/email-RLZFUFUN.js +10 -0
- package/dist/events-2V5VRBWP.js +15 -0
- package/dist/groups-HDG5DVFY.js +8 -0
- package/dist/index.js +97 -1
- package/dist/install-Z5FYXUYM.js +1 -0
- package/dist/login-KHJBC64Z.js +1 -0
- package/dist/mcp-EFDUKJ5V.js +1 -0
- package/dist/provider-EOI5PTFH.js +13 -0
- package/dist/release-74J5ZIL3.js +1 -0
- package/dist/restore-FFGYV7NO.js +3 -0
- package/dist/secret-7FKKTLHB.js +1 -0
- package/dist/setup-PAKRCAFO.js +1 -0
- package/dist/signin-AP3D4XM4.js +12 -0
- package/dist/status-RMWNHOEK.js +4 -0
- package/dist/teardown-E4JNKAZJ.js +22 -0
- package/dist/update-DWVZFNPS.js +1 -0
- package/dist/workspace-CJC5I66L.js +21 -0
- package/package.json +19 -16
- package/skills/build-every-app/SKILL.md +199 -0
- package/skills/build-every-app/patterns.md +140 -0
- package/skills/everyapp/SKILL.md +292 -0
- package/skills/everyapp/mcp.md +350 -0
- package/skills/everyapp/security-review.md +61 -0
- package/skills/everyapp/setup/README.md +274 -0
- package/skills/everyapp/setup/access.md +178 -0
- package/skills/everyapp/setup/context.md +117 -0
- package/skills/everyapp/setup/dataforseo.md +287 -0
- package/skills/everyapp/setup/email.md +366 -0
- package/skills/everyapp/setup/gateway.md +243 -0
- package/skills/everyapp/setup/google.md +360 -0
- package/skills/everyapp/setup/microsoft-365.md +281 -0
- package/skills/everyapp/setup/openai.md +318 -0
- package/skills/everyapp/setup/openrouter.md +309 -0
- package/skills/everyapp/setup/providers.md +1253 -0
- package/skills/everyapp/setup/remote-mcp.md +199 -0
- package/skills/everyapp/setup/signin-apple.md +178 -0
- package/skills/everyapp/setup/signin-cloudflare.md +148 -0
- package/skills/everyapp/setup/signin-github.md +139 -0
- package/skills/everyapp/setup/signin-google.md +178 -0
- package/skills/everyapp/setup/signin-microsoft.md +183 -0
- package/skills/everyapp/setup/signin-oidc.md +163 -0
- package/skills/everyapp/setup/slack.md +344 -0
- package/skills/everyapp/setup/workers-ai.md +138 -0
- package/bin/__everyapp_bash_complete.js +0 -12
- package/dist/bash-complete.js +0 -3
- package/dist/chunk-7BOQJFI5.js +0 -8
- package/dist/chunk-7YVJFS4A.js +0 -1
- package/dist/chunk-BIXKPCDH.js +0 -2
- package/dist/chunk-DLGPLHBH.js +0 -47
- package/dist/chunk-FD6K2YA7.js +0 -9
- package/dist/chunk-GAJEQYJH.js +0 -39
- package/dist/chunk-O2KDOP5R.js +0 -13
- package/dist/chunk-OI2MBGBG.js +0 -4
- package/dist/chunk-POSDLD3G.js +0 -8
- package/dist/chunk-RB5D2R45.js +0 -1
- package/dist/chunk-U4LIQ5VR.js +0 -1
- package/dist/chunk-VEYSNPDH.js +0 -3
- package/dist/chunk-VP6SKW44.js +0 -7
- package/dist/chunk-WO3NE7ZU.js +0 -7
- package/dist/chunk-XTO2VTPY.js +0 -6
- package/dist/chunk-YJ2DKIZS.js +0 -1
- package/dist/create-DYQ3NBWJ.js +0 -22
- package/dist/deploy-PYTCMDGV.js +0 -7
- package/dist/deploy-RMAHOA4Z.js +0 -55
- package/dist/dev-SAE237FS.js +0 -0
- package/dist/generateConfig-46Z3ERF3.js +0 -1
- package/dist/login-B6EF3SMX.js +0 -1
- package/dist/logout-XMKZBLNV.js +0 -1
- package/dist/remoteD1Shell-A67JMO3H.js +0 -6
- package/dist/setupLocal-TZJUW5ES.js +0 -6
- package/gateway/every-app-gateway-build.tar.gz +0 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import{b as O,c as Ce,d as Se,e as $e,f as Ae}from"./chunk-N4E5YE4X.js";import{g as de}from"./chunk-AGTCKFRB.js";import{e as q}from"./chunk-E3EPK27P.js";import{A as me}from"./chunk-IFCPALVC.js";import{a as he,b as ve,c as T,d as ke,e as De}from"./chunk-2Y5Q6A5K.js";import{c as we,j as fe,k as ge,n as M,o as ye}from"./chunk-H6QQMY7B.js";import{c as P,i as L}from"./chunk-6OGVO7QK.js";import{e as I,g as be,h as N,i as _}from"./chunk-N5GQLGEC.js";import{a as G}from"./chunk-W3JCQHHU.js";import{g as ue}from"./chunk-ZFCUH5PK.js";import{a as Y}from"./chunk-4JRIS6S6.js";import{a as R,j as oe,s as ie,u as le,v as ce}from"./chunk-RMF4YGD6.js";import{c as ne,d as se,f as re}from"./chunk-T2GD7RHS.js";import{b as X,c as J,e as Q,f as ee,g as te}from"./chunk-CCWBPAKH.js";import{Bb as C,Cb as D,Db as B,Fb as z,Tb as x,ac as Z,b as E,bc as K,c as S,d as W,e as H,jc as U,lc as ae,qb as V,qc as pe}from"./chunk-LYNBZ7RV.js";import{z as b}from"zod";var Fe=b.array(b.looseObject({state:b.string().nullish(),rate_plan:b.looseObject({id:b.string().nullish(),public_name:b.string().nullish()}).nullish(),product:b.looseObject({name:b.string().nullish()}).nullish()}));var We=/cancel|expired|failed/i;async function Ee(t){let n;try{n=await K(t,{plane:"account",args:["accounts","subscriptions","get"]},Fe)}catch{return"unreadable"}let a=n.filter(e=>!We.test(e.state??"")).map(e=>[e.rate_plan?.id,e.rate_plan?.public_name,e.product?.name].filter(Boolean).join(" ")).filter(e=>/workers/i.test(e));return a.some(e=>/paid|standard|bundled|unbound/i.test(e))?"paid":a.some(e=>/free/i.test(e))?"free":"unknown"}import{setTimeout as xe}from"node:timers/promises";var Ue=6e5,Le=3e3,Me=15e3;function je(t){let n=o=>[...t].filter(([,l])=>l===o).map(([l])=>l),a=[],e=n("tls");e.length>0&&a.push(`Waiting for ${e.length===1?"a certificate":"certificates"}: ${e.join(", ")}`);let s=n("dns");s.length>0&&a.push(`Waiting for DNS: ${s.join(", ")} ${s.length===1?"has":"have"} no record at the zone's nameservers yet`);let r=n("other");return r.length>0&&a.push(`Waiting for ${r.map(o=>`https://${o}`).join(", ")} to answer`),a.join("; ")}async function F({hosts:t,out:n,step:a,maxWaitMs:e=Ue,pollMs:s=Le,progressEveryMs:r=Me,probe:o,localDns:l=o?void 0:ke,sleep:m=xe,now:p=Date.now}){let u=p(),w=[],c=[],i=[...new Set(t)],y=null,f=o??(h=>T(h));for(;i.length>0;){let h=await Promise.all(i.map(v=>f(`https://${v}/`))),d=new Map;for(let[v,k]of i.entries()){let $=h[v];if(!$.answered){d.set(k,$.kind);continue}w.push(k),n.emit({type:"progress",step:a,message:`https://${k} has its certificate.`,data:{host:k}}),l&&await De({host:k,lead:`https://${k} has its certificate and the gateway serves it`,out:n,step:a,localDns:l})&&c.push(k)}if(i=[...d.keys()],i.length===0)break;let g=p()-u;if(g>=e){n.emit({type:"warning",code:"CERT_PENDING",step:a,message:`${i.map(v=>`https://${v}`).join(", ")} ${i.length===1?"has":"have"} no certificate after ${ae(g)}. It usually comes within five minutes; the gateway serves ${i.length===1?"it":"them"} as soon as it does. If it never comes, check the zone's CAA records allow Cloudflare's certificate authorities. Check later with \`${S} status\`.`,data:{hosts:i}});break}(y===null||p()-y>=r)&&(n.emit({type:"progress",step:a,message:`${je(d)} (usually under five minutes)...`,data:{hosts:i,waitedMs:g,waitingFor:Object.fromEntries(d)}}),y=p()),await m(s)}return{ready:w,pending:i,staleLocally:c}}async function Re({cf:t,accountId:n,install:a,domain:e,out:s}){if(a&&(a.liveVersionId!==null||a.gatewayHost===e)){if(a.gatewayHost!==e)throw new C("DOMAIN_CHANGE_UNSUPPORTED",`The Gateway can't move to ${e}
|
|
2
|
+
It's installed at ${a.gatewayHost}, and moving an installed Gateway isn't supported.`,{rerun:H("--domain"),rerunNote:"(without --domain) to update it where it is"});return{domain:e,zone:{id:a.zoneId,name:a.zoneName},appBaseDomain:a.appBaseDomain}}let r=await He(t,e,n);return Ve(e,r,s),{domain:e,zone:r,appBaseDomain:e}}async function He(t,n,a){let e=await be(t,n,a);if(!e){let s=(await _(t,a)).filter(r=>!r.status||r.status==="active").map(r=>r.name);throw new C("ZONE_NOT_FOUND",`${n} isn't under a domain in this Cloudflare account${s.length>0?`
|
|
3
|
+
This account's domains: ${s.join(", ")}`:""}`,{fix:s.length>0?`use a name under one of them, or add ${n}'s domain to Cloudflare`:`add ${n}'s domain to Cloudflare`,data:{url:I(a),zones:s}})}if(e.status&&e.status!=="active")throw new D("add_domain",`Finish activating ${e.name} on Cloudflare
|
|
4
|
+
Its nameservers don't point at Cloudflare yet.`,N(a,e.name),{data:{zone:e.name,status:e.status}});return{id:e.id,name:e.name}}async function Pe({cf:t,out:n,reason:a,release:e,accountId:s,target:r,interactive:o,...l}){let{certificates:m,...p}=l,u=await ie(t);n.emit({type:"step",step:"gateway.resources",status:"ok",message:u.created.length?`Created ${u.created.join(", ")}`:"The Gateway's database and KV namespace are there"});let w=R(t,u.d1Id),c=await ye({cf:t,out:n,reason:a,release:e,accountId:s,gatewayHost:r.domain,zone:r.zone,appBaseDomain:r.appBaseDomain,resources:u,db:w,interactive:o,cliVersion:E,...p});return await F({hosts:c.newHosts,out:n,step:"gateway.tls",...m}),{result:c,db:w}}function Ve(t,n,a){t===n.name&&a.emit({type:"warning",code:"GATEWAY_AT_ZONE_APEX",message:`The Gateway's sign-in cookie will cover every subdomain of ${n.name}
|
|
5
|
+
Apps take names directly below it too. Unless the domain is only for Every App,
|
|
6
|
+
install on a subdomain instead, e.g. --domain apps.${n.name}`,data:{suggestedDomain:`apps.${n.name}`}})}function Jt({gateway:t,interactive:n}){return{createCf:a=>Z({accountId:a}),openRelease:t.openRelease,source:t.source,interactive:n,prompts:tt,openBrowser:Ae,cliVersion:E}}async function Qt(t,n,a){let e=Ie(t.domain);_e(n);let{whoami:s,discovery:r}=await Te(t,n,a,{host:e,hostFlag:"--domain"});return Ne({whoami:s,discovery:r,flags:t,out:n,deps:a})}async function ea(t,n,a){_e(n);let{whoami:e,discovery:s}=await Te(t,n,a);if(!ce(s,e).install?.liveVersionId)throw oe();return Ne({whoami:e,discovery:s,flags:t,out:n,deps:a,offerAccess:!1})}async function Te(t,n,a,e){let s=await se({cf:a.createCf(),interactive:a.interactive,onDeviceLogin:t.json?ne(n,"setup.auth"):void 0});n.emit({type:"step",step:"setup.auth",status:"ok",message:`Logged in to Cloudflare${s.email?` as ${s.email}`:""}`,data:{email:s.email??null}});let r=await le({whoami:s,createCf:a.createCf,accountId:t["account-id"],...e,interactive:a.interactive});return{whoami:s,discovery:r}}function Ie(t){try{return G(t)}catch(n){throw n instanceof C?new C(n.code,`--domain ${t} isn't a full hostname`,{fix:n.fix}):n}}async function Ne({whoami:t,discovery:n,flags:a,out:e,deps:s,offerAccess:r=!0}){let o=n.gateway,l=o?.account??await re({whoami:t,flag:a["account-id"],interactive:s.interactive}),m=l.name??l.id,p=o?.cf??s.createCf(l.id),u=o?.install??null,w=u?.liveVersionId?u:null;e.emit({type:"step",step:"setup.account",status:"ok",message:`Setting up Every App in ${m}`,data:{id:l.id,name:l.name,email:t.email??null,gateway:w!==null}});let c=await s.source();c.minCli&&L({version:c.version,minCli:c.minCli},s.cliVersion),w||await ze(p,l.id,e);let i=await Re({cf:p,accountId:l.id,install:u,domain:Ie(a.domain)??u?.gatewayHost??await Ke(p,l.id,s),out:e}),y=!w?.liveDomains.includes(i.domain);y&&await we({cf:p,out:e,step:"gateway.domains",zone:i.zone,domains:[i.domain],liveDomains:[],forceDns:a["force-dns"],cfAsks:s.interactive&&e.verbose}),e.emit({type:"step",step:"setup.domain",status:"ok",message:`Apps will live one level below ${i.appBaseDomain}`,data:{gatewayHost:i.domain,appBaseDomain:i.appBaseDomain,zone:i.zone.name}});let f=`https://${i.domain}`,h=await Ye({cf:p,accountId:l.id,accountName:m,install:u,databaseId:o?.databaseId??null,target:i,source:c,checkedDomains:y?[i.domain]:[],flags:a,out:e,deps:s}),{owner:d,created:g}=await Xe({db:h.db,gatewayUrl:f,flags:a,out:e,deps:s}),v=w?.deploymentMode??"self_hosted",k=s.interactive&&!a.yes&&v==="self_hosted",$=k?await Y(p,V):[];if(k&&!$.includes("CF_DEPLOY_TOKEN")){let A=await s.prompts.browserDeploymentToken();A!==null&&await me({flags:{json:a.json,"account-id":l.id,gateway:f},out:e,names:["CF_DEPLOY_TOKEN"],readValue:async()=>A,createCf:()=>p})}let j=null;return k&&r&&d&&!q.every(A=>$.includes(A))&&(j=await Be({cf:p,accountId:l.id,gatewayUrl:f,owner:d.email,cloudflareEmail:t.email??null,flags:a,out:e,deps:s})),{gatewayUrl:f,account:m,owner:d?.email??null,organizationName:d?.organizationName||null,release:h.release,releaseName:P(c),gateway:h.outcome,ownerCreated:g,mode:v,accessOn:j}}async function Be({cf:t,accountId:n,gatewayUrl:a,owner:e,cloudflareEmail:s,flags:r,out:o,deps:l}){if(!await l.prompts.accessInFront({owner:e,cloudflareEmail:s}))return!1;try{return await de({flags:{json:r.json,"account-id":n,gateway:a},out:pe(o,"setup.access"),interactive:!0,createCf:()=>t,askTeam:l.askTeam}),!0}catch(m){if(m instanceof B)throw m;return o.emit({type:"warning",code:"ACCESS_SETUP_SKIPPED",step:"setup.access",message:`Cloudflare Access wasn't turned on
|
|
7
|
+
${z(m).split(`
|
|
8
|
+
`)[0]}
|
|
9
|
+
The Gateway works without it: passwords sign people in.`,data:{rerun:`${S} access on`,rerunNote:"to try again"}}),!1}}function _e(t){t.emit({type:"step",step:"setup.toolchain",status:"ok",message:`Node ${process.versions.node}, cf ${x}`,data:{node:process.versions.node,cf:x}})}async function ze(t,n,a){let e=await Ee(t),s=ue(n);switch(e){case"paid":a.emit({type:"step",step:"setup.plan",status:"ok",message:"Account is on Workers Paid",data:{plan:e}});return;case"free":throw new D("upgrade_workers_paid",`Subscribe this account to Workers Paid
|
|
10
|
+
It's on the Free plan. Every App needs Workers Paid ($5 a month, then usage): on Free, the Gateway stops once D1 hits its daily limit.`,s,{data:{plan:e}});case"unknown":a.emit({type:"warning",code:"WORKERS_PAID_UNVERIFIED",step:"setup.plan",message:`Couldn't confirm this account is on Workers Paid
|
|
11
|
+
Every App needs it ($5 a month, then usage). On Free, the Gateway stops once D1 hits its daily limit.`,data:{url:s,plan:e}});return;case"unreadable":a.emit({type:"step",step:"setup.plan",status:"skip",message:"Couldn't read this account's plan; Cloudflare refuses the upload if it's on Free",data:{url:s,plan:e}});return}}async function Ze(t,n){let a=await _(t,n),e=a.filter(r=>!r.status||r.status==="active");if(e.length>0)return e.map(r=>r.name);let[s]=a;throw s?new D("add_domain",`Finish activating ${a.map(r=>r.name).join(", ")} on Cloudflare
|
|
12
|
+
${a.length===1?"Its nameservers don't":"Their nameservers don't"} point at Cloudflare yet.`,N(n,s.name)):new D("add_domain",`Add a domain to this Cloudflare account
|
|
13
|
+
Every App needs one. Buy one in the dashboard (about $10 a year for a .com, ready in minutes),
|
|
14
|
+
or point a domain you own at Cloudflare's nameservers.`,I(n))}async function Ke(t,n,a){let e=await Ze(t,n);if(!a.interactive){let s=o=>W(["--domain",`apps.${o}`]),[r]=e;throw new C("DOMAIN_REQUIRED",`Choose the Gateway's address with --domain
|
|
15
|
+
It must be under one of this account's domains: ${e.join(", ")}. A subdomain works best.`,e.length===1?{fix:`add --domain apps.${r}, or another name under ${r}`,rerun:s(r),rerunNote:`or another name under ${r}`,data:{zones:e}}:{fix:`add --domain apps.${r}, or another name under ${Oe(e)}`,data:{zones:e,choices:e.map(o=>({label:o,rerun:s(o)}))}})}return G(await a.prompts.gatewayAddress(e))}function Oe(t){return t.length<=1?t[0]??"":`${t.slice(0,-1).join(", ")} or ${t.at(-1)}`}async function Ye({cf:t,accountId:n,accountName:a,install:e,databaseId:s,target:r,source:o,checkedDomains:l,flags:m,out:p,deps:u}){let w=`https://${r.domain}`,c=e?.liveVersionId?e:null,i=m["allow-downgrade"]??!1,y=g=>qe({cf:t,accountId:n,accountName:a,install:c,databaseId:s,openRelease:g,source:o,flags:m,out:p,deps:u});if(c&&s){if(o.treeSha256&&o.treeSha256===c.sourceTreeSha256||o.sha256&&o.sha256===c.releaseSha256)return y(u.openRelease);i||M(o,c,{allowDowngradeFlag:!0})}let f=P(o),h=c?"upgrade":e?.gatewayHost===r.domain?"resume":"install";p.emit({type:"step",step:"setup.gateway",status:"start",message:c?`Upgrading the Gateway to ${f}`:`Installing the Gateway at ${r.domain} (${f})`,data:{change:h,release:o.version,releaseName:f,from:c?.releaseVersion??null,gatewayUrl:w,account:a,...h==="install"?{expectedMinutes:Je}:{}}});let d=await u.openRelease();try{let g=d.manifest;if(L(g,u.cliVersion),c&&s){if(ge(d,c))return await y(async()=>d);i||M(fe(d),c,{allowDowngradeFlag:!0})}let{result:v,db:k}=await Pe({cf:t,out:p,reason:c?"upgrade":"deploy",release:d,accountId:n,target:r,interactive:u.interactive,forceDns:m["force-dns"],checkedDomains:l,allowDowngrade:i,allowDowngradeFlag:!0,sleep:u.seams?.sleep,leaseWaitMs:u.seams?.leaseWaitMs,certificates:u.seams?.certificates});return p.emit({type:"step",step:"setup.gateway",status:"ok",message:`The Gateway (${f}) is live at ${w}`,data:{versionId:v.versionId,release:g.version,releaseName:f}}),{db:k,release:g.version,outcome:c?"upgraded":"installed"}}finally{await d.cleanup()}}async function qe({cf:t,accountId:n,accountName:a,install:e,databaseId:s,openRelease:r,source:o,flags:l,out:m,deps:p}){let u=R(t,s),w=`https://${e.gatewayHost}`,c=e.releaseVersion,i=P(o),{inSync:y,desired:f}=await ve(t,u,e);if(y&&!l.redeploy)return m.emit({type:"step",step:"setup.gateway",status:"skip",message:`The Gateway is up to date with ${i}`,data:{release:c,releaseName:i,gatewayUrl:w,upToDate:!0,account:a,apps:f.appWorkers.length}}),{db:u,release:c,outcome:"up-to-date"};let h=!e.liveDomains.includes(e.gatewayHost),d=[...new Set(f.apps.filter(v=>!e.liveAppWorkers.includes(v.workerName)).map(v=>v.appId))].sort();m.emit({type:"step",step:"setup.gateway",status:"start",message:y?`Redeploying the Gateway (${i}) for --redeploy`:h?`Finishing the Gateway's first publication at ${e.gatewayHost} (${i})`:`Repairing the Gateway (${i}): ${f.appWorkers.length} apps, was ${e.liveAppWorkers.length}`,data:{change:y?"redeploy":h?"resume":"repair",release:c,releaseName:i,from:c,gatewayUrl:w,account:a,apps:f.appWorkers.length,was:e.liveAppWorkers.length,redeploy:y}});let g=await he({cf:t,out:m,accountId:n,databaseId:s,openRelease:r,interactive:p.interactive,cliVersion:p.cliVersion,force:!0,forceDns:l["force-dns"],sleep:p.seams?.sleep,leaseWaitMs:p.seams?.leaseWaitMs});return await F({hosts:g.newHosts,out:m,step:"gateway.tls",...p.seams?.certificates}),m.emit({type:"step",step:"setup.gateway",status:"ok",message:y?`The Gateway (${i}) is redeployed`:h?`The Gateway (${i}) is live at ${w}`:`The Gateway (${i}) routes ${g.appWorkers.length} apps`,data:{versionId:g.versionId,release:c,releaseName:i,appWorkers:g.appWorkers,...y||h?{}:{repaired:!0,added:d,apps:g.appWorkers.length,was:e.liveAppWorkers.length}}}),{db:u,release:c,outcome:h?"installed":"repaired"}}async function Xe({db:t,gatewayUrl:n,flags:a,out:e,deps:s}){let r=await O(t);if(r)return e.emit({type:"step",step:"setup.owner",status:"skip",message:`Owner account is ${r.email}`,data:{...r}}),{owner:r,created:!1};if(!$e({terminal:s.interactive,relayed:a.json}))return e.emit({type:"warning",code:"OWNER_NOT_CLAIMED",step:"setup.owner",message:`The Gateway has no owner yet
|
|
16
|
+
Apps deploy without one. To create it, run setup at a terminal with this Cloudflare login.`,data:{rerun:`${S} setup`,rerunNote:"at a terminal",needsTerminal:!0}}),{owner:null,created:!1};await et(n,e,s.seams?.fetch);let o=await Ce({db:t,gatewayUrl:n}),l=()=>U(o.expiresAt.getTime()-Date.now());e.emit({type:"action_required",action:"claim_owner",step:"setup.owner",message:o.replaced?`Open this new link to create the owner account
|
|
17
|
+
The link shown before no longer works. This one works once and expires in ${l()}. Treat it like a password.`:`Open this link to create the owner account
|
|
18
|
+
Works once and expires in ${l()}. Treat it like a password.`,data:{url:o.url,expiresAt:o.expiresAt.toISOString(),replaced:o.replaced,waiting:!0,waitingFor:"the owner account (up to 15 minutes)"}}),s.interactive&&await s.openBrowser(o.url);let m=Date.now(),p=await Se({db:t,id:o.id,...s.seams?.owner}),u=p.status==="claimed"?p.owner??await O(t):p.status==="gone"?await O(t):null;if(u)return e.emit({type:"step",step:"setup.owner",status:"ok",message:`Owner account created for ${u.email}`,data:{...u}}),{owner:u,created:!0};throw p.status==="waiting"?new D("claim_owner",`Open the setup link above to create the owner account
|
|
19
|
+
Nobody opened it within ${U(Date.now()-m)}. It still works for ${l()}; running setup before it's opened replaces it.`,void 0,{rerun:Ge(a),rerunNote:"to finish",data:{setupUrl:o.url,expiresAt:o.expiresAt.toISOString()}}):new D("claim_owner",`Use the newer setup link, or get a new one
|
|
20
|
+
This link stopped working before anyone used it: setup ran again on another machine, or it expired.`,void 0,{rerun:Ge(a),rerunNote:"for a new link"})}function Ge(t){return W([],{argv:t.json?["setup","--json"]:["setup"]})}var Je={min:5,max:10},Qe={tls:()=>"Its certificate is probably still on the way (TLS handshake failed).",dns:t=>`DNS has no address for ${t} yet.`,other:(t,n)=>`It didn't answer (${n}).`};async function et(t,n,a){let e=new URL(t).host,s=await T(`${t}/`,a);s.answered?s.access&&n.emit({type:"warning",code:"ACCESS_IN_FRONT",step:"setup.owner",message:`Cloudflare Access protects ${e}
|
|
21
|
+
Whoever opens the setup link signs in to Access first.`}):n.emit({type:"warning",code:"GATEWAY_UNREACHABLE",step:"setup.owner",message:`${e} doesn't answer over HTTPS yet
|
|
22
|
+
${Qe[s.kind](e,s.reason)} The link below works as soon as it does.`,data:{kind:s.kind,reason:s.reason}})}var tt={accessInFront:({owner:t,cloudflareEmail:n})=>J("Put Cloudflare Access in front of your Gateway?",["One command: people sign in at Cloudflare's edge before they reach your Gateway or its apps,","with their Cloudflare account (members of your Cloudflare account) or a code sent by email.",`Cloudflare's free Zero Trust plan covers 50 people. Turn it off any time: ${S} access off.`,...n&&n.toLowerCase()!==t.toLowerCase()?[`Your Cloudflare account is ${n}; your Gateway account is ${t}:`,`sign in with the code emailed to ${t}, or invite ${n} later.`]:[]]),browserDeploymentToken:async()=>await X("Configure browser app installs?",["Install apps on this Gateway through your browser, without running deployment commands."])?(await te("Cloudflare API token",{context:["1. Open https://dash.cloudflare.com/profile/api-tokens"," Select Create Token, then Custom token > Get started.","2. Add permissions:"," Account > Workers Scripts > Edit; Account > D1 > Edit; Zone > DNS > Read."," Limit account resources to this account and zone resources to the Gateway's zone.","3. Continue to summary, create the token, then paste it below (input is hidden).","The token is stored as a secret on your Gateway."]})).trim():null,pickZone:t=>Q("Which of your domains should Every App live under?",t.map(n=>({label:n,value:n}))),gatewayAddress:t=>ee("Gateway address",{context:[t.length===1?`Apps get addresses one level below the Gateway, e.g. todo.apps.${t[0]}`:`Your domains: ${t.join(", ")}. Apps live one level below the Gateway.`],initial:`apps.${t[0]}`,validate:n=>{let a;try{a=G(n)}catch{return`Enter a hostname like apps.${t[0]}`}return t.some(e=>a===e||a.endsWith(`.${e}`))?null:`Use a name under ${Oe(t)}`}})};export{Jt as a,Qt as b,ea as c,Ne as d,Ze as e};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{i as d}from"./chunk-ONLNJXVQ.js";import{e as g,f as c}from"./chunk-H7PDL3X5.js";import{a as m,e as y}from"./chunk-JYKRUS5C.js";import{Wb as a,bc as l,pb as p}from"./chunk-LYNBZ7RV.js";import e from"node:path";var u=".cloudflare/state",A=6e5;async function L(i,t){let r=t.resources?.d1??[];if(r.length===0)return{status:"skipped",reason:"no_d1"};let o=g(r,t.migrations),n=c(t);return await a(e.resolve(i,n))?{status:"found",binding:o,dir:n}:{status:"skipped",reason:"no_migrations_dir"}}async function b({cwd:i,manifest:t,cf:r,onApply:o}){let n=await L(i,t);return n.status==="skipped"?n:(o?.(),{status:"applied",...await R({cwd:i,manifest:t,cf:r,...n})})}async function R({cwd:i,manifest:t,cf:r,binding:o,dir:n}){let s=d(p(t.id),o);return{applied:(await l(r,{plane:"project",cwd:i,local:!0,timeoutMs:A,env:f(i),args:["d1","migrations","apply",s,"--local","--persist-to",u,"--dir",n]},m)).map(M=>M.name),database:s}}async function k({cwd:i,manifest:t,cf:r}){let o=g(t.resources?.d1??[],t.migrations);return(await l(r,{plane:"project",cwd:i,local:!0,env:f(i),args:["d1","migrations","list",d(p(t.id),o),"--local","--persist-to",u,"--dir",c(t)]},y)).map(s=>s.Name)}function f(i){let t=e.join(i,".everyapp","registry");return{CLOUDFLARE_REGISTRY_PATH:t,MINIFLARE_REGISTRY_PATH:t}}async function I(i){let t=await a(e.join(i,".wrangler","state")),r=await a(e.join(i,u));return!t||r?null:`Local data now lives in .cloudflare/state
|
|
2
|
+
Rows in the old .wrangler/state database weren't copied over.`}export{L as a,b,R as c,k as d,f as e,I as f};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
var s=`CREATE TABLE IF NOT EXISTS _everyapp_access (
|
|
2
|
+
id TEXT PRIMARY KEY CHECK (id = 'access'),
|
|
3
|
+
team_domain TEXT NOT NULL,
|
|
4
|
+
gateway_aud TEXT NOT NULL,
|
|
5
|
+
apps_aud TEXT NOT NULL,
|
|
6
|
+
written_at INTEGER NOT NULL
|
|
7
|
+
)`;async function r(t){let[a=[]]=await t.run([{sql:"SELECT name FROM sqlite_master WHERE type = 'table' AND name = '_everyapp_access'"}]);if(a.length===0)return null;let[n=[]]=await t.run([{sql:"SELECT team_domain, gateway_aud, apps_aud, written_at FROM _everyapp_access WHERE id = 'access'"}]),e=n[0];return e?{teamDomain:String(e.team_domain),gatewayAud:String(e.gateway_aud),appsAud:String(e.apps_aud),writtenAt:Number(e.written_at)}:null}async function o(t,a,n=[]){await t.run([{sql:s},{sql:`INSERT INTO _everyapp_access (id, team_domain, gateway_aud, apps_aud, written_at)
|
|
8
|
+
VALUES ('access', ?1, ?2, ?3, ?4)
|
|
9
|
+
ON CONFLICT(id) DO UPDATE SET team_domain = excluded.team_domain,
|
|
10
|
+
gateway_aud = excluded.gateway_aud, apps_aud = excluded.apps_aud, written_at = excluded.written_at`,params:[a.teamDomain,a.gatewayAud,a.appsAud,a.writtenAt]},...n])}async function d(t,a=[]){await t.run([{sql:s},{sql:"DELETE FROM _everyapp_access WHERE id = 'access'"},...a])}function u(t,a){return t.teamDomain===a.teamDomain&&t.gatewayAud===a.gatewayAud&&t.appsAud===a.appsAud}var i=["CLOUDFLARE_ACCESS_TEAM_DOMAIN","CLOUDFLARE_ACCESS_APPS_AUD","CLOUDFLARE_ACCESS_AUD"];function c(t){return i.every(a=>t.includes(a))}function p(t,a){return{on:c(t),teamDomain:a?.teamDomain??null}}export{r as a,o as b,d as c,u as d,i as e,p as f};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{r as p,s as u,u as f,v as d}from"./chunk-JYKRUS5C.js";import{Hb as a,bc as i,cc as c}from"./chunk-LYNBZ7RV.js";var l=20,g=10;async function y(n){let r=new Map;for(let e=1;e<=g;e+=1){let o=await i(n,{plane:"account",args:["hyperdrive","list","--per-page",String(l),"--page",String(e)]},d),t=r.size;for(let s of o)r.set(s.id,s);if(o.length<l||r.size===t)break}return[...r.values()]}async function H(n,r){return(await y(n)).find(e=>e.name===r)??null}async function b(n,r,e,o="off"){return(await i(n,{plane:"account",files:{"hyperdrive.json":{name:r,origin:e,...o==="off"?{caching:{disabled:!0}}:{}}},args:s=>["hyperdrive","create","--body",`@${s["hyperdrive.json"]}`]},f)).id}async function P(n,r,e){let o={...e.origin?{origin:e.origin}:{},...e.caching?{caching:{disabled:e.caching==="off"}}:{}};await i(n,{plane:"account",files:{"hyperdrive.json":o},args:t=>["hyperdrive","update",r,"--body",`@${t["hyperdrive.json"]}`]},f)}async function k(n,r){await n.run({plane:"account",mode:"json",args:["hyperdrive","delete",r,"--force"]})}function x(n,r){return n.caching?.disabled===!0==(r==="off")}function R(n,r){let e=n.origin;return e?.host===r.host&&(e.port??null)===r.port&&e.database===r.database&&e.user===r.user}var v=100,w=50;async function S(n,r){try{return await i(n,{plane:"account",args:["workflows","get",r]},p)}catch(e){if(a(e,"not_found"))return null;throw e}}function j(n,r){return c(n,["workflows","list","--search",r],u,{perPage:v,maxPages:w})}async function C(n,r){await n.run({plane:"account",mode:"json",args:["workflows","delete",r,"--force"]})}async function _(n,r){try{return await C(n,r),!0}catch(e){if(a(e,"not_found"))return!1;throw e}}export{y as a,H as b,b as c,P as d,k as e,x as f,R as g,S as h,j as i,_ as j};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{e as m,f as d}from"./chunk-M2QQ2UD7.js";import{qa as l,sa as p}from"./chunk-RMF4YGD6.js";import{a as i}from"./chunk-CCWBPAKH.js";import{Bb as o}from"./chunk-LYNBZ7RV.js";import s from"chalk";async function b(e){let{flags:t,out:r,createCf:n}=e,a=await p({gateway:l(t.gateway),accountId:t["account-id"],interactive:i(t.json??!1),login:{json:t.json,out:r,step:"login"},createCf:n}),g=await m(a.db,a.deployer,{org:t.org,now:e.now?.()});return{gateway:a,ws:g,gatewayUrl:a.gatewayUrl}}function x(e){return e.interactive??i(e.flags.json??!1)}async function W(e,t){try{let r=await d(e,t);return{id:r.id,email:r.email,member:!0}}catch(r){if(!(r instanceof o)||r.code!=="USER_NOT_FOUND"||t.includes("@"))throw r;return{id:t.trim(),email:null,member:!1}}}var v=e=>e.member?e.email??e.id:`${e.id} (no longer a member)`;function F(e){return e===null?s.dim("never"):new Date(e).toISOString().slice(0,16).replace("T"," ")}var c=e=>e===null?null:new Date(e).toISOString();function C(e){return e.deactivated?s.yellow("deactivated"):s.green("active")}function h(e){return{id:e.id,email:e.email,name:e.name,role:e.primaryRole??e.role,deactivated:e.deactivated,createdAt:c(e.createdAt)}}function O(e){return{id:e.id,email:e.email,role:e.role,status:e.status,expiresAt:c(e.expiresAt),expired:!e.live&&e.status==="pending",createdAt:c(e.createdAt)}}function A(e){let{add:t,remove:r,set:n}=e;if(n&&(t||r))throw new o("FLAGS_CONFLICT","--set replaces the whole list: give it alone, or --add and --remove without it");return!t&&!r&&!n?{change:null}:{change:{add:t,remove:r,set:n}}}export{b as a,x as b,W as c,v as d,F as e,c as f,C as g,h,O as i,A as j};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import{a as ir,b as or,c as sr,d as dr,f as be}from"./chunk-GKBPYVP3.js";import{b as cr,c as lr}from"./chunk-PNLU5U3P.js";import{a as rr,d as nr,e as he}from"./chunk-CZTEDWZ2.js";import{a as ar,b as pr}from"./chunk-BHMRY53V.js";import{b as Dt}from"./chunk-IFCPALVC.js";import{a as Ct}from"./chunk-WOVS3GV5.js";import{a as Et,b as At,d as me,e as It,m as St,q as Nt}from"./chunk-OM2HDWVP.js";import{a as zt,b as Bt,c as Kt,d as Ft,e as Ht}from"./chunk-J455FAEN.js";import{b as Zt,c as Qt,d as Xt,f as er,g as we,h as ye,j as tr}from"./chunk-EGEWRFVY.js";import{d as Mt,e as xt,f as Ut,g as Wt,m as jt}from"./chunk-H6QQMY7B.js";import{n as Gt}from"./chunk-6OGVO7QK.js";import{a as Vt,b as qt,c as Yt,d as Jt,g as ge}from"./chunk-PS7S74DG.js";import{P as ct}from"./chunk-TLRM3P7V.js";import{c as Ot,e as fe,f as $t}from"./chunk-ZFCUH5PK.js";import{a as _,b as F,e as de,f as T,g as kt,h as W}from"./chunk-ZECBN24L.js";import{c as $,d as _t,g as H,h as Tt}from"./chunk-ONLNJXVQ.js";import{b as Lt}from"./chunk-6PGUCTJ6.js";import{g as pt}from"./chunk-HOUHG236.js";import{$ as gt,ga as wt,ia as yt,ja as ht,m as lt,n as dt,o as mt,p as ft,qa as bt,sa as Rt,u as ut}from"./chunk-RMF4YGD6.js";import{f as le}from"./chunk-T2GD7RHS.js";import{a as Y,e as Pt,f as ue}from"./chunk-H7PDL3X5.js";import{a as ot,b as st,h as at}from"./chunk-CCWBPAKH.js";import{$b as rt,Bb as d,Cb as Je,Db as Ze,Eb as Qe,Fb as Xe,H as Ke,Hb as K,Sb as et,Wb as ce,Yb as tt,b as ae,c as N,d as O,dc as nt,fc as it,jb as Fe,k as pe,nb as He,ob as Ve,sb as qe,tb as Ye,wc as vt}from"./chunk-LYNBZ7RV.js";import Or from"node:path";import Wr from"chalk";async function mr({whoami:e,discovery:i,out:n,offer:t}){let{deps:s}=t,o=t.accountId?["--account-id",t.accountId]:[];if(!s.interactive){let f=await Gr(e,t).catch(()=>null),u=[N,"setup","--domain",f??"<hostname>",...o].join(" ");throw new Je("install_gateway",`Install a Gateway first: ${jr(i)}
|
|
2
|
+
Apps deploy behind one. Setup needs a person once, to create the owner account.`,void 0,{rerun:u,data:{accounts:i.probed,...f?{domain:f}:{}}})}let r=await le({whoami:e,flag:t.accountId,interactive:!0}),a=r.name??r.id,l=await he(s.createCf(r.id),r.id),g=`apps.${l.length===1?l[0]:await s.prompts.pickZone(l)}`;if(t.yes)at(Wr.dim(`${a} has no Gateway yet, so --yes installs one at ${g} first.`));else if(!await(t.confirm??st)(`Install a Gateway at ${g}?`,[`${a} has no Gateway yet. Apps deploy behind one, so it's installed first.`]))throw new Ze(`Cancelled. Nothing deployed.
|
|
3
|
+
Apps deploy behind a Gateway. To install one elsewhere: ${[N,"setup","--domain","<hostname>",...o].join(" ")}`);return await nr({whoami:e,discovery:i,flags:{domain:g,"account-id":r.id,"force-dns":t.forceDns,yes:t.yes,verbose:t.verbose},out:n,deps:s}),ut({whoami:e,createCf:s.createCf,accountId:r.id,interactive:!0})}async function Gr(e,i){let n=await le({whoami:e,flag:i.accountId,interactive:!1});return`apps.${(await he(i.deps.createCf(n.id),n.id))[0]}`}function jr(e){let i=e.probed.map(n=>n.name??n.id);return i.length===1?`${i[0]} has none yet`:`none of ${i.join(", ")} has one yet`}import zr from"node:fs/promises";var fr=64,Br=["d1","kv","hyperdrive","r2"];function Kr(e){return Br.includes(e)}function Fr(e,i){let n=structuredClone(e),t=n.name===$.workerName,s=n.env??{};for(let[l,m]of Object.entries(s))Hr(l,m,i);i.shared&&s.EVERY_APP_ORG_ID&&(delete s.EVERY_APP_ORG_ID,s.EVERYAPP_SHARED={type:"text",value:"1"});let o=JSON.stringify([$.publicKey]),r=Re(n,l=>l===o?JSON.stringify(i.identityPublicKeys):l.replaceAll($.gatewayUrl,()=>i.gatewayUrl).replaceAll($.organizationId,()=>i.organizationId).replaceAll($.workerName,()=>i.workerName));if(t&&i.deletedDurableObjects?.length){let l=r.exports??={};for(let m of i.deletedDurableObjects){if(l[m])throw new d("APP_POLICY",`Durable Object class ${m} is both exported by the build and being deleted; declare it in everyapp.config.ts, or stop exporting it.`);l[m]={type:"durable-object",state:"deleted"}}}let a=gr(r);if(a.length>0)throw new d("INSTALL_PLACEHOLDER_LEFT",`The build of ${String(r.name)} still holds a build placeholder after installing it, at ${a.join(", ")}. Build the Worker from everyAppWorker() in cloudflare.config.ts, and leave its names, keys and ids to the deploy.`);return Vr(r),r}async function ur({cwd:e,target:i}){for await(let{file:n,config:t}of Gt(e))await zr.writeFile(n,`${JSON.stringify(Fr(t,i),null,2)}
|
|
4
|
+
`)}function Hr(e,i,n){let t=String(i.type);if(!Kr(t))return;let s=_t(e);if(i[t==="d1"||t==="r2"?"name":"id"]!==s)return;let r=n.resources[t]?.[e];if(!r)throw new d("INSTALL_INPUTS_MISSING",`The build binds ${_[t]} ${e}, which the deploy didn't provision`,{fix:"declare it in everyapp.config.ts's resources"});Object.assign(i,r)}function Re(e,i){return typeof e=="string"?i(e):Array.isArray(e)?e.map(n=>Re(n,i)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([n,t])=>[n,Re(t,i)])):e}function gr(e,i=""){let n=[$.workerName,$.organizationId,$.gatewayUrl,$.publicKey].flatMap(s=>[s,JSON.stringify(s).slice(1,-1)]),t=s=>n.some(o=>s.includes(o));return typeof e=="string"?t(e)?[i||"(root)"]:[]:e&&typeof e=="object"?Object.entries(e).flatMap(([s,o])=>{let r=i?`${i}.${s}`:s;return t(s)?[r]:gr(o,r)}):[]}function Vr(e){let i=[...Object.entries(e.env??{}),...Object.entries(e.exports??{})].filter(([,n])=>n.type==="workflow");for(let[n,t]of i){let s=String(t.name);if(s.length>fr)throw new d("WORKFLOW_NAME_TOO_LONG",`${n} would be the Workflow "${s}", longer than Cloudflare's ${fr} characters`,{fix:"shorten its binding name in everyapp.config.ts"})}}import qr from"node:fs/promises";import wr from"node:path";import{parseEnv as Yr}from"node:util";var I=".everyapp/secrets.env",A="POSTGRES_DATABASE_URL";async function yr(e){let i;try{i=await qr.readFile(wr.join(e,I),"utf8")}catch(t){if(tt(t))return{};throw t}ir(e,`${wr.dirname(I)}/`);let n={};for(let[t,s]of Object.entries(Yr(i)))s?.trim()&&(n[t]=s.trim());return n}function ve(e){return`${e}_ORIGIN_URL`}function hr(e,i,n){let t=ve(n);return e[t]?{url:e[t],variable:t}:(i.resources?.hyperdrive??[]).length===1&&e[A]?{url:e[A],variable:A}:null}var Jr={postgres:5432,postgresql:5432,mysql:3306};function J(e,i){let n=l=>new d("DATABASE_URL_INVALID",`${i} in ${I} ${l}`,{fix:"write it as postgres://<user>:<password>@<host>:<port>/<database>"}),t;try{t=new URL(e)}catch{throw n("isn't a URL")}let s=t.protocol.replace(/:$/,"");if(s!=="postgres"&&s!=="postgresql"&&s!=="mysql")throw n("isn't a postgres:// or mysql:// URL");let o=decodeURIComponent(t.pathname.replace(/^\//,"")),r=decodeURIComponent(t.username),a=decodeURIComponent(t.password);if(!t.hostname||!o||!r||!a)throw n("needs a host, a database, a user and a password");return{scheme:s,host:t.hostname,port:t.port?Number(t.port):Jr[s],database:o,user:r,password:a}}function br(e,i){let n=e;for(let t of i)t&&(n=n.split(t).join("***"));return n}async function Rr({cf:e,names:i,appId:n,out:t}){let s=[];for(let o of[...new Set(i)].sort()){try{if(await cr(e,o))continue;await lr(e,o)}catch(r){if(K(r,"already_exists"))continue;throw K(r,"r2_not_enabled")?new d("R2_NOT_ENABLED",`R2 isn't enabled in this Cloudflare account, and ${n} needs an R2 bucket (${o})
|
|
5
|
+
Enable it once in the dashboard: R2 Object Storage \u2192 Get started (free until something is stored).`,{fix:"enable R2 in the Cloudflare dashboard (R2 Object Storage)",rerun:O()}):r}s.push(o),t.emit({type:"progress",step:"app.build",message:`Created R2 bucket "${o}".`,data:{bucket:o}})}return s}async function Ee({cf:e,gatewayDb:i,registration:n},t){let s=t?.name??"",o=t?.workerName??n.workerName;if(!(await F(i,n.workerName)).some(a=>a.kind==="worker"&&a.binding===s)){if(await Ot(e,o)!==null)throw new d("WORKER_NAME_TAKEN",`A Worker named ${o} already exists in this Cloudflare account
|
|
6
|
+
No deploy of this app created it; it may belong to another Gateway or project.`,{fix:"delete or rename it",rerun:O()});await T(i,n.workerName,{kind:"worker",binding:s,name:o,resourceId:o})}}async function vr(e){let{cf:i,registration:n,manifest:t}=e,s=await F(e.gatewayDb,n.workerName),o=(p,w)=>Xr({...e,owned:s,kind:p,binding:w,name:ke(n,p,w),find:p==="d1"?v=>lt(i,v):v=>mt(i,v),create:p==="d1"?v=>dt(i,v):v=>ft(i,v)}),r={};for(let p of t.resources?.d1??[])r[p]={name:ke(n,"d1",p),id:await o("d1",p)};let a={};for(let p of t.resources?.kv??[])a[p]={id:await o("kv",p)};let l=t.resources?.r2??[],m=l.length?{r2:Object.fromEntries(l.map(p=>[p,{name:ke(n,"r2",p)}]))}:{},g=t.resources?.hyperdrive??[];if(g.length===0)return{d1:r,kv:a,...m};let f=new Map(g.map(({name:p})=>{let w=hr(e.secrets??{},t,p);return[p,w?J(w.url,w.variable):null]})),u={};for(let{name:p,caching:w="off"}of g)u[p]={id:await Qr({...e,owned:s,binding:p,name:Zr(n.workerName,p),origin:f.get(p)??null,caching:w})};return{d1:r,kv:a,...m,hyperdrive:u}}function Zr(e,i){return`${e}${Ye}${i.toLowerCase().replaceAll("_","-")}`}async function Qr(e){let{cf:i,gatewayDb:n,registration:t,owned:s,binding:o,name:r,origin:a,caching:l}=e,{onRecreated:m,onChanged:g}=e,{workerName:f}=t,u={kind:"hyperdrive",binding:o,name:r},p=W(u),w=ve(o),v=s.find(k=>k.kind==="hyperdrive"&&k.binding===o&&k.name===r),R=await Zt(i,r),h=async k=>{let S=a!==null&&!we(k,a),D=!er(k,l);!S&&!D||(await Xt(i,k.id,{...S?{origin:a}:{},...D||l==="off"?{caching:l}:{}}),S&&g?.(`Pointed ${p} at the database in ${I}.`),D&&g?.(l==="off"?`Turned off query caching on ${p} (Hyperdrive never invalidates a cached read when the app writes; caching: "default" in everyapp.config.ts turns it on).`:`Turned on Hyperdrive's query caching on ${p} (caching: "default").`))};if(v?.resourceId){if(R?.id===v.resourceId)return await h(R),R.id;if(R)throw Er(u,v.resourceId);m?.(p,u.kind)}else if(v){if(R)return await T(n,f,{...u,resourceId:R.id}),await h(R),R.id}else if(R){if(a&&we(R,a))return await T(n,f,{...u,resourceId:R.id}),g?.(`Adopted ${p}, which connects to the database in ${I}.`),await h(R),R.id;throw new d("RESOURCE_NAME_TAKEN",`A Hyperdrive config named "${r}" already exists in this Cloudflare account
|
|
7
|
+
No deploy of this app created it.`,{fix:`to use it, set ${w} in ${I} to the URL of the database it connects to; otherwise delete or rename it`,rerun:O()})}if(!a)throw new d("HYPERDRIVE_ORIGIN_MISSING",`${o} needs the database its Hyperdrive config connects to
|
|
8
|
+
Creating the config needs its URL.`,{fix:`set ${w} (or POSTGRES_DATABASE_URL, when it is the app's only config) in ${I} to postgres://<user>:<password>@<host>:<port>/<database>`,rerun:O()});return kr(e,u,()=>Qt(i,r,a,l))}function ke(e,i,n){let t=e.resources[i][n];if(!t||qe(t))throw new d("RESOURCE_NAME_MISSING",`The Gateway assigned no usable ${_[i]} name for binding ${n}`,{rerun:`${N} setup`,rerunNote:"to upgrade the Gateway"});return t}async function Xr(e){let{gatewayDb:i,registration:n,owned:t,kind:s,binding:o,name:r,find:a,create:l,onRecreated:m}=e,{workerName:g}=n,f={kind:s,binding:o,name:r},u=t.find(w=>w.kind===s&&w.binding===o&&w.name===r),p=await a(r);if(u?.resourceId){if(p===u.resourceId)return p;if(p)throw Er(f,u.resourceId);m?.(W(f),s)}else if(u){if(p)return await T(i,g,{...f,resourceId:p}),p}else if(p)throw new d("RESOURCE_NAME_TAKEN",`A ${_[s]} named "${r}" already exists in this Cloudflare account
|
|
9
|
+
No deploy of this app created it; it may belong to another Gateway, app or project.`,{fix:"delete or rename it",rerun:O()});return kr(e,f,()=>l(r))}async function kr({gatewayDb:e,registration:i,onCreated:n},t,s){let{workerName:o}=i;await T(e,o,{...t,resourceId:null});let r;try{r=await s()}catch(a){throw K(a,"already_exists")?(await kt(e,o,{kind:t.kind,binding:t.binding}),new d("RESOURCE_NAME_TAKEN",`${W(t)} was created by someone else while this deploy was creating it`,{fix:"delete or rename it",rerun:O()})):a}return await T(e,o,{...t,resourceId:r}),n?.(W(t),t.kind),r}function Er(e,i){return new d("RESOURCE_REPLACED",`${W(e)} isn't the one this app created
|
|
10
|
+
That one (${i}) was deleted, and this one was created by someone else since.`,{fix:"delete or rename it",rerun:O()})}function Ae(e,i){return(i.resources?.workflows??[]).map(n=>({binding:n.name,className:n.className,name:Tt(e,n.name),worker:n.worker?H(e,n.worker):e}))}async function Ar({cf:e,workerName:i,names:n}){for(let t of n){let s=await ye(e,t);if(s&&s.script_name!==i)throw new d("WORKFLOW_NAME_TAKEN",`A Workflow named "${t}" already exists in this Cloudflare account
|
|
11
|
+
It runs on Worker ${s.script_name??"(unknown)"}, not ${i}; deploying would take it over.`,{fix:"delete or rename it",rerun:O()})}}async function Ir({cf:e,workerName:i,previousManifest:n,names:t}){let s=Fe.safeParse(n);if(!s.success)return[];let o=[];for(let r of Ae(i,s.data))t.includes(r.name)||(await ye(e,r.name))?.script_name===r.worker&&o.push(r);return o}import{execa as en}from"execa";var tn=10*6e4;function Z({packageName:e,binName:i,env:n={},missing:t}){return async({args:s,cwd:o,env:r})=>{let a;try{a=(await et(o,e,i)).binPath}catch{throw t()}let l=await en(process.execPath,[a,...s],{cwd:o,env:{NODE_NO_WARNINGS:"1",...n,...r},stdin:"ignore",reject:!1,timeout:tn});return{exitCode:l.timedOut?124:l.exitCode??1,stdout:String(l.stdout??""),stderr:String(l.stderr??"")}}}async function Q({run:e,args:i,cwd:n,databaseUrl:t,reasonPatterns:s,failed:o}){let{password:r}=J(t,A),a=await e({args:i,cwd:n,env:{[A]:t}});if(a.exitCode===0)return a.stdout;let m=br(`${a.stderr}
|
|
12
|
+
${a.stdout}`,[t,r,encodeURIComponent(r)]).split(`
|
|
13
|
+
`).map(f=>f.trim()).filter(Boolean),g=s.map(f=>m.find(u=>f.test(u))).find(f=>f!==void 0);throw o(g??m.at(-1)??`exit ${a.exitCode}`)}function rn(){return Z({packageName:"drizzle-kit",binName:"drizzle-kit",missing:()=>new d("DRIZZLE_KIT_MISSING",`Postgres migrations need drizzle-kit, which isn't installed
|
|
14
|
+
Nothing was migrated or uploaded.`,{fix:"add drizzle-kit to devDependencies, then deploy again"})})}async function Sr({cwd:e,databaseUrl:i,config:n,run:t=rn()}){await Q({run:t,args:["migrate",...n?["--config",n]:[]],cwd:e,databaseUrl:i,reasonPatterns:[/error/i],failed:s=>new d("MIGRATION_FAILED",`drizzle-kit couldn't migrate the Postgres database
|
|
15
|
+
${s}. Nothing was uploaded.`,{fix:`check ${A} in ${I} and the migrations`})})}function nn(){return Z({packageName:"prisma",binName:"prisma",env:{PRISMA_HIDE_UPDATE_MESSAGE:"1"},missing:()=>new d("PRISMA_MISSING",`Prisma migrations need prisma, which isn't installed
|
|
16
|
+
Nothing was migrated or uploaded.`,{fix:"add prisma to devDependencies, then deploy again"})})}async function Nr({cwd:e,databaseUrl:i,config:n,run:t=nn()}){return[...(await Q({run:t,args:["migrate","deploy",...n?["--config",n]:[]],cwd:e,databaseUrl:i,reasonPatterns:[/\bP\d{4}\b/,/error/i],failed:o=>new d("MIGRATION_FAILED",`prisma migrate deploy couldn't migrate the Postgres database
|
|
17
|
+
${o}. Nothing was uploaded.`,{fix:`check ${A} in ${I}, prisma.config.ts (its datasource reads it) and the migrations`})})).matchAll(/^Applying migration `([^`]+)`/gm)].map(o=>o[1])}var on=new Set(["pending","binding"]);async function $r(e){let i={rollback:null};try{return await sn(e,i)}catch(n){throw Qe(n,i.rollback)}}async function sn(e,i){let{cwd:n,out:t}=e,s=e.interactive??ot(e.json??!1),o=e.release,r=o?.manifest??e.manifest??await Y(n),a=o?.dir??n;o&&cn(r);let l=r.migrations?.dialect==="postgresql",m=l||r.resources?.hyperdrive?.length?await yr(n):{};if(l&&!m[A])throw new d("POSTGRES_URL_MISSING",`${r.id} needs a Postgres URL to migrate its database
|
|
18
|
+
Format: postgres://<user>:<password>@<host>:<port>/<database>`,{fix:`set ${A} in ${I}, then deploy again`});let g=o?null:await pr(n);if(!o&&!g)throw new d("MISSING_CLOUDFLARE_CONFIG",ar);g&&!g.usesEveryAppWorker&&t.emit({type:"warning",code:"NONSTANDARD_CLOUDFLARE_CONFIG",message:`cloudflare.config.ts doesn't use everyAppWorker()
|
|
19
|
+
The deploy checks the Worker it builds against the app policy.`});let f=e.offerInstall,u=zt(e.reconcile,t,e.verbose);t.emit({type:"step",step:"app.connect",status:"start",message:"Finding your Gateway..."});let{cf:p,accountId:w,accountName:v,databaseId:R,db:h,install:k,gatewayUrl:S,deployer:D}=await Rt({gateway:e.gateway,accountId:e.accountId,interactive:s,login:{json:e.json,out:t,step:"app.login"},createCf:e.createCf,onNoGateway:f?({whoami:x,discovery:re})=>mr({whoami:x,discovery:re,out:t,offer:{accountId:e.accountId,yes:f.yes,confirm:f.confirm,forceDns:e.forceDns,verbose:e.verbose,deps:{...rr({gateway:u,interactive:s}),...e.createCf?{createCf:e.createCf}:{},...f.setup}}}):void 0});t.emit({type:"step",step:"app.connect",status:"ok",data:{gatewayUrl:S}});let Ie=await Ct(h,k);pn(r,Ie,S);let[Dr,Se]=await Promise.all([gt(h),yt(h,r.id)]),Ne=!Se||on.has(Se.status);t.emit({type:"step",step:"app.deploy",status:"ok",message:`Deploying ${r.id}${o?` ${o.release.version} from ${be(o.origin)}`:""} to ${S}.`,data:{appId:r.id,organizationName:Dr?.organization.name??v,firstDeploy:Ne,gatewayUrl:S,gatewayHost:new URL(S).host,...o?{version:o.release.version,origin:be(o.origin),release:{version:o.release.version,gitSha:o.release.gitSha,origin:o.origin,sha256:o.release.sha256}}:{}}}),await jt(k,u.source);let Oe=k.jwtPublicKey;if(!Oe)throw new d("IDENTITY_KEY_UNKNOWN",`The Gateway is missing its sign-in public key
|
|
20
|
+
App Workers need it to check who is signed in.`,{fix:"restore JWT_PUBLIC_KEY as in https://github.com/every-app/every-app/blob/main/docs/runbooks/key-rotation.md"});let{plan:E,organization:L,hasOwner:Pr,deployerGranted:_r}=await Bt(h,{manifest:r,install:k,deployer:D,accountName:v}),C=E.app.hostname,y=E.app.workerName,$e=E.kind!=="existing",Ce=Ve(r,E.app.tier);if(Ce.length>0)throw new d("TIER_POLICY",`${r.id} can't be deployed as configured
|
|
21
|
+
${Ce.join(`
|
|
22
|
+
`)}`,{fix:"change everyapp.config.ts, then deploy again"});let X=nt(r),ee=it(r);t.emit({type:"step",step:"app.register",status:"ok",message:`${$e?"Registered":"Updating"} ${r.id} as ${y} at https://${C} (${E.app.status}).`,data:{appId:r.id,workerName:y,hostname:C,status:E.app.status,existingApp:!$e,firstDeploy:Ne,defaultAccess:E.app.isDefault,deployerAccess:_r,hasOwner:Pr,publicRoutes:X,mcp:ee,scope:E.app.scope,organizationId:L.id,organizationName:L.name,gatewayUrl:S}});let{outsideBase:G,newHost:De}=await Mt({cf:p,out:t,install:k,hostname:C,forceDns:e.forceDns,cfAsks:s&&t.verbose}),j=await pt({db:h,out:t},{workerName:y,appId:r.id,purpose:"app.deploy"}),z,te,V=[];try{let x=ln(E,r,e.allowDeleteDurableObjectData??!1),re=await dn({cf:p,plan:E,workerName:y,manifest:r,allowDelete:e.allowDeleteWorkflows??!1}),Te=!1,ne={cf:p,gatewayDb:h,registration:{workerName:y,resources:E.resources},onCreated:(c,b)=>{t.emit({type:"progress",step:"app.resources",message:`Created ${c}.`}),b==="hyperdrive"&&(Te=!0)},onRecreated:(c,b)=>t.emit({type:"warning",code:"RESOURCE_RECREATED",step:"app.resources",message:`The ${b==="d1"?"database":_[b]} ${r.id} used before is gone; creating a new, empty one
|
|
23
|
+
${c} no longer exists in this Cloudflare account.`}),onChanged:c=>t.emit({type:"progress",step:"app.resources",message:c})},P=(r.workers??[]).map(c=>({name:c.name,workerName:H(y,c.name)}));t.emit({type:"step",step:"app.resources",status:"start",message:"Preparing the app's resources..."}),await Ee(ne);for(let c of P)await Ee(ne,c);let U=await ht(h,E.app.id),ie=ge(r).receives;!ie&&U.inbound.length>0&&t.emit({type:"warning",code:"EMAIL_INBOUND_UNDECLARED",step:"app.email",message:`everyapp.config.ts no longer declares inbound email; removing the app's mail routes
|
|
24
|
+
Its addresses (${U.inbound.join(", ")}) stay on the Gateway until you clear them.`,data:{rerun:`${N} email unset inbound`}});let B=await Vt({cf:p,gatewayDb:h,accountId:w,workerName:y,addresses:ie?U.inbound:[],interactive:s,enableRouting:e.enableEmailRouting,confirm:e.confirm}),Le=await vr({...ne,manifest:r,secrets:m});if(t.emit({type:"step",step:"app.resources",status:"ok",message:"The app's resources are ready."}),Te){let c=r.resources?.hyperdrive?.some(b=>b.caching==="default")?"default":"off";t.emit({type:"step",step:"app.hyperdrive",status:"ok",message:"Created the app's Hyperdrive config.",data:{caching:c}})}!o&&r.install!==!1&&(t.emit({type:"step",step:"app.install",status:"start",message:"Installing dependencies..."}),await(e.installDeps??rt)({cwd:n,description:"Installing dependencies...",install:r.install,verbose:e.verbose??!1}),t.emit({type:"step",step:"app.install",status:"ok"}));let Me={workerName:y,organizationId:L.id,gatewayUrl:S,identityPublicKeys:[Oe],resources:Le,deletedDurableObjects:x,helperWorkers:P.map(c=>c.workerName),declared:r.resources};o||(t.emit({type:"step",step:"app.build",status:"start",message:"Building..."}),await sr({cwd:n,cf:p,buildCommand:r.build,verbose:e.verbose??!1})),await ur({cwd:a,target:Me});let{workflows:xe,helperWorkflows:Ue,r2Buckets:Tr}=await dr({cwd:a,inputs:Me});await Rr({cf:p,names:Tr,appId:r.id,out:t});for(let c of[{workerName:y,names:xe},...P.map(b=>({workerName:b.workerName,names:Ue[b.workerName]??[]}))])await Ar({cf:p,...c});t.emit({type:"step",step:"app.build",status:"ok",message:`${o?"Installed the release":"Built the app"} and checked its Worker${P.length?"s":""}.`,data:{release:o!==void 0,workflows:[...xe,...Object.values(Ue).flat()]}}),o?t.emit({type:"progress",step:"app.schema",message:`The release's publisher checked its migrations against its schema when it packed ${r.id} ${o.release.version}.`}):await or({cwd:n,manifest:r,out:t});let Lr=(await F(h,y)).filter(c=>c.kind==="worker"),We=c=>Lr.find(b=>b.binding===c)?.versionId,Mr={question:"Replace the version that's serving?",effect:"Migrations run first."};for(let c of[{workerName:y,shownAs:r.id,recordedVersionIds:[E.versionId,We("")]},...P.map(b=>({workerName:b.workerName,shownAs:`${r.id}'s ${b.name} Worker`,recordedVersionIds:[We(b.name)]}))])await $t({cf:p,...c,interactive:s,confirm:e.confirm,change:Mr});await j.check(),i.rollback=await mn({cf:p,out:t,cwd:a,manifest:r,resources:Le,accountId:w,registry:h,workerName:y,restoreCommand:`${N} db restore${o?` ${r.id}`:""}`,appSecrets:m,drizzleKit:e.drizzleKit,prisma:e.prisma});let Ge={GATEWAY_URL:S,EVERY_APP_ORG_ID:L.id};for(let c of P)await j.check(),t.emit({type:"step",step:"app.helper",status:"start",message:`Uploading ${c.workerName}...`,data:{name:c.name,workerName:c.workerName}}),await fe({cf:p,cwd:a,workerName:c.workerName,buildOutputWorker:c.workerName,accountId:w,message:`everyapp ${ae} ${r.id} ${c.name}`,secrets:Ge,interactive:s,attach:t.verbose,out:t,step:"app.helper",onUploaded:b=>de(h,y,b,c.name)}),t.emit({type:"step",step:"app.helper",status:"ok",message:`Uploaded ${c.workerName}.`,data:{name:c.name,workerName:c.workerName}});await j.check(),t.emit({type:"step",step:"app.upload",status:"start",message:`Uploading ${y}...`});let je=await fe({cf:p,cwd:a,workerName:y,accountId:w,message:`everyapp ${ae} ${r.id}`,secrets:Ge,interactive:s,attach:t.verbose,out:t,step:"app.upload",onUploaded:c=>de(h,y,c)});if(!je.versionId)throw new d("VERSION_UNKNOWN",`Cloudflare reports no version for ${r.id} after the upload`,{data:{workerName:y}});z=je.versionId,t.emit({type:"step",step:"app.upload",status:"ok",message:`Uploaded version ${z}.`,data:{versionId:z}});for(let c of re)await tr(p,c.name),t.emit({type:"step",step:"app.workflows",status:"ok",message:`Deleted the Workflow ${c.binding} (${c.name}) with its instances.`,data:{binding:c.binding,name:c.name}});let ze=ge(r).sends&&k.deploymentMode!=="hosted";if(B){await j.check(),t.emit({type:"step",step:"app.email",status:"start",message:`Routing ${r.id}'s mail...`,data:{removing:B.routes.length===0}});let{routed:c,removed:b}=await qt({cf:p,gatewayDb:h,plan:B,onProgress:se=>t.emit({type:"progress",step:"app.email",message:se})}),q={appId:r.id,workerName:y,senders:U.senders,routed:c,removed:b,sendersSettable:ze},Be=q.sendersSettable?Jt(q.routed,q.senders):[];t.emit({type:"step",step:"app.email",status:"ok",message:Yt(q),data:{addresses:c,removed:b,enabled:B.enable.map(({domain:se})=>se),...Be.length>0?{replyHint:`To reply from ${Be.join(", ")}, set up Email Sending, then: ${N} email set --sender`}:{}}})}!B&&ie&&U.inbound.length===0&&(t.emit({type:"step",step:"app.email",status:"skip",message:`${r.id} receives no mail yet.`}),V.push({command:`${N} email set --inbound <address>`,note:`routes mail to ${r.id}`})),ze&&U.senders.length===0&&V.push({command:`${N} email set --sender '*@<domain>'`,note:`lets ${r.id} send as your domain`});let xr=(E.previousManifest?.workers??[]).map(c=>String(c.name)).filter(c=>!P.some(b=>b.name===c));for(let c of xr)t.emit({type:"warning",code:"HELPER_WORKER_KEPT",step:"app.upload",message:`Helper Worker ${c} is no longer in everyapp.config.ts, but it still runs
|
|
25
|
+
Its Worker is ${H(y,c)}.`,data:{fix:"delete that Worker in the Cloudflare dashboard"}});let oe=await At(p,y).catch(c=>(t.emit({type:"progress",step:"app.secrets",message:`Couldn't list ${y}'s secrets: ${Xe(c).split(`
|
|
26
|
+
`)[0]}`}),null));te=await wt(h,E.app.id,{versionId:z,manifest:r,actor:D.actor,email:D.email,source:o?"release":"cli",...oe?{secretNames:oe}:{}});let Ur=await an({cf:p,manifest:r,appId:r.id,secretNames:oe,out:t,next:V,providers:Ie});await Dt(h,{appRowId:E.app.id,setup:Ur,deployer:D},t)}finally{await j.release()}await Kt({cf:p,db:h,databaseId:R,out:t,accountId:w,appId:r.id,workerName:y,publishHost:De,interactive:s,forceDns:e.forceDns,seams:{...e.reconcile,openRelease:u.openRelease,source:u.source},verb:"deploy"});let M=`https://${C}`,Pe=!G&&(e.waitForLive??!0),_e=await Ft({wait:Pe,db:h,appRowId:E.app.id,appId:r.id,hostname:C,out:t,seams:e.live,message:`${r.id} is live at ${M}.`,verb:"deploy"});if(!_e){let x=G?"outside-base":Pe?void 0:De?"certificate":"first-visit";t.emit(te==="active"&&!G?{type:"step",step:"app.live",status:"ok",message:`${r.id} is live at ${M}.`,data:{hostname:C,url:M}}:{type:"step",step:"app.live",status:"skip",message:`${r.id} isn't live yet: ${M}.`,data:{hostname:C,url:M,...x?{reason:x}:{}}})}return await ct({cf:p,db:h,install:k,out:t},{appId:r.id,surface:{publicRoutes:X.length>0,mcp:ee!==null}}),G&&t.emit({type:"warning",code:"APP_HOST_OUTSIDE_BASE",step:"app.domain",message:`${C} isn't one label below ${k.appBaseDomain}
|
|
27
|
+
The Gateway only serves names directly under ${k.appBaseDomain}, so ${r.id} can't be reached.`}),{liveUrl:M,gatewayUrl:S,organizationId:L.id,organizationName:L.name,hostname:C,workerName:y,versionId:z,live:_e||te==="active"&&!G,publicRoutes:X,mcp:ee,next:V}}async function an({cf:e,manifest:i,appId:n,secretNames:t,out:s,next:o,providers:r}){if(!It(i,r))return me({manifest:i,appId:n,gatewayNames:[],secretNames:[],lookup:r}).setup;let a=await Et(e).catch(()=>null),{setup:l}=me({manifest:i,appId:n,gatewayNames:a,secretNames:t,lookup:r});if(l.ready||!l.command)return l;let m=Nt(l),g=l.unmet.find(f=>f.why);return s.emit({type:"warning",code:"APP_NEEDS_SETUP",step:"app.secrets",message:[`${n} won't open until ${pe(m)} ${m.length===1?"is":"are"} set`,...g?[St(g)[0]]:[]].join(`
|
|
28
|
+
`),data:{setup:l}}),o.push({command:l.command.command,note:`asks for each; ${n} opens once they are set`}),l}function pn(e,i,n){let t=Object.keys(e.capabilities??{}).filter(s=>!i.get(s));if(t.length>0){let s=Ke(i);throw new d("CAPABILITY_UNKNOWN",[`${e.id} lists ${pe(t)} under capabilities, which ${n.replace(/^https:\/\//,"")} doesn't offer`,`Neither the built-in catalog nor the providers registered on this Gateway ${t.length===1?"has it":"have them"}. It offers: ${s.join(", ")}.`].join(`
|
|
29
|
+
`),{fix:`register ${t.length===1?"it":"each"} with ${N} provider add <spec.json or https URL> (or fix the id in everyapp.config.ts), then deploy again`,data:{unknown:t,offered:s}})}He(e,{capabilities:i})}function cn(e){if(e.migrations?.dialect==="postgresql")throw new d("RELEASE_MIGRATIONS_UNSUPPORTED",`${e.id} can't deploy from a release: its Postgres migrations need the source`,{fix:`clone it, then run pnpm install in it and this checkout's ${N} deploy from its directory`})}function ln(e,i,n){let t=new Map((i.resources?.durableObjects??[]).map(o=>[o.className,o.worker]));for(let o of e.previousManifest?.resources?.durableObjects??[]){let r=String(o.className),a=o.worker?String(o.worker):void 0;if(t.has(r)&&t.get(r)!==a)throw new d("DURABLE_OBJECT_MOVED",`${r} can't move to another Worker
|
|
30
|
+
A Durable Object's data can't follow it.`,{fix:"give the class a new name in everyapp.config.ts"});if(!t.has(r)&&a)throw new d("HELPER_DURABLE_OBJECT_REMOVED",`The helper Worker ${a} still defines ${r}
|
|
31
|
+
Removing a helper Worker's Durable Object class isn't supported yet.`,{fix:`keep declaring ${r} in everyapp.config.ts`})}let s=(e.previousManifest?.resources?.durableObjects??[]).map(o=>String(o.className)).filter(o=>!t.has(o));if(s.length>0&&!n){let o=s.length===1;throw new d("DURABLE_OBJECT_REMOVED",`Deploying would delete ${o?`${s[0]}'s data`:`the data of ${s.join(", ")}`} for good
|
|
32
|
+
everyapp.config.ts no longer declares the Durable Object class${o?"":"es"} ${s.join(", ")}.`)}return s}async function dn({cf:e,plan:i,workerName:n,manifest:t,allowDelete:s}){let o=await Ir({cf:e,workerName:n,previousManifest:i.previousManifest,names:Ae(n,t).map(r=>r.name)});if(o.length>0&&!s){let r=o.length===1;throw new d("WORKFLOW_REMOVED",`Deploying would delete the Workflow${r?"":"s"} ${o.map(a=>a.binding).join(", ")} and ${r?"its":"their"} instances
|
|
33
|
+
everyapp.config.ts no longer declares ${r?"it":"them"}. Renaming a binding renames its Workflow.`)}return o}async function mn({cf:e,out:i,cwd:n,manifest:t,resources:s,accountId:o,registry:r,workerName:a,restoreCommand:l,appSecrets:m,drizzleKit:g,prisma:f}){if(t.migrations?.dialect==="postgresql")return await fn({out:i,cwd:n,manifest:t,appSecrets:m,drizzleKit:g,prisma:f}),null;let u=t.resources?.d1??[];if(u.length===0)return null;let p=Pt(u,t.migrations),w=s.d1?.[p]?.id,v=Or.resolve(n,ue(t));if(!w||!await ce(v))return Cr(i),null;i.emit({type:"step",step:"app.migrations",status:"start",message:"Migrating the database..."});let R=await xt({cf:e,databaseId:w,accountId:o,dir:v,registry:r,target:Lt(a),restoreCommand:l});return i.emit({type:"step",step:"app.migrations",status:"ok",message:R.applied.length>0?`Applied ${R.applied.join(", ")}.${Ut(R.rollback)}`:"The app's database is up to date.",data:Wt(R)}),R.rollback}async function fn({out:e,cwd:i,manifest:n,appSecrets:t,drizzleKit:s,prisma:o}){let r=n.migrations?.engine==="prisma"?"prisma":"drizzle",a=r==="drizzle"?ue(n):n.migrations?.dir;if(a!==void 0&&!await ce(Or.resolve(i,a))){Cr(e);return}e.emit({type:"step",step:"app.migrations",status:"start",message:"Migrating the Postgres database...",data:{dialect:"postgresql",engine:r}});let l={cwd:i,databaseUrl:t[A],config:n.migrations?.config},m;r==="prisma"?m=await Nr({...l,...o?{run:o}:{}}):await Sr({...l,...s?{run:s}:{}}),e.emit({type:"step",step:"app.migrations",status:"ok",message:`Migrated the app's Postgres database (${r==="prisma"?"prisma migrate deploy":"drizzle-kit migrate"}).`,data:{dialect:"postgresql",engine:r,...m?{applied:m}:{}}})}function Cr(e){e.emit({type:"step",step:"app.migrations",status:"skip",message:"No migrations to apply."})}async function uo(e){await vt(e,async i=>{let n=process.cwd(),t=await $r({cwd:n,manifest:await Y(n),gateway:bt(e.gateway),accountId:e["account-id"],out:i,json:e.json,verbose:e.verbose,allowDeleteDurableObjectData:e["allow-delete-durable-object-data"],allowDeleteWorkflows:e["allow-delete-workflows"],forceDns:e["force-dns"],enableEmailRouting:e["enable-email-routing"],waitForLive:!e["no-wait"],offerInstall:{yes:e.yes}});i.emit({type:"done",...un(t)})})}function un(e){return{data:{...Ht(e),organization:e.organizationName,publicRoutes:e.publicRoutes,mcp:e.mcp,...e.next.length>0?{next:e.next}:{}}}}export{$r as a,uo as b,un as c};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import{b as ne,e as ie,g as se,i as oe,l as ae,m as D,n as pe,o as I,r as ce,s as le}from"./chunk-6OGVO7QK.js";import{d as te,e as re,f as C}from"./chunk-H7PDL3X5.js";import{Bb as l,Gb as q,Pb as J,Qb as X,Sb as Q,Yb as Z,Zb as _,_b as ee,b as N,c as W,j as G,lb as Y,nb as H,qb as K,tb as $}from"./chunk-LYNBZ7RV.js";import{spawn as Ce,spawnSync as Ue}from"node:child_process";import F from"node:fs";import k from"node:fs/promises";import{createRequire as Be}from"node:module";import h from"node:path";import{z as v}from"zod";import Ne from"node:fs";import We from"node:path";import Ie from"node:fs/promises";import ue from"node:path";var Le=200*1024*1024,Pe=5*6e4,Te=5,je=new Set([301,302,303,307,308]);function L(e){let t=/^([\w.-]+)\/([\w.-]+)$/.exec(e.trim());if(t)return`${t[1]}/${t[2].replace(/\.git$/,"")}`;let r;try{r=new URL(e.trim())}catch{return null}if(r.protocol!=="https:"||r.hostname!=="github.com")return null;let[n,i]=r.pathname.split("/").filter(Boolean);return!n||!i?null:`${n}/${i.replace(/\.git$/,"")}`}async function he({repo:e,asset:t,tag:r,...n}){let i=L(e);if(!i)throw new l("RELEASE_NOT_FOUND",`${e} isn't a GitHub repository (https://github.com/<owner>/<repo>).`);let o=r?`https://github.com/${i}/releases/download/${encodeURIComponent(r)}/${encodeURIComponent(t)}`:`https://github.com/${i}/releases/latest/download/${encodeURIComponent(t)}`,s=await U(o,{...n,notFound:`${i} has no ${r?`release ${r}`:"published release"} with ${t} that can be downloaded without signing in (https://github.com/${i}/releases).`});if(!s.tag)throw await s.cleanup(),new l("RELEASE_DOWNLOAD_FAILED",`GitHub didn't say which release of ${i} ${o} is.`);return{...s,tag:s.tag,repo:i}}async function U(e,{fetch:t=fetch,timeoutMs:r=Pe,maxBytes:n=Le,notFound:i}={}){let o=AbortSignal.timeout(r),{response:s,current:a,tag:c}=await xe(e,t,o).catch(p=>{throw me(p,e)});if(s.status===404)throw await s.body?.cancel(),new l("RELEASE_NOT_FOUND",i??`${e} doesn't exist (404).`);if(!s.ok||!s.body)throw await s.body?.cancel(),new l("RELEASE_DOWNLOAD_FAILED",`Couldn't download ${e}: HTTP ${s.status}.`,{retryable:s.status>=500});if(Number(s.headers.get("content-length"))>n)throw await s.body.cancel(),ge(e,n);let{dir:u,cleanup:w}=await _("release-download-"),g=ue.join(u,ue.posix.basename(a.pathname)||"release.tar.gz");try{let p=await Ie.open(g,"wx",384);try{let f=0;for await(let m of s.body){if(f+=m.byteLength,f>n)throw ge(e,n);await p.write(m)}}finally{await p.close()}}catch(p){throw await s.body.cancel().catch(()=>{}),await w(),me(p,e)}return{tarball:g,tag:c,url:e,cleanup:w}}async function xe(e,t,r){let n=de(e,e),i=fe(n);for(let o=0;;o+=1){let s=await t(n.href,{redirect:"manual",credentials:"omit",signal:r,headers:{accept:"application/octet-stream"}});if(!je.has(s.status))return{response:s,current:n,tag:i};let a=s.headers.get("location");if(await s.body?.cancel(),!a||o>=Te)throw new l("RELEASE_DOWNLOAD_FAILED",`${e} redirects ${a?"too many times":"nowhere"}.`);n=de(new URL(a,n).href,e),i??=fe(n)}}function de(e,t){let r;try{r=new URL(e)}catch{throw new l("RELEASE_DOWNLOAD_FAILED",`${e} isn't a URL.`)}if(r.protocol!=="https:")throw new l("RELEASE_DOWNLOAD_FAILED",`${t} ${e===t?"isn't":`redirects to ${e}, which isn't`} an HTTPS URL.`);return r}function fe(e){if(e.hostname!=="github.com")return null;let t=/^\/[^/]+\/[^/]+\/releases\/download\/([^/]+)\/[^/]+$/.exec(e.pathname);return t?decodeURIComponent(t[1]):null}function ge(e,t){return new l("RELEASE_TOO_LARGE",`${e} is over ${Math.round(t/1024/1024)} MB, too big for a release
|
|
2
|
+
A release is a few MB. Check the URL.`)}function me(e,t){if(e instanceof l)return e;let r=e.name;return new l("RELEASE_DOWNLOAD_FAILED",r==="TimeoutError"||r==="AbortError"?`Downloading ${t} timed out.`:`Couldn't download ${t}: ${e.message}`,{retryable:!0})}function P(e){return/^[a-z][a-z0-9+.-]*:\/\//i.test(e)}async function we(e,{asset:t,what:r,step:n,missing:i,out:o,fetch:s}){if(!P(e)){let u=We.resolve(e);if(!Ne.existsSync(u))throw new l("RELEASE_NOT_FOUND",i);return{tarball:u,origin:{kind:"file",path:u},cleanup:async()=>{}}}let a=B(e);o.emit({type:"progress",step:n,message:`Downloading ${r} from ${a?`${a.repo}${a.tag?` release ${a.tag}`:"'s latest release"}`:e}...`,data:{url:e}});let c,d;if(a){let u=await he({repo:a.repo,asset:t,tag:a.tag,fetch:s});c=u,d={kind:"github",repo:u.repo,tag:u.tag}}else{c=await U(e,{fetch:s});let u=c.tag?L(e):null;d=u&&c.tag?{kind:"github",repo:u,tag:c.tag}:{kind:"url",url:e}}return{tarball:c.tarball,origin:d,cleanup:c.cleanup}}function B(e){let t=L(e);if(!t||!P(e))return null;let r=new URL(e).pathname.split("/").filter(Boolean).slice(2);return r.length===0||r.length===1&&r[0]==="releases"?{repo:t}:r.length===3&&r[0]==="releases"&&r[1]==="tag"?{repo:t,tag:decodeURIComponent(r[2])}:r.length===2&&r[0]==="releases"&&r[1]==="latest"?{repo:t}:null}var M="everyapp-release.tar.gz",O="migrations",ye=h.join(".cloudflare","output"),S="v0",Fe="0.3.0",Me="0.3.0",Ee=/^(\.DS_Store|\._.*)$/;function ze(e){try{return Be(h.join(e,"package.json"))("@every-app/sdk/package.json").version??null}catch{return null}}var Ve=ne.extend({kind:v.literal("app"),appId:v.string().min(1),cliVersion:v.string(),sdkVersion:v.string().nullable(),manifest:v.record(v.string(),v.unknown())});function xt(e){switch(e.kind){case"github":return`github.com/${e.repo} (release ${e.tag})`;case"url":return e.url;case"file":return e.path;case"checkout":return"this checkout"}}function Ge(e){if(e.migrations?.engine==="prisma")throw new l("RELEASE_MIGRATIONS_UNSUPPORTED",`${e.id} migrates with Prisma, which a release can't carry
|
|
3
|
+
Prisma migrations (migrations.engine "prisma") need the app's source and its Prisma CLI.`,{rerun:`${W} deploy`,rerunNote:"from the app's checkout"});if(e.migrations?.dialect==="postgresql")return C(e);let t=e.resources?.d1??[];return t.length===0?null:(re(t,e.migrations),C(e))}async function Ye(e){return(await k.readdir(e,{recursive:!0,withFileTypes:!0})).filter(t=>!t.isDirectory()).map(t=>h.relative(e,h.join(t.parentPath,t.name)).split(h.sep).join("/")).sort()}async function He(e){let t=(await Ye(e)).filter(r=>{let n=h.posix.basename(r);return n.startsWith(".dev.vars")||n.startsWith(".env")||n.endsWith(".pem")||/(^|\/)\.cloudflare\/(state|types)(\/|$)/.test(r)||/(^|\/)\.(wrangler|everyapp)(\/|$)/.test(r)});if(t.length>0)throw new l("RELEASE_LOCAL_STATE",`Refusing to pack local state or secrets into the release:
|
|
4
|
+
${t.join(`
|
|
5
|
+
`)}`)}async function Ke(e){let t;try{t=await k.readFile(h.join(e,"meta","_journal.json"),"utf8")}catch(n){if(Z(n))return[];throw n}return(JSON.parse(t).entries??[]).map(({tag:n,when:i})=>({tag:n,when:i}))}function be(e,t){let r=Ue("git",t,{cwd:e,encoding:"utf8"});return r.status===0?r.stdout.trim():null}function qe(e){return new Promise((t,r)=>{let n=Ce("tar",e,{stdio:["ignore","ignore","pipe"],env:{...process.env,COPYFILE_DISABLE:"1"}}),i="";n.stderr.on("data",o=>i+=o.toString()),n.once("error",r),n.once("close",o=>o===0?t():r(new l("RELEASE_PACK_FAILED",`tar couldn't pack the release (exit ${o}): ${i.trim()}`)))})}async function Nt({cwd:e,manifest:t,outFile:r,cfVersion:n,builtAt:i=new Date}){let o=h.join(e,ye),s=F.existsSync(o)?(await k.readdir(o)).filter(w=>!Ee.test(w)):[];if(s.length!==1||s[0]!==S)throw new l("RELEASE_PACK_FAILED",`Expected the Build Output ${S} alone in ${o}, found ${s.length?s.join(", "):"none"}.`);let a=h.join(o,S);if(!await I(a))throw new l("RELEASE_PACK_FAILED",`The app's Build Output isn't a production build
|
|
6
|
+
A release ships only one.`,{fix:"build with `cf build` (production by default)"});let c=Ge(t),{dir:d,cleanup:u}=await _("app-release-stage-");try{let w=(E,x)=>k.cp(E,h.join(d,x),{recursive:!0,dereference:!0,filter:R=>!Ee.test(h.basename(R))});await w(a,h.join(ye,S));let g=c?h.resolve(e,c):null,p=g!==null&&F.existsSync(g)&&F.statSync(g).isDirectory();p&&await w(g,O),await He(d);let f=JSON.parse(await k.readFile(h.join(e,"package.json"),"utf8").catch(()=>"{}")),m=be(e,["rev-parse","HEAD"]),A=m!==null&&!!be(e,["status","--porcelain","--","."]),j={schema:1,kind:"app",appId:t.id,version:f.version??"0.0.0",gitSha:m?`${m}${A?"-dirty":""}`:"unknown",builtAt:i.toISOString(),cfVersion:n,cliVersion:N,sdkVersion:ze(e),buildOutputVersion:S,sha256:await ie(d),migrations:p?await Ke(h.join(d,O)):[],minCli:Fe,minSdk:Me,manifest:t.migrations||p?{...t,migrations:{engine:"drizzle",...t.migrations,dir:O}}:t};return await k.writeFile(h.join(d,"release.json"),`${JSON.stringify(j,null,2)}
|
|
7
|
+
`),await k.mkdir(h.dirname(r),{recursive:!0}),await k.rm(r,{force:!0}),await qe(["-czf",r,"-C",d,"."]),j}finally{await u()}}async function Je(e,{origin:t={kind:"file",path:e},version:r=N}={}){let{dir:n,manifest:i,cleanup:o}=await se(e,"app",Ve);try{oe(i,r,`${i.appId} ${i.version}`);let s;try{s=H(i.manifest,te)}catch(c){throw c instanceof Y?new l("RELEASE_INVALID",`${e} carries a manifest this everyapp refuses: ${c.message}`):c}if(s.id!==i.appId)throw new l("RELEASE_INVALID",`${e} says it is ${i.appId}, but its manifest is ${s.id}'s.`);let a=s.migrations?.dir;if(a!==void 0&&a!==O)throw new l("RELEASE_INVALID",`${e}'s manifest keeps its migrations in ${a}; a release keeps them in ${O}/.`);return{dir:n,release:i,manifest:s,origin:t,cleanup:o}}catch(s){throw await o(),s}}async function Wt(e,{out:t,fetch:r,version:n}){let i=P(e)?B(e):null,o;try{o=await we(e,{asset:M,what:"the app",step:"app.release",missing:`${e} is neither a URL nor a file
|
|
8
|
+
Pass a GitHub repository URL (https://github.com/<owner>/<repo>), a release tarball's URL, or a downloaded ${M}.`,out:t,fetch:r})}catch(s){throw i&&s instanceof l&&s.code==="RELEASE_NOT_FOUND"?new l("NO_RELEASE",`${i.repo} publishes no everyapp release${i.tag?` ${i.tag}`:""}
|
|
9
|
+
Its GitHub releases have no ${M}.`,{fix:`clone it, then run pnpm install in it and this checkout's ${W} deploy from its directory`}):s}try{let s=await Je(o.tarball,{origin:o.origin,version:n});return{...s,cleanup:async()=>{await s.cleanup(),await o.cleanup()}}}catch(s){throw await o.cleanup(),s}}import{rmSync as Qe}from"node:fs";import b from"node:fs/promises";import y from"node:path";import{execa as Ze}from"execa";import T from"node:fs";import Xe from"node:path";function ke(e,t){let r=Xe.join(e,".gitignore");if(!T.existsSync(r)){T.writeFileSync(r,t+`
|
|
10
|
+
`);return}let n=T.readFileSync(r,"utf-8");n.split(`
|
|
11
|
+
`).some(o=>o.trim()===t||o.trim()===t.replace(/\/$/,""))||T.appendFileSync(r,(n.endsWith(`
|
|
12
|
+
`)?"":`
|
|
13
|
+
`)+t+`
|
|
14
|
+
`)}var et=["drizzle.config.ts","drizzle.config.js"],ve=12e4;async function Jt({cwd:e,manifest:t,out:r}){let n=t.migrations?.engine??"drizzle",i=t.migrations?.dialect==="postgresql",o=(g,p={})=>r.emit({type:"warning",code:"SCHEMA_CHECK_SKIPPED",step:"app.schema",message:`Can't check the schema against the migrations: ${g}${p.detail?`
|
|
15
|
+
${p.detail}`:""}`,...p.fix?{data:{fix:p.fix}}:{}});if(n==="prisma"){r.emit({type:"progress",step:"app.schema",message:"To check a Prisma schema against its migrations: prisma migrate diff --from-migrations <dir> --to-schema <schema> --exit-code, with datasource.shadowDatabaseUrl set in prisma.config.ts."}),r.emit({type:"step",step:"app.schema",status:"skip",message:"Schema not checked against migrations (Prisma needs a shadow database; --verbose shows how)",data:{engine:n}});return}if(!i&&!t.resources?.d1?.length||n!=="drizzle")return;let s;try{s=(await Q(e,"drizzle-kit","drizzle-kit")).binPath}catch{o("drizzle-kit isn't installed",{fix:"add drizzle-kit to devDependencies"});return}let a=t.migrations?.config,c=await tt(e,a?[a]:et);if(!c){o(a?`no ${a} (migrations.config)`:"no drizzle.config.ts",a?{}:{detail:'An app whose drizzle config lives elsewhere sets migrations.config to its path; an app that writes its SQL by hand sets migrations.engine to "d1-sql".'});return}r.emit({type:"step",step:"app.schema",status:"start",message:"Checking the schema..."});let d=y.resolve(e,t.migrations?.dir??"drizzle");ke(e,".everyapp/"),await b.mkdir(y.join(e,".everyapp"),{recursive:!0});let u=await b.mkdtemp(y.join(e,".everyapp","schema-check-")),w=J({sync:()=>Qe(u,{recursive:!0,force:!0})});try{let g=y.join(u,"migrations");await b.cp(d,g,{recursive:!0}).catch(async E=>{if(E.code!=="ENOENT")throw E;await b.mkdir(g)});let p=new Set(await Ae(g)),f=y.join(u,"drizzle.config.ts");await b.writeFile(f,[`import config from ${JSON.stringify(c)};`,`export default { ...config, out: ${JSON.stringify(y.relative(e,g).split(y.sep).join("/"))} };`,""].join(`
|
|
16
|
+
`));let m=y.join(u,"report-failure.cjs");await b.writeFile(m,["const report = console.error;","console.error = (...args) => {"," if (args.some((arg) => arg instanceof Error)) process.exitCode = 1;"," report(...args);","};",""].join(`
|
|
17
|
+
`));let A=await Ze(process.execPath,["--require",m,s,"generate","--config",f],{cwd:e,stdin:"ignore",reject:!1,timeout:ve,env:{NODE_NO_WARNINGS:"1"}});if((await Ae(g)).filter(E=>!p.has(E)).length>0)throw new l("SCHEMA_DRIFT",`The schema has changes no migration covers
|
|
18
|
+
drizzle-kit would write a new migration for them. Nothing was migrated or uploaded.`,{rerun:"pnpm db:generate",rerunNote:"then run this again"});if(A.failed){let E=A.stderr.split(`
|
|
19
|
+
`).map(R=>R.trim()).filter(Boolean),x=E.find(R=>/^\w*Error\b/.test(R))??E.at(-1)??(A.timedOut?`no answer in ${ve/1e3} s`:`exit ${A.exitCode}`);throw new l("SCHEMA_CHECK_FAILED",`drizzle-kit couldn't compare the schema with the migrations
|
|
20
|
+
${x}. Nothing was migrated or uploaded.`,{rerun:"pnpm db:generate",rerunNote:"in a terminal; it asks about renamed columns and tables"})}r.emit({type:"step",step:"app.schema",status:"ok",message:"The schema matches the migrations."})}finally{await b.rm(u,{recursive:!0,force:!0}),w()}}async function tt(e,t){for(let r of t){let n=y.join(e,r);try{if((await b.stat(n)).isFile())return n}catch{}}return null}async function Ae(e){return(await b.readdir(e,{recursive:!0,withFileTypes:!0})).filter(r=>r.isFile()&&r.name.endsWith(".sql")).map(r=>y.relative(e,y.join(r.parentPath,r.name)))}var rt=6e5,Re={EVERYAPP_BUILD:"1"};async function nr({cwd:e,cf:t,buildCommand:r,verbose:n}){if(r){await ee(r,[],{cwd:e,env:{...process.env,...Re,NODE_OPTIONS:X(process.env.NODE_OPTIONS)},shell:!0,echo:n,what:"Build",code:"BUILD_FAILED"});return}await t.run({args:["build"],plane:"project",cwd:e,mode:"text",env:Re,timeoutMs:rt,...n?{onOutput:i=>void process.stderr.write(i)}:{}}).catch(i=>{throw i instanceof q?new l("BUILD_FAILED",["Build failed","cf build's last lines:",...G(i.stdout,i.stderr).map(o=>` ${o}`)].join(`
|
|
21
|
+
`)):i})}import nt from"node:fs/promises";import z from"node:path";var it=new Set(["text","json","secret","version-metadata","assets","d1","kv","r2","durable-object","workflow","worker","hyperdrive","ai"]);function Se(e,t){return e==="EVERY_APP_GATEWAY"&&t.worker===K&&t.exportName==="AppGateway"}function V(e,t){return e===t||e.startsWith(`${t}${$}`)}function st(e,t){let{workerName:r,helperWorkers:n=[]}=t,i=[];e.name!==r&&i.push(`its name is "${e.name}", not "${r}"`),i.push(...Oe(e));let o=e.env??{};for(let a of["EVERYAPP_IDENTITY_PUBLIC_KEYS","EVERYAPP_IDENTITY_ISSUER"])o[a]?.type!=="text"&&i.push(`${a} isn't built in`);let s=o.EVERYAPP_AUDIENCE;return(s?.type!=="text"||s.value!==r)&&i.push(`EVERYAPP_AUDIENCE isn't the Worker's name ("${r}")`),i.push(..._e(o,t,(a,c)=>Se(a,c)||n.includes(String(c.worker))),...De(e.exports??{},t.deletedDurableObjects??[],r)),i}function ot(e,t,r){let n=[];return e.name!==t&&n.push(`its name is "${e.name}", not "${t}"`),n.push(...Oe(e),..._e(e.env??{},r,Se),...De(e.exports??{},[],r.workerName)),n}function Oe(e){let t=[];e.workersDev!==!1&&t.push("workersDev isn't false"),e.previewUrls!==!1&&t.push("previewUrls isn't false"),e.domains?.length&&t.push("it declares domains (apps are served through the gateway)");for(let r of e.triggers??[])r.type!=="scheduled"&&t.push(r.type==="fetch"?"it declares routes (apps are served through the gateway)":`it declares a trigger of type "${String(r.type)}" (apps may only declare cron schedules)`);return e.env?.EVERYAPP_DEV&&t.push("EVERYAPP_DEV is set, which only `everyapp dev` may do"),t}function _e(e,{workerName:t,resources:r,helperWorkers:n=[],declared:i},o){let s=[],a=new Set([t,...n]),c=new Set(Object.values(r.d1??{}).map(p=>p.id)),d=new Set(Object.values(r.kv??{}).map(p=>p.id)),u=new Set(Object.values(r.hyperdrive??{}).map(p=>p.id)),w=Object.values(r.r2??{}).map(p=>p.name),g=i?.ai??[];for(let[p,f]of Object.entries(e)){if(!it.has(String(f.type))){s.push(`${p} is a ${String(f.type)} binding, which Every App apps can't use`);continue}switch(f.type){case"worker":o(p,f)||s.push(`${p} binds Worker "${String(f.worker)}"; apps may only bind the gateway's AppGateway and, from the app's own Worker, its helper Workers`);break;case"durable-object":a.has(String(f.worker))||s.push(`${p} binds another Worker's Durable Object ("${String(f.worker)}")`);break;case"d1":c.has(String(f.id))||s.push(`${p} isn't a D1 database the deploy provisioned`);break;case"kv":d.has(String(f.id))||s.push(`${p} isn't a KV namespace the deploy provisioned`);break;case"hyperdrive":u.has(String(f.id))||s.push(`${p} isn't a Hyperdrive config the deploy provisioned`);break;case"ai":g.includes(p)||s.push(g.length>0?`${p} is a Workers AI binding, which isn't one of the app's in resources.ai (${g.join(", ")})`:`${p} is a Workers AI binding, which everyapp.config.ts doesn't declare; list it in resources.ai`);break;case"r2":{let m=String(f.name??"");w.length>0?w.includes(m)||s.push(`${p} is bucket "${m}", which isn't one of the app's buckets in resources.r2 (${w.join(", ")})`):V(m,t)||s.push(`${p} is bucket "${m}"; an app's buckets are named after its Worker (${t} or ${t}${$}<name>)`);break}case"workflow":{let m=String(f.name??"");(!a.has(String(f.worker))||!V(m,t))&&s.push(`${p} binds Workflow "${m}" of Worker "${String(f.worker)}"; an app binds only its own Workflows, named after its Worker (${t}${$}<name>)`);break}}}return s}function De(e,t,r){let n=[];for(let[i,o]of Object.entries(e))if(o.type!=="worker"){if(o.type==="workflow"){let s=String(o.name??"");V(s,r)||n.push(`Workflow ${i} is named "${s}"; an app's Workflows are named after its Worker (${r}${$}<name>)`);continue}if(o.type!=="durable-object"){n.push(`export ${i} is a ${String(o.type)}, which Every App apps can't declare`);continue}switch(o.container!==void 0&&n.push(`Durable Object class ${i} is backed by a container, which Every App apps can't run`),o.state??"created"){case"created":case"renamed":break;case"deleted":t.includes(i)||n.push(`Durable Object class ${i} is marked deleted, which deletes its data; remove it from everyapp.config.ts and deploy with --allow-delete-durable-object-data instead`);break;case"transferred":n.push(`Durable Object class ${i} would move its data to Worker "${String(o.transferredTo)}"`);break;case"expecting-transfer":n.push(`Durable Object class ${i} would take the data of Worker "${String(o.transferFrom)}"'s class`);break;default:n.push(`Durable Object class ${i} has state "${o.state}", which everyapp doesn't deploy`)}}return n}async function ur({cwd:e,inputs:t}){if(!await I(z.join(e,ae)))throw new l("APP_POLICY","The app's Build Output isn't a production build. The manifest's build command must run `cf build` (production by default).");let r=await pt(e),n=t.helperWorkers??[],i=[],o=r.get(D);if(!o)throw new l("APP_POLICY","The app's Build Output has no default Worker. Build it from everyAppWorker() in cloudflare.config.ts.");i.push(...st(o.config,t));for(let[a,{config:c}]of r){if(a===D)continue;let d=String(c.name);if(!n.includes(d)){i.push(`the build has a Worker "${d}" that everyapp.config.ts doesn't declare in workers`);continue}i.push(...ot(c,d,t).map(u=>`${d}: ${u}`))}for(let a of n)[...r.values()].some(({config:c})=>c.name===a)||i.push(`the build has no Worker ${a}, which everyapp.config.ts declares; add it to the Vite plugin's auxiliaryWorkers with everyAppAuxiliaryWorker()`);if(i.length>0)throw new l("APP_POLICY",`The built Worker can't be deployed as an Every App app:
|
|
22
|
+
- ${i.join(`
|
|
23
|
+
- `)}
|
|
24
|
+
Build it from everyAppWorker() in cloudflare.config.ts.`);let s={};for(let[a,{config:c,directory:d}]of r){if(a!==D){let u=String(c.name);s[u]=$e(c,u)}if(c.manifest){let u={...c.manifest.modules??{}};for(let w of await le(z.join(d,"bundle")))u[w]={type:"sourcemap"};c.manifest={...c.manifest,modules:u}}ce(c),await nt.writeFile(z.join(d,"worker.config.json"),`${JSON.stringify(c,null,2)}
|
|
25
|
+
`)}return{workflows:$e(o.config,t.workerName),helperWorkflows:s,r2Buckets:[...new Set([...r.values()].flatMap(({config:a})=>at(a)))].sort()}}function at(e){let t=e.env??{};return Object.values(t).filter(r=>r?.type==="r2"&&typeof r.name=="string").map(r=>r.name)}function $e(e,t){let r=[...Object.values(e.exports??{}).filter(n=>n.type==="workflow").map(n=>String(n.name)),...Object.values(e.env??{}).filter(n=>n.type==="workflow"&&n.worker===t).map(n=>String(n.name))];return[...new Set(r)]}async function pt(e){let t=new Map;for await(let{name:r,config:n,directory:i}of pe(e))t.set(r,{config:n,directory:i});return t}export{ke as a,Jt as b,nr as c,ur as d,M as e,xt as f,Nt as g,Wt as h};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import{a as ue,d as fe,f as we,h as G,j as ge,k as he,p as ve,q as be}from"./chunk-6OGVO7QK.js";import{a as ke,c as De,d as M}from"./chunk-N5GQLGEC.js";import{b as ye,c as T}from"./chunk-W3JCQHHU.js";import{b as C,c as P,e as ie,f as le}from"./chunk-ZFCUH5PK.js";import{b as ce}from"./chunk-23HJ5I2A.js";import{a as pe,c as de,e as me}from"./chunk-6PGUCTJ6.js";import{h as Q}from"./chunk-HOUHG236.js";import{V as se,d as ee,f as te,g as ae,h as re,i as oe,k as ne,l as _}from"./chunk-RMF4YGD6.js";import{a as X}from"./chunk-T2GD7RHS.js";import{Bb as h,Eb as F,Fb as V,Gb as K,Hb as Y,Qb as Z,Xb as A,Zb as q,_b as J,c as R,d as S,f as O,qb as D,vb as j}from"./chunk-LYNBZ7RV.js";import{execFile as x}from"node:child_process";import y from"node:fs/promises";import k from"node:path";import{promisify as L}from"node:util";var N=["apps/every-app-gateway","packages/sdk","packages/perimeter","packages/toolbus","pnpm-workspace.yaml","pnpm-lock.yaml"],_e=3;function gt({out:e,verbose:t}){let a=ce();return{describe:()=>Me(a),open:()=>Le({root:a,out:e,verbose:t})}}function Ge(e){return k.join(e,"node_modules",".cache","everyapp")}async function W(e){let t;try{({stdout:t}=await L(x)("git",["ls-files","-z","--cached","--others","--exclude-standard","--",...N],{cwd:e,maxBuffer:64*1024*1024}))}catch{return null}let a=[...new Set(t.split("\0").filter(Boolean))];return a.length>0?we(e,a):null}async function Re(e){try{let{stdout:t}=await L(x)("git",["log","-1","--format=%ct","--",...N],{cwd:e}),a=Number.parseInt(t.trim(),10);return Number.isFinite(a)?a*1e3:null}catch{return null}}async function Te(e,t){let a=r=>L(x)("git",r,{cwd:e}),o=()=>a(["diff","--quiet",`gateway-v${t}`,"HEAD","--",...N]).then(()=>!1,()=>!0);try{let[r,l]=await Promise.all([a(["rev-parse","--short","HEAD"]),a(["status","--porcelain","--",...N])]),n=l.stdout.trim()!=="";return!n&&!await o()?null:{hash:r.stdout.trim(),uncommittedChanges:n}}catch{return null}}async function Me(e){let t=k.join(e,"apps","every-app-gateway"),a=async c=>JSON.parse(await y.readFile(k.join(t,c),"utf8")),[o,r,l,n]=await Promise.all([W(e),Re(e),a("drizzle/meta/_journal.json"),a("package.json")]),s=String(n.version??"unknown"),i=await Te(e,s);return{treeSha256:o,origin:{kind:"checkout"},...i?{commit:i}:{},version:s,order:{schema:ge(l.entries??[]),committedAt:r??Date.now()}}}async function We({root:e,out:t,build:a,keep:o=_e}){let[r,l]=await Promise.all([W(e),Re(e)]),n=Ge(e),s=r?k.join(n,`${r}.tar.gz`):null,i={origin:{kind:"checkout"},treeSha256:r,committedAt:l};if(s&&await A(s))try{let m=await G(s,i),d=new Date;return await y.utimes(s,d,d),t.emit({type:"step",step:"gateway.release",status:"ok",message:`Using the Gateway ${m.manifest.version} built from this checkout before (${r.slice(0,12)}).`,data:{cached:!0,treeSha256:r,release:m.manifest.version}}),m}catch{await y.rm(s,{force:!0})}let c=await a();s&&await W(e)===r&&await xe(c,s,o);let p=await G(c,{origin:{kind:"checkout"},treeSha256:s&&await A(s)?r:null,committedAt:l});return t.emit({type:"step",step:"gateway.release",status:"ok",message:`Built the Gateway ${p.manifest.version} from this checkout.`,data:{cached:!1,treeSha256:p.source.treeSha256,release:p.manifest.version}}),p}async function xe(e,t,a){let o=k.dirname(t);await y.mkdir(o,{recursive:!0});let r=`${t}.${process.pid}.partial`;await y.copyFile(e,r),await y.rename(r,t);let l=await Promise.all((await y.readdir(o)).filter(n=>n.endsWith(".tar.gz")).map(async n=>({file:k.join(o,n),usedAt:(await y.stat(k.join(o,n))).mtimeMs})));for(let{file:n}of l.sort((s,i)=>i.usedAt-s.usedAt).slice(a))n!==t&&await y.rm(n,{force:!0})}function Le({root:e,out:t,verbose:a}){return We({root:e,out:t,build:()=>ze(e,t,a??!1)})}async function ze(e,t,a,o=process.env){let r=k.join(e,"apps","every-app-gateway");t.emit({type:"step",step:"gateway.release",status:"start",message:"Building the Gateway from this checkout (usually 1\u20132m)",data:{dir:r}});let l=(n,s)=>J("pnpm",n,{cwd:s,env:{...o,NODE_OPTIONS:Z(o.NODE_OPTIONS)},echo:a,what:"Building the Gateway",code:"GATEWAY_BUILD_FAILED",fix:"fix the build error above, then run this again",logName:"gateway-build"});return await l(["--filter","@every-app/sdk","build"],e),await l(["run","build:release"],r),k.join(r,ue)}var Be=`SELECT apps.app_slug, apps.worker_name, apps.hostname, apps.status,
|
|
2
|
+
organization_keys.org_key
|
|
3
|
+
FROM apps LEFT JOIN organization_keys
|
|
4
|
+
ON organization_keys.organization_id = apps.organization_id
|
|
5
|
+
WHERE apps.status IN ('binding', 'active', 'disabled')
|
|
6
|
+
AND apps.worker_name IS NOT NULL AND apps.hostname IS NOT NULL
|
|
7
|
+
ORDER BY apps.worker_name`;function Se(e){let t=new Map;return a=>{let o=t.get(a);return o||(o=P(e,a).then(r=>r!==null),t.set(a,o)),o}}var Ie=4;async function z(e,t){let[a=[]]=await e.run([{sql:Be}]),o=[],r=[];for(let c of a){let p={appId:String(c.app_slug),workerName:String(c.worker_name),hostname:String(c.hostname),status:String(c.status)};j({appId:p.appId,workerName:p.workerName,orgKey:typeof c.org_key=="string"?c.org_key:null})?o.push(p):r.push({appId:p.appId,workerName:p.workerName})}let l=[];for(let c=0;c<o.length;c+=Ie){let p=o.slice(c,c+Ie);l.push(...await Promise.all(p.map(m=>t(m.workerName))))}let n=o.filter((c,p)=>l[p]),s=o.filter((c,p)=>!l[p]).map(({appId:c,workerName:p})=>({appId:c,workerName:p})),i=[...new Set(n.map(c=>c.workerName))].sort();return{apps:n,appWorkers:i,appHosts:[...new Set(n.map(c=>c.hostname.toLowerCase()))].sort(),skipped:r,missing:s}}import Ze from"node:fs/promises";import qe from"node:os";import Je from"node:path";var He=new Set(["A","AAAA","CNAME","NS"]),E=100,Ue=95;async function B(e){let t=new Set(e.liveDomains),a=[...new Set(e.domains)].filter(c=>!t.has(c));if(a.length===0)return[];let{out:o,step:r,zone:l}=e,n=new Set(e.domains).size;if(n>E)throw new h("ZONE_CUSTOM_DOMAIN_LIMIT",`${l.name} would go over Cloudflare's ${E} Custom Domains per zone
|
|
8
|
+
The Gateway alone needs ${n} there, before other Workers' domains.`,{fix:`delete apps you no longer use (${R} delete <app>), or install a second Gateway on another domain`,data:{total:n,limit:E}});n>=Ue&&o.emit({type:"warning",code:"ZONE_CUSTOM_DOMAIN_LIMIT_NEAR",step:r,message:`${l.name} is close to Cloudflare's ${E} Custom Domains per zone
|
|
9
|
+
It will hold at least ${n}, and other Workers' domains there count too.`,data:{total:n,limit:E}});let s=await Fe(e,a),i=a.filter(c=>!s.includes(c));return!e.cfAsks&&i.length>0&&o.emit({type:"warning",code:"CUSTOM_DOMAIN_OWNER_UNCHECKED",step:r,message:`If another Worker already serves ${i.length===1?i[0]:`any of ${i.join(", ")}`}, it will be replaced by this deployment.`,data:{hosts:i}}),a}function je(e){let t;return()=>t??=C(e,D).then(a=>new Set(a)).catch(a=>{if(a instanceof K)return new Set;throw a})}async function Ae({cf:e,zone:t,forceDns:a},o){try{return await ke(e,t.id,o)}catch(r){if(!Y(r,"auth"))throw r;if(a)return[];throw new h("DNS_UNREADABLE",`Can't read ${t.name}'s DNS records with this Cloudflare login
|
|
10
|
+
So it can't tell whether publishing ${o} would replace one.`,{fix:"give the API token Zone \u2192 DNS \u2192 Read",rerun:S(["--force-dns"]),authorize:!0})}}async function Fe(e,t){let{cf:a,out:o,step:r,zone:l,forceDns:n}=e,s=[],i=[],c=je(a),p=!1,m=f=>f.filter(u=>He.has(u.type.toUpperCase())),d=new Map;for(let f of t){let u=await Ae(e,f),$=m(u);if($.length>0&&(await c()).has(f)){o.emit({type:"progress",step:r,message:`${f} is already this Gateway's Custom Domain (an earlier run published it, then stopped)`,data:{host:f}}),i.push(f);continue}if($.length>0&&s.push({host:f,records:$.map(M).join(", ")}),u.length===0&&f!==l.name){let I=De(f);d.has(I)||d.set(I,Ae(e,I));let U=m(await d.get(I));U.length>0&&(s.push({host:f,records:`${U.map(M).join(", ")}, through ${I}`}),p=!0)}}if(s.length===0)return i;let w=s.length===1,v=w?`${s[0].host} already points somewhere else`:`${s.length} hostnames already point somewhere else`,b=w?`Its DNS record: ${s[0].records}.`:`${s.map(f=>`${f.host} (${f.records})`).join("; ")}.`,g=p?" A wildcard record stays, and keeps answering every other name.":"";if(n)return o.emit({type:"warning",code:"DNS_RECORD_REPLACED",step:r,message:w?`Replacing ${s[0].host}'s DNS record (${s[0].records})${g?`
|
|
11
|
+
${g.trim()}`:""}`:`Replacing the DNS records of ${s.length} hostnames
|
|
12
|
+
${b}${g}`,data:{conflicts:s}}),i;throw new h("DNS_RECORD_CONFLICT",`${v}
|
|
13
|
+
${b} Publishing ${w?"it replaces the record":"them replaces those records"}.${g}`,{fix:`delete ${w?"the record":"the records"} in Cloudflare (${l.name} \u2192 DNS), or use another name`})}async function Ct({cf:e,out:t,install:a,hostname:o,forceDns:r,cfAsks:l}){let n=!ye(o,a.appBaseDomain),s=!n&&!a.liveDomains.includes(o);return s&&await B({cf:e,out:t,step:"app.domain",zone:{id:a.zoneId,name:a.zoneName},domains:[...a.liveDomains,o],liveDomains:a.liveDomains,forceDns:r,cfAsks:l}),{outsideBase:n,newHost:s}}import Ve from"node:fs/promises";import Ke from"node:path";async function Ee({cf:e,databaseId:t,accountId:a,dir:o,registry:r,target:l,restoreCommand:n}){let{nested:s,count:i}=await Ye(o),c=await ae({cf:e,databaseId:t,dir:o,nested:s});if(c.length===0)return{applied:[],fresh:!1,rollback:null};let p=c.length===i,m=null;if(p)await me(r,l);else{let d=await ee(e,t),{email:w}=await X(e);await de(r,{target:l,databaseId:t,bookmark:d,migrations:c,createdAt:Date.now(),createdBy:se(w,a).actor}),m={restoreCommand:n,rollbackCommand:te(t,d,a)}}try{return{applied:await re({cf:e,databaseId:t,dir:o,nested:s}),fresh:p,rollback:m}}catch(d){throw new h("MIGRATION_FAILED",["Database migration failed",V(d),"Nothing was uploaded; the version that's serving keeps running.",...m?[`To roll the database back to before this run: ${m.restoreCommand}`]:[]].join(`
|
|
14
|
+
`),{data:{fix:"correct the migration",...m?{rollbackCommand:m.rollbackCommand}:{}}})}}async function Ye(e){let t=await Ve.readdir(e,{withFileTypes:!0}).catch(()=>[]),a=t.filter(r=>r.isDirectory()&&r.name!=="meta"),o=(await Promise.all(a.map(r=>A(Ke.join(e,r.name,"migration.sql"))))).filter(Boolean).length;return o>0?{nested:!0,count:o}:{nested:!1,count:t.filter(r=>r.isFile()&&r.name.endsWith(".sql")).length}}function Ce(e){return e?` Restore point saved; to undo: ${e.restoreCommand}`:""}function Pe(e){return{applied:e.applied,fresh:e.fresh,...e.rollback}}var Xe={deploy:"gateway.deploy",upgrade:"gateway.upgrade",reconcile:"gateway.reconcile"};function Qe(e){return{...e.source,version:e.manifest.version,sha256:e.manifest.sha256,minCli:e.manifest.minCli}}function et(e,t){return t.liveVersionId===null?!1:e.manifest.sha256===t.releaseSha256||e.source.treeSha256!==null&&e.source.treeSha256===t.sourceTreeSha256}function tt(e,t){return e.sha256&&e.sha256===t.releaseSha256||e.treeSha256&&e.treeSha256===t.sourceTreeSha256?!1:he(e.order,t.releaseOrder)<0}async function sa(e,t){Ne(await t(),e)}function Ne(e,t,a={}){if(tt(e,t))throw at(e,t,a)}function at(e,t,{allowDowngradeFlag:a=!1}={}){let o=e.version===t.releaseVersion,r=c=>new Date(c.committedAt).toLocaleDateString("en-US",{month:"short",day:"numeric",timeZone:"UTC"}),l=e.origin.kind==="checkout",n=l?"This checkout's Gateway":`The Gateway from ${fe(e.origin)}`,s=o?`${n} (${e.version} from ${r(e.order)}) is older than the live one (from ${r(t.releaseOrder)})`:`${n} (${e.version}) is older than the live one (${t.releaseVersion})`,i={live:t.releaseVersion,candidate:e.version};return a?new h("DOWNGRADE_REFUSED",s,{fix:l?"git pull, then run setup again":"pass --release a newer Gateway release",rerun:S(["--allow-downgrade"]),authorize:!0,data:i}):new h("DOWNGRADE_REFUSED",s,{fix:l?"git pull":"run everyapp from a checkout at least as new",rerun:S(),rerunNote:"after that",data:i})}var H=class{constructor(t,a){this.options=t;this.liveDomains=a;this.checked=new Set(t.checkedDomains)}checked;warned=new Set;domainsFor(t){let{appBaseDomain:a,gatewayHost:o,out:r}=this.options,l=T(t,a),s=t.filter(i=>!l.includes(i)).filter(i=>!this.warned.has(i));if(s.length>0){r.emit({type:"warning",code:"APP_HOST_OUTSIDE_BASE",message:`Skipping ${s.join(", ")}: ${s.length===1?"it isn't":"they aren't"} under ${a}
|
|
15
|
+
Apps live one level below the Gateway's domain (<name>.${a}).`,data:{hosts:s}});for(let i of s)this.warned.add(i)}return ve({gatewayHost:o,appHosts:l})}async check(t){await B({cf:this.options.cf,out:this.options.out,step:"gateway.domains",zone:this.options.zone,domains:t,liveDomains:[...this.liveDomains,...this.checked],forceDns:this.options.forceDns,cfAsks:this.options.interactive&&this.options.out.verbose});for(let a of t)this.checked.add(a)}};async function ia(e){let{cf:t,reason:a,release:o,db:r}=e,l=e.heldLease?null:await Q(e,Xe[a]),n=e.heldLease??l,s=null;try{let i=await ne(r);i&&!e.allowDowngrade&&Ne(Qe(o),i,{allowDowngradeFlag:e.allowDowngradeFlag});let c=i!==null&&i.liveVersionId===null&&(await C(t,D)).includes(i.gatewayHost.toLowerCase());(!i||i.liveVersionId===null)&&await _(r,Oe(e,{liveVersionId:null,liveDomains:[],liveAppWorkers:[],jwtPublicKey:null,deploymentMode:null}));let p=new H(e,i?.liveDomains??[]),m=Se(t),d=i!==null&&et(o,i);if(a!=="reconcile"||!d){await $e(e,{appWorkers:[],appHosts:[]},async()=>{});let v=await z(r,m).catch(()=>null);await p.check(p.domainsFor(v?.appHosts??[])),c?e.out.emit({type:"step",step:"gateway.resume",status:"ok",message:`Replacing the Gateway an earlier run uploaded at ${i.gatewayHost}
|
|
16
|
+
That run stopped before it could finish; nothing uses that upload yet.`,data:{gatewayHost:i.gatewayHost}}):await le({cf:t,workerName:D,shownAs:"the Gateway",recordedVersionIds:[i?.liveVersionId],interactive:e.interactive,confirm:e.confirm,change:{question:`Replace it with ${o.manifest.version}?`,effect:"If it runs a newer release (an upgrade that stopped before recording itself), this puts an older one back."}}),await n.check(),s=await rt(e)}let w=i?.deploymentMode??e.deploymentMode;return await ot({...e,deploymentMode:w},p,m,{liveDomains:i?.liveDomains??[],liveVersionId:i?.liveVersionId??null},n)}catch(i){throw F(i,s)}finally{await l?.release()}}async function rt({cf:e,out:t,resources:a,release:o,accountId:r,db:l}){t.emit({type:"step",step:"gateway.migrations",status:"start",message:"Migrating the Gateway's database"});let n=await Ee({cf:e,databaseId:a.d1Id,accountId:r,dir:Je.join(o.dir,"drizzle"),registry:l,target:pe,restoreCommand:`${R} db restore --gateway`});return t.emit({type:"step",step:"gateway.migrations",status:"ok",message:n.fresh?"Database created":n.applied.length>0?`Applied ${O(n.applied.length,"migration")}.${Ce(n.rollback)}`:"Database up to date",data:Pe(n)}),n.rollback}async function ot(e,t,a,o,r){let{cf:l,out:n,release:s,db:i,gatewayHost:c}=e,p=await P(l,D)===null,m=p||o.liveVersionId===null,d=await z(i,a);for(let u of d.skipped)n.emit({type:"warning",code:"APP_NOT_BOUND",message:`Skipping ${u.appId}: its Worker isn't the one everyapp registered
|
|
17
|
+
So the Gateway won't route to it.`,data:{appId:u.appId,workerName:u.workerName,fix:`deploy ${u.appId} again, or remove it with ${R} delete ${u.appId}`}});for(let u of d.missing)n.emit({type:"warning",code:"APP_WORKER_MISSING",message:`Skipping ${u.appId}: its Worker is missing
|
|
18
|
+
It was deleted by hand or never uploaded, so the Gateway won't route to it.`,data:{appId:u.appId,workerName:u.workerName,fix:`deploy ${u.appId} again, or remove it with ${R} delete ${u.appId}`}});let w=t.domainsFor(d.appHosts);await t.check(w),await r.check(),n.emit({type:"step",step:"gateway.deploy",status:"start",message:`Uploading Gateway ${s.manifest.version} with ${O(d.appWorkers.length,"app")}`,data:{appWorkers:d.appWorkers,domains:w}});let v=e.deploymentMode??"self_hosted",b=m?oe({gatewayUrl:`https://${c}`,accountId:e.accountId,deploymentMode:v}):null,g=await nt(e,d,w,{before:o,secrets:{...b?.secrets,...e.stagedSecrets},jwtPublicKey:b?.jwtPublicKey??null,deploymentMode:b?v:null}),f=w.filter(u=>!t.liveDomains.includes(u));return n.emit({type:"step",step:"gateway.deploy",status:"ok",message:g.versionId?`Uploaded version ${g.versionId}`:"Uploaded",data:{versionId:g.versionId}}),{versionId:g.versionId,firstDeploy:p,appWorkers:d.appWorkers,domains:w,newHosts:f}}function nt(e,t,a,{before:o,secrets:r,jwtPublicKey:l,deploymentMode:n}){return $e(e,t,s=>ie({cf:e.cf,cwd:s,workerName:D,accountId:e.accountId,message:`everyapp ${e.cliVersion} gateway ${e.release.manifest.version} (${e.reason})`,secrets:r,interactive:e.interactive,attach:e.out.verbose,cliCf:!0,out:e.out,step:"gateway.deploy",onUploaded:(i,c)=>st(e,t,i,c?{liveDomains:a}:o,{jwtPublicKey:l,deploymentMode:n})}))}async function $e(e,t,a){let{dir:o,cleanup:r}=await q("gateway-deploy-");try{return await Ze.cp(e.release.dir,o,{recursive:!0}),await be(o,{d1Id:e.resources.d1Id,oauthKvId:e.resources.oauthKvId,release:{version:e.release.manifest.version,sha256:e.release.manifest.sha256},gatewayHost:e.gatewayHost,appBaseDomain:e.appBaseDomain,appWorkers:t.appWorkers,appHosts:T(t.appHosts,e.appBaseDomain)}),await a(o)}finally{await r()}}function st(e,t,a,o,r){return _(e.db,Oe(e,{liveVersionId:a,liveDomains:o.liveDomains,liveAppWorkers:t.appWorkers,...r}))}function Oe(e,t){return{accountId:e.accountId,zoneId:e.zone.id,zoneName:e.zone.name,gatewayHost:e.gatewayHost,appBaseDomain:e.appBaseDomain,oauthKvId:e.resources.oauthKvId,releaseVersion:e.release.manifest.version,releaseSha256:e.release.manifest.sha256,releaseOrder:e.release.source.order,sourceTreeSha256:e.release.source.treeSha256,...t,updatedAt:Date.now(),updatedBy:`everyapp ${e.cliVersion} on ${qe.hostname()}`}}export{gt as a,Me as b,B as c,Ct as d,Ee as e,Ce as f,Pe as g,Se as h,z as i,Qe as j,et as k,tt as l,sa as m,Ne as n,ia as o};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Bb as s,Yb as e,nb as o}from"./chunk-LYNBZ7RV.js";import p from"node:fs/promises";import a from"node:path";import{pathToFileURL as c}from"node:url";import{createJiti as m}from"jiti";async function y(r){return g(a.join(r,"everyapp.config.ts"),{message:"No everyapp.config.ts in this directory",fix:"run this from the app's directory"})}async function w(r){try{await p.access(a.join(r,"everyapp.config.ts"))}catch(i){if(e(i))return null;throw i}return y(r)}async function g(r,i={message:`No manifest at ${r}`}){try{await p.access(r)}catch(n){throw e(n)?new s("MANIFEST_NOT_FOUND",i.message,{fix:i.fix}):n}let f=await m(c(r).href).import(r,{default:!0});return o(f,l)}var l={unknownCapabilities:"accept"};function h(r,i){let t=i?.binding??r[0];if(!r.includes(t))throw new Error(`Manifest migrations binding "${t}" is not declared in resources.d1.`);return t}function N(r){return r.migrations?.dir??"drizzle"}export{y as a,w as b,g as c,l as d,h as e,N as f};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import{b as k}from"./chunk-T2GD7RHS.js";import{Bb as S,Fb as C,Jb as M,Pb as U,c as q,g as H,i as h,jc as p}from"./chunk-LYNBZ7RV.js";import{randomBytes as J}from"node:crypto";import R from"node:os";var Z={["app.deploy"]:{noun:"deploy",of:e=>`a deploy${e?` of ${e}`:""}`},["app.register"]:{noun:"registration",of:e=>`a registration${e?` of ${e}`:""}`},["app.secrets"]:{noun:"secret change",of:e=>`a secret change${e?` on ${e}`:""}`},["app.email"]:{noun:"email change",of:e=>`an email change${e?` on ${e}`:""}`},["gateway.deploy"]:{noun:"Gateway install",of:()=>"a Gateway install"},["gateway.upgrade"]:{noun:"Gateway upgrade",of:()=>"a Gateway upgrade"},["gateway.reconcile"]:{noun:"Gateway update",of:()=>"an update of the Gateway's apps"},["gateway.secrets"]:{noun:"Gateway settings change",of:()=>"a change to the Gateway's settings"},["access.sync"]:{noun:"Cloudflare Access update",of:()=>"an update of Cloudflare Access"},["db.restore"]:{noun:"database restore",of:e=>`a restore of ${e?`${e}'s database`:"the Gateway's database"}`}},ee=`CREATE TABLE IF NOT EXISTS _everyapp_deploy_lease (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
holder TEXT NOT NULL,
|
|
4
|
+
purpose TEXT NOT NULL,
|
|
5
|
+
acquired_at INTEGER NOT NULL,
|
|
6
|
+
expires_at INTEGER NOT NULL,
|
|
7
|
+
app TEXT,
|
|
8
|
+
deployer TEXT,
|
|
9
|
+
machine TEXT
|
|
10
|
+
)`,B=["app","deployer","machine"],te=`INSERT INTO _everyapp_deploy_lease (id, holder, purpose, acquired_at, expires_at, app, deployer, machine)
|
|
11
|
+
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)
|
|
12
|
+
ON CONFLICT(id) DO UPDATE SET holder = excluded.holder, purpose = excluded.purpose,
|
|
13
|
+
acquired_at = excluded.acquired_at, expires_at = excluded.expires_at,
|
|
14
|
+
app = excluded.app, deployer = excluded.deployer, machine = excluded.machine
|
|
15
|
+
WHERE _everyapp_deploy_lease.expires_at < ?4 OR _everyapp_deploy_lease.holder = ?2
|
|
16
|
+
RETURNING holder`,ae="UPDATE _everyapp_deploy_lease SET expires_at = ? WHERE id = ? AND holder = ? RETURNING holder",g=3*6e4,re=3e4,W=2e4,se=5*6e4,ne=5e3;function oe(){return R.hostname().split(".")[0]||R.hostname()}function ie(){return`${R.hostname()}:${process.pid}:${J(4).toString("hex")}`}var X=`SELECT id, holder, purpose, acquired_at, expires_at, ${B.join(", ")} FROM _everyapp_deploy_lease`,$=new WeakMap;function b(e){let t=$.get(e);return t||(t=(async()=>{let[,r=[]]=await e.run([{sql:ee},{sql:"PRAGMA table_info(_everyapp_deploy_lease)"}]),u=new Set(r.map(s=>String(s.name))),n=B.filter(s=>!u.has(s));n.length>0&&await e.run(n.map(s=>({sql:`ALTER TABLE _everyapp_deploy_lease ADD COLUMN ${s} TEXT`})))})(),t.catch(()=>$.delete(e)),$.set(e,t)),t}function F(e){let t=String(e.holder);return{id:String(e.id),holder:t,purpose:String(e.purpose),acquiredAt:Number(e.acquired_at),expiresAt:Number(e.expires_at),app:h(e.app),deployer:h(e.deployer),machine:h(e.machine)??t.split(":")[0].split(".")[0]}}async function pe(e,t){await b(e);let[r=[]]=await e.run([{sql:`${X} WHERE id = ?`,params:[t]}]);return r[0]?F(r[0]):null}async function Ae(e,t=Date.now()){await b(e);let[r=[]]=await e.run([{sql:`${X} WHERE expires_at > ? ORDER BY acquired_at`,params:[t]}]);return r.map(F)}var D=e=>Z[e.purpose];function x(e){return D(e)?.of(e.app)??"another run"}function Y(e,t=Date.now()){return`${e.deployer?`${e.deployer} on `:""}${e.machine}, started ${p(t-e.acquiredAt)} ago`}function Le(e,t=Date.now()){return`${x(e)} from ${Y(e,t)}`}async function j({db:e,id:t,purpose:r,app:u,out:n,step:s,now:o=Date.now,sleep:z=l=>new Promise(A=>setTimeout(A,l)),waitMs:_=se,heartbeatMs:v=re}){let l=ie(),A=o()+_,d=t==="gateway"?"the Gateway":u??"this app";await b(e);let I,m=null;for(;;){let i=o(),[c=[]]=await e.run([{sql:te,params:[t,l,r,i,i+g,u??null,k(),oe()]}]);if(c[0]?.holder===l){I=i;break}let a=await pe(e,t);if(o()>=A)throw new S("LEASE_HELD",a?`${H(x(a))} is still running after ${p(_)}
|
|
17
|
+
It's from ${a.deployer?`${a.deployer} on `:""}${a.machine}. If it stopped without cleaning up, it's released within ${p(a.expiresAt-o())}.`:`Couldn't take hold of ${d} after ${p(_)}`,{retryable:!0,rerunNote:`once it's done (${q} status shows it)`,...a?{data:{holder:a}}:{}});a&&(m=a,n.emit({type:"progress",step:s,message:`Waiting for ${x(a)} to finish (${Y(a,o())})`,data:{holder:a}})),await z(ne)}m&&n.emit({type:"step",step:s,status:"ok",message:`The other ${D(m)?.noun??"run"} finished.`,data:{waitedFor:D(m)?.noun??"run"}});let L=I,f=!1,T=!1,y=!1,w=null,N=i=>n.emit({type:"warning",code:"LEASE_HEARTBEAT",step:s,message:i}),K=async()=>{if(f||y)return;let i=o();try{let[c=[]]=await e.run([{sql:ae,params:[i+g,t,l]}],{timeoutMs:W});c.length>0?L=i:f=!0}catch(c){if(y)return;let a=o()-L;if(a>g/2){f=!0;return}let V=c instanceof M?`The database didn't answer within ${p(W)}`:C(c);N(`Can't reach Cloudflare to keep hold of ${d} (${p(a)} so far)
|
|
18
|
+
${V}. Another run can take over in ${p(L+g-o())} if this continues.`)}},P=()=>w??=K().finally(()=>{w=null}),E=v>0?setInterval(()=>{P().then(()=>{!f||y||T||(T=!0,clearInterval(E),N(`This run lost its hold on ${d}
|
|
19
|
+
Its hold expired, and another run may have started. It stops before its next change.`))})},v):void 0;E?.unref();let G=()=>e.run([{sql:"DELETE FROM _everyapp_deploy_lease WHERE id = ? AND holder = ?",params:[t,l]}]),O=()=>{y=!0,clearInterval(E)},Q=U({label:`freeing ${d} for other runs`,async:async()=>{O(),await G()}});return{id:t,holder:l,async check(){if(await w,await P(),f)throw T=!0,clearInterval(E),new S("LEASE_LOST",`Stopped: this run lost its hold on ${d}
|
|
20
|
+
Its hold expired, so it stopped before its next change to avoid overlapping another run.`,{retryable:!0})},async release(){O(),await G(),Q()}}}var le="gateway",Te="access";function ue(e){return`app:${e}`}function we({db:e,out:t},{workerName:r,appId:u,purpose:n}){return j({db:e,id:ue(r),purpose:n,app:u,out:t,step:"app.lease"})}function Se(e,t){return j({db:e.db,id:le,purpose:t,out:e.out,step:"gateway.lease",waitMs:e.leaseWaitMs,...e.sleep?{sleep:e.sleep}:{}})}export{Ae as a,Le as b,j as c,le as d,Te as e,ue as f,we as g,Se as h};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import{a as Pe,b as Ht,e as Bt}from"./chunk-WOVS3GV5.js";import{a as se,b as Oe,c as Me,d as j,e as Pt,f as ue,g as Lt,h as Ut,j as me,k as xt,l as Ce,p as Gt}from"./chunk-OM2HDWVP.js";import{c as zt,f as Ft}from"./chunk-ZFCUH5PK.js";import{a as ce,c as ut}from"./chunk-4JRIS6S6.js";import{b as Ct,e as ve}from"./chunk-ZECBN24L.js";import{g as wt,h as yt}from"./chunk-HOUHG236.js";import{$ as De,B as q,W as te,X as Ie,Y as ne,Z as D,_ as re,aa as $t,ca as Tt,da as kt,ea as be,ha as It,ia as le,k as St,l as ht,la as Dt,na as bt,qa as vt,sa as Ot,y as V,z as ke}from"./chunk-RMF4YGD6.js";import{a as Et,e as O,o as ee,p as W,q as Rt,r as At,s as _t,t as Nt}from"./chunk-NFU4YFXB.js";import{b as Le}from"./chunk-H7PDL3X5.js";import{a as B,f as mt,g as gt,i as ft}from"./chunk-CCWBPAKH.js";import{$ as _e,Aa as ot,Ba as it,Bb as S,C as Ye,Ca as pt,D as ie,Da as Te,Fb as C,Ga as ct,I as Ke,N as Se,P as he,R as Je,S as Ee,T as Xe,V as H,W as pe,X as Re,Y as J,Ya as lt,Z as Ze,_ as Ae,aa as Qe,ba as G,c as g,ca as M,da as et,ea as Ne,fa as $e,ga as tt,k as I,ma as nt,mb as dt,pc as Mt,qb as Q,sa as X,ua as rt,va as st,wc as de,ya as at,za as Z}from"./chunk-LYNBZ7RV.js";import{stripVTControlCharacters as Xn}from"node:util";import v from"chalk";function Wt(e){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(e))throw new S("SECRET_NAME_INVALID",`"${e}" isn't a valid secret name`,{fix:"use letters, digits and underscores, starting with a letter, e.g. GITHUB_TOKEN"});if(G(e))throw new S("SECRET_NAME_RESERVED",`${e} is a reserved name
|
|
2
|
+
everyapp manages ${Qe}.`,{fix:"pick another name"})}function _n(e){return e.ready?e.settings.some(n=>n.set===null&&n.names.length>0&&n.need.kind!=="optional")?null:"ready":"needs_setup"}function Nn(e){return[...new Set(e.unmet.flatMap(t=>t.names))]}var Vt="id, organization_id, app_slug, name, status, setup_state",qt=e=>({id:String(e.id),organizationId:String(e.organization_id),appSlug:String(e.app_slug),name:String(e.name),status:String(e.status),setupState:e.setup_state==null?null:String(e.setup_state)});async function jt(e,t){if(!await ke(e))return null;let n=_n(t.setup);if(!n)return null;let r=t.row??await $n(e,t.appRowId);if(!r||r.status===O)return null;let s=r.setupState==="ready"||r.setupState==="needs_setup"?r.setupState:null;if(s===n)return{state:n,previous:s,event:null};let a=n==="needs_setup"?"app.needs_setup":s==="needs_setup"?"app.ready":null,i={id:r.appSlug,rowId:r.id,name:r.name},o=a?await q(e,{organizationId:r.organizationId,type:a,actor:V(t.deployer),data:a==="app.needs_setup"?{app:i,unmet:Nn(t.setup)}:{app:i},appRowId:r.id,onlyIf:{sql:"changes() > 0",params:[]},now:t.now}):[];return await e.run([{sql:"UPDATE apps SET setup_state = ? WHERE id = ? AND setup_state IS ?",params:[n,r.id,s]},...o]),{state:n,previous:s,event:a}}async function $n(e,t){let[n=[]]=await e.run([{sql:`SELECT ${Vt} FROM apps WHERE id = ?`,params:[t]}]);return n[0]?qt(n[0]):null}async function Yt(e,t,n){try{let{cf:r,db:s,deployer:a}=e;if(t.gateway.length===0&&t.appRowId===null||!await ke(s))return;let[i=[]]=await s.run([{sql:`SELECT ${Vt}, tier, manifest, secret_names FROM apps
|
|
3
|
+
WHERE status NOT IN ('${O}', 'pending') AND tier NOT IN ('${M}', 'dispatch')`}]),o=i.flatMap(c=>{let u=Tn(c.manifest);return!u||typeof u!="object"||c.id===t.except?[]:c.id===t.appRowId||ue(u).some(d=>t.gateway.includes(d))?[{row:qt(c),manifest:u,secretNames:Et(D(c.secret_names))}]:[]});if(o.length===0)return;let p=await se(r);for(let c of o){let{setup:u}=j({manifest:c.manifest,appId:c.row.appSlug,gatewayNames:p,secretNames:c.secretNames});await jt(s,{appRowId:c.row.id,setup:u,deployer:a,row:c.row})}}catch(r){n.emit({type:"progress",step:"app.setup_state",message:`Couldn't record whether the apps are set up (${C(r).split(`
|
|
4
|
+
`)[0]}); the Gateway records it when it next lists them`})}}function Tn(e){if(typeof e!="string")return null;try{return JSON.parse(e)}catch{return null}}async function _r(e,t,n){try{await jt(e,t)}catch(r){n.emit({type:"progress",step:"app.setup_state",message:`Couldn't record whether the app is set up (${C(r).split(`
|
|
5
|
+
`)[0]}); the Gateway records it when it next lists it`})}}var Kt=new WeakMap;function z(e){let t=Kt.get(e);return t||(t=e.run([{sql:"SELECT name FROM sqlite_master WHERE type = 'table' AND name IN ('remote_mcp_credentials', 'remote_mcp_tools')"}]).then(([n=[]])=>{let r=new Set(n.map(s=>String(s.name)));return{credentials:r.has("remote_mcp_credentials"),tools:r.has("remote_mcp_tools")}}),Kt.set(e,t)),t}function Jt(e){return{app:{id:e.appSlug,rowId:e.id,name:e.name},kind:ee(e)?"remote":"builtin"}}function kn(e){return W(e)?.url??null}async function Xt(e,t,n){let[r=[]]=await e.run([{sql:`SELECT ${await ne(e)} FROM apps WHERE organization_id = ? AND app_slug = ?`,params:[t,n]}]);return r[0]?re(r[0]):null}async function In(e,t){let[n=[]]=await e.run([{sql:`SELECT ${await ne(e)} FROM apps WHERE organization_id = ? AND tier = ? AND status != '${O}' ORDER BY app_slug`,params:[t,M]}]);return n.map(re).filter(ee).map(r=>r.appSlug)}async function vr(e,t){let r=(await De(e))?.organization??null,s=r?await Xt(e,r.id,t):null;if($e(t))return{kind:"builtin",id:t,organization:r,app:s&&s.tier===M?s:null};if(s&&ee(s))return{kind:"remote",id:t,organization:r,app:s};if(s&&s.tier!==M&&s.status!==O)throw new S("PROVIDER_APP_UNKNOWN",`"${t}" is an app deployed to this Gateway, not an MCP app
|
|
6
|
+
${g} delete ${t} removes a deployed app.`,{rerun:`${g} mcp list`,rerunNote:"lists the MCP apps"});let a=r?await In(e,r.id):[],i=/^[a-z][a-z0-9+.-]*:\/\//i.test(t);throw new S("PROVIDER_APP_UNKNOWN",[`"${t}" is not an MCP app on this Gateway`,`Built in: ${Ne.join(", ")}. Added: ${a.length>0?a.join(", "):"none yet"}.`].join(`
|
|
7
|
+
`),i?{rerun:`${g} mcp add ${t}`,rerunNote:"adds the server at that address"}:{rerun:`${g} mcp list`,rerunNote:"lists the MCP apps"})}function Or(e){let t=e.app?kn(e.app):null;return new S("APP_NOT_FOUND",`${e.id} was removed from this Gateway
|
|
8
|
+
Adding it again starts fresh: nobody's access or tools are kept.`,t?{rerun:`${g} mcp add ${t} --name ${e.id}`,rerunNote:"adds it again"}:{rerun:`${g} mcp list`,rerunNote:"lists the MCP apps"})}async function Zt(e){let[t=[]]=await e.run([{sql:`SELECT tier, manifest FROM apps WHERE tier = ? AND status != '${O}'`,params:[M]}]),n=new Map;for(let r of t){let s=W({tier:String(r.tier),manifest:D(r.manifest)}),a=s?X(s.auth):null;if(!s||!a)continue;let i;try{i=new URL(s.url).origin}catch{continue}let o=n.get(a)??new Set;o.add(i),n.set(a,o)}return n}function Dn(e,t,n){let{app:r}=e,s=e.grants.map(a=>({sql:`INSERT INTO user_app_access (id, user_id, app_row_id, organization_id, granted_by)
|
|
9
|
+
VALUES (?, ?, ?, ?, NULL) ON CONFLICT DO NOTHING`,params:[a.id,a.userId,a.appRowId,a.organizationId]}));return e.kind==="new"?[{sql:`INSERT INTO apps (id, organization_id, app_slug, name, description, hostname,
|
|
10
|
+
worker_name, tier, manifest, status, version_id, deployed_at, deployed_by_actor,
|
|
11
|
+
is_default, created_at, updated_at, scope)
|
|
12
|
+
VALUES (?1, ?2, ?3, ?4, ?5, NULL, NULL, ?6, ?7, ?8, NULL, ?9, ?10, 0, ?11, ?11, ?12)`,params:[r.id,r.organizationId,r.appSlug,r.name,r.description,r.tier,r.manifest,r.status,r.deployedAt,r.deployedByActor,t,r.scope]},...s]:[{sql:`UPDATE apps SET name = ?, description = ?, manifest = ?, status = ?, is_default = 0,
|
|
13
|
+
deployed_at = ?, deployed_by_actor = ?, updated_at = ?
|
|
14
|
+
WHERE id = ? AND status = '${O}'`,params:[r.name,r.description,r.manifest,r.status,r.deployedAt,r.deployedByActor,t,r.id]},...be(r,t,{secretNames:n.secretNames}),...n.remoteTools?[Qt(r)]:[],...s]}function Qt(e){return{sql:"DELETE FROM remote_mcp_tools WHERE app_row_id = ? AND organization_id = ?",params:[e.id,e.organizationId]}}function Mr(e,t){return te(async()=>{let n=t.now??Date.now(),r=t.url.trim(),s=(t.id??"").trim()||nt(r)||"",{organization:a,hasOwner:i}=await $t(e,t.organizationName,n),[o=[],p=[],c=[]]=await e.run([{sql:`SELECT ${await ne(e)} FROM apps WHERE organization_id = ? AND app_slug = ?`,params:[a.id,s]},...Tt(a.id,t.deployer.email)]),u=o[0]?re(o[0]):null,m=await Zt(e),d=D(c[0]?.id),h=Rt({organizationId:a.id,url:r,id:t.id,name:t.name,description:t.description,auth:t.auth,risk:t.risk,env:t.env,existingApp:R=>{if(R!==s)throw new Error(`The rules asked for "${R}", not "${s}".`);return u},secretUsedAt:R=>{let A=[...m.get(R)??[]],y=new URL(r).origin;return A.find(f=>f!==y)??A[0]??null},members:kt(p),actorUserId:d,actor:t.deployer.actor,now:n}),E=await z(e),w=await q(e,{organizationId:a.id,type:"mcp_app.added",actor:V(t.deployer),data:{app:{id:h.app.appSlug,rowId:h.app.id,name:h.app.name},kind:"remote"},appRowId:h.app.id,onlyIf:{sql:"EXISTS (SELECT 1 FROM apps WHERE id = ? AND status = ? AND updated_at = ?)",params:[h.app.id,h.app.status,n]},now:n});return await e.run([...Dn(h,n,{secretNames:await Ie(e),remoteTools:E.tools}),...w]),{plan:h,organization:a,hasOwner:i,actorGranted:d!==null&&h.grants.some(R=>R.userId===d)}})}function Cr(e,t,n,r,s=Date.now()){return te(async()=>{let a=_t(t,n);if(!a)return{changed:!1};let i=await q(e,{organizationId:t.organizationId,type:a.status==="active"?"mcp_app.enabled":"mcp_app.disabled",actor:V(r),data:Jt(t),appRowId:t.id,onlyIf:{sql:"EXISTS (SELECT 1 FROM apps WHERE id = ? AND status = ? AND updated_at = ?)",params:[t.id,a.status,s]},now:s}),[o=[]]=await e.run([{sql:"UPDATE apps SET status = ?, updated_at = ? WHERE id = ? AND status = ? RETURNING id",params:[a.status,s,t.id,t.status]},...i]);if(o.length===0)throw new S("APP_CHANGING",`${t.appSlug} changed while this ran
|
|
15
|
+
Nothing was written; run it again.`,{retryable:!0});return{changed:!0}})}function Pr(e,t,n,r=Date.now()){return te(async()=>{let s=Nt(t);if(!t||!s)return{removed:!1};let a=await z(e);return await e.run([{sql:"UPDATE apps SET status = ?, is_default = ?, updated_at = ? WHERE id = ?",params:[s.status,s.isDefault?1:0,r,t.id]},...be(t,r,{secretNames:await Ie(e)}),...a.tools?[Qt(t)]:[],...await q(e,{organizationId:t.organizationId,type:"mcp_app.removed",actor:V(n),data:Jt(t),appRowId:t.id,now:r})]),{removed:!0}})}function Ue(e){return e?{status:String(e.status),toolCount:Number(e.tool_count??0),listedAt:e.fetched_at==null?null:Number(e.fetched_at),lastError:D(e.last_error)}:null}async function Lr(e,t){let n=[t.id,t.organizationId],[r=[]]=await e.run([{sql:"SELECT status, tool_count, fetched_at, last_error FROM app_tool_catalogs WHERE app_row_id = ? AND organization_id = ?",params:n},{sql:"DELETE FROM app_tools WHERE app_row_id = ? AND organization_id = ?",params:n},{sql:"DELETE FROM app_tool_catalogs WHERE app_row_id = ? AND organization_id = ?",params:n}]);return Ue(r[0])}async function bn(e){if(!(await z(e)).credentials)return new Map;let[t=[]]=await e.run([{sql:"SELECT name, origin, bound_by, bound_at FROM remote_mcp_credentials ORDER BY name"}]);return new Map(t.map(n=>[String(n.name),{origin:String(n.origin),boundBy:D(n.bound_by),boundAt:n.bound_at==null?null:Number(n.bound_at)}]))}async function Ur(e){let t=await De(e),n=[],r=new Map;if(t){let[o=[],p=[]]=await e.run([{sql:`SELECT ${await ne(e)} FROM apps WHERE organization_id = ? AND tier = ? AND status != '${O}' ORDER BY app_slug`,params:[t.organization.id,M]},{sql:"SELECT app_row_id, status, tool_count, fetched_at, last_error FROM app_tool_catalogs WHERE organization_id = ?",params:[t.organization.id]}]);n.push(...o.map(re));for(let c of p)r.set(String(c.app_row_id),Ue(c))}let s=new Map(n.map(o=>[o.appSlug,o])),a=Ne.map(o=>{let p=s.get(o)??null;return{id:o,name:et[o].name,kind:"builtin",app:p,remote:null,keyName:tt(o),snapshot:p?r.get(p.id)??null:null}}),i=n.filter(o=>!$e(o.appSlug)&&ee(o)).map(o=>{let p=W(o);return{id:o.appSlug,name:o.name,kind:"remote",app:o,remote:p,keyName:p?X(p.auth):null,snapshot:r.get(o.id)??null}});return[...a,...i]}function xr(e,t,n){if(!e.app||e.app.status===O)return"not added";if(e.app.status!=="active")return"off";if(e.kind==="remote"&&!e.remote||e.keyName&&!t.includes(e.keyName))return"needs setup";if(e.kind==="remote"&&e.keyName&&e.remote){let r=n.get(e.keyName);if(r&&r.origin!==vn(e.remote.url))return"needs setup"}return"on"}function vn(e){try{return new URL(e).origin}catch{return""}}function On(e){return e==="read"?{readOnlyHint:!0}:e==="destructive"?{destructiveHint:!0}:{}}function Mn(e,t,n,r){return n.map(s=>{let a=String(s.upstream_name),i=String(s.risk_hint),o=D(s.local_name),p=rt(On(i),t,a),c=p.source==="default"&&i==="write"?"hint":p.source,u=o?r.get(o):void 0,m=st(t,a),d=!!Number(s.listed);return{name:o?`${e}_${o}`:null,serverName:a,title:D(s.title),risk:u??p.risk,source:c,on:m&&d,problem:m?d?null:D(s.problem)??"not listed":d?"turned off; leaves the catalog at the next listing":"turned off"}})}async function Gr(e,t,n){let r=[t.app.id,t.app.organizationId],s=await z(e),a=n?X(n.auth):null,[i=[],o=[],p=[],c=[]]=await e.run([{sql:"SELECT status, tool_count, fetched_at, last_error FROM app_tool_catalogs WHERE app_row_id = ? AND organization_id = ?",params:r},{sql:"SELECT name, title, risk FROM app_tools WHERE app_row_id = ? AND organization_id = ? ORDER BY name",params:r},...s.tools&&n?[{sql:`SELECT upstream_name, local_name, title, risk_hint, listed, problem, listed_at FROM remote_mcp_tools
|
|
16
|
+
WHERE app_row_id = ? AND organization_id = ? ORDER BY upstream_name`,params:r}]:[{sql:"SELECT 1 WHERE 0"}],...s.credentials&&a?[{sql:"SELECT origin, bound_by, bound_at FROM remote_mcp_credentials WHERE name = ?",params:[a]}]:[{sql:"SELECT 1 WHERE 0"}]]),u=new Map(o.map(d=>[String(d.name),String(d.risk)])),m=c[0];return{snapshot:Ue(i[0]),remoteTools:n?Mn(t.id,n,p,u):[],catalogTools:o.map(d=>({name:`${t.id}_${String(d.name)}`,title:D(d.title),risk:String(d.risk)})),binding:m?{origin:String(m.origin),boundBy:D(m.bound_by),boundAt:m.bound_at==null?null:Number(m.bound_at)}:null,listingKnown:s.tools}}var Cn=3;function zr(e,t,n,r,s=Date.now()){return te(async()=>{let a=await z(e),[i=[]]=await e.run([a.tools?{sql:`SELECT upstream_name, local_name FROM remote_mcp_tools
|
|
17
|
+
WHERE app_row_id = ?1 AND (upstream_name = ?2 OR local_name = ?2 OR ?3 || local_name = ?2)
|
|
18
|
+
ORDER BY (upstream_name = ?2) DESC, upstream_name LIMIT 1`,params:[t.app.id,n,`${t.id}_`]}:{sql:"SELECT 1 WHERE 0"}]),o=i[0],p=o?String(o.upstream_name):n,c=o?D(o.local_name):null,u={};r.risk==="annotations"?u.risk=void 0:r.risk&&(u.risk=r.risk),r.enabled!==void 0&&(u.enabled=r.enabled);let m=t.app;for(let d=1;;d+=1){let h=W(m)?.tools[p]??null,E=At(m,{tool:{name:p,override:u}}),[w=[]]=await e.run([{sql:`UPDATE apps SET manifest = ?, name = ?, description = ?, updated_at = ?
|
|
19
|
+
WHERE id = ? AND manifest = ? AND status != '${O}' RETURNING id`,params:[E.manifest,E.name,E.description,s,m.id,m.manifest]}]);if(w.length>0)return{serverName:p,listedName:c?`${t.id}_${c}`:null,inListing:!!o,before:h,after:E.remote.tools[p]??null,rev:E.remote.rev};let R=await Xt(e,m.organizationId,m.appSlug);if(!R||d>=Cn)throw new S("APP_CHANGING",`${t.id} keeps changing while this writes its tool settings
|
|
20
|
+
Nothing was written; run it again.`,{retryable:!0});m=R}})}async function en(e,t,n,r=Date.now()){let s={bound:[],undeclared:[],ambiguous:[]},a=t.filter(Re);if(a.length===0||!(await z(e)).credentials)return s;let i=await Zt(e),o=await bn(e),p=[];for(let c of a){let u=[...i.get(c)??[]].sort();u.length===0?s.undeclared.push({name:c,kept:o.get(c)?.origin??null}):u.length>1?s.ambiguous.push({name:c,origins:u}):(s.bound.push({name:c,origin:u[0]}),p.push({sql:`INSERT INTO remote_mcp_credentials (name, origin, bound_by, bound_at) VALUES (?, ?, ?, ?)
|
|
21
|
+
ON CONFLICT(name) DO UPDATE SET origin = excluded.origin, bound_by = excluded.bound_by, bound_at = excluded.bound_at`,params:[c,u[0],n,r]}))}return p.length>0&&await e.run(p),s}async function tn(e,t){let n=t.filter(Re);if(n.length===0||!(await z(e)).credentials)return[];let[r=[]]=await e.run([{sql:`DELETE FROM remote_mcp_credentials WHERE name IN (${n.map(()=>"?").join(", ")}) RETURNING name`,params:n}]);return r.map(s=>String(s.name))}async function nn(e){let[t=[]]=await e.run([{sql:`SELECT app_slug, tier, manifest FROM apps WHERE tier = ? AND status != '${O}' ORDER BY app_slug`,params:[M]}]),n=new Map;for(let r of t){let s=W({tier:String(r.tier),manifest:D(r.manifest)}),a=s?X(s.auth):null;a&&n.set(a,[...n.get(a)??[],String(r.app_slug)])}return n}import{text as Gn}from"node:stream/consumers";var xe=40,Pn=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|common|organizations|consumers)$/i,Ln={issuer:"the issuer's https URL, which serves /.well-known/openid-configuration (no query, fragment or user:password@)",tenant:"the Directory (tenant) ID, a GUID like 72f988bf-86f1-41af-91ab-2d7cd011db47, or common, organizations or consumers",label:`the button text after "Continue with", at most ${xe} characters`};function Un(e,t){switch(e){case"issuer":{let n;try{n=new URL(t)}catch{return`"${t}" isn't a URL.`}if(n.protocol!=="https:")return`"${t}" isn't an https URL.`;if(n.username||n.password)return"It carries a user name or password; the issuer's URL has none.";if(n.search||n.hash)return"It has a query or a fragment; the issuer's URL has neither.";let r=n.hostname.toLowerCase();return r==="localhost"||r==="127.0.0.1"?"A deployed Gateway can't reach a loopback issuer.":null}case"tenant":return Pn.test(t)?null:`"${t}" isn't a Directory (tenant) ID, common, organizations or consumers.`;case"label":return t.length<=xe?null:`It is ${t.length} characters; the button takes ${xe} at most.`;default:return null}}function xn(e){return Ln[e]??null}function rn(e){let t=Xe(e)?.settings.find(r=>r.name===e),n=t?xn(t.role):null;if(!(!t||!n))return{takes:n,check:r=>Un(t.role,r)}}function on(e){return e?"env":process.stdin.isTTY?"prompt":"stdin"}function pn(e,t){let n=on(t);if(!(n==="prompt"||e.length<2))throw new S("SECRET_SEVERAL_NAMES",`${n==="env"?"--from-env":"A piped value"} sets one secret at a time, and you named ${e.length}`,{fix:`run it once per name, e.g. ${n==="env"?`${g} secret set ${e[0]} --from-env ${t}`:`echo "$${e[0]}" | ${g} secret set ${e[0]}`}`})}function cn(e){return e.length<2?e[0]??"":`${e.slice(0,-1).join(", ")} or ${e.at(-1)}`}function U(e,{exact:t=!1}={}){return n=>e.includes(t?n:n.toLowerCase())?null:`Not ${e.length>2?"one of ":""}${cn(e)}.`}function ae(e,t){return n=>{let r=n.split(/[\s,]+/).filter(Boolean),s=r.find(a=>!e(a));return s!==void 0?`"${s}" isn't ${t}.`:r.length>0?null:`Name ${t}.`}}var Ge=["true","false","1","0","on","off","yes","no"],zn=/^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/,Fn=/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9-]{2,63}$/,Hn=/^(?=.{1,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/,Bn=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.cloudflareaccess\.com$/,sn=/^[A-Za-z0-9._:-]{1,256}$/,Wn=/^\/v1(\/[a-z0-9_-]+)+$/,ze=3650,Vn=e=>Fn.test(e.toLowerCase().replace(/^@/,"")),qn=e=>Hn.test(e.toLowerCase().replace(/\.$/,""));function jn(e){try{let t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"?t:null}catch{return null}}function ln(e){let t;try{t=new URL(e)}catch{return null}return t.username||t.password||t.search||t.hash?null:t.protocol==="https:"&&Bn.test(t.hostname.toLowerCase())?t:null}function Yn(e){let t=ln(/^[a-z]+:\/\//i.test(e)?e:`https://${e}`);return t!==null&&(t.pathname==="/"||t.pathname==="")}var Kn={EMAIL_FROM:{takes:"an address, or Name <address> (with EMAIL_FROM_NAME set, unless the name is in it)",check:e=>{let t=ct(e,"sender");return t&&zn.test(t.address)?null:`"${e}" isn't an address or Name <address>.`}},EMAIL_FROM_NAME:{takes:"the sender's display name, e.g. Acme Support"},EMAIL_PROVIDER:{takes:`${cn(Te)}: which provider sends when both are set up`,check:U(Te)},EMAIL_PASSWORD_SIGN_IN:{takes:"true or false; false turns password sign-in off (only while Cloudflare Access sign-in is on)",check:U(Ge)},MASTODON_URL:{takes:"the Mastodon instance's https origin, e.g. https://mastodon.social",check:e=>Ke(Ye.mastodon,{MASTODON_URL:e})?null:`"${e}" isn't an https origin (no path).`},AI_PROXY_EXTRA_ROUTES:{takes:"/v1 paths beyond inference the AI proxy may forward, comma separated, e.g. /v1/files",check:ae(e=>Wn.test(e),"a /v1/... path")},MCP_OAUTH_ENABLED:{takes:"true or false; false turns the OAuth server for MCP clients off",check:U(Ge)},MCP_DCR_ENABLED:{takes:"true or false; false turns dynamic client registration off",check:U(Ge)},MCP_ALLOWED_ORIGINS:{takes:"browser origins allowed to call /mcp, comma separated, e.g. http://localhost:6274",check:ae(e=>jn(e)!==null,"an http or https URL")},MCP_AUDIT_RETENTION_DAYS:{takes:`days of MCP tool-call audit rows to keep: a whole number from 1 to ${ze}`,check:e=>/^\d+$/.test(e)&&Number(e)>=1&&Number(e)<=ze?null:`Not a whole number from 1 to ${ze}.`},CLOUDFLARE_ACCESS_OIDC_ISSUER:{takes:"https://<team>.cloudflareaccess.com/cdn-cgi/access/sso/oidc/<client id>",check:e=>{let t=ln(e);return t&&/^\/cdn-cgi\/access\/sso\/oidc\/[^/]+\/?$/.test(t.pathname)?null:`"${e}" isn't an Access for SaaS issuer URL.`}},CLOUDFLARE_ACCESS_OIDC_CLIENT_ID:{takes:"the Access for SaaS application's client id"},CLOUDFLARE_ACCESS_OIDC_LABEL:{takes:`the sign-in button's label ("Continue with <label>"), at most 40 characters`},CLOUDFLARE_ACCESS_TEAM_DOMAIN:{takes:"<team>.cloudflareaccess.com",check:e=>Yn(e)?null:`"${e}" isn't <team>.cloudflareaccess.com.`},CLOUDFLARE_ACCESS_AUD:{takes:"the AUD tag of the Access application on the Gateway's host (several: comma separated)",check:ae(e=>sn.test(e),"an AUD tag")},CLOUDFLARE_ACCESS_APPS_AUD:{takes:"the AUD tag of the Access application on the apps' hosts (several: comma separated)",check:ae(e=>sn.test(e),"an AUD tag")},CLOUDFLARE_ACCESS_AUTO_JOIN_DOMAINS:{takes:"email domains whose people join without an invitation, comma separated, e.g. example.com",check:ae(Vn,"a domain like example.com")},CLOUDFLARE_ACCESS_OUTER_RING_AUTO_JOIN:{takes:`everyone (anyone the outer ring admits joins); to turn it off: ${g} secret unset CLOUDFLARE_ACCESS_OUTER_RING_AUTO_JOIN`,check:U(["everyone"])},HOSTED_OPEN_SIGNUP:{takes:"true or false; false keeps a hosted Gateway's sign-up invite-only",check:U(["true","false"])},BROWSER_APP_INSTALLS:{takes:"on or off, in lowercase; off turns browser app installs off",check:U(["on","off"],{exact:!0})},EVENTS_ALLOW_PRIVATE_TARGETS:{takes:"true or false, in lowercase; true lets event webhooks reach http: URLs and private host names",check:U(["true","false"],{exact:!0})},DISPATCH_NAMESPACE:{takes:"the Workers for Platforms namespace third-party Workers go into (hosted Gateway only)"},THIRD_PARTY_DOMAIN:{takes:"the registrable domain third-party apps are named on (hosted Gateway only)",check:e=>qn(e)?null:`"${e}" isn't a domain like example.com.`}};function Fe(e){return Kn[e]??rn(e)}function Jn(e){let t=Fe(e);return t?[`Takes ${t.takes}`]:[]}function dn(e,t){return t.trim()?Fe(e)?.check?.(t.trim())??null:"Enter a value."}function an(e,t){let n=t.trim(),r=dn(e,n);if(r===null)return n;let s=Fe(e),a=n.replace(/\s+/g," ").slice(0,64);throw new S("SETTING_VALUE_INVALID",`${e} can't be "${a}"
|
|
22
|
+
${r}`,{...s?{fix:`use ${s.takes}`}:{},data:{name:e}})}async function un(e,t){let n=Ze(e),r=t.fromEnv,s=on(r);if(s==="env"){let a=process.env[r],i=n?a?.trim():a;if(!i)throw new S("SECRET_EMPTY",`$${r} is empty or not set`,{fix:`export ${r} first, or name another variable with --from-env`});return n?an(e,i):i}if(s==="stdin"){let a=(await Gn(process.stdin)).replace(/\r?\n$/,""),i=n?a.trim():a;if(i)return n?an(e,i):i}if(s==="stdin"||!B(t.json??!1))throw new S("SECRET_VALUE_REQUIRED",`Can't ask for ${e}'s value without a terminal
|
|
23
|
+
Or pipe it in: echo "$${e}" | ${g} secret set ${e}`,{rerun:`${g} secret set ${e} --from-env ${e}`});return n?(await mt(e,{context:Jn(e),validate:i=>dn(e,i)})).trim():(await gt(`Value for ${e}`)).trim()}async function _s(e,...t){await de(e,async n=>{pn(t,e["from-env"]),await Zn({flags:e,out:n,names:t,readValue:r=>un(r,{fromEnv:e["from-env"],json:e.json})})})}async function Ns(e,...t){await de(e,n=>nr({flags:e,out:n,names:t}))}async function $s(e,t){await de(e,n=>rr({flags:e,out:n,appId:t}))}async function Zn(e){let{applied:t,gatewayHost:n}=await Qn(e),r=(t.gateway?.pinned??[]).map(({name:s,origin:a})=>`${s} is sent to ${a} and nowhere else.`);e.out.emit({type:"done",message:[`Set ${Be(t,"on")}`,...r].join(`
|
|
24
|
+
`),display:[...r,v.dim(t.app?"Live now. No deploy needed.":`Live now on ${n}. No deploy needed.`)].join(`
|
|
25
|
+
`),data:Ve(t)})}async function Qn(e){let t=await yn(e.names,e,"set");tr(t.providers,e.names,e.out);let n={};for(let s of e.names)n[s]=await e.readValue(s);return{applied:await fe(t,n,e,"set"),gatewayHost:t.gatewayHost}}function er(e){return I([...e.hosts,...e.hostSetting?[`the host ${e.hostSetting} names`]:[]])}function tr(e,t,n){for(let r of e){let{capability:s}=r;for(let a of ie(s).filter(i=>t.includes(i))){let i=r.addedAt?` on ${new Date(r.addedAt).toISOString().slice(0,10)}`:"",o=r.addedBy?` by ${r.addedBy}`:"";n.emit({type:"step",step:"secrets.provider",status:"ok",message:`${a} is ${s.label}'s, registered${o}${i}; the key is sent to ${er(s)}.`,data:{name:a,provider:r.id,addedBy:r.addedBy,addedAt:r.addedAt,hosts:[...s.hosts],...s.hostSetting?{hostSetting:s.hostSetting}:{}}})}}}async function Ts(e,t,n){let r=Object.keys(t),s=Object.values(t).every(i=>i===null);for(let i of r)if(!J(i))throw new Error(`${i} isn't a Gateway setting`);let a={route:{gateway:r,app:null,undeclared:[]},cf:e.cf,db:e.db,deployer:e.deployer,accountName:e.accountName,gatewayHost:e.gatewayUrl.replace(/^https:\/\//,""),app:null,providers:[]};return fe(a,t,n,s?"unset":"set")}async function ks(e,t,n,r){let s=Object.keys(n),a=await He(s,t.manifest,e,"set"),i=ge(s,t.manifest,t.source,"set",a.names);if(i.app&&!t.app)throw new S("APP_NOT_FOUND",`${t.manifest.id} isn't deployed yet
|
|
26
|
+
Its own ${I(i.app.names)} can be set after its first deploy. Nothing was changed.`,{rerun:`${g} deploy`});let o={route:i,cf:e.cf,db:e.db,deployer:e.deployer,accountName:e.accountName,gatewayHost:e.gatewayUrl.replace(/^https:\/\//,""),app:i.app&&t.app?{...i.app,...t.app}:null,providers:a.providers};return await fe(o,n,r,"set")}async function nr(e){let{names:t,out:n}=e,r=await yn(t,e,"unset"),{route:s}=r,a=()=>{let p=`${I(t)} ${t.length===1?"isn't":"aren't"} set on ${or(s).join(" or ")}. Nothing changed.`;n.emit({type:"done",message:p,display:v.dim(p),data:{removed:!1}})};if(!await lr(r)){a();return}await ft({yes:e.flags.yes,interactive:e.interactive??B(e.flags.json??!1),confirm:e.confirm,question:`Remove ${Be({...s.gateway.length>0?{gateway:{names:s.gateway,versions:{}}}:{},...s.app?{app:{id:s.app.manifest.id,workerName:"",names:s.app.names,versions:{}}}:{}},"from")}?`,unattended:"Removing secrets needs confirmation, and there's no terminal to ask in",context:s.undeclared.map(p=>s.app?.source==="registry"?`${p} isn't listed in ${s.app.manifest.id}'s deployed manifest.`:`${p} isn't listed in everyapp.config.ts.`)});let i=Object.fromEntries(t.map(p=>[p,null])),o=await fe(r,i,e,"unset");if(!o){a();return}n.emit({type:"done",message:`Removed ${Be(o,"from")}`,display:v.dim("Live now. No deploy needed."),data:Ve(o)})}async function rr(e){let{out:t}=e,n=e.appId?null:await Le(e.cwd??process.cwd()),{cf:r,db:s,gatewayUrl:a,install:i}=await gn(e),[o,p]=await Promise.all([se(r),Pe(s,i)]),c=[...pe,...p.rows().flatMap(N=>ie(N.capability))],u=(N,T)=>t.emit({type:"done",message:Xn(N),display:N,data:T});if(!e.appId&&!n){let N=o.filter(l=>!H(l)),T=o.filter(l=>H(l)),$=await bt(s),k=new Set($.flatMap(l=>l.manifest?ue(l.manifest,p):[])),x=i.deploymentMode==="hosted",F=c.filter(l=>x||!Ae(l)).filter(l=>!o.includes(l)),P=await nn(s),L=[...F.filter(l=>k.has(l)||x&&Ae(l)),...[...P.keys()].filter(l=>!o.includes(l))],qe=F.filter(l=>!L.includes(l)&&!Ee(l)).length,oe=[],ye=[];for(let l of $){if(!l.manifest||!Pt(l.manifest,p)||l.tier==="dispatch")continue;if(l.tier===M){let K=it(ot(l.manifest),(Rn,An)=>Rn==="gateway"?o.includes(An):null);if(K.ready)continue;let En=pt(K,{cli:g,appId:l.appSlug,provider:!0});oe.push({id:l.appSlug,setup:En,rows:me(l.appSlug,K.settings)});continue}let Y=l.status==="pending"?null:await Oe(r,l.workerName).catch(K=>(ye.push({id:l.appSlug,reason:C(K).split(`
|
|
27
|
+
`)[0]}),null)),{report:Sn,setup:hn}=j({manifest:l.manifest,appId:l.appSlug,gatewayNames:o,secretNames:Y,lookup:p});oe.push({id:l.appSlug,setup:hn,rows:me(l.appSlug,Sn.settings)})}let je=oe.flatMap(l=>l.rows);u([v.dim(`Gateway secrets \xB7 ${a.replace(/^https:\/\//,"")}`),"",...Mt(["NAME","SET BY"],[...N.map(l=>[l,"you"]),...T.map(l=>[l,v.dim("setup")]),...L.map(l=>[l,v.dim("not set")])]),...qe>0?[v.dim(`${qe} more can be set; see docs/capabilities.md`)]:[],v.dim(`Sign-in providers (${Object.values(he).map(l=>l.label).join(", ")}): ${g} signin list`),...je.length>0?["",...Ce(je)]:[],...ye.length>0?[v.dim(sr(ye))]:[]].join(`
|
|
28
|
+
`),{gateway:{workerName:Q,names:o,settable:c,mcpCredentials:[...P].map(([l,Y])=>({name:l,apps:Y,set:o.includes(l)}))},apps:oe.map(({id:l,setup:Y})=>({id:l,setup:Y}))});return}let m=e.appId?await It(s,e.appId):await le(s,n.id),d=e.appId?fn(m):n,h=m&&m.status!=="pending"?m.workerName:null,E=Z(d),w=[];if(h){let N=(await We(s,h)).filter(T=>T.binding!=="").map(T=>T.name);for(let T of[h,...N]){let $=await ce(r,T);w.push({workerName:T,names:$,missing:E.filter(k=>!$.includes(k))})}}let R=w[0]?w[0].names.filter(N=>!G(N)):null,{report:A,setup:y}=j({manifest:d,appId:d.id,gatewayNames:o,secretNames:R,lookup:p}),f=me(d.id,A.settings).map(N=>!h&&N.where===d.id?{...N,status:v.dim("after first deploy")}:N);for(let N of w.slice(1)){let T=N.names.filter(k=>!G(k)),{report:$}=j({manifest:d,appId:d.id,gatewayNames:o,secretNames:T,lookup:p});f.push(...xt(d.id,N.workerName.split("--").at(-1),$.settings))}let _=`${v.green("\u2713")} set`;if(e.flags.verbose&&w[0])for(let N of w[0].names.filter(G))f.push({app:d.id,setting:N,where:d.id,status:_});let b=h?y.command?[y.command.command]:[]:[...y.command?[{command:`${g} configure`,note:"in the app's directory"}]:[],`${g} deploy`];u(f.length>0?[...Ce(f,{app:!1}),...y.unmet.length>0?["",...Gt(y.unmet)]:[],...!h&&E.length>0?["",v.dim(`${d.id} isn't deployed yet; its own secrets can be set after that.`)]:[]].join(`
|
|
29
|
+
`):v.dim(`${d.id} declares no secrets and needs no Gateway settings.`),{app:{id:d.id,deployed:h!==null,workerName:h,declared:E,workers:w,secretNames:R,settings:A.settings,setup:y},gateway:{workerName:Q,names:o,needed:Lt(A.settings,Me(o,p)),missing:Ut(A.settings,Me(o,p)),settable:c},...f.length>0&&b.length>0?{next:b}:{}})}function sr(e){return`Couldn't list ${I(e.map(n=>`${n.id}'s`))} secrets. Cloudflare said: ${e[0].reason}. They show as not recorded.`}var ar=(n=>(n.Directory="directory",n.Registry="registry",n))(ar||{});function or(e){return[...e.gateway.length>0?["the Gateway"]:[],...e.app?[e.app.manifest.id]:[]]}function ge(e,t,n,r,s=new Set){let a=u=>J(u)||s.has(u),i=e.filter(a),o=e.filter(u=>!a(u));if(o.length===0)return{gateway:i,app:null,undeclared:[]};let p=t?Z(t):[],c=[];for(let u of o){let m=ir(u,e,t,n,r);if(m)throw m;p.includes(u)||c.push(u)}return{gateway:i,app:{manifest:t,names:o,source:n},undeclared:c}}function ir(e,t,n,r,s){let a=n?Z(n):[];if(n&&a.includes(e))return null;let i=r==="registry"&&n?` --app ${n.id}`:"",o=mn(e,[...pe,...a]);return o?new S("SECRET_NOT_DECLARED",`${e} isn't a Gateway setting${n?` or one of ${n.id}'s secrets`:""}`,{rerun:`${g} secret ${s} ${t.map(p=>p===e?o:p).join(" ")}${i}`,data:{didYouMean:o}}):Ee(e)?cr(e,s):H(e)&&!n?new S("SECRET_NOT_SETTABLE",`${e} can't be changed with secret ${s}
|
|
30
|
+
${e==="THIRD_PARTY_DEPLOYS"?"It's the hosted Gateway's launch gate, opened by hand.":"It's one of the Gateway's own keys, written once by setup."}`):_e(e)?new S("SECRET_NOT_SETTABLE",`${e} only works in local development
|
|
31
|
+
A deployed Gateway doesn't read it.`,{fix:"set it in the Gateway's .dev.vars"}):(Wt(e),n?s==="unset"?null:new S("SECRET_NOT_DECLARED",[`${n.id} doesn't list ${e} as a secret`,r==="registry"?`Its deployed manifest (what --app ${n.id} reads) doesn't list it, and it isn't a Gateway setting either.`:H(e)?`It's one of the Gateway's own keys; listing it under secrets gives ${n.id} a secret of its own.`:"It isn't a Gateway setting either."].join(`
|
|
32
|
+
`),{fix:`add it to secrets in everyapp.config.ts: ${pr(n,e)}${r==="registry"?` and deploy ${n.id} again`:""}`,rerun:`${g} secret set ${e}${i}`}):new S("SECRET_NOT_DECLARED",`${e} isn't a Gateway setting, and there's no app here
|
|
33
|
+
An app's own secrets are ${s==="set"?"set":"removed"} from the app's directory (where everyapp.config.ts is), or from anywhere with --app <id>.
|
|
34
|
+
Gateway settings: ${g} secret list`,{fix:"cd into the app's directory and run this again, or add --app <id>"}))}function pr(e,t){let n=e.secrets??[],r=a=>typeof a=="string"?JSON.stringify(a):`{ ${Object.entries(a).map(([i,o])=>`${i}: ${JSON.stringify(o)}`).join(", ")} }`,s=n.every(a=>typeof a=="string")?JSON.stringify(t):`{ name: ${JSON.stringify(t)} }`;return`secrets: [${[...n.map(r),s].join(", ")}],`}function cr(e,t){let n=(/^(.+)_SIGNIN_[A-Z_]+$/.exec(e)?.[1]??e).toLowerCase();if(Je(n)){let r=he[n],s=r.settings.map(a=>a.name);return new S("SECRET_NOT_SETTABLE",`${e} isn't a setting of Sign in with ${r.label}
|
|
35
|
+
It reads ${I(s)}.`,{rerun:`${g} signin show ${n}`,data:{provider:n,names:s}})}return new S("SECRET_NOT_SETTABLE",`${n.toUpperCase()} isn't a sign-in provider (${Se.join(", ")}): ${g} signin list`,{fix:`${t} a provider's own settings, as ${g} signin show <id> names them`,data:{providers:[...Se]}})}function mn(e,t){let n=r=>r.toUpperCase().replace(/_/g,"");return t.find(r=>r!==e&&n(r)===n(e))}function gn({flags:e,out:t,createCf:n}){return Ot({gateway:vt(e.gateway),accountId:e["account-id"],interactive:B(e.json??!1),login:{json:e.json,out:t,step:"login"},createCf:n})}async function We(e,t){return(await Ct(e,t)).filter(n=>n.kind==="worker")}function fn(e){if(!e.manifest)throw new S("MANIFEST_NOT_FOUND",`${e.appSlug}'s registry row holds no manifest
|
|
36
|
+
Deploying it again stores one.`,{rerun:`${g} deploy`,rerunNote:"in the app's directory"});try{return dt(e.manifest)}catch(t){throw new S("INVALID_MANIFEST",`${e.appSlug}'s deployed manifest can't be read
|
|
37
|
+
${C(t)}`,{rerun:`${g} deploy`,rerunNote:"in the app's directory"})}}function wn(e,t){let n=t?Z(t):[];return e.filter(r=>!J(r)&&!n.includes(r)&<.test(r)&&!H(r)&&!_e(r)&&!G(r)&&!mn(r,[...pe,...n]))}async function He(e,t,n,r){let s=wn(e,t);if(s.length===0)return{names:new Set,providers:[]};let a=await Pe(n.db,n.install),i=Ht(a,s),o=new Set(i.flatMap(c=>ie(c.capability)).filter(c=>s.includes(c))),p=s.filter(c=>!o.has(c));if(r==="unset"&&p.length>0){let c=await se(n.cf);for(let u of p)c.includes(u)&&o.add(u)}return{names:o,providers:i}}async function yn(e,t,n){let r=e.every(E=>J(E)),s=t.flags.app,a,i=async()=>a??=await gn(t),o=(E,w,R,A=[])=>({route:w,cf:E.cf,db:E.db,deployer:E.deployer,accountName:E.accountName,gatewayHost:E.gatewayUrl.replace(/^https:\/\//,""),app:R,providers:A});if(r)return o(await i(),ge(e,null,"directory",n),null);if(s){let E=await i(),w=await le(E.db,s);if(!w)throw new S("APP_NOT_FOUND",`${s} isn't deployed to this Gateway
|
|
38
|
+
An app's secrets can be set after its first deploy. Nothing was changed.`,{rerun:`${g} status`,rerunNote:"lists its apps"});let R=fn(w),A={id:R.id,secrets:at(R)},y=await He(e,A,E,n),f=ge(e,A,"registry",n,y.names);return o(E,f,f.app?{...f.app,workerName:w.workerName,rowId:w.id}:null,y.providers)}let p=await Le(t.cwd??process.cwd()),c=wn(e,p).length>0?await He(e,p,await i(),n):{names:new Set,providers:[]},u=ge(e,p,"directory",n,c.names);if(!u.app)return o(await i(),u,null,c.providers);let m=await i(),{id:d}=u.app.manifest,h=await le(m.db,d);if(!h)throw new S("APP_NOT_FOUND",`${d} isn't deployed yet
|
|
39
|
+
Its secrets can be set after its first deploy. Nothing was changed.`,{rerun:`${g} deploy`});return o(m,u,{...u.app,workerName:h.workerName,rowId:h.id},c.providers)}async function lr({cf:e,db:t,route:n,app:r}){let s=[...n.gateway.length>0?[{workerName:Q,names:n.gateway}]:[],...r?(await We(t,r.workerName)).map(a=>({workerName:a.name,names:r.names})):[]];for(let{workerName:a,names:i}of s){let o=await ce(e,a);if(i.some(p=>o.includes(p)))return!0}return!1}async function fe(e,t,n,r){let{out:s}=n,{cf:a,db:i,route:o,app:p,deployer:c}=e,u=B(n.flags.json??!1),m=E=>Object.fromEntries(E.map(w=>[w,t[w]??null])),d=r==="unset",h=o.gateway.length>0?await yt({db:i,out:s},"gateway.secrets"):null;try{let E=p?await wt({db:i,out:s},{workerName:p.workerName,appId:p.manifest.id,purpose:"app.secrets"}):null;try{let w=[],R=null;if(h){let y=await St(i);if(R=y,!y)throw new S("GATEWAY_NOT_INSTALLED",`The Gateway${e.accountName?` in ${e.accountName}`:""} isn't fully installed`,{rerun:`${g} setup`});w.push({step:"secrets.gateway",shownAs:"the Gateway",names:o.gateway,targets:[{workerName:Q,changes:m(o.gateway),recordedVersionIds:[y.liveVersionId],record:f=>ht(i,{...y,liveVersionId:f,updatedAt:Date.now(),updatedBy:c.actor})}]})}if(p){let y=await We(i,p.workerName),f=y.map(_=>_.versionId);w.push({step:"secrets.app",shownAs:p.manifest.id,names:p.names,targets:[{workerName:p.workerName,changes:m(p.names),recordedVersionIds:f,record:_=>ve(i,p.workerName,_)},...y.filter(_=>_.binding!=="").map(_=>({workerName:_.name,changes:m(p.names),recordedVersionIds:f,record:b=>ve(i,p.workerName,b,_.binding)}))]})}for(let y of w)for(let f of y.names)s.emit({type:"progress",step:"secrets.route",message:`${f} is ${y.step==="secrets.gateway"?"a Gateway setting":`${y.shownAs}'s secret`} \u2192 Worker ${y.targets.map(_=>_.workerName).join(", ")}`});for(let y of w)for(let f of y.targets){let _=I(Object.keys(f.changes));await Ft({cf:a,workerName:f.workerName,shownAs:y.shownAs,recordedVersionIds:f.recordedVersionIds,interactive:u,change:d?{question:`Remove ${_} from it anyway?`,effect:`Removing ${_} creates a new version from it.`}:{question:`Set ${_} on it anyway?`,effect:`Setting ${_} creates a new version from it.`}})}if(d&&!await mr(a,w,s))return null;let A={};for(let[y,f]of w.entries()){let _=f.targets.filter($=>Object.keys($.changes).length>0);if(_.length===0)continue;let b=f.names.filter($=>_.some(k=>Object.hasOwn(k.changes,$))),N=`${d?"Removed":"Set"} ${I(b)} ${d?"from":"on"} ${f.shownAs}`;s.emit({type:"step",step:f.step,status:"start",message:d?"Removing...":`Updating ${f.shownAs}...`});let T={};for(let $ of _){try{await ut(a,$.workerName,$.changes)}catch(we){let F=Object.values(A).flatMap(L=>L.names);if(F.length===0)throw we;let P=w.slice(y).flatMap(L=>L.names);throw new S("SECRETS_PARTIALLY_APPLIED",[`Couldn't ${d?"remove":"set"} ${I(f.names)} ${d?"from":"on"} ${f.shownAs}`,`Cloudflare said: ${C(we).split(`
|
|
40
|
+
`)[0]}`,`${I(F)} ${F.length===1?"is":"are"} ${d?"removed":"set"}; only ${I(P)} ${P.length===1?"is":"are"} left.`].join(`
|
|
41
|
+
`),{rerun:`${g} secret ${r} ${P.join(" ")}${p&&o.app?.source==="registry"&&P.some(L=>p.names.includes(L))?` --app ${p.manifest.id}`:""}`,retryable:!0,data:{applied:Ve(A),left:P}})}let x=(await zt(a,$.workerName))?.versionId??null;x&&await $.record(x),T[$.workerName]=x,s.emit({type:"progress",step:"secrets.version",message:`${$.workerName} is now at version ${x??"unknown"}`})}if(f.step==="secrets.gateway"){let $=await dr(i,b,d,c.actor,s).catch(k=>(s.emit({type:"progress",step:"secrets.pin",message:`Couldn't record which origin ${I(b)} ${b.length===1?"is":"are"} pinned to (${C(k).split(`
|
|
42
|
+
`)[0]}); the Gateway pins it on first use`}),[]));if(A.gateway={names:b,versions:T,...$.length>0?{pinned:$}:{}},!d&&e.providers.length>0&&R){let k=await Bt(i,R,b);k.length>0&&(A.gateway.bound=k,s.emit({type:"progress",step:"secrets.bind",message:`Bound ${I(k)}'s key to the hosts ${k.length===1?"its row names":"their rows name"}`,data:{providers:k}}))}}else A.app={id:p.manifest.id,workerName:p.workerName,names:b,versions:T},await ur(a,i,p,s);s.emit({type:"step",step:f.step,status:"ok",message:N,data:{action:r,names:b,versions:T}})}return await Yt({cf:a,db:i,deployer:c},{gateway:A.gateway?.names??[],appRowId:A.app&&p?p.rowId:null,except:n.setupRecordedBy},s),A}finally{await E?.release()}}finally{await h?.release()}}async function dr(e,t,n,r,s){if(n){for(let i of await tn(e,t))s.emit({type:"progress",step:"secrets.pin",message:`${i}'s pin to its MCP server's origin is gone`});return[]}let a=await en(e,t,r);for(let{name:i,origin:o}of a.bound)s.emit({type:"progress",step:"secrets.pin",message:`${i} is pinned to ${o}`});for(let{name:i,kept:o}of a.undeclared)s.emit({type:"warning",code:"REMOTE_MCP_SECRET_UNDECLARED",step:"secrets.gateway",message:o?`No MCP app declares ${i} now
|
|
43
|
+
It stays pinned to ${o}, where it was set before; the Gateway sends it nowhere else.`:`No MCP app declares ${i}
|
|
44
|
+
The Gateway pins it to the first MCP app that uses it.`,data:{name:i,pinnedTo:o,fix:`${g} mcp add <url> --secret ${i}`}});for(let{name:i,origins:o}of a.ambiguous)s.emit({type:"warning",code:"REMOTE_MCP_SECRET_AMBIGUOUS",step:"secrets.gateway",message:`MCP apps at ${I(o)} all declare ${i}
|
|
45
|
+
It isn't pinned to any of them, so the Gateway sends it to none until one is removed.`,data:{name:i,origins:o,rerun:`${g} mcp list`,rerunNote:"names the apps"}});return a.bound}async function ur(e,t,n,r){try{await Dt(t,n.rowId,await Oe(e,n.workerName))}catch(s){r.emit({type:"progress",step:"secrets.record",message:`Couldn't record ${n.manifest.id}'s secret names (${C(s).split(`
|
|
46
|
+
`)[0]}); ${g} status records them`})}}async function mr(e,t,n){let r=!1;for(let s of t.flatMap(a=>a.targets)){let a=await ce(e,s.workerName);for(let i of Object.keys(s.changes)){if(a.includes(i)){r=!0;continue}delete s.changes[i],n.emit({type:"progress",step:"secrets.held",message:`${i} isn't set on ${s.workerName}`})}}return r}function Be(e,t){return[...e.gateway?[`${I(e.gateway.names)} ${t} the Gateway`]:[],...e.app?[`${I(e.app.names)} ${t} ${e.app.id}`]:[]].join(", and ")}function Ve(e){return{...e.gateway?{gateway:e.gateway}:{},...e.app?{app:e.app}:{}}}export{Yt as a,_r as b,z as c,vr as d,Or as e,Mr as f,Cr as g,Pr as h,Lr as i,bn as j,Ur as k,xr as l,vn as m,Gr as n,zr as o,en as p,Un as q,xn as r,Jn as s,dn as t,an as u,un as v,_s as w,Ns as x,$s as y,Zn as z,Qn as A,Ts as B,ks as C,nr as D,rr as E,ar as F,fn as G,Ve as H};
|