everyapp 0.2.2 → 0.3.0-rc.1
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/README.md +6 -77
- package/bin/everyapp.js +235 -0
- package/dist/access-F3GKBKAW.js +1 -0
- package/dist/activity-4MFMH5JP.js +12 -0
- package/dist/apps-63K2DGVT.js +9 -0
- package/dist/chunk-2UFJRKEE.js +4 -0
- package/dist/chunk-3AAHHUJC.js +11 -0
- package/dist/chunk-3Z53CH4F.js +6 -0
- package/dist/chunk-5ZTFC6DK.js +1 -0
- package/dist/chunk-6O3GJS5H.js +15 -0
- package/dist/chunk-74EST4VW.js +2 -0
- package/dist/chunk-7LG3F4FF.js +10 -0
- package/dist/chunk-AUDGOIHE.js +1 -0
- package/dist/chunk-BHMRY53V.js +2 -0
- package/dist/chunk-DQWOXSL3.js +32 -0
- package/dist/chunk-E3EPK27P.js +10 -0
- package/dist/chunk-E7EUXUVD.js +1 -0
- package/dist/chunk-ECLJ5IAL.js +126 -0
- package/dist/chunk-EQX4GKJ2.js +4 -0
- package/dist/chunk-EUNGJMJ6.js +20 -0
- package/dist/chunk-F6IH47GT.js +4 -0
- package/dist/chunk-G64S77GC.js +33 -0
- package/dist/chunk-GD2JZMD3.js +1 -0
- package/dist/chunk-GRFPP4UW.js +7 -0
- package/dist/chunk-IA534DGW.js +10 -0
- package/dist/chunk-IG26HYRR.js +45 -0
- package/dist/chunk-IZEOAOKL.js +6 -0
- package/dist/chunk-JYKRUS5C.js +1 -0
- package/dist/chunk-KMAOZRV4.js +18 -0
- package/dist/chunk-MC56CUQI.js +7 -0
- package/dist/chunk-MDORVBPD.js +1 -0
- package/dist/chunk-N4E5YE4X.js +5 -0
- package/dist/chunk-NJFWEYX7.js +1 -0
- package/dist/chunk-OEOVNJAN.js +1 -0
- package/dist/chunk-OVKVV6MK.js +2 -0
- package/dist/chunk-PL6EORDJ.js +15 -0
- package/dist/chunk-PMPIMHKG.js +6 -0
- package/dist/chunk-QZWSSWMP.js +22 -0
- package/dist/chunk-R4CGF622.js +2 -0
- package/dist/chunk-RFVMR32Y.js +1 -0
- package/dist/chunk-RQFHVU3Y.js +25 -0
- package/dist/chunk-SAT3PGZU.js +57 -0
- package/dist/chunk-SPPR6WCI.js +1 -0
- package/dist/chunk-TPWSGRNT.js +30 -0
- package/dist/chunk-VVQRET35.js +2 -0
- package/dist/chunk-VXJQGJ7Y.js +2 -0
- package/dist/chunk-WEM3WLOC.js +1 -0
- package/dist/chunk-Y3VIFPN5.js +1 -0
- package/dist/chunk-YJBYZWSP.js +22 -0
- package/dist/chunk-ZYL2ZHCF.js +98 -0
- package/dist/configure-2KMHM22T.js +8 -0
- package/dist/create-ELEJMZBS.js +22 -0
- package/dist/db-MZIAKGBN.js +9 -0
- package/dist/delete-H47KPJSB.js +3 -0
- package/dist/deploy-HGFJLLUO.js +1 -0
- package/dist/dev-62VA7UEM.js +86 -0
- package/dist/email-NNFD3VVB.js +10 -0
- package/dist/events-JDY76EG6.js +15 -0
- package/dist/groups-NQFXDZZP.js +8 -0
- package/dist/index.js +92 -1
- package/dist/install-JTZWRZIL.js +1 -0
- package/dist/login-P6LYQQWP.js +1 -0
- package/dist/mcp-NCFWEBMD.js +1 -0
- package/dist/provider-WVBI2VED.js +13 -0
- package/dist/release-6FYSPXXA.js +1 -0
- package/dist/restore-XBU7DOJV.js +3 -0
- package/dist/secret-ML5EXS3O.js +1 -0
- package/dist/setup-IEXCISLP.js +1 -0
- package/dist/status-OPLPKJ4U.js +4 -0
- package/dist/teardown-3JMMLK6O.js +22 -0
- package/dist/update-37ZDATLR.js +1 -0
- package/dist/workspace-DAFZVYQ2.js +21 -0
- package/package.json +30 -27
- package/skills/build-every-app/SKILL.md +199 -0
- package/skills/build-every-app/patterns.md +134 -0
- package/skills/everyapp/SKILL.md +292 -0
- package/skills/everyapp/mcp.md +336 -0
- package/skills/everyapp/security-review.md +61 -0
- package/skills/everyapp/setup/README.md +263 -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 +353 -0
- package/skills/everyapp/setup/remote-mcp.md +199 -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,2 @@
|
|
|
1
|
+
import{q as d}from"./chunk-JYKRUS5C.js";import{Wb as p,xb as u,zb as l}from"./chunk-SAT3PGZU.js";var P=50,y=20;function g(t,r,e={}){return p(t,["ssl","certificate-packs","list","-z",r,...e.allStatuses?["--status","all"]:[]],d,{perPage:P,maxPages:y})}function m(t){return!t.status||t.status==="active"}function C(t){return(t.hosts??[]).map(r=>r.toLowerCase())}function w(t,r){let e=t.toLowerCase();if(e===r)return!0;if(!e.startsWith("*."))return!1;let[,...i]=r.split(".");return i.join(".")===e.slice(2)}async function b(t,r,e){let i=(await g(t,r)).filter(m);return e.map(o=>({host:o,ready:i.some(s=>(s.hosts??[]).some(n=>w(n,o.toLowerCase())))}))}function v(t,r){let e=r.toLowerCase(),i=new Set([e,`*.${e}`]),o=[...t],s=[];for(let n of t){if(n.type==="universal")continue;let a=C(n);if(!a.includes(e))continue;let f=o.filter(c=>c!==n&&m(c));a.every(c=>i.has(c)||f.some(k=>C(k).includes(c)))&&(o.splice(o.indexOf(n),1),s.push(n))}return s}var S=new Set(["pending_deletion","deleted","pending_cleanup"]);function R(t,r){let e=t.find(i=>i.id===r);return!e||S.has((e.status??"").toLowerCase())}async function h(t,r,e){await t.run({plane:"account",mode:"json",args:["ssl","certificate-packs","delete",e,"-z",r,"--force"]})}async function T({cf:t,out:r,zoneId:e,hostname:i}){let o="app.certificate",s=[];try{let n=v(await g(t,e),i);for(let a of n)try{await h(t,e,a.id),s.push(a.id)}catch(f){if(!l(f,"not_found"))throw f}}catch(n){return r.emit({type:"warning",code:"CERT_CLEANUP_FAILED",step:o,message:[`Couldn't remove ${i}'s certificate`,`It serves nothing now. Cloudflare said: ${u(n)}.`,"Optional: delete it in the Cloudflare dashboard (SSL/TLS \u2192 Edge Certificates)."].join(`
|
|
2
|
+
`)}),s}return s.length>0&&r.emit({type:"step",step:o,status:"ok",message:`Removed ${i}'s certificate.`,data:{hostname:i,certificatePacks:s}}),s}export{g as a,b,v as c,R as d,h as e,T as f};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as E,b as v}from"./chunk-YJBYZWSP.js";import{a as A}from"./chunk-KMAOZRV4.js";import{a as y}from"./chunk-F6IH47GT.js";import{c as a,cc as f,gc as w,oc as g}from"./chunk-SAT3PGZU.js";import I from"chalk";async function N(t){await S(t,(e,o)=>v(t,e,o))}async function S(t,e){let o=Date.now();await g(t,async n=>{let r=A({out:n,verbose:t.verbose}),i=await e(n,E({gateway:{openRelease:r.open,source:r.describe},interactive:y(t.json??!1)}));_(n,i,o)})}function _(t,e,o){let{gatewayUrl:n,organizationName:r,release:i,releaseName:p,owner:c,mode:d}=e,l=`${n}/admin`,s={gatewayUrl:n,adminUrl:l,organizationName:r,owner:c,release:i,mode:d,gateway:e.gateway,accessOn:e.accessOn},m={label:"Gateway",value:n},u=e.accessOn?[{label:"Access",value:"on",note:"everyone signs in through Cloudflare Access first"}]:[];if(e.gateway==="upgraded"&&!e.ownerCreated){t.emit({type:"done",message:`Upgraded to ${p}`,data:s,display:[...w([{label:"Gateway",value:I.cyan(n)}]),I.dim(`Upgraded to ${p} in ${f(Date.now()-o)}`)].join(`
|
|
2
|
+
`)});return}if(!c){t.emit({type:"done",data:{...s,facts:[m]}});return}if(e.gateway==="installed"||e.ownerCreated){t.emit({type:"done",data:{...s,facts:[m,{label:"Admin",value:l,note:"invite people, choose who opens which app"},...u],next:O(d,e.accessOn===!0)}});return}t.emit({type:"done",data:{...s,facts:[m,...u],...e.gateway==="up-to-date"?{next:[{command:`${a} status`,note:"see apps, domains and certificates"}]}:{}}})}function O(t,e){return t==="hosted"?[{command:`${a} create my-app`,note:"start your first app"},{command:`${a} secret set OPENAI_API_KEY`,note:"turn on AI for apps"},{command:`${a} secret set EMAIL_FROM EMAIL_FROM_NAME`,note:"email invites; needs Cloudflare Email Sending"}]:[{command:`${a} create my-app`,note:"start your first app"},...e?[]:[{command:`${a} access on`,note:"put Cloudflare Access in front of your Gateway (recommended)"}],{command:`${a} secret set OPENAI_API_KEY`,note:"AI for apps (or OPENROUTER_API_KEY, WORKERS_AI_API_TOKEN)"},{command:`${a} secret set EMAIL_FROM EMAIL_FROM_NAME`,note:"email invites and password resets; needs Cloudflare Email Sending"}]}export{N as a,S as b,_ as c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{f as i}from"./chunk-74EST4VW.js";async function o(a,e){let t=await i(a);t&&e.emit({type:"warning",code:"LEGACY_LOCAL_STATE",message:t})}function p(a,e,t){a.emit({type:"step",step:e,status:"ok",message:t.applied.length>0?`Applied ${t.applied.join(", ")}.`:"The local database is up to date.",data:{database:t.database,applied:t.applied}})}export{o as a,p as b};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as a}from"./chunk-JYKRUS5C.js";import{Vb as i,yb as c}from"./chunk-SAT3PGZU.js";async function m(e,t){return(await i(e,{plane:"account",args:["workers","secrets","list","--worker",t]},a)).map(r=>r.name).sort()}async function p(e,t,n){try{return await e.run({plane:"account",mode:"json",args:["workers","secrets","delete",n,"--worker",t,"--force"]}),!0}catch(r){if(r instanceof c&&(r.kind==="not_found"||/not[_ ]found/i.test(r.message)))return!1;throw r}}async function d(e,t,n){let r={secrets:Object.fromEntries(Object.entries(n).map(([s,o])=>[s,o===null?null:{name:s,type:"secret_text",text:o}]))};await e.run({plane:"account",mode:"json",files:{"secrets.json":r},args:s=>["workers","secrets","bulk","--worker",t,"--body",`@${s["secrets.json"]}`]})}export{m as a,p as b,d as c};
|
|
@@ -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-QZWSSWMP.js";import{e as q}from"./chunk-E3EPK27P.js";import{y as me}from"./chunk-IG26HYRR.js";import{a as he,b as ve,c as T,d as ke,e as De}from"./chunk-IZEOAOKL.js";import{c as we,j as fe,k as ge,n as M,o as ye}from"./chunk-KMAOZRV4.js";import{c as P,i as L}from"./chunk-PMPIMHKG.js";import{e as I,g as be,h as N,i as _}from"./chunk-OVKVV6MK.js";import{a as G}from"./chunk-RFVMR32Y.js";import{g as ue}from"./chunk-GRFPP4UW.js";import{a as Y}from"./chunk-Y3VIFPN5.js";import{a as R,j as oe,s as ie,u as le,v as ce}from"./chunk-ZYL2ZHCF.js";import{c as ne,d as se,f as re}from"./chunk-7LG3F4FF.js";import{b as X,c as J,e as Q,f as ee,g as te}from"./chunk-F6IH47GT.js";import{Lb as x,Ub as Z,Vb as K,b as E,bc as U,c as S,d as W,dc as ae,e as H,ib as V,ic as pe,tb as C,ub as D,vb as B,xb as z}from"./chunk-SAT3PGZU.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,98 @@
|
|
|
1
|
+
import{a as xe,b as V,e as E,f as C,g as $e,h as Ue,i as Me,j as ze,k as Ge,l as We}from"./chunk-SPPR6WCI.js";import{c as q,d as Pe}from"./chunk-7LG3F4FF.js";import{a as Ce,e as ke}from"./chunk-F6IH47GT.js";import{a as De,c as be,d as Re,e as Te,f as Ae,g as Ne,h as ve,i as Se,j as Ie}from"./chunk-JYKRUS5C.js";import{Ca as U,Da as me,Ea as M,Fa as z,Ga as G,Ha as W,Ia as F,Ja as H,La as ge,Lb as ye,Na as _e,Oa as fe,Pa as Ee,Ub as we,Vb as f,W as pe,Wb as he,Yb as Oe,_b as Le,c,d as ce,e as A,i as N,tb as l,ub as L,xa as $,za as v,zb as S}from"./chunk-SAT3PGZU.js";import Fe from"node:path";function He(e,t){return{run:async(a,n)=>(await Ot(e,t,a,n)).map(r=>r.rows)}}var It=6e5;function An(e){let[,t=e,a]=/^([\s\S]*?)(?::\s*(SQLITE_[A-Z_]+))?(?:\s*\[code: \d+\])?$/.exec(e.trim())??[];return{problem:t,...a?{sqliteCode:a}:{}}}async function Ot(e,t,a,{timeoutMs:n}={}){let r=a.length===1?a[0]:{batch:a};return(await f(e,{plane:"account",...n?{timeoutMs:n}:{},args:s=>["d1","query",t,"--body",`@${s["query.json"]}`],files:{"query.json":r}},Ae)).map(s=>({rows:s.results??[],duration:s.meta?.duration??0,changes:s.meta?.changes??0}))}async function Nn(e,t){let{bookmark:a}=await f(e,{plane:"account",args:["d1","time-travel","get-bookmark",t]},Ne);return a}async function vn(e,t,a){await f(e,{plane:"account",args:["d1","time-travel","restore",t,"--bookmark",a,"--force"]},ve)}function Sn(e,t,a,{platform:n=process.platform,shell:r=process.env.SHELL}={}){let i=`npx cf@${ye} d1 time-travel restore ${e} --bookmark ${t} --force`;return a?n==="win32"&&!r?`$env:CLOUDFLARE_ACCOUNT_ID="${a}"; ${i}`:`CLOUDFLARE_ACCOUNT_ID=${a} ${i}`:i}function qe(e,t){let a=Fe.resolve(e);return["--dir",a,...t?["--pattern",Fe.join(a,"*","migration.sql")]:[]]}async function In({cf:e,databaseId:t,dir:a,nested:n=!1}){return(await f(e,{plane:"account",args:["d1","migrations","list",t,...qe(a,n)]},Te)).map(i=>i.Name)}async function On({cf:e,databaseId:t,dir:a,nested:n=!1}){let r=await f(e,{plane:"account",timeoutMs:It,args:["d1","migrations","apply",t,...qe(a,n)]},De),i=r.filter(s=>s.status!=="\u2705");if(i.length>0)throw new Error(`cf reported ${i.map(s=>`${s.name} ${s.status}`).join(", ")} (applying ${r.map(s=>s.name).join(", ")}).`);return r.map(s=>s.name)}import{generateKeyPairSync as Lt,randomBytes as Ct}from"node:crypto";var Ve=["self_hosted","hosted"];function kn({gatewayUrl:e,accountId:t,deploymentMode:a}){let{privateKey:n,publicKey:r}=Lt("rsa",{modulusLength:2048,publicKeyEncoding:{type:"spki",format:"pem"},privateKeyEncoding:{type:"pkcs8",format:"pem"}});return{secrets:{GATEWAY_URL:e,BETTER_AUTH_SECRET:Ct(32).toString("base64"),JWT_PRIVATE_KEY:n,JWT_PUBLIC_KEY:r,GATEWAY_DEPLOYMENT_MODE:a,CLOUDFLARE_ACCOUNT_ID:t},jwtPublicKey:r}}var kt=`CREATE TABLE IF NOT EXISTS _everyapp_install (
|
|
2
|
+
id TEXT PRIMARY KEY CHECK (id = 'install'),
|
|
3
|
+
account_id TEXT NOT NULL,
|
|
4
|
+
zone_id TEXT NOT NULL,
|
|
5
|
+
zone_name TEXT NOT NULL,
|
|
6
|
+
gateway_host TEXT NOT NULL,
|
|
7
|
+
app_base_domain TEXT NOT NULL,
|
|
8
|
+
oauth_kv_id TEXT NOT NULL,
|
|
9
|
+
release_version TEXT NOT NULL,
|
|
10
|
+
release_sha256 TEXT NOT NULL,
|
|
11
|
+
release_schema INTEGER NOT NULL,
|
|
12
|
+
release_committed_at INTEGER NOT NULL,
|
|
13
|
+
source_tree_sha256 TEXT,
|
|
14
|
+
live_version_id TEXT,
|
|
15
|
+
live_domains TEXT NOT NULL DEFAULT '[]',
|
|
16
|
+
live_app_workers TEXT NOT NULL DEFAULT '[]',
|
|
17
|
+
updated_at INTEGER NOT NULL,
|
|
18
|
+
updated_by TEXT,
|
|
19
|
+
jwt_public_key TEXT,
|
|
20
|
+
deployment_mode TEXT
|
|
21
|
+
)`;function Be(e){try{let t=JSON.parse(String(e??"[]"));return Array.isArray(t)?t.map(String):[]}catch{return[]}}var Pt=e=>Ve.includes(e)?e:null;function Ye(){return new l("GATEWAY_NOT_INSTALLED",`The Gateway's install didn't finish
|
|
22
|
+
Setup stopped before it recorded the install.`,{rerun:`${c} setup`,rerunNote:"asks for the hostname again"})}async function Ke(e){let[t=[]]=await e.run([{sql:"SELECT name FROM sqlite_master WHERE type = 'table' AND name = '_everyapp_install'"}]);if(t.length===0)return null;let[a=[]]=await e.run([{sql:"SELECT * FROM _everyapp_install WHERE id = 'install'"}]),n=a[0];return n?{accountId:String(n.account_id),zoneId:String(n.zone_id),zoneName:String(n.zone_name),gatewayHost:String(n.gateway_host),appBaseDomain:String(n.app_base_domain),oauthKvId:String(n.oauth_kv_id),releaseVersion:String(n.release_version),releaseSha256:String(n.release_sha256),releaseOrder:{schema:Number(n.release_schema),committedAt:Number(n.release_committed_at)},sourceTreeSha256:N(n.source_tree_sha256),liveVersionId:N(n.live_version_id),liveDomains:Be(n.live_domains),liveAppWorkers:Be(n.live_app_workers),updatedAt:Number(n.updated_at),updatedBy:N(n.updated_by),jwtPublicKey:N(n.jwt_public_key),deploymentMode:Pt(n.deployment_mode)}:null}async function zn(e,t){let a=[t.accountId,t.zoneId,t.zoneName,t.gatewayHost,t.appBaseDomain,t.oauthKvId,t.releaseVersion,t.releaseSha256,t.releaseOrder.schema,t.releaseOrder.committedAt,t.sourceTreeSha256,t.liveVersionId,JSON.stringify(t.liveDomains),JSON.stringify(t.liveAppWorkers),t.updatedAt,t.updatedBy,t.jwtPublicKey,t.deploymentMode];await e.run([{sql:kt},{sql:`INSERT INTO _everyapp_install (id, account_id, zone_id, zone_name, gateway_host,
|
|
23
|
+
app_base_domain, oauth_kv_id, release_version, release_sha256, release_schema,
|
|
24
|
+
release_committed_at, source_tree_sha256, live_version_id, live_domains,
|
|
25
|
+
live_app_workers, updated_at, updated_by, jwt_public_key, deployment_mode)
|
|
26
|
+
VALUES ('install', ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?16, ?17, ?18)
|
|
27
|
+
ON CONFLICT(id) DO UPDATE SET account_id = excluded.account_id,
|
|
28
|
+
zone_id = excluded.zone_id, zone_name = excluded.zone_name,
|
|
29
|
+
gateway_host = excluded.gateway_host, app_base_domain = excluded.app_base_domain,
|
|
30
|
+
oauth_kv_id = excluded.oauth_kv_id, release_version = excluded.release_version,
|
|
31
|
+
release_sha256 = excluded.release_sha256, release_schema = excluded.release_schema,
|
|
32
|
+
release_committed_at = excluded.release_committed_at,
|
|
33
|
+
source_tree_sha256 = excluded.source_tree_sha256,
|
|
34
|
+
live_version_id = excluded.live_version_id, live_domains = excluded.live_domains,
|
|
35
|
+
live_app_workers = excluded.live_app_workers, updated_at = excluded.updated_at,
|
|
36
|
+
updated_by = excluded.updated_by,
|
|
37
|
+
jwt_public_key = COALESCE(excluded.jwt_public_key, _everyapp_install.jwt_public_key),
|
|
38
|
+
deployment_mode = COALESCE(excluded.deployment_mode, _everyapp_install.deployment_mode)`,params:a}])}var xt=100,$t=50;async function je(e,t){let a=await e();if(a)return{id:a,created:!1};try{return{id:await t(),created:!0}}catch(n){let r=S(n,"already_exists")?await e():null;if(r)return{id:r,created:!1};throw n}}async function B(e,t){return(await f(e,{plane:"account",args:["d1","list","--name",t,"--per-page","100"]},Re)).find(n=>n.name===t)?.uuid??null}async function Ut(e,t){return(await f(e,{plane:"account",args:["d1","create","--name",t]},be)).uuid}function Xe(e,t){return je(()=>B(e,t),()=>Ut(e,t))}async function Mt(e,t){return(await he(e,["kv","namespaces","list"],Ie,{perPage:xt,maxPages:$t})).find(n=>n.title===t)?.id??null}async function zt(e,t){return(await f(e,{plane:"account",args:["kv","namespaces","create","--title",t]},Se)).id}function Je(e,t){return je(()=>Mt(e,t),()=>zt(e,t))}async function qn(e,t){await e.run({plane:"account",mode:"json",args:["d1","delete",t,"--force"]})}async function Vn(e,t){await e.run({plane:"account",mode:"json",args:["kv","namespaces","delete",t,"--force"]})}import{randomBytes as qt}from"node:crypto";import{randomBytes as Y}from"node:crypto";var Ze="0123456789ABCDEFGHJKMNPQRSTVWXYZ",Gt=10,Wt=16;function Ft(e=Date.now()){let t="",a=Math.max(0,Math.floor(e));for(let r=0;r<Gt;r+=1)t=Ze[a%32]+t,a=Math.floor(a/32);let n=[...Y(Wt)].map(r=>Ze[r%32]).join("");return`${t}${n}`}var K=e=>`evt_${Ft(e)}`,j=()=>`sub_${Y(12).toString("hex")}`,X=()=>`dlv_${Y(12).toString("hex")}`;var Ht=/^\d{1,3}(\.\d{1,3}){3}$/,J=e=>e.trim().toLowerCase().replace(/\.$/,""),Qe=(e,t)=>t!==""&&(e===t||e.endsWith(`.${t}`)),y=(e,t=!1)=>({ok:!1,reason:e,private:t});function et(e,t){let a=e.trim();if(a.length>F)return y(`A webhook URL is at most ${F.toLocaleString("en-US")} characters.`);let n;try{n=new URL(a)}catch{return y("It isn't a URL: give the whole address, like https://hooks.example.com/everyapp.")}if(n.protocol==="http:"){if(!t.allowPrivate)return y("A webhook URL starts with https://: the event and its signature would cross the internet in the clear.",!0)}else if(n.protocol!=="https:")return y(`A webhook URL starts with https://, not ${n.protocol}//.`);if(n.username||n.password)return y("A webhook URL carries no user name or password: the subscription's secret signs each delivery instead.");if(n.hash||a.includes("#"))return y("A webhook URL has no fragment (#\u2026): it is never sent to the receiver.");let r=J(n.hostname),i=J(t.gatewayHost),s=J(t.appBaseDomain);return Qe(r,i)||Qe(r,s)?y(`${r} is the Gateway's own host, or under its apps' domain ${s}: a delivery there would loop back into the Gateway.`):r.startsWith("[")||Ht.test(r)?t.allowPrivate?{ok:!0,url:n.toString()}:y("A webhook URL names its host, not an IP address.",!0):ge(r)&&!t.allowPrivate?y(`${r} is a local or internal name, which the Gateway's Worker can't reach.`,!0):{ok:!0,url:n.toString()}}function Xn(e){try{let t=new URL(e),a=t.pathname==="/"?"":t.pathname;return`${t.protocol==="http:"?"http://":""}${t.host}${a}`}catch{return"(unreadable URL)"}}function Jn(e){try{return new URL(e).hostname}catch{return"Webhook"}}function Q(e){return{kind:"operator",id:e.actor,...e.email?{email:e.email}:{}}}var tt=new WeakMap;function ee(e){let t=tt.get(e);return t||(t=e.run([{sql:"PRAGMA table_info(events)"}]).then(([a=[]])=>a.length>0),tt.set(e,t)),t}async function R(e){if(!await ee(e))throw new l("GATEWAY_OUTDATED",`The Gateway predates events
|
|
39
|
+
Its database has no event tables until the Gateway is updated to a release that has them.`,{rerun:`${c} update`,rerunNote:"then run this again"})}async function te(e,t){if(!await ee(e))return[];let a=U(t.type);if(!a)throw new Error(`${t.type} isn't in the event catalogue`);let n=Ee(t.data,me);if(!n.ok)throw new Error(`${t.type}'s data: ${n.message}`);let r=t.now??Date.now(),i=K(r),[s=[]]=await e.run([{sql:"SELECT id, events FROM event_subscriptions WHERE organization_id = ? AND enabled = 1",params:[t.organizationId]}]),o=s.filter(u=>_e(nt(u.events),t.type)).map(u=>String(u.id));return[{sql:`INSERT INTO events (id, organization_id, type, version, time, actor, data, app_row_id, dedupe_key, created_at)
|
|
40
|
+
SELECT ?, ?, ?, ?, ?, ?, ?, ?, ?, ? WHERE 1${t.onlyIf?` AND (${t.onlyIf.sql})`:""}
|
|
41
|
+
ON CONFLICT DO NOTHING`,params:[i,t.organizationId,t.type,a.version,r,JSON.stringify(t.actor),JSON.stringify(t.data),t.appRowId??null,t.dedupeKey??null,r,...t.onlyIf?.params??[]]},...o.map(u=>Vt(i,u,t.organizationId,r))]}function Vt(e,t,a,n){return{sql:`INSERT INTO event_deliveries (id, event_id, subscription_id, organization_id, status, attempts, next_attempt_at, created_at)
|
|
42
|
+
SELECT ?1, ?2, ?3, ?4, 'pending', 0, ?5, ?5
|
|
43
|
+
WHERE EXISTS (SELECT 1 FROM events WHERE id = ?2)
|
|
44
|
+
AND EXISTS (SELECT 1 FROM event_subscriptions WHERE id = ?3 AND organization_id = ?4 AND enabled = 1)`,params:[X(),e,t,a,n]}}var Bt="cap_alerts",Yt="Cap alerts",Kt=["cap.warning","cap.reached"];async function ia(e,t){return await ee(e)?{sql:`INSERT INTO event_subscriptions (id, organization_id, name, sink, url, secret, recipients, events, enabled,
|
|
45
|
+
builtin, description, created_at, updated_at, created_by, consecutive_failures)
|
|
46
|
+
SELECT ?1, ?2, ?3, 'email', NULL, NULL, 'admins', ?4, 1, ?5, ?6, ?7, ?7, ?8, 0
|
|
47
|
+
WHERE NOT EXISTS (SELECT 1 FROM event_subscriptions WHERE organization_id = ?2 AND builtin = ?5)
|
|
48
|
+
RETURNING id`,params:[j(),t.organizationId,Yt,JSON.stringify(Kt),Bt,"Owners and admins get an email at 80% and at the cap.",t.now,`operator:${t.deployer.actor}`]}:null}function nt(e){try{let t=JSON.parse(String(e));if(Array.isArray(t)&&t.every(a=>typeof a=="string"))return t}catch{}return[]}var ne="id, name, sink, url, recipients, events, enabled, builtin, description, created_at, created_by, last_delivery_at, last_delivery_status, consecutive_failures",b=e=>e==null?null:Number(e),h=e=>e==null?null:String(e);function ae(e){return{id:String(e.id),name:String(e.name),sink:e.sink==="email"?"email":"webhook",url:h(e.url),recipients:e.recipients==="owners"||e.recipients==="admins"?e.recipients:null,events:nt(e.events),enabled:Number(e.enabled)===1,builtin:h(e.builtin),description:h(e.description),createdAt:Number(e.created_at),createdBy:h(e.created_by),lastDeliveryAt:b(e.last_delivery_at),lastDeliveryStatus:h(e.last_delivery_status),consecutiveFailures:Number(e.consecutive_failures??0)}}async function sa(e,t){await R(e);let[a=[]]=await e.run([{sql:`SELECT ${ne} FROM event_subscriptions WHERE organization_id = ? ORDER BY created_at, id`,params:[t]}]);return a.map(ae)}function jt(e,t){return new l("EVENT_SUBSCRIPTION_NOT_FOUND",`No subscription ${e} in ${t}
|
|
49
|
+
Subscriptions belong to one organization; --org names another.`,{rerun:`${c} events list`,rerunNote:"lists them"})}async function re(e,t,a){await R(e);let[n=[]]=await e.run([{sql:`SELECT ${ne} FROM event_subscriptions WHERE id = ? AND organization_id = ?`,params:[a.trim(),t.id]}]);if(!n[0])throw jt(a.trim(),t.name);return ae(n[0])}function oa(e){let t=[...new Set((e??[]).flatMap(n=>n.split(",")).map(n=>n.trim()).filter(Boolean))];if(t.length===0)return["*"];let a=t.flatMap(n=>{let r=fe(n);return r?[{pattern:n,problem:r}]:[]});if(a.length>0)throw new l("EVENT_TYPE_UNKNOWN",[a.length===1?`${a[0].pattern} isn't an event type`:`${a.length} of --events aren't event types`,...a.map(n=>n.problem)].join(`
|
|
50
|
+
`),{fix:"name types (member.joined), prefixes (member.*), an app's own events (app.crm.*) or * for everything",rerun:`${c} events types`,rerunNote:"lists the types",data:{patterns:a.map(n=>n.pattern)}});return t.includes("*")?["*"]:t}function la(e,t){let a=et(e,t);if(a.ok)return a.url;throw new l("EVENT_TARGET_REFUSED",`The Gateway won't deliver to that URL
|
|
51
|
+
${a.reason}`,{...a.private?{fix:`use a public https:// receiver; for one on a private network, set EVENTS_ALLOW_PRIVATE_TARGETS on the Gateway (${c} secret set EVENTS_ALLOW_PRIVATE_TARGETS, value true; self-host only)`}:{fix:"give the receiver's full https:// URL (Slack's, Zapier's, n8n's, your own)"}})}var Xt=/^[\x21-\x7e]+$/;function ua(e){let t=e.length<z||e.length>G?`A signing secret is ${z} to ${G} characters (this one is ${e.length}).`:Xt.test(e)?null:"A signing secret is printable ASCII with no spaces, so every receiver's HMAC reads the same bytes.";if(!t)return e;throw new l("EVENT_SECRET_INVALID",`That signing secret won't do
|
|
52
|
+
${t}`,{fix:"leave --secret out and the CLI makes one, or give one of 16 to 128 printable characters"})}var da=()=>`whsec_${qt(32).toString("base64url")}`;function ca(e){let t=e?.replace(/\s+/g," ").trim()??"";return t===""?null:t.length>H?t.slice(0,H):t}async function pa(e,t){await R(e);let a=t.now??Date.now(),n=j(),{target:r}=t,[i=[]]=await e.run([{sql:`INSERT INTO event_subscriptions (id, organization_id, name, sink, url, secret, recipients, events, enabled,
|
|
53
|
+
builtin, description, created_at, updated_at, created_by, consecutive_failures)
|
|
54
|
+
SELECT ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, 1, NULL, NULL, ?9, ?9, ?10, 0
|
|
55
|
+
WHERE (SELECT COUNT(*) FROM event_subscriptions WHERE organization_id = ?2) < ?11
|
|
56
|
+
RETURNING ${ne}`,params:[n,t.organization.id,t.name,r.sink,r.sink==="webhook"?r.url:null,r.sink==="webhook"?r.secret:null,r.sink==="email"?r.recipients:null,JSON.stringify(t.events),a,`operator:${t.deployer.actor}`,M]}]);if(!i[0])throw new l("EVENT_SUBSCRIPTIONS_LIMIT",`${t.organization.name} has ${M} subscriptions, the most an organization may have
|
|
57
|
+
Nothing was added.`,{fix:`remove one you no longer need (${c} events remove <id>), or widen one's --events instead of adding another`,rerun:`${c} events list`,rerunNote:"lists them"});return ae(i[0])}async function ma(e,t,a,n=Date.now()){let r=await re(e,t,a);return r.builtin?(await e.run([{sql:"UPDATE event_subscriptions SET enabled = 0, updated_at = ? WHERE id = ? AND organization_id = ?",params:[n,r.id,t.id]}]),{subscription:{...r,enabled:!1},outcome:"disabled"}):(await e.run([{sql:"DELETE FROM event_subscriptions WHERE id = ? AND organization_id = ?",params:[r.id,t.id]}]),{subscription:r,outcome:"removed"})}async function ga(e,t,a,n,r=Date.now()){let i=await re(e,t,a);return i.enabled===n?{subscription:i,changed:!1}:(await e.run([{sql:"UPDATE event_subscriptions SET enabled = ?, updated_at = ? WHERE id = ? AND organization_id = ?",params:[n?1:0,r,i.id,t.id]}]),{subscription:{...i,enabled:n},changed:!0})}function Jt(e,t){return new l("EVENT_SUBSCRIPTION_DISABLED",`${e.name} (${e.id}) is disabled
|
|
58
|
+
The Gateway drops what is queued for a disabled subscription, so ${t} would go nowhere.`,{rerun:`${c} events enable ${e.id}`,rerunNote:"then run this again"})}var at=`d.id, d.event_id, e.type, d.subscription_id, s.name AS subscription_name, s.sink, d.status, d.attempts,
|
|
59
|
+
d.next_attempt_at, d.claimed_until, d.last_attempt_at, d.last_status_code, d.last_error, d.delivered_at,
|
|
60
|
+
d.redelivered_at, d.created_at`,rt=`FROM event_deliveries d
|
|
61
|
+
LEFT JOIN events e ON e.id = d.event_id
|
|
62
|
+
LEFT JOIN event_subscriptions s ON s.id = d.subscription_id AND s.organization_id = d.organization_id`;function it(e){let t=String(e.status);return{id:String(e.id),eventId:String(e.event_id),type:h(e.type),subscriptionId:String(e.subscription_id),subscriptionName:h(e.subscription_name),sink:e.sink==="email"?"email":e.sink==="webhook"?"webhook":null,status:t==="delivered"||t==="dead"?t:"pending",attempts:Number(e.attempts??0),nextAttemptAt:b(e.next_attempt_at),claimedUntil:b(e.claimed_until),lastAttemptAt:b(e.last_attempt_at),lastStatusCode:b(e.last_status_code),lastError:h(e.last_error),deliveredAt:b(e.delivered_at),redeliveredAt:b(e.redelivered_at),createdAt:Number(e.created_at)}}function Zt(e,t=Date.now()){if(e.status!=="pending")return e.status;let a=e.claimedUntil!==null&&e.claimedUntil>t;return e.attempts>0&&e.lastError!==null&&!a?"failed":"pending"}var Qt=200;async function _a(e,t){await R(e);let a=(t.now??Date.now())-W*24*60*60*1e3,n=["d.organization_id = ?","d.created_at >= ?",...t.subscriptionId?["d.subscription_id = ?"]:[],...t.dead?["d.status = 'dead'"]:[]],[r=[]]=await e.run([{sql:`SELECT ${at} ${rt} WHERE ${n.join(" AND ")} ORDER BY d.created_at DESC, d.id DESC LIMIT ?`,params:[t.organizationId,a,...t.subscriptionId?[t.subscriptionId]:[],Math.min(Math.max(1,Math.floor(t.limit)),Qt)]}]);return r.map(it)}async function Z(e,t,a){let[n=[]]=await e.run([{sql:`SELECT ${at} ${rt} WHERE d.id = ? AND d.organization_id = ?`,params:[a,t]}]);return n[0]?it(n[0]):null}async function fa(e,t,a,n=Date.now()){await R(e);let r=await Z(e,t.id,a.trim());if(!r)throw new l("EVENT_DELIVERY_NOT_FOUND",`No delivery ${a.trim()} in ${t.name}
|
|
63
|
+
Deliveries are kept ${W} days, under the organization of their subscription.`,{rerun:`${c} events deliveries`,rerunNote:"lists the last ones"});let i=await re(e,t,r.subscriptionId).catch(u=>{throw u instanceof l&&u.code==="EVENT_SUBSCRIPTION_NOT_FOUND"?new l("EVENT_SUBSCRIPTION_NOT_FOUND",`${r.id} was for ${r.subscriptionId}, which is removed
|
|
64
|
+
There is nowhere to send it again.`,{rerun:`${c} events list`,rerunNote:"lists the subscriptions there are"}):u});if(!i.enabled)throw Jt(i,"sending it again");let[s=[]]=await e.run([{sql:`UPDATE event_deliveries SET status = 'pending', attempts = 0, next_attempt_at = ?1, redelivered_at = ?1, claimed_until = NULL
|
|
65
|
+
WHERE id = ?2 AND organization_id = ?3 AND status IN ('pending', 'dead') AND (claimed_until IS NULL OR claimed_until <= ?1)
|
|
66
|
+
RETURNING id`,params:[n,r.id,t.id]}]),o=await Z(e,t.id,r.id)??r,d=s.length>0?"queued":o.status==="delivered"?"delivered":"attempting";return{delivery:o,previous:r,outcome:d}}async function Ea(e,t){await R(e);let a=t.now??Date.now(),n=K(a),r=X(),i={subscription:{id:t.subscription.id,name:t.subscription.name},message:"A test event from everyapp events test. A signed delivery like this one means the subscription works."};return await e.run([{sql:`INSERT INTO events (id, organization_id, type, version, time, actor, data, app_row_id, dedupe_key, created_at)
|
|
67
|
+
VALUES (?1, ?2, 'ping', ?3, ?4, ?5, ?6, NULL, NULL, ?4)`,params:[n,t.organizationId,U("ping").version,a,JSON.stringify(t.actor),JSON.stringify(i)]},{sql:`INSERT INTO event_deliveries (id, event_id, subscription_id, organization_id, status, attempts, next_attempt_at, created_at)
|
|
68
|
+
VALUES (?1, ?2, ?3, ?4, 'pending', 0, ?5, ?5)`,params:[r,n,t.subscription.id,t.organizationId,a]}]),{eventId:n,deliveryId:r}}var en=9e4;async function ya(e,t,a,n={}){let r=n.sleep??(o=>new Promise(d=>setTimeout(d,o))),i=n.now??Date.now,s=i()+(n.timeoutMs??en);for(;;){let o=await Z(e,t,a);if(o&&Zt(o,i())!=="pending")return o;if(i()>=s)return null;await r(Math.min(n.intervalMs??3e3,Math.max(0,s-i())))}}import{randomUUID as tn}from"node:crypto";function ut(e,t,a=process.env){return a.CLOUDFLARE_API_TOKEN||!e?{actor:`api-token:${t}`,email:null}:{actor:e,email:e}}function nn(e){return e instanceof C?new l(e.code,e.message,{retryable:e.status>=500}):e}async function oe(e){try{return await e()}catch(t){throw nn(t)}}var dt="id, organization_id, app_slug, name, description, hostname, worker_name, tier, scope, manifest, status, version_id, deployed_at, deployed_by_actor, is_default, email_senders, email_inbound",an=`${dt}, secret_names`,st=new WeakMap;function I(e){let t=st.get(e);return t||(t=e.run([{sql:"PRAGMA table_info(apps)"}]).then(([a=[]])=>a.some(n=>n.name==="secret_names")),st.set(e,t)),t}async function k(e){return await I(e)?an:dt}var m=e=>e==null?null:String(e);function P(e){return{id:String(e.id),organizationId:String(e.organization_id),appSlug:String(e.app_slug),name:String(e.name),description:String(e.description),hostname:m(e.hostname),workerName:m(e.worker_name),tier:String(e.tier),scope:String(e.scope),manifest:m(e.manifest),status:String(e.status),versionId:m(e.version_id),deployedAt:e.deployed_at==null?null:Number(e.deployed_at),deployedByActor:m(e.deployed_by_actor),isDefault:!!Number(e.is_default),emailSenders:m(e.email_senders),emailInbound:m(e.email_inbound),secretNames:m(e.secret_names)}}function ot(e){return e?{organizationId:String(e.organization_id),appSlug:String(e.app_slug),hostname:m(e.hostname),workerName:m(e.worker_name)}:null}function lt(e){return e?{id:String(e.id),name:String(e.name),slug:String(e.slug)}:null}var ct={sql:`SELECT id, name, slug FROM organizations
|
|
69
|
+
WHERE EXISTS (SELECT 1 FROM members WHERE members.organization_id = organizations.id AND members.role = 'owner')
|
|
70
|
+
ORDER BY created_at, id LIMIT 1`},pt={sql:"SELECT id, name, slug FROM organizations ORDER BY created_at, id LIMIT 1"};async function mt(e){let[t=[],a=[]]=await e.run([ct,pt]);return gt(t,a)}function gt(e,t){let a=lt(e[0]);if(a)return{organization:a,hasOwner:!0};let n=lt(t[0]);return n?{organization:n,hasOwner:!1}:null}function rn(e){return e.trim().toLowerCase().replace(/[^a-z0-9\s-]/g,"").replace(/\s+/g,"-").replace(/-+/g,"-").replace(/^-|-$/g,"").slice(0,48)}async function sn(e,t,a){let n=await mt(e);if(n)return n;let r=t.trim()||"My Organization",[,i=[],s=[]]=await e.run([{sql:`INSERT INTO organizations (id, name, slug, created_at)
|
|
71
|
+
SELECT ?1, ?2, ?3, ?4 WHERE NOT EXISTS (SELECT 1 FROM organizations)`,params:[tn(),r,rn(r)||"default",a]},ct,pt]),o=gt(i,s);if(!o)throw new Error("The gateway's database has no organization.");return o}function on(e,t){let a=$e(t);return{sql:`WITH candidates(rank, candidate) AS (VALUES ${a.map((r,i)=>`(${i}, ?${i+2})`).join(", ")})
|
|
72
|
+
INSERT OR IGNORE INTO organization_keys (organization_id, org_key)
|
|
73
|
+
SELECT ?1, candidate FROM candidates
|
|
74
|
+
WHERE NOT EXISTS (SELECT 1 FROM organization_keys WHERE organization_id = ?1)
|
|
75
|
+
AND candidate NOT IN (SELECT org_key FROM organization_keys)
|
|
76
|
+
ORDER BY rank LIMIT 1`,params:[e,...a]}}function va(e,t){return oe(()=>ln(e,t))}async function ln(e,t){let a=t.now??Date.now(),{organization:n,hasOwner:r}=await sn(e,t.organizationName,a),[,i=[],s=[],o=[],d=[]]=await e.run([on(n.id,n.slug),{sql:"SELECT org_key FROM organization_keys WHERE organization_id = ?",params:[n.id]},{sql:`SELECT ${await k(e)} FROM apps WHERE organization_id = ? AND app_slug = ?`,params:[n.id,t.appSlug]},..._t(n.id,t.deployer.email)]),u=m(i[0]?.org_key);if(!u)throw new C({status:409,code:"ORG_KEY_UNAVAILABLE",message:`Every key for organization "${n.slug}" is taken by another organization on this gateway.`});let g=s[0]?P(s[0]):null,D=Ue({appSlug:t.appSlug,orgKey:u,isInstallOrganization:!0,appBaseDomain:t.appBaseDomain,existingApp:g}),[O=[],p=[]]=await e.run([{sql:"SELECT organization_id, app_slug, hostname, worker_name FROM apps WHERE hostname = ?",params:[D.hostname]},{sql:"SELECT organization_id, app_slug, hostname, worker_name FROM apps WHERE worker_name = ?",params:[D.workerName]}]),_=m(d[0]?.id),T=ft(o),w=ze({organizationId:n.id,isInstallOrganization:!0,scope:t.scope,appSlug:t.appSlug,name:t.name,description:t.description,manifest:t.manifest,appBaseDomain:t.appBaseDomain,orgKey:u,existingApp:g,hostnameOwner:ot(O[0]),workerNameOwner:ot(p[0]),members:T,deployerUserId:_});if(w.app.scope==="shared"&&Et(t.deployer,_,T,n,t.expectedWorkerName===void 0?"deploy":"register"),t.expectedWorkerName!==void 0&&w.app.workerName!==t.expectedWorkerName)throw new l("WORKER_NAME_MISMATCH",`${t.appSlug}'s Worker must be named ${w.app.workerName}, not ${t.expectedWorkerName}
|
|
77
|
+
The Gateway binds each app's Worker by that name only.`,{fix:`deploy the Worker as ${w.app.workerName}`,rerun:`${A("--worker")} --worker ${w.app.workerName}`});return await e.run(dn(w,a,{secretNames:await I(e)})),{plan:w,organization:n,hasOwner:r,deployerGranted:_!==null&&w.grants.some(St=>St.userId===_)}}function _t(e,t){return[{sql:"SELECT user_id, role FROM members WHERE organization_id = ?",params:[e]},{sql:"SELECT id FROM users WHERE lower(email) = lower(?) AND email_verified = 1",params:[t]}]}function ft(e){return e.map(t=>({id:String(t.user_id),role:m(t.role)}))}var un=e=>(e??"").split(",").some(t=>["owner","admin"].includes(t.trim()));function Et(e,t,a,n,r){if(e.email===null)return;let i=a.find(s=>s.id===t);if(!(i&&un(i.role)))throw new l("SHARED_APP_FORBIDDEN",`Only ${n.name} owners and admins can ${r} shared apps
|
|
78
|
+
${e.email} isn't an owner or admin of ${n.name}, the platform organization.`,{fix:`ask an owner of ${n.name} to make you an admin, or to do it for you`})}function dn(e,t,a){let{app:n}=e;if(e.kind==="existing")return[{sql:"UPDATE apps SET name = ?, description = ?, updated_at = ? WHERE id = ?",params:[n.name,n.description,t,n.id]}];let r=e.grants.map(i=>({sql:`INSERT INTO user_app_access (id, user_id, app_row_id, organization_id, granted_by)
|
|
79
|
+
VALUES (?, ?, ?, ?, NULL) ON CONFLICT DO NOTHING`,params:[i.id,i.userId,i.appRowId,i.organizationId]}));return e.kind==="new"?[{sql:`INSERT INTO apps (id, organization_id, app_slug, name, description, hostname,
|
|
80
|
+
worker_name, tier, manifest, status, version_id, deployed_at, deployed_by_actor,
|
|
81
|
+
is_default, created_at, updated_at, scope)
|
|
82
|
+
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15, ?15, ?16)`,params:[n.id,n.organizationId,n.appSlug,n.name,n.description,n.hostname,n.workerName,n.tier,n.manifest,n.status,n.versionId,n.deployedAt,n.deployedByActor,n.isDefault?1:0,t,n.scope]},...r]:[{sql:`UPDATE apps SET name = ?, description = ?, hostname = ?, worker_name = ?,
|
|
83
|
+
manifest = ?, status = ?, is_default = ?, updated_at = ?
|
|
84
|
+
WHERE id = ? AND status = '${E}'`,params:[n.name,n.description,n.hostname,n.workerName,n.manifest,n.status,n.isDefault?1:0,t,n.id]},...yt(n,t,a),...r]}function yt(e,t,{secretNames:a=!0}={}){let n=[e.id,e.organizationId];return[{sql:`UPDATE apps SET email_senders = NULL, email_inbound = NULL${a?", secret_names = NULL":""} WHERE id = ? AND organization_id = ?`,params:n},{sql:"DELETE FROM user_app_access WHERE app_row_id = ? AND organization_id = ?",params:n},{sql:"DELETE FROM group_app_access WHERE app_row_id = ? AND organization_id = ?",params:n},{sql:`UPDATE user_access_tokens SET revoked_at = ?1, updated_at = ?1
|
|
85
|
+
WHERE app_row_id = ?2 AND organization_id = ?3 AND revoked_at IS NULL`,params:[t,...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},{sql:"DELETE FROM mcp_connection_apps WHERE app_row_id = ?",params:[e.id]},{sql:"DELETE FROM org_app_settings WHERE app_row_id = ?",params:[e.id]}]}async function cn(e,t){let[a=[]]=await e.run([{sql:`SELECT ${await k(e)} FROM apps WHERE id = ?`,params:[t]}]);return a[0]?P(a[0]):null}var pn=3,ie=e=>({id:e.appSlug,rowId:e.id,name:e.name});async function mn(e,t,a,n){let r=t.status==="pending";return!r&&t.versionId===a.versionId?[]:te(e,{organizationId:t.organizationId,type:r?"app.installed":"app.updated",actor:Q({actor:a.actor,email:a.email??null}),data:r?{app:ie(t),version:a.versionId,...t.hostname?{hostname:t.hostname}:{},scope:t.scope==="shared"?"shared":"org",source:a.source??"cli"}:{app:ie(t),version:a.versionId,...t.versionId?{previousVersion:t.versionId}:{}},appRowId:t.id,onlyIf:{sql:"EXISTS (SELECT 1 FROM apps WHERE id = ? AND version_id = ?)",params:[t.id,a.versionId]},now:n})}function Sa(e,t,a){return oe(async()=>{let n=await I(e);for(let r=1;;r+=1){let i=await cn(e,t);if(!i)throw new C({status:404,code:"APP_NOT_FOUND",message:"The app's registry row is gone; deploy it again."});let s=Ge(i,a),o=await mn(e,i,a,s.deployedAt),[d=[]]=await e.run([{sql:`UPDATE apps SET manifest = ?, version_id = ?, deployed_at = ?, deployed_by_actor = ?,
|
|
86
|
+
status = ?, updated_at = ?${n?", secret_names = COALESCE(?, secret_names)":""}
|
|
87
|
+
WHERE id = ? AND status = ? RETURNING status`,params:[s.manifest,s.versionId,s.deployedAt,s.deployedByActor,s.status,s.deployedAt,...n?[a.secretNames?V(a.secretNames):null]:[],t,i.status]},...o]);if(d.length>0)return s.status;if(r>=pn)throw new l("APP_CHANGING",`The app's registry row keeps changing while this deploy records its upload
|
|
88
|
+
The upload is kept.`,{retryable:!0})}})}function x(e){return{id:e.id,appSlug:e.appSlug,organizationId:e.organizationId,status:e.status,workerName:e.workerName??"",hostname:e.hostname??"",resources:Me(e),email:{senders:v(e.emailSenders),inbound:v(e.emailInbound)},declaresInbound:_n(e.manifest),publicRoutes:Oe(e.manifest),mcp:Le(e.manifest),manifest:gn(e.manifest),secretNames:xe(e.secretNames),tier:e.tier}}function gn(e){if(!e)return null;try{let t=JSON.parse(e);return t&&typeof t=="object"&&!Array.isArray(t)?t:null}catch{return null}}function _n(e){if(!e)return!1;try{let a=JSON.parse(e)?.email?.inbound;return a===!0||Array.isArray(a)}catch{return!1}}async function le(e,t){let a=await mt(e);if(!a)return null;let[n=[]]=await e.run([{sql:`SELECT ${await k(e)} FROM apps WHERE organization_id = ? AND app_slug = ?`,params:[a.organization.id,t]}]);return n[0]?{app:P(n[0]),organization:a.organization}:null}async function wt(e,t,a,n){if(t.email===null)return;let[r=[],i=[]]=await e.run(_t(a.id,t.email));Et(t,m(i[0]?.id),ft(r),a,n)}function se(e){return new l("APP_NOT_FOUND",`${e} isn't deployed to this Gateway yet`,{rerun:`${c} deploy`,rerunNote:"in the app's directory"})}async function Ia(e,t){let a=await fn(e,t);if(!a)throw se(t);return a}async function fn(e,t){let a=(await le(e,t))?.app;return a&&ht(a)?x(a):null}function ht(e){return e.status!==E&&!!e.workerName}async function Oa(e,t){let[a=[]]=await e.run([{sql:"SELECT email_senders, email_inbound FROM apps WHERE id = ?",params:[t]}]),n=a[0];if(!n)throw new l("APP_NOT_FOUND","The app is no longer registered on this Gateway",{rerun:`${c} deploy`,rerunNote:"in the app's directory"});return{senders:v(n.email_senders),inbound:v(n.email_inbound)}}async function La(e,t,a,n,r=Date.now()){return oe(async()=>{let i=await le(e,t);if(!i||!ht(i.app))throw se(t);let{app:s,organization:o}=i;s.scope==="shared"&&await wt(e,n,o,"change the email of");let d=$(a.senders),u=$(a.inbound),[g=[]]=await e.run([{sql:`UPDATE apps SET email_senders = ?, email_inbound = ?, updated_at = ?
|
|
89
|
+
WHERE id = ? AND status != '${E}' RETURNING id`,params:[d,u,r,s.id]}]);if(g.length===0)throw se(t);return x({...s,emailSenders:d,emailInbound:u})})}async function Ca(e,t,a,n=Date.now()){await I(e)&&await e.run([{sql:`UPDATE apps SET secret_names = ?, updated_at = ?
|
|
90
|
+
WHERE id = ? AND status != '${E}'`,params:[V(a),n,t]}])}async function ka(e,t){let[a=[]]=await e.run([{sql:`SELECT app_slug FROM apps WHERE status != '${E}' AND (worker_name = ? OR substr(?, 1, length(worker_name) + 2) = worker_name || '--')`,params:[t,t]}]);return m(a[0]?.app_slug)}async function Pa(e){let[t=[]]=await e.run([{sql:`SELECT ${await k(e)} FROM apps WHERE status != '${E}' ORDER BY app_slug, organization_id`}]);return t.map(P).map(a=>({...x(a),deployedBy:a.deployedByActor,deployedAt:a.deployedAt}))}async function xa(e){let[t=[]]=await e.run([{sql:"SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'apps'"}]);if(t.length===0)return[];let[a=[]]=await e.run([{sql:"SELECT app_slug, hostname, worker_name, status FROM apps ORDER BY app_slug"}]);return a.map(n=>({appSlug:String(n.app_slug),hostname:m(n.hostname),workerName:m(n.worker_name),status:String(n.status)}))}async function $a(e,t,a,n=Date.now(),{purge:r=!1}={}){let i=await le(e,t);if(i&&i.app.tier===pe&&i.app.status!==E)throw new l("APP_NOT_FOUND",`${t} is an MCP app, not an app deployed to this Gateway`,{rerun:`${c} mcp remove ${t}`,rerunNote:"removes an MCP app"});if(!i||!i.app.workerName)throw new l("APP_NOT_FOUND",`No app named ${t} on this Gateway`,{rerun:`${c} status`,rerunNote:"lists its apps"});let{app:s,organization:o}=i;s.scope==="shared"&&await wt(e,a,o,"delete");let d=We(s);return d&&await e.run([{sql:"UPDATE apps SET status = ?, is_default = ?, updated_at = ? WHERE id = ?",params:[d.status,d.isDefault?1:0,n,s.id]},...yt(s,n,{secretNames:await I(e)}),...await te(e,{organizationId:s.organizationId,type:"app.removed",actor:Q(a),data:{app:ie(s),purged:r},appRowId:s.id,now:n})]),{...x(s),status:E,alreadyDeleted:d===null}}var ue="every-app-gateway",Dt="every-app-gateway-OAUTH_KV";async function za(e){let t=await Xe(e,ue),a=await Je(e,Dt);return{d1Id:t.id,oauthKvId:a.id,created:[...t.created?[`D1 ${ue}`]:[],...a.created?[`KV ${Dt}`]:[]]}}function bt(e){return B(e,ue)}async function Rt({whoami:e,createCf:t,accountId:a,host:n,hostFlag:r,interactive:i,pick:s=wn}){let o=a||process.env.CLOUDFLARE_ACCOUNT_ID||void 0,d=(e.accounts??[]).map(p=>({id:p.id,name:p.name??null})),u=o&&!d.some(p=>p.id===o)?[...d,{id:o,name:null}]:d,g=(await Promise.all(u.map(p=>En(p,t)))).filter(p=>p!==null),D={probed:u,found:g,...o?{requestedAccountId:o}:{}};if(o)return{...D,gateway:g.find(p=>p.account.id===o)??null};if(g.length<=1)return{...D,gateway:g[0]??null};let O=n?g.filter(p=>p.install?.gatewayHost.toLowerCase()===n.toLowerCase()):[];if(O.length===1)return{...D,gateway:O[0]};if(i)return{...D,gateway:await s(g,e)};throw new L("choose_account",`Choose which Gateway to use
|
|
91
|
+
${e.email??"This login"} sees a Gateway in ${g.length} Cloudflare accounts. Run one of:`,void 0,{rerun:null,data:{choices:g.map(p=>{let _=p.install?.gatewayHost,T=r&&_;return{accountId:p.account.id,accountName:p.account.name,gatewayUrl:_?`https://${_}`:null,label:T?p.account.name??p.account.id:[p.account.name,_].filter(Boolean).join(" \xB7 "),rerun:T?`${A(r)} ${r} ${_}`:ce(["--account-id",p.account.id])}})}})}async function En(e,t){let a=t(e.id);try{let n=await bt(a);if(!n)return null;let r=He(a,n);return{account:e,cf:a,databaseId:n,db:r,install:await Ke(r)}}catch(n){if(S(n,"auth")||S(n,"not_found"))return null;throw n}}function de(e,t){if(e.gateway)return e.gateway;let a=t.email?[`Logged in to Cloudflare as ${t.email}.`]:[],n={accounts:e.probed};if(e.requestedAccountId&&e.found.length>0)throw new l("GATEWAY_NOT_FOUND",[`Cloudflare account ${e.requestedAccountId} has no Gateway`,`This login's Gateway${e.found.length===1?" is":"s are"} in ${e.found.map(yn).join("; ")}.`].join(`
|
|
92
|
+
`),{fix:"pass that account's id to --account-id (or CLOUDFLARE_ACCOUNT_ID), or drop it",data:n});if(e.probed.length===0)throw new l("GATEWAY_NOT_FOUND",["This Cloudflare login lists no accounts",...a].join(`
|
|
93
|
+
`),{fix:"pass the Gateway's account with --account-id, or set CLOUDFLARE_ACCOUNT_ID",data:n});let r=e.probed.map(i=>i.name??i.id);throw new l("GATEWAY_NOT_FOUND",[r.length===1?`No Gateway in ${r[0]}, the only account this login sees`:`No Gateway in the ${r.length} accounts this login sees`,...r.length===1?[]:[`${r.join(", ")}.`],...a,`Or log in to the Gateway's account: ${c} login`].join(`
|
|
94
|
+
`),{rerun:`${c} setup --domain <hostname>`,rerunNote:"to install one",data:n})}function Tt(e,t,a=process.argv.slice(2)){if(!t)return;let n=new URL(t).host.toLowerCase(),r=e.install.gatewayHost.toLowerCase();if(n===r)return;let i=a.some(o=>o==="--gateway"||o.startsWith("--gateway=")),s=e.account.name??e.account.id;throw new l("GATEWAY_URL_MISMATCH",`The Gateway here is ${r}, not ${n}
|
|
95
|
+
Found in ${s}. For ${n}, pass its account with --account-id.`,i?{rerun:A("--gateway",a),rerunNote:`to use ${r}`}:{fix:`unset EVERYAPP_GATEWAY_URL to use ${r}`})}function yn(e){return`${e.account.name??e.account.id}${e.install?` at https://${e.install.gatewayHost}`:""}`}function wn(e,t){return ke("Which Gateway?",e.map(a=>{let n=a.account.name??a.account.id;return a.install?{label:a.install.gatewayHost,hint:n,value:a}:{label:n,value:a}}),{context:[`${t.email??"This login"} sees a Gateway in ${e.length} Cloudflare accounts`]})}var Nt=e=>we({accountId:e});function At(e,t){let a;try{a=new URL(e)}catch{throw new l("INVALID_GATEWAY_URL",t==="--gateway"?`--gateway must be a full URL, not "${e}"
|
|
96
|
+
For example https://apps.example.com.`:`EVERYAPP_GATEWAY_URL must be a full URL, not "${e}"`,t==="--gateway"?{}:{fix:`set it to https://${e.replace(/^\w+:\/\//,"")}, or unset it`})}return a.pathname=a.pathname.replace(/\/+$/,""),a.search="",a.hash="",a.toString().replace(/\/+$/,"")}function ar(e){if(e)return At(e,"--gateway");let t=process.env.EVERYAPP_GATEWAY_URL;return t?At(t,"EVERYAPP_GATEWAY_URL"):void 0}async function vt({createCf:e=Nt,accountId:t,host:a,interactive:n,onDeviceLogin:r}){let i=await Pe({cf:e(),interactive:n,onDeviceLogin:r}),s=await Rt({whoami:i,createCf:e,accountId:t,host:a,interactive:n});return{whoami:i,discovery:s}}function hn(e){let{install:t}=e;if(!t)throw Ye();if(t.liveVersionId===null)throw new l("GATEWAY_NOT_INSTALLED",`The Gateway at https://${t.gatewayHost} isn't finished installing
|
|
97
|
+
Setup stopped before its first upload.`,{rerun:`${c} setup`});return{...e,install:t}}async function rr({json:e,out:t,accountId:a,createCf:n}){let{whoami:r,discovery:i}=await vt({createCf:n,accountId:a,interactive:Ce(e??!1),onDeviceLogin:e?q(t,"gateway.login"):void 0});if(i.found.length===0&&i.probed.length>0&&!i.requestedAccountId){let s=i.probed.map(o=>o.name??o.id);throw new L("install_gateway",[`No Gateway in ${s.length===1?`${s[0]}'s Cloudflare account`:`the ${s.length} Cloudflare accounts this login sees`}${r.email?` (logged in as ${r.email})`:""}`,`Gateway in another account? Log in to it: ${c} login`].join(`
|
|
98
|
+
`),void 0,{rerun:`${c} setup`,rerunNote:"installs one",data:{accounts:i.probed}})}return de(i,r)}async function ir({gateway:e,accountId:t,interactive:a,createCf:n=Nt,onNoGateway:r,login:i}){let s=await vt({createCf:n,accountId:t,host:e?new URL(e).host.toLowerCase():void 0,interactive:a,onDeviceLogin:i?.json?q(i.out,i.step):void 0}),{whoami:o}=s,{discovery:d}=s;r&&d.gateway===null&&d.found.length===0&&d.probed.length>0&&(d=await r({whoami:o,discovery:d}));let u=hn(de(d,o));return Tt(u,e),{cf:u.cf,accountId:u.account.id,accountName:u.account.name,databaseId:u.databaseId,db:u.db,install:u.install,gatewayUrl:`https://${u.install.gatewayHost}`,deployer:ut(o.email,u.account.id)}}export{He as a,An as b,Ot as c,Nn as d,vn as e,Sn as f,In as g,On as h,kn as i,Ye as j,Ke as k,zn as l,B as m,Ut as n,Mt as o,zt as p,qn as q,Vn as r,za as s,bt as t,Rt as u,de as v,Xn as w,Jn as x,Q as y,ee as z,R as A,te as B,ia as C,sa as D,re as E,oa as F,la as G,ua as H,da as I,ca as J,pa as K,ma as L,ga as M,Jt as N,Zt as O,Qt as P,_a as Q,fa as R,Ea as S,en as T,ya as U,ut as V,oe as W,I as X,k as Y,m as Z,P as _,mt as $,sn as aa,va as ba,_t as ca,ft as da,yt as ea,cn as fa,Sa as ga,Ia as ha,fn as ia,Oa as ja,La as ka,Ca as la,ka as ma,Pa as na,xa as oa,$a as pa,ar as qa,rr as ra,ir as sa};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import{A as z,E as Q,F as B,a as j,b as V,q as P,r as Z,s as Y}from"./chunk-IG26HYRR.js";import{a as v}from"./chunk-IA534DGW.js";import{a as O,b as _,c as M,d as D,i as G,j as q,l as L,m as E,n as F,p as U}from"./chunk-MDORVBPD.js";import"./chunk-GRFPP4UW.js";import"./chunk-Y3VIFPN5.js";import"./chunk-PL6EORDJ.js";import"./chunk-EUNGJMJ6.js";import{ia as b,qa as k,sa as x}from"./chunk-ZYL2ZHCF.js";import"./chunk-SPPR6WCI.js";import"./chunk-7LG3F4FF.js";import{b as W}from"./chunk-GD2JZMD3.js";import{a as S,b as A,e as I,f as N,g as R,h as T}from"./chunk-F6IH47GT.js";import"./chunk-JYKRUS5C.js";import{R as $,c as m,k as y,oc as C,tb as g}from"./chunk-SAT3PGZU.js";import{text as ee}from"node:stream/consumers";import w from"chalk";var te={secret:(e,{context:i,optional:n})=>R(e,{context:i,optional:n}),text:(e,{context:i,optional:n,validate:o})=>N(e,{context:i,validate:s=>n&&!s.trim()?null:o(s)}),confirm:A,choose:(e,i,n)=>I(e,i,{context:n})};async function Oe(e,i){await C(e,n=>ne({flags:e,out:n,appId:i}))}async function ne(e){let{out:i,flags:n}=e,o=e.interactive??S(n.json??!1),s=e.prompter??te;ie(e.appId);let t=await re(e),r=await J(t),a=se(r,t);if(o){let h=e.tell??T;for(let X of ae(t,r))h(X)}let c=await ce(t,r,a,e),p=o?await ue(t,r,a,c,s):{},l=de({...c,...p},r),d=Object.keys(l);if(d.length===0&&!r.setup.ready&&!o)throw me(t,r,a);let f=d.length>0?await oe(t,l,e):null,u=f?await J({...t,registry:f.gateway?.bound?.length?await v(t.connection.db,t.connection.install):t.registry}):r;t.deployed&&t.source==="registry"?await V(t.connection.db,{appRowId:t.deployed.rowId,setup:u.setup,deployer:t.connection.deployer},i):t.deployed&&await j(t.connection,{gateway:[],appRowId:t.deployed.rowId},i),ge(t,u,a,d,f,i)}async function oe(e,i,n){try{return await z(e.connection,{manifest:e.manifest,source:e.source,app:e.deployed},i,{...n,...e.deployed&&e.source==="registry"?{setupRecordedBy:e.deployed.rowId}:{}})}catch(o){throw!(o instanceof g)||o.code!=="SECRETS_PARTIALLY_APPLIED"?o:new g(o.code,o.message,{...K(e,"to set what is left"),retryable:!0,data:o.data})}}function K(e,i,n=""){return e.deployed?{rerun:`${m} configure ${e.appId}${n}`,rerunNote:i}:{rerun:`${m} configure${n}`,rerunNote:`in the app's directory, ${i}`}}function ie(e){if(!e?.includes("="))return;let i=e.split("=")[0];throw new g("VALUE_ON_COMMAND_LINE",`${i}=\u2026 looks like a value on the command line, which configure never takes
|
|
2
|
+
It lands in the shell's history and the process list: rotate it if it was real. Nothing was set.`,{fix:`pipe NAME=value lines in (one per line), or export ${i} and add --from-env`})}async function re(e){let i=()=>x({gateway:k(e.flags.gateway),accountId:e.flags["account-id"],interactive:S(e.flags.json??!1),login:{json:e.flags.json,out:e.out,step:"login"},createCf:e.createCf});if(e.appId){let t=await i(),r=await b(t.db,e.appId);if(!r||r.status==="pending")throw new g("APP_NOT_FOUND",`${e.appId} isn't deployed to this Gateway
|
|
3
|
+
An app is configured by name after its first deploy; in its directory, configure works before that too (for the Gateway's settings). Nothing was changed.`,{rerun:`${m} status`,rerunNote:"lists its apps"});let a=Q(r);return{appId:a.id,manifest:a,source:"registry",deployed:{workerName:r.workerName,rowId:r.id},connection:t,registry:await v(t.db,t.install)}}let n=await W(e.cwd??process.cwd());if(!n)throw new g("MANIFEST_NOT_FOUND","No everyapp.config.ts in this directory, and no app named",{fix:`name the app: ${m} configure <app> (${m} status lists them), or run this from its directory`});let o=await i(),s=await b(o.db,n.id);return{appId:n.id,manifest:n,source:"directory",deployed:s&&s.status!=="pending"?{workerName:s.workerName,rowId:s.id}:null,connection:o,registry:await v(o.db,o.install)}}async function J(e){let{cf:i}=e.connection,n=M(await O(i),e.registry),o=e.deployed?await _(i,e.deployed.workerName):null,{report:s,setup:t}=D({manifest:e.manifest,appId:e.appId,gatewayNames:n,secretNames:o,lookup:e.registry}),r=new Set;for(let a of s.settings){let c=a.holder==="gateway"?n:o??[];for(let p of[...a.names,...a.alsoReads])c.includes(p)&&r.add(p)}return{report:s,setup:t,held:r}}function se({report:e},i){let n=t=>t.names.length>0&&(t.holder==="gateway"||i.deployed!==null),o=t=>t.set===!1&&n(t),s=new Set(e.groups.filter(t=>t.met).map(t=>t.group));return{required:e.settings.filter(t=>t.need.kind==="required"&&o(t)),groups:e.groups.filter(t=>!t.met&&t.members.some(r=>r.blocking)).map(t=>({group:t.group,members:t.members.filter(o)})).filter(t=>t.members.length>0),optional:e.settings.filter(t=>o(t)&&!t.blocking&&(t.need.kind==="optional"||t.need.kind==="anyOf"&&s.has(t.need.group))),afterDeploy:e.settings.filter(t=>t.holder==="app"&&t.names.length>0&&i.deployed===null)}}function ae(e,{report:i}){let n=q(e.appId,i.settings).map(o=>!e.deployed&&o.where===e.appId?{...o,status:w.dim("after first deploy")}:o);return[w.dim(`${e.appId}'s settings are held as the Gateway's secrets: an AI key or a capability's client on the Gateway Worker, once for every app; ${e.appId}'s own secrets on its Worker. Changes are live at once, no deploy needed.`),"",...n.length>0?L(n,{app:!1}):[w.dim(`${e.appId} declares no secrets and needs no Gateway settings.`)],""]}function le({report:e},i){return e.settings.find(n=>n.names.includes(i))??e.settings.find(n=>n.alsoReads.includes(i))}function de(e,{report:i}){let n={};for(let o of i.settings)for(let s of[...o.names,...o.alsoReads])e[s]!==void 0&&n[s]===void 0&&(n[s]=e[s]);return n}async function ce(e,i,n,o){let s={},t=(a,c)=>$(a)?Y(a,c):c,r=o.flags["from-env"]?null:await(o.readStdin??pe)();if(r!==null)for(let{name:a,value:c,line:p}of fe(r)){let l=le(i,a);if(!l){let d=/^[A-Z][A-Z0-9_]*$/.test(a)?a:`line ${p} (not shown: it may be a value)`;throw new g("SECRET_NOT_DECLARED",`${e.appId} doesn't declare ${d}
|
|
4
|
+
The piped lines set what its ${e.source==="registry"?"deployed manifest":"everyapp.config.ts"} lists (a provider, a capability or one of its secrets). Nothing was set.`,{fix:`leave it out, or declare it in everyapp.config.ts${e.source==="registry"?" and deploy again":""}; a bare value goes to ${m} secret set NAME`})}if(l.holder==="app"&&!e.deployed)throw new g("APP_NOT_FOUND",`${e.appId} isn't deployed yet
|
|
5
|
+
Its own ${a} can be set after its first deploy. Nothing was set.`,{rerun:`${m} deploy`});if(!c.trim())throw new g("SECRET_EMPTY",`${a} is empty in the piped lines`,{fix:`give ${a} a value, or leave the line out`});s[a]=t(a,c)}if(o.flags["from-env"]){let a=o.env??process.env,c=[...n.required,...n.groups.flatMap(p=>p.members),...n.optional];for(let p of c)for(let l of p.names){if(s[l]!==void 0||i.held.has(l))continue;let d=a[l];d===void 0||!d.trim()||(s[l]=t(l,d),o.out.emit({type:"progress",step:"configure.env",message:`${l} from $${l}`}))}}return s}async function pe(){if(process.stdin.isTTY)return null;let e=await ee(process.stdin);return e.trim()?e:null}function fe(e){let i=[];return e.split(/\r?\n/).forEach((n,o)=>{let s=n.trim();if(!s||s.startsWith("#"))return;let t=/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=(.*)$/.exec(s);if(!t)throw new g("PIPED_LINE_INVALID",`Line ${o+1} of the piped input isn't NAME=value
|
|
6
|
+
Nothing was set.`,{fix:`pipe NAME=value lines, one per line; a bare value goes to ${m} secret set NAME`});let r=t[2].trim(),a=r.length>=2&&(r.startsWith('"')||r.startsWith("'"))?r[0]:null;a&&r.endsWith(a)&&(r=r.slice(1,-1)),i.push({name:t[1],value:r,line:o+1})}),i}async function ue(e,i,n,o,s){let t={},r=l=>o[l]!==void 0||t[l]!==void 0||i.held.has(l),a=l=>l.names.every(r),c=async(l,d)=>{let f=!0;for(let u of l.names){if(r(u))continue;let h=await H(u,l,s,{optional:d,context:f});f=!1,h&&(t[u]=h)}};if(n.required.length>0||n.groups.length>0){for(let d of n.required)await c(d,!1);for(let d of n.groups){if(d.members.some(a))continue;let f=d.members.length===1?d.members[0]:await s.choose(`Which ${d.group}? One is enough.`,d.members.map(u=>({label:u.label,hint:u.names.join(" + "),value:u})));await c(f,!1)}let l=n.optional.filter(d=>!a(d));if(l.length>0&&await s.confirm(`Set the ${l.length===1?"optional setting":`${l.length} optional settings`} too?`,l.map(f=>E(f)[0])))for(let f of l)await c(f,!0);return t}let p=i.report.settings.filter(l=>l.names.length>0&&(l.holder==="gateway"||e.deployed!==null));if(p.length===0)return t;for(;;){let l=await s.choose(`Everything ${e.appId} needs is set. Change one?`,[...p.map(d=>({label:d.names.join(" + "),hint:`${d.label!==d.names.join("+")?`${d.label} \xB7 `:""}${G(d)}`,value:d})),{label:"No, done",value:null}]);if(!l)return t;for(let d of l.names){let f=await H(d,l,s,{optional:!0,context:d===l.names[0]});f&&(t[d]=f)}}}async function H(e,i,n,{optional:o,context:s}){let t=F(i),r=s?[...E(i),...t?[t]:[],...P(e)]:P(e),a=o?`${e} (Enter to skip)`:e;return($(e)?await n.text(a,{context:r,optional:o,validate:p=>Z(e,p)}):await n.secret(a,{context:r,optional:o})).trim()}function me(e,i,n){let o=[...n.required,...n.groups.map(s=>s.members[0])].flatMap(s=>s.names).filter(s=>!i.held.has(s));return new g("SECRET_VALUE_REQUIRED",`Can't ask for ${e.appId}'s settings without a terminal
|
|
7
|
+
${e.appId} needs ${y(o)}. Run this at a terminal, pipe NAME=value lines in (one per line), or export them under those names and add --from-env (which also takes the variable of any unset optional setting).`,{...K(e,"with the variables exported"," --from-env"),data:{names:o}})}function ge(e,i,n,o,s,t){let{appId:r}=e,{setup:a}=i,c=n.afterDeploy.flatMap(h=>h.names),p=a.ready?[]:U(a).filter(h=>!i.held.has(h)),l=o.length>0?`Set ${y(o)}. `:"",d=[],f,u;a.ready?e.deployed?(f=`${l}${r} is ready`,u=w.green(`${r} is ready.`)):(c.length>0?d.push({command:`${m} deploy`,note:`then ${m} configure ${r} for ${y(c)}`}):d.push({command:`${m} deploy`,note:"in the app's directory"}),f=`${l}${r}'s Gateway settings are set${c.length>0?`; its own ${y(c)} come after its first deploy`:""}`,u=`${r}'s Gateway settings are set.${c.length>0?` Its own ${y(c)} come after its first deploy.`:""}`):(t.emit({type:"warning",code:"APP_NEEDS_SETUP",step:"app.secrets",message:`${r} won't open until ${y(p)} ${p.length===1?"is":"are"} set`,data:{setup:a}}),d.push(e.deployed?{command:`${m} configure ${r}`,note:"at a terminal, with NAME=value lines on stdin, or with --from-env"}:{command:`${m} configure`,note:"in the app's directory: at a terminal, with NAME=value lines on stdin, or with --from-env"}),f=`${l}${r} still needs ${y(p)}`,u=w.yellow(`${r} still needs ${y(p)}.`)),o.length>0&&(u=`${u}
|
|
8
|
+
${w.dim("Live now. No deploy needed.")}`),t.emit({type:"done",message:f,display:u,data:{app:{id:r,deployed:e.deployed!==null,setup:a},set:[...o],...s?{changed:B(s)}:{},...d.length>0?{next:d}:{}}})}export{Oe as configure,ne as configureApp,fe as parsePipedLines};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import{a as X}from"./chunk-E7EUXUVD.js";import{b as H}from"./chunk-74EST4VW.js";import{b as Q,c as j,d as h}from"./chunk-R4CGF622.js";import"./chunk-DQWOXSL3.js";import{a as q}from"./chunk-GD2JZMD3.js";import{a as B,f as Y}from"./chunk-F6IH47GT.js";import"./chunk-JYKRUS5C.js";import{Nb as W,Ob as J,Pb as K,Sb as U,Tb as G,Ub as z,c as x,cb as O,h as I,hb as R,ib as _,l as C,oc as V,tb as m,xb as M}from"./chunk-SAT3PGZU.js";import $ from"node:path";import w from"node:fs/promises";import E from"node:path";var ue=[".claude/skills",".agents/skills"],D={everyapp:"- Before running everyapp, read the everyapp skill: `.agents/skills/everyapp/SKILL.md` (also in `.claude/skills/`).","build-every-app":"- To build or change this app, read the build-every-app skill: `.agents/skills/build-every-app/SKILL.md` (patterns in patterns.md beside it)."};function N(e){return E.join(e,"packages","cli","skills")}async function he(e){let t=[];for(let r of await w.readdir(N(e),{withFileTypes:!0}))if(r.isDirectory())try{await w.access(E.join(N(e),r.name,"SKILL.md")),t.push(r.name)}catch{}let i=Object.keys(D).filter(r=>t.includes(r)),n=t.filter(r=>!(r in D)).sort();return[...i,...n]}function Z(e){return D[e]??`- Read the ${e} skill: \`.agents/skills/${e}/SKILL.md\` (also in \`.claude/skills/\`).`}async function ee({root:e,appDir:t}){let i=await he(e),n=[];for(let r of i)for(let a of ue){let o=`${a}/${r}`,l=E.join(t,o);await w.rm(l,{recursive:!0,force:!0}),await w.cp(E.join(N(e),r),l,{recursive:!0}),n.push(o)}return{skills:i,paths:n,agentsMd:await ye(t,i)}}async function ye(e,t){let i=E.join(e,"AGENTS.md"),n;try{n=await w.readFile(i,"utf8")}catch{return await w.writeFile(i,`# Agent instructions
|
|
2
|
+
|
|
3
|
+
${t.map(Z).join(`
|
|
4
|
+
`)}
|
|
5
|
+
`),"created"}let r=t.filter(a=>!n.includes(`skills/${a}`));return r.length===0?"mentions":(await w.writeFile(i,`${n.replace(/\s*$/,"")}
|
|
6
|
+
${r.map(Z).join(`
|
|
7
|
+
`)}
|
|
8
|
+
`),"added")}import ke from"node:fs/promises";import A from"node:path";import g from"node:fs/promises";import u from"node:path";async function te({targetDir:e,appId:t,root:i}){let n=u.join(e,"package.json"),r=JSON.parse(await g.readFile(n,"utf-8"));if(r.name=t,!h(e,i)){let a=await we(await g.realpath(i)),o=await g.realpath(e);for(let l of["dependencies","devDependencies"]){let p=r[l];if(p)for(let[k,d]of Object.entries(p)){if(typeof d!="string"||!d.startsWith("workspace:"))continue;let f=a.get(k);if(!f)throw new Error(`Template dependency "${k}" is a workspace package ("${d}") that isn't in ${u.join(i,"packages")}.`);p[k]=`link:${u.relative(o,f).split(u.sep).join("/")}`}}}await g.writeFile(n,JSON.stringify(r,null,2)+`
|
|
9
|
+
`,"utf-8")}async function we(e){let t=new Map,i=u.join(e,"packages");for(let n of await g.readdir(i,{withFileTypes:!0})){if(!n.isDirectory())continue;let r=u.join(i,n.name);try{let{name:a}=JSON.parse(await g.readFile(u.join(r,"package.json"),"utf-8"));typeof a=="string"&&t.set(a,r)}catch{}}return t}function ie(e){return e.split("-").filter(t=>t.length>0).map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ")}async function ne({targetDir:e,appId:t}){let i=u.join(e,"everyapp.config.ts");try{let n=await g.readFile(i,"utf-8"),r=n.replace(/(\bid\s*:\s*)["'][^"']+["']/,`$1"${t}"`);if(r===n)throw new Error("Could not find an id field in everyapp.config.ts");let a=r.replace(/(\bname\s*:\s*)["'][^"']+["']/,`$1"${ie(t)}"`);if(a===r)throw new Error("Could not find a name field in everyapp.config.ts");await g.writeFile(i,a,"utf-8")}catch(n){throw n instanceof Error&&"code"in n&&n.code==="ENOENT"?new Error("Starter template does not include everyapp.config.ts, which is required for deployments."):n}}async function re({targetDir:e,appId:t}){let i=u.join(e,"README.md"),n;try{n=await g.readFile(i,"utf-8")}catch(a){if(a instanceof Error&&"code"in a&&a.code==="ENOENT")return;throw a}let r=n.replace(/^# .*$/m,`# ${ie(t)}`);r!==n&&await g.writeFile(i,r,"utf-8")}var Ae=["node_modules",".git","pnpm-lock.yaml","package-lock.json",".env",".env.local",".env.production",".dev.vars",".cloudflare",".everyapp",".wrangler",".output",".tanstack","dist","manual-steps.md"];function $e(e){return A.join(e,"starter")}function ae({appId:e,cwd:t,root:i}){return h(t,i)?A.join(i,"apps",e):A.join(t,e)}function se(e,t){return h(e,t)?j(A.dirname(e))===j(A.join(t,"apps"))?"apps":"inside":"outside"}var ve=`allowBuilds:
|
|
10
|
+
esbuild: true
|
|
11
|
+
sharp: true
|
|
12
|
+
workerd: true
|
|
13
|
+
`;async function oe({root:e,targetDir:t,appId:i}){await W($e(e),t,{exclude:Ae}),h(t,e)||await ke.writeFile(A.join(t,"pnpm-workspace.yaml"),ve),await te({targetDir:t,appId:i,root:e}),await ne({targetDir:t,appId:i}),await re({targetDir:t,appId:i})}async function pe({targetDir:e,verbose:t=!1}){let i=n=>U("git",n,{cwd:e,echo:t,what:"Initializing the app's git repository",code:"GIT_FAILED"});await i(["init"]),await i(["add","."]),await i(["commit","-m","Starter template"])}import Ie from"node:os";import b from"node:path";var ce=/^[a-z]([a-z0-9-]*[a-z0-9])?$/,Ee="my-app";function L(e){let t=`"${e}" isn't a valid app name`;if(e.length>64)return{headline:t,fix:"use 64 characters or fewer"};if(e.includes("--"))return{headline:t,fix:`don't put two dashes in a row, e.g. ${e.replace(/-{2,}/g,"-")}`};if(!ce.test(e)){let i=le(e);return{headline:t,fix:`use lowercase letters, digits and dashes${i?`, e.g. ${i}`:", starting with a letter"}`}}return O(e)||R(e)===_?{headline:`"${e}" is reserved for the platform`,fix:"pick another name",reserved:!0}:null}function le(e){let t=e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^[^a-z]+|-+$/g,"");return t&&t.length<=64&&ce.test(t)?t:null}function be(e){return e.includes("/")||e.startsWith(".")||e.startsWith("~")||b.isAbsolute(e)}function Pe(e,{cwd:t,home:i}){return e==="~"||e.startsWith("~/")?b.resolve(i,e.slice(2)):b.resolve(t,e)}async function de(e,{interactive:t,yes:i,cwd:n,home:r=Ie.homedir()}){if(e!==void 0&&be(e)){let o=Pe(e,{cwd:n,home:r}),l=b.basename(o),p=L(l);if(p)throw new m("INVALID_APP_ID",`${p.headline}
|
|
14
|
+
An app is named after the last part of its path, ${e}.`,{fix:p.fix});return{appId:l,dir:o,absolute:b.isAbsolute(e)||e.startsWith("~")}}if(e!==void 0){let o=L(e);if(o)throw new m("INVALID_APP_ID",o.headline,{fix:o.fix});return{appId:e,dir:null,absolute:!1}}if(!t)throw new m("APP_ID_REQUIRED",`No app name given
|
|
15
|
+
${i?"--yes means nothing is asked.":"There's no terminal to ask for one."}`,{rerun:`${x} create <name>${i?" --yes":""}`});return{appId:await Y("App name",{context:["Lowercase letters, digits and dashes. It becomes part of the app's URL."],initial:Ee,validate:o=>{let l=L(o);if(!l)return null;if(l.reserved)return`${o} is reserved for the platform. Pick another name.`;let p=le(o);return`Use lowercase letters, digits and dashes.${p&&!L(p)?` Try ${p}`:""}`}}),dir:null,absolute:!1}}async function xe(e,t){await V(e,i=>Le({flags:e,appIdArg:t,out:i}))}async function Le({flags:e,appIdArg:t,out:i,cwd:n=process.cwd(),root:r=Q(),cf:a=z(),install:o=G,git:l=pe,home:p}){let k=e.verbose??!1;if(await K($.join(n,"everyapp.config.ts")))throw new m("NESTED_APP",`This directory is already an app
|
|
16
|
+
It has an everyapp.config.ts. New apps go next to it, not inside it.`,{fix:"run create from the directory that holds your apps"});let d=await de(t,{interactive:!e.yes&&B(e.json??!1),yes:e.yes??!1,cwd:n,...p===void 0?{}:{home:p}}),{appId:f}=d,c=d.dir??ae({appId:f,cwd:n,root:r}),P=$.relative(n,c),S=d.absolute?c:P,y=d.absolute||P.startsWith("..")?S:`./${P}`;if(d.dir!==null&&se(d.dir,r)==="inside"){let s=v=>d.absolute?v:$.relative(n,v);throw new m("APP_DIR_IN_CHECKOUT",`${y} is inside your Every App checkout but not in its apps/ folder
|
|
17
|
+
An app inside the checkout goes in apps/<name>; one anywhere else is its own git repository.`,{fix:`use ${s($.join(r,"apps",f))} (inside the checkout) or ${s($.join($.dirname(r),f))} (beside it)`})}if(await J(c))throw new m("APP_DIR_EXISTS",`${y} already exists`,{fix:`pick another name, or move ${y} away`});i.emit({type:"step",step:"create.copy",status:"start",message:"Copying the starter template",data:{appId:f,shown:y,elsewhere:d.dir===null&&P.startsWith("..")}}),await oe({root:r,targetDir:c,appId:f}),i.emit({type:"step",step:"create.copy",status:"ok",message:"Copied the starter template",data:{appId:f,dir:c}});let T=await ee({root:r,appDir:c});i.emit({type:"step",step:"create.skill",status:"ok",message:`Added the ${T.skills.join(" and ")} ${T.skills.length===1?"skill":"skills"} for coding agents`,data:T}),await F(i,"create.install",["Installing dependencies","Installed dependencies"],async()=>{try{await o({cwd:c,description:"Installing dependencies",verbose:k})}catch(s){throw Te(s,{shown:y,cdTo:S})}});let fe=await q(c);try{await F(i,"create.types",["Generating types","Generated types"],()=>X(a,c))}catch(s){i.emit({type:"warning",code:"WORKER_TYPES_FAILED",step:"create.types",message:`Couldn't generate types
|
|
18
|
+
${me(s)}. pnpm dev tries again.`})}try{i.emit({type:"step",step:"migrations.local",status:"start",message:"Setting up the local database"});let s=await H({cwd:c,manifest:fe,cf:a});i.emit({type:"step",step:"migrations.local",status:s.status==="applied"?"ok":"skip",message:"Set up the local database",data:s.status==="applied"?{database:s.database,applied:s.applied}:{reason:s.reason}})}catch(s){i.emit({type:"step",step:"migrations.local",status:"fail"}),i.emit({type:"warning",code:"MIGRATIONS_FAILED",step:"migrations.local",message:`Couldn't set up the local database
|
|
19
|
+
${me(s)}. pnpm dev tries again.`,data:{rerun:`${x} db migrate`}})}if(!h(c,r))try{await F(i,"create.git",["Starting a git repository","Started a git repository"],()=>l({targetDir:c,verbose:k}))}catch(s){if(!(s instanceof m)||s.code!=="GIT_FAILED")throw s;let v=I(s.data?.command)?.startsWith("git commit")??!1;i.emit({type:"warning",code:"GIT_FAILED",step:"create.git",message:`${v?"Couldn't make the first git commit":"Couldn't start a git repository"}
|
|
20
|
+
git: ${C(s.data?.tail).at(-1)??"failed"}. Full log: ${I(s.data?.log)}`,data:{fix:v?`set git's user.name and user.email, then commit in ${y}`:`start one yourself in ${y}: git init, then commit`}})}let ge=[{command:`cd ${S}`},{command:"pnpm dev",note:"run it locally"},{command:"pnpm run deploy",note:"put it live"}];i.emit({type:"done",data:{appId:f,dir:c,next:ge}})}async function F(e,t,[i,n],r){let a=Date.now();e.emit({type:"step",step:t,status:"start",message:i});try{await r()}catch(o){throw e.emit({type:"step",step:t,status:"fail"}),o}e.emit({type:"step",step:t,status:"ok",message:n,data:{ms:Date.now()-a}})}function me(e){return(M(e).split(`
|
|
21
|
+
`)[0]??"").replace(/\.$/,"")}var Se=5;function Te(e,{shown:t,cdTo:i}){if(!(e instanceof m)||e.code!=="INSTALL_FAILED")return e;let n=e.data??{},r=C(n.tail).slice(-Se);return new m("INSTALL_FAILED",["Couldn't install dependencies",`${I(n.command)} exited ${String(n.exitCode)}.${r.length>0?" Its last lines:":""}`,...r.map(a=>` ${a}`),`Full log: ${I(n.log)}`,`${t} is created; only the install is left.`].join(`
|
|
22
|
+
`),{rerun:`cd ${i} && pnpm install`,data:n})}export{Le as createApp,xe as default};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{a as Y,b as K}from"./chunk-WEM3WLOC.js";import{b as B,d as W,e as J}from"./chunk-74EST4VW.js";import{b as _}from"./chunk-PL6EORDJ.js";import{i as G}from"./chunk-DQWOXSL3.js";import{b as C,c as F,ha as P,qa as q,sa as T}from"./chunk-ZYL2ZHCF.js";import"./chunk-SPPR6WCI.js";import"./chunk-7LG3F4FF.js";import{a as E,e as U,f as A}from"./chunk-GD2JZMD3.js";import{a as Q,i as x}from"./chunk-F6IH47GT.js";import{t as k}from"./chunk-JYKRUS5C.js";import{Qb as O,Ub as $,Vb as S,c as D,d as L,f as w,hb as M,hc as j,oc as R,tb as s,xb as N,yb as v}from"./chunk-SAT3PGZU.js";import ot from"node:fs/promises";import it from"node:path";import{text as at}from"node:stream/consumers";import u from"chalk";function V(t,e){let n=nt(t.reduce((r,o)=>r+o.duration,0));if(t.length===1){let[r]=t;if(z(r))return`${w(r.changes,"row")} changed ${u.green("\u2713")} ${u.dim(`${e} \xB7 ${n}`)}`;let o=u.dim(`${w(r.rows.length,"row")} \xB7 ${e} \xB7 ${n}`);return r.rows.length===0?o:[...H(r),"",o].join(`
|
|
2
|
+
`)}return[...t.flatMap(r=>[...z(r)?[`${w(r.changes,"row")} changed`]:H(r),""]),u.dim(`${w(t.length,"statement")} \xB7 ${e} \xB7 ${n}`)].join(`
|
|
3
|
+
`)}var z=t=>t.rows.length===0&&t.changes>0;function H({rows:t}){let e=Object.keys(t[0]??{});return e.length===0?[u.dim("0 rows")]:j(e,t.map(n=>e.map(r=>et(n[r]))))}function et(t){return t==null?u.dim("NULL"):typeof t=="string"?t.replaceAll(`
|
|
4
|
+
`,"\\n"):typeof t=="object"?JSON.stringify(t):String(t)}var nt=t=>t<1?"<1ms":`${Math.round(t)}ms`,rt=[/^(select|explain|values)\b/i,/^with\b(?![\s\S]*\b(insert|update|delete|replace)\b)/i,/^pragma\b[^=]*$/i];function X(t){let e=t.split(";").map(n=>n.trim()).filter(Boolean);return e.length>0&&e.every(n=>rt.some(r=>r.test(n)))}var I="db.migrate";async function jt(t){await R(t,async e=>{await st({cwd:process.cwd(),out:e}),e.emit({type:"done"})})}async function st({cwd:t,out:e,cf:n=$()}){let r=await E(t);await Y(t,e);let o;try{o=await B({cwd:t,manifest:r,cf:n,onApply:()=>e.emit({type:"step",step:I,status:"start",message:"Applying migrations to the local database..."})})}catch(a){throw await ct({cwd:t,manifest:r,cf:n,error:a})}if(o.status==="skipped"){e.emit({type:"step",step:I,status:"skip",message:o.reason==="no_d1"?`${r.id} declares no D1 database, so there's nothing to migrate.`:`No migrations in ${A(r)}/ yet, so there's nothing to migrate.`,data:{reason:o.reason}});return}K(e,I,o)}async function ct({cwd:t,manifest:e,cf:n,error:r}){let{problem:o,sqliteCode:a}=C(N(r)),[i]=await W({cwd:t,manifest:e,cf:n}).catch(()=>[]);return new s("MIGRATIONS_FAILED",[i?`Migration ${i} failed`:"A local migration failed",a?`${o} (${a})`:o].join(`
|
|
5
|
+
`),{data:{...i?{migration:i}:{},fix:`correct ${i?it.posix.join(A(e),i):"the migration"}`}})}async function _t(t,e){await R(t,async n=>{let r=t.local?"local":"production",o=await pt({cwd:process.cwd(),sql:await dt(e,t.file),local:t.local??!1,binding:t.binding,gateway:t.local?void 0:q(t.gateway),accountId:t["account-id"],yes:t.yes,json:t.json,out:n});n.emit({type:"done",data:{database:r,results:o.map(a=>a.rows),meta:o.map(({duration:a,changes:i})=>({duration:a,changes:i}))},display:V(o,r)})})}async function dt(t,e){if(t!==void 0&&e!==void 0)throw new s("SQL_TWICE","Pass the SQL or --file, not both",{data:{fix:"drop one of them"}});if(e===void 0){if(t===void 0)throw new s("SQL_REQUIRED","No SQL to run",{data:{fix:"pass it as an argument, or with --file <path> (- for stdin)"}});return t}if(e==="-")return at(process.stdin);try{return await ot.readFile(e,"utf8")}catch(n){throw O(n)?new s("SQL_FILE_NOT_FOUND",`No file at ${e}`):n}}async function pt({cwd:t,sql:e,local:n,binding:r,gateway:o,accountId:a,yes:i,json:c,out:d,cf:l=$(),createCf:g,interactive:h=Q(c??!1),confirm:b}){let p=await E(t),f=p.resources?.d1??[];if(f.length===0)throw new s("NO_D1",`${p.id} declares no D1 database`,{rerun:`${D} deploy`,data:{fix:"add a binding to resources.d1 in everyapp.config.ts"}});let m=r??U(f,p.migrations);if(!f.includes(m))throw new s("UNKNOWN_D1_BINDING",`No D1 binding ${m} in everyapp.config.ts
|
|
6
|
+
It declares ${f.join(", ")}.`,{rerun:L([],{argv:mt(process.argv.slice(2),f[0])})});let y=n?"local":"production";d.emit({type:"step",step:"db.query",status:"start",data:{database:y}});let tt=n?await lt({cwd:t,manifest:p,binding:m,sql:e,cf:l}):await ft({manifest:p,binding:m,sql:e,gateway:o,accountId:a,yes:i,json:c,out:d,createCf:g,interactive:h,confirm:b});return d.emit({type:"step",step:"db.query",status:"ok",data:{database:y}}),tt}function mt(t,e){return t.map((n,r)=>t[r-1]==="--binding"?e:n.startsWith("--binding=")?`--binding=${e}`:n)}async function lt({cwd:t,manifest:e,binding:n,sql:r,cf:o}){return(await Z("local",()=>S(o,{plane:"project",cwd:t,local:!0,env:J(t),args:["d1","raw",G(M(e.id),n),"--local","--persist-to",".cloudflare/state","--sql",r]},k))).map(({results:i,meta:c})=>({rows:(i?.rows??[]).map(d=>Object.fromEntries((i?.columns??[]).map((l,g)=>[l,d[g]]))),duration:c?.duration??0,changes:c?.changes??0}))}async function ft({manifest:t,binding:e,sql:n,gateway:r,accountId:o,yes:a,json:i,out:c,createCf:d,interactive:l,confirm:g}){let{cf:h,db:b}=await T({gateway:r,accountId:o,interactive:l,login:{json:i,out:c,step:"db.login"},createCf:d}),p=await P(b,t.id),m=(await _(b,p.workerName)).find(y=>y.kind==="d1"&&y.binding===e)?.resourceId;if(!m)throw new s("D1_NOT_FOUND",`${t.id} has no ${e} database yet
|
|
7
|
+
It's created on the app's first deploy.`,{rerun:`${D} deploy`});return X(n)||await x({yes:a,interactive:l,confirm:g,question:`Change data in ${t.id}'s production database?`,unattended:`This SQL can change ${t.id}'s production database
|
|
8
|
+
A person at a terminal confirms it first, or --yes does.`}),Z("production",()=>F(h,m,[{sql:n}]))}async function Z(t,e){try{return await e()}catch(n){if(!(n instanceof v))throw n;let{problem:r,sqliteCode:o}=C(n.message);throw o?new s("QUERY_FAILED",`Query failed: ${r}
|
|
9
|
+
${o} from the ${t} database.`):n}}export{jt as migrate,st as migrateLocal,_t as query,pt as queryAppD1};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{f as ee}from"./chunk-VVQRET35.js";import{a as Y}from"./chunk-MC56CUQI.js";import{e as Q,i as X,j as Z}from"./chunk-NJFWEYX7.js";import{a as q}from"./chunk-IZEOAOKL.js";import{m as V}from"./chunk-KMAOZRV4.js";import"./chunk-PMPIMHKG.js";import{e as J}from"./chunk-3Z53CH4F.js";import"./chunk-AUDGOIHE.js";import"./chunk-OVKVV6MK.js";import{b as H}from"./chunk-RFVMR32Y.js";import{M as E,P as I}from"./chunk-6O3GJS5H.js";import{c as b,d as z}from"./chunk-GRFPP4UW.js";import"./chunk-Y3VIFPN5.js";import"./chunk-R4CGF622.js";import{a as $,b as M,g as U,h as v}from"./chunk-PL6EORDJ.js";import"./chunk-DQWOXSL3.js";import"./chunk-3AAHHUJC.js";import"./chunk-EUNGJMJ6.js";import{k as P,m as j,o as x,pa as G,q as T,qa as O,r as F,sa as L}from"./chunk-ZYL2ZHCF.js";import"./chunk-SPPR6WCI.js";import"./chunk-7LG3F4FF.js";import{c as B}from"./chunk-GD2JZMD3.js";import{a as A,f as N,i as K}from"./chunk-F6IH47GT.js";import"./chunk-JYKRUS5C.js";import{b as D,c as y,f as R,k as W,oc as _,vb as C,zb as S}from"./chunk-SAT3PGZU.js";import ae from"node:path";import te from"chalk";async function Fe(t,n){await _(t,async l=>{let o=n??(await B(ae.join(process.cwd(),"everyapp.config.ts"),{message:"Which app? There's no everyapp.config.ts here",fix:`run this from the app's directory, or name it: ${y} delete <id>`})).id,a=A(t.json??!1);await ce({appId:o,flags:t,interactive:a});let m=await se({appId:o,gateway:O(t.gateway),accountId:t["account-id"],out:l,json:t.json,interactive:a,purge:t.purge??!1});l.emit({type:"done",...ie(o,m)})})}async function se({appId:t,gateway:n,accountId:l,out:o,json:a,interactive:m,purge:r,createCf:c,reconcile:g}){let i=await L({gateway:n,accountId:l,interactive:m,login:{json:a,out:o,step:"app.login"},createCf:c}),{cf:p,db:f}=i,k=Y(g,o);await V(i.install,k.source),o.emit({type:"step",step:"app.delete",status:"start",message:`Removing ${t} from the Gateway...`,data:{appId:t}});let h=(await E(f)).find(ne=>ne.appId===t),u={publicRoutes:(h?.publicPaths.length??0)>0,mcp:h?.mcp??!1},d=await G(f,t,i.deployer,Date.now(),{purge:r}),e=i.install,s=e.liveAppWorkers.includes(d.workerName)||e.liveDomains.includes(d.hostname);(!d.alreadyDeleted||s)&&await q({cf:p,out:o,accountId:i.accountId,databaseId:i.databaseId,interactive:m,cliVersion:D,...g,openRelease:k.openRelease}),await I({cf:p,db:f,install:i.install,out:o},{appId:t,surface:u,removing:!0}),o.emit({type:"step",step:"app.delete",status:"ok",message:`${t} is deleted on the gateway; ${d.hostname} stops serving it.`,data:{appId:t,hostname:d.hostname,workerName:d.workerName,alreadyDeleted:d.alreadyDeleted&&!s}});let w=await P(f);if(w&&H(d.hostname,w.appBaseDomain)&&!w.liveDomains.includes(d.hostname)&&await ee({cf:p,out:o,zoneId:w.zoneId,hostname:d.hostname}),!r)return d;let re=await le(p,f,i.accountId,o,t,d);return{...d,purged:re}}function ie(t,{workerName:n,alreadyDeleted:l,purged:o}){let a=`${y} delete ${t} --purge`,m=o?o.kept.length>0?`Deleted ${t}${o.removed.length>0?` and ${o.removed.join(", ")}`:""}; kept ${o.kept.join(", ")}.`:o.removed.length>0?`Deleted ${t} and ${o.removed.join(", ")}.`:`Deleted ${t}; nothing of it was left in Cloudflare.`:`${l?`${t} was already deleted`:`Deleted ${t}`}; its Worker and data are kept, and any cron triggers, Workflows and mail routes keep running.`,r=o?"":l?te.dim(`Its Worker and data are kept. To delete them: ${a}`):["Its Worker and data are kept, and any cron triggers, Workflows and mail routes keep running.",`To delete those too: ${a}`].map(c=>te.dim(c)).join(`
|
|
2
|
+
`);return{message:m,display:r,data:{appId:t,workerName:n,alreadyDeleted:l,purged:o?o.kept.length===0:!1,removed:o?.removed??[],kept:o?.kept??[]}}}var me=["Worker","Workflow","D1 database","KV namespace","Hyperdrive config","mail route"],oe={worker:"Compute (Workers) \u2192 Workers & Pages",d1:"Storage & Databases \u2192 D1",kv:"Storage & Databases \u2192 KV",workflow:"Compute (Workers) \u2192 Workflows"};async function le(t,n,l,o,a,m){o.emit({type:"step",step:"app.purge",status:"start",message:`Deleting ${a}'s Worker and data...`,data:{appId:a}});let r=new Map,c=e=>r.set(e,(r.get(e)??0)+1),g=await M(n,m.workerName),i=await J({cf:t,gatewayDb:n,accountId:l,workerName:m.workerName,routes:g.filter(e=>e.kind==="email-route")});i.length>0&&r.set("mail route",i.length);let p=g.filter(e=>e.kind!=="email-route"),f=[],k=new Set(p.flatMap(e=>e.kind==="worker"&&e.resourceId?[e.resourceId]:[]));if(k.size>0)for(let e of await X(t,m.workerName)){if(!k.has(e.script_name??"")){if(e.name.startsWith(`${m.workerName}--`)){let s=e.script_name??"unknown";f.push({described:`Workflow "${e.name}" (Worker ${s}'s)`,shown:`the Workflow ${e.name}, which Worker ${s} runs`,place:oe.workflow})}continue}await Z(t,e.name)&&(i.push(`Workflow "${e.name}"`),c("Workflow"))}let h=e=>e.kind!=="worker"?2:e.binding===""?0:1;for(let e of p.sort((s,w)=>h(s)-h(w)))if(e.resourceId)try{if(e.kind==="worker"){if(!await b(t,e.resourceId))continue;await z(t,e.resourceId)}else e.kind==="d1"?await T(t,e.resourceId):e.kind==="hyperdrive"?await Q(t,e.resourceId):await F(t,e.resourceId);i.push(v(e)),c($[e.kind])}catch(s){if(!S(s,"not_found"))throw s}await U(n,m.workerName);let u=[...await de(t,m,p),...f],d=me.flatMap(e=>{let s=r.get(e)??0;return s===0?[]:[s===1?e:R(s,e)]});if(o.emit({type:"step",step:"app.purge",status:"ok",message:i.length?`Deleted ${i.join(", ")}.`:"Nothing deleted in Cloudflare.",data:{appId:a,removed:i,kinds:d}}),u.length>0){let e=u.length===1;o.emit({type:"warning",code:"RESOURCES_KEPT",step:"app.purge",message:[`Kept ${W(u.map(s=>s.shown))}`,e?`It has ${a}'s name, but no deploy recorded creating it, so it may belong to something else.`:`They have ${a}'s names, but no deploy recorded creating them, so they may belong to something else.`].join(`
|
|
3
|
+
`),data:{kept:u.map(s=>s.described),fix:e?`if it is ${a}'s, delete it in the Cloudflare dashboard (${u[0].place})`:`if they are ${a}'s, delete them in the Cloudflare dashboard`}})}return{removed:i,kept:u.map(e=>e.described)}}async function de(t,n,l){let o=new Set(l.filter(r=>r.resourceId).map(r=>`${r.kind}:${r.name}`)),a=[],m=(r,c)=>a.push({described:v({kind:r,name:c}),shown:`the ${$[r]} ${c}`,place:oe[r]});!o.has(`worker:${n.workerName}`)&&await b(t,n.workerName)&&m("worker",n.workerName);for(let r of["d1","kv"])for(let c of new Set(Object.values(n.resources[r])))o.has(`${r}:${c}`)||await(r==="d1"?j:x)(t,c)&&m(r,c);return a}async function ce({appId:t,flags:n,interactive:l}){if(n.purge&&l&&!n.yes){let o=(await N(`Type ${t} to confirm`,{context:[`This deletes ${t}'s Worker and all its data for good.`]})).trim();if(o!==t)throw new C(o?`"${o}" doesn't match ${t}. Nothing deleted.`:"Cancelled. Nothing deleted.");return}await K({yes:n.yes,interactive:l,question:`Delete ${t} from the Gateway?`,unattended:"Deleting an app needs confirmation at a terminal, or --yes",context:["Its Worker and data stay; --purge deletes them too."],cancelled:"Cancelled. Nothing deleted."})}export{Fe as deleteApp,ie as deletionSummary,se as removeApp};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as a,c as b}from"./chunk-G64S77GC.js";import"./chunk-RQFHVU3Y.js";import"./chunk-5ZTFC6DK.js";import"./chunk-YJBYZWSP.js";import"./chunk-N4E5YE4X.js";import"./chunk-BHMRY53V.js";import"./chunk-QZWSSWMP.js";import"./chunk-E3EPK27P.js";import"./chunk-IG26HYRR.js";import"./chunk-IA534DGW.js";import"./chunk-MDORVBPD.js";import"./chunk-MC56CUQI.js";import"./chunk-NJFWEYX7.js";import"./chunk-IZEOAOKL.js";import"./chunk-KMAOZRV4.js";import"./chunk-PMPIMHKG.js";import"./chunk-3Z53CH4F.js";import"./chunk-AUDGOIHE.js";import"./chunk-OVKVV6MK.js";import"./chunk-RFVMR32Y.js";import"./chunk-6O3GJS5H.js";import"./chunk-GRFPP4UW.js";import"./chunk-Y3VIFPN5.js";import"./chunk-R4CGF622.js";import"./chunk-PL6EORDJ.js";import"./chunk-DQWOXSL3.js";import"./chunk-3AAHHUJC.js";import"./chunk-EUNGJMJ6.js";import"./chunk-ZYL2ZHCF.js";import"./chunk-SPPR6WCI.js";import"./chunk-7LG3F4FF.js";import"./chunk-GD2JZMD3.js";import"./chunk-F6IH47GT.js";import"./chunk-JYKRUS5C.js";import"./chunk-SAT3PGZU.js";export{a as deploy,b as deployDone};
|