everyapp 0.3.0-rc.2 → 0.3.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/access-FZ2ARRET.js +1 -0
- package/dist/activity-2RGC4KBA.js +14 -0
- package/dist/ai-ZGVUY7AM.js +5 -0
- package/dist/apps-IKTWTDHD.js +14 -0
- package/dist/{chunk-4JRIS6S6.js → chunk-36VCEEIH.js} +1 -1
- package/dist/{chunk-N5GQLGEC.js → chunk-3GZA6EEZ.js} +1 -1
- package/dist/{chunk-ONLNJXVQ.js → chunk-475IB5UG.js} +3 -3
- package/dist/chunk-4MMHVIHT.js +20 -0
- package/dist/{chunk-W3JCQHHU.js → chunk-52NQ23OH.js} +1 -1
- package/dist/chunk-6ILATTGU.js +34 -0
- package/dist/{chunk-CZXHKPRZ.js → chunk-7BC42ZUS.js} +1 -1
- package/dist/{chunk-CB4U7H2G.js → chunk-7SCPBFKI.js} +1 -1
- package/dist/{chunk-5PTNYZK6.js → chunk-AEYRJ3TD.js} +3 -3
- package/dist/{chunk-23HJ5I2A.js → chunk-AIDX5IYA.js} +1 -1
- package/dist/{chunk-OM2HDWVP.js → chunk-CGFABBZA.js} +1 -1
- package/dist/{chunk-PNLU5U3P.js → chunk-DB5CMXEV.js} +1 -1
- package/dist/{chunk-ELK7QZ2M.js → chunk-DONNKBKB.js} +1 -1
- package/dist/{chunk-AGTCKFRB.js → chunk-EEF4FY26.js} +1 -1
- package/dist/chunk-EJE6K5GO.js +146 -0
- package/dist/chunk-HHVABFYD.js +1 -0
- package/dist/chunk-HT76NR3O.js +1 -0
- package/dist/chunk-IWP4Q3KV.js +15 -0
- package/dist/{chunk-ZFCUH5PK.js → chunk-J2XKGQO7.js} +1 -1
- package/dist/{chunk-OP4DYXYI.js → chunk-JBTV62V7.js} +1 -1
- package/dist/chunk-JT3R24Y7.js +1 -0
- package/dist/{chunk-ZEXVHB22.js → chunk-KS7DIYIJ.js} +1 -1
- package/dist/{chunk-H7PDL3X5.js → chunk-KTX5YGBL.js} +1 -1
- package/dist/{chunk-J35DDCNU.js → chunk-LKI3XV7I.js} +1 -1
- package/dist/{chunk-T2GD7RHS.js → chunk-LTMQP62I.js} +1 -1
- package/dist/{chunk-WOVS3GV5.js → chunk-LTYAIGEB.js} +4 -4
- package/dist/{chunk-CCWBPAKH.js → chunk-MLZJBYSY.js} +1 -1
- package/dist/chunk-NXO2BC3M.js +57 -0
- package/dist/{chunk-RMF4YGD6.js → chunk-OHDR7JWQ.js} +39 -38
- package/dist/{chunk-6OGVO7QK.js → chunk-ONGI463M.js} +1 -1
- package/dist/chunk-Q44H7KLY.js +1 -0
- package/dist/{chunk-6PGUCTJ6.js → chunk-RXSJENSN.js} +1 -1
- package/dist/{chunk-CZTEDWZ2.js → chunk-SMCUCFS4.js} +1 -1
- package/dist/{chunk-2Y5Q6A5K.js → chunk-TQWCYF2T.js} +1 -1
- package/dist/chunk-U4ATZJEU.js +6 -0
- package/dist/{chunk-YHJZMJYZ.js → chunk-UEQMNXMZ.js} +1 -1
- package/dist/{chunk-LXYMDZER.js → chunk-VX4Z3D7A.js} +1 -1
- package/dist/{chunk-IFCPALVC.js → chunk-WTKBB5HE.js} +23 -23
- package/dist/{chunk-PS7S74DG.js → chunk-WV4G6E4T.js} +1 -1
- package/dist/{chunk-IUOBIB5M.js → chunk-WY2V27RK.js} +1 -1
- package/dist/{chunk-TLRM3P7V.js → chunk-XEPXX3AI.js} +1 -1
- package/dist/chunk-Y6CGMZEB.js +1 -0
- package/dist/{chunk-J455FAEN.js → chunk-YCADEJVJ.js} +5 -5
- package/dist/{chunk-HOUHG236.js → chunk-ZCJTJDAI.js} +1 -1
- package/dist/{chunk-H6QQMY7B.js → chunk-ZH6IAPVK.js} +1 -1
- package/dist/{configure-F7UZCJUG.js → configure-EJKUEVYS.js} +1 -1
- package/dist/{create-2E5HVWYK.js → create-BKEFXQ5N.js} +1 -1
- package/dist/{db-HEQVTDTM.js → db-66QZCKMG.js} +1 -1
- package/dist/delete-JR5R2OHE.js +3 -0
- package/dist/deploy-G4NB5R2P.js +1 -0
- package/dist/{dev-JL3ZP5BT.js → dev-EFDXNBFY.js} +43 -43
- package/dist/{email-RLZFUFUN.js → email-LAQDDSYC.js} +1 -1
- package/dist/{events-2V5VRBWP.js → events-RRF7OOCI.js} +1 -1
- package/dist/{groups-HDG5DVFY.js → groups-CFTGDYZU.js} +1 -1
- package/dist/index.js +89 -83
- package/dist/install-GXMHD5XS.js +1 -0
- package/dist/{login-KHJBC64Z.js → login-YWNHPSC2.js} +1 -1
- package/dist/mcp-72WLLKTK.js +1 -0
- package/dist/provider-IPV6BDP3.js +13 -0
- package/dist/release-4T7BVUZ5.js +1 -0
- package/dist/{restore-FFGYV7NO.js → restore-BWPOK4UP.js} +1 -1
- package/dist/secret-NLQQNZMK.js +1 -0
- package/dist/setup-6PNOX4NZ.js +1 -0
- package/dist/{signin-AP3D4XM4.js → signin-X4Z42R7E.js} +1 -1
- package/dist/status-VEUCYFRY.js +4 -0
- package/dist/teardown-J4CP2EI5.js +22 -0
- package/dist/update-NU2SFDNF.js +1 -0
- package/dist/{workspace-CJC5I66L.js → workspace-ZLKGLW35.js} +1 -1
- package/package.json +4 -4
- package/skills/build-every-app/SKILL.md +4 -1
- package/skills/build-every-app/patterns.md +6 -0
- package/skills/everyapp/SKILL.md +18 -8
- package/skills/everyapp/mcp.md +4 -2
- package/skills/everyapp/setup/README.md +2 -0
- package/skills/everyapp/setup/ai-gateway.md +117 -0
- package/skills/everyapp/setup/ai.md +139 -0
- package/skills/everyapp/setup/providers.md +26 -8
- package/dist/access-LGEN3ABJ.js +0 -1
- package/dist/activity-RSD4D66F.js +0 -12
- package/dist/apps-4RCFXT74.js +0 -13
- package/dist/chunk-EGEWRFVY.js +0 -1
- package/dist/chunk-FJJSSVET.js +0 -33
- package/dist/chunk-GKBPYVP3.js +0 -25
- package/dist/chunk-JYKRUS5C.js +0 -1
- package/dist/chunk-LYNBZ7RV.js +0 -57
- package/dist/chunk-M2QQ2UD7.js +0 -132
- package/dist/chunk-NFU4YFXB.js +0 -1
- package/dist/chunk-ZECBN24L.js +0 -15
- package/dist/delete-XCSIQIRS.js +0 -3
- package/dist/deploy-3QOZEZHC.js +0 -1
- package/dist/install-Z5FYXUYM.js +0 -1
- package/dist/mcp-EFDUKJ5V.js +0 -1
- package/dist/provider-EOI5PTFH.js +0 -13
- package/dist/release-74J5ZIL3.js +0 -1
- package/dist/secret-7FKKTLHB.js +0 -1
- package/dist/setup-PAKRCAFO.js +0 -1
- package/dist/status-RMWNHOEK.js +0 -4
- package/dist/teardown-E4JNKAZJ.js +0 -22
- package/dist/update-DWVZFNPS.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as l,c as i}from"./chunk-6ILATTGU.js";import{g as n}from"./chunk-4MMHVIHT.js";import"./chunk-HHVABFYD.js";import"./chunk-U4ATZJEU.js";import"./chunk-DB5CMXEV.js";import"./chunk-SMCUCFS4.js";import"./chunk-N4E5YE4X.js";import"./chunk-BHMRY53V.js";import"./chunk-EEF4FY26.js";import"./chunk-E3EPK27P.js";import"./chunk-WTKBB5HE.js";import"./chunk-LTYAIGEB.js";import"./chunk-CGFABBZA.js";import"./chunk-YCADEJVJ.js";import"./chunk-Y6CGMZEB.js";import"./chunk-Q44H7KLY.js";import"./chunk-TQWCYF2T.js";import"./chunk-ZH6IAPVK.js";import"./chunk-ONGI463M.js";import"./chunk-WV4G6E4T.js";import"./chunk-UEQMNXMZ.js";import"./chunk-3GZA6EEZ.js";import"./chunk-52NQ23OH.js";import"./chunk-XEPXX3AI.js";import"./chunk-J2XKGQO7.js";import"./chunk-36VCEEIH.js";import"./chunk-AIDX5IYA.js";import"./chunk-IWP4Q3KV.js";import"./chunk-475IB5UG.js";import"./chunk-RXSJENSN.js";import"./chunk-ZCJTJDAI.js";import{ra as a}from"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import"./chunk-KTX5YGBL.js";import"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import{Pc as r}from"./chunk-NXO2BC3M.js";async function b(e,p){await r(e,async o=>{let m=a(e.gateway),t=await n(p,{out:o});try{let s=await l({cwd:process.cwd(),manifest:t.manifest,release:t,gateway:m,accountId:e["account-id"],out:o,json:e.json,verbose:e.verbose,allowDeleteDurableObjectData:e["allow-delete-durable-object-data"],allowDeleteWorkflows:e["allow-delete-workflows"],forceDns:e["force-dns"],enableEmailRouting:e["enable-email-routing"],waitForLive:!e["no-wait"],offerInstall:{yes:e.yes}});o.emit({type:"done",...i(s)})}finally{await t.cleanup()}})}export{b as install};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as l,c as m,e as s}from"./chunk-
|
|
1
|
+
import{a as l,c as m,e as s}from"./chunk-LTMQP62I.js";import{a as r}from"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import{Pc as p,tc as i}from"./chunk-NXO2BC3M.js";var n="cloudflare.login";async function v(e){await p(e,async o=>{await f({out:o,interactive:r(e.json??!1)}),o.emit({type:"done"})})}async function f({out:e,interactive:o,cf:t=i()}){let a=await l(t);if(a.authenticated){e.emit({type:"step",step:n,status:"skip",message:"Already logged in to Cloudflare.",data:{email:a.email??null,token:!!process.env.CLOUDFLARE_API_TOKEN}});return}let c=await s({cf:t,interactive:o,onDeviceLogin:m(e,n)});e.emit({type:"step",step:n,status:"ok",message:"Logged in to Cloudflare.",data:{email:c.email??null}})}export{f as logInToCloudflare,v as login};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p}from"./chunk-WY2V27RK.js";import"./chunk-WTKBB5HE.js";import"./chunk-LTYAIGEB.js";import"./chunk-CGFABBZA.js";import"./chunk-J2XKGQO7.js";import"./chunk-36VCEEIH.js";import"./chunk-IWP4Q3KV.js";import"./chunk-ZCJTJDAI.js";import"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import"./chunk-KTX5YGBL.js";import"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import"./chunk-NXO2BC3M.js";export{a as add,i as addServer,p as changeTool,e as list,m as listMcp,d as off,c as on,g as refresh,o as refreshApp,b as remove,l as removeApp,f as show,n as showApp,h as tool,k as turnOff,j as turnOn};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import{j as V,k as W}from"./chunk-WY2V27RK.js";import"./chunk-WTKBB5HE.js";import{a as x,c as z,d as K}from"./chunk-LTYAIGEB.js";import"./chunk-CGFABBZA.js";import"./chunk-J2XKGQO7.js";import{a as _}from"./chunk-36VCEEIH.js";import"./chunk-IWP4Q3KV.js";import"./chunk-ZCJTJDAI.js";import{oa as T,ra as D,ta as M}from"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import"./chunk-KTX5YGBL.js";import{a as B}from"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import{Ca as I,D as $,Db as j,Ic as J,J as U,Pc as v,Ra as N,Ub as P,Yb as E,c as g,k as y,pc as L,rb as F,sb as A}from"./chunk-NXO2BC3M.js";import S from"node:fs/promises";import k from"node:path";import{stripVTControlCharacters as q}from"node:util";import m from"chalk";var R=64*1024;async function Ne(e,t){await v(e,n=>ne({flags:e,out:n},t))}async function Ae(e){await v(e,t=>ie({flags:e,out:t}))}async function je(e,t){await v(e,n=>de({flags:e,out:n},t))}async function Ee(e,t){await v(e,n=>ce({flags:e,out:n},t))}async function _e(e,t){await v(e,n=>Y({flags:e,out:n},"on",t))}async function Te(e,t){await v(e,n=>Y({flags:e,out:n},"off",t))}async function Y(e,t,n){e.out.emit({type:"step",step:"provider.alias",status:"ok",message:`everyapp provider ${t} is now everyapp mcp ${t}; this alias goes after launch week.`,data:{command:`${g} mcp ${t} ${n}`}}),await(t==="on"?V:W)(e,n)}function b({flags:e,out:t,createCf:n}){return M({gateway:D(e.gateway),accountId:e["account-id"],interactive:B(e.json??!1),login:{json:e.json,out:t,step:"login"},createCf:n})}async function X(e){try{return await S.access(k.join(e,"everyapp.config.ts")),!0}catch{return!1}}function u(e,t){return new P("PROVIDER_SPEC_INVALID",e,{fix:t})}async function ee(e,{cwd:t,fetcher:n=fetch}){let a;if(/^[a-z][a-z0-9+.-]*:\/\//i.test(e)){let c;try{c=new URL(e)}catch{throw u(`${e} isn't a URL`,"give the spec's https URL, or a path to the file")}if(c.protocol!=="https:")throw u(`${e} isn't https`,"fetch specs over https only, or save the file and give its path");let o;try{o=await n(c,{headers:{accept:"application/json"},redirect:"follow"})}catch(i){throw u(`Couldn't fetch ${e}: ${E(i).split(`
|
|
2
|
+
`)[0]}`,"check the URL, or save the file and give its path")}if(o.url&&!o.url.startsWith("https://"))throw u(`${e} redirected to a URL that isn't https`,"give the spec's final https URL");if(!o.ok)throw u(`${e} answered ${o.status}`,"check the URL, or save the file and give its path");a=await te(o,e)}else{let c=k.resolve(t,e),o;try{if((await S.stat(c)).size>R)throw u(`${e} is over ${R/1024} KiB`,"a spec is a short JSON file");o=await S.readFile(c)}catch(i){throw i instanceof P?i:L(i)?u(`No file at ${e}`,"give the path to the spec's JSON file, or its https URL"):i}a=o.toString("utf8")}try{return JSON.parse(a)}catch(c){throw u(`${e} isn't JSON: ${E(c).split(`
|
|
3
|
+
`)[0]}`,"fix the file, then add it again")}}async function te(e,t){let n=Number(e.headers.get("content-length")),a=()=>u(`${t} is over ${R/1024} KiB`,"a spec is a short JSON file");if(Number.isFinite(n)&&n>R)throw a();if(!e.body)return"";let c=e.body.getReader(),o=[],i=0;for(;;){let{done:l,value:r}=await c.read();if(l)break;if(i+=r.byteLength,i>R)throw await c.cancel(),a();o.push(r)}return Buffer.concat(o).toString("utf8")}function H(e){return e.mode==="oauth_client"?y([...e.api]):y([...e.hosts,...e.hostSetting?[`the host ${e.hostSetting} names`]:[]])}function se(e){if(e.mode==="oauth_client")return"as the bearer token of the person's connection";let{auth:t}=e;switch(t.kind){case"bearer":return`as ${t.scheme??"a bearer"} token`;case"header":return`in the ${t.header} header`;case"query":return`as the ${t.param} query parameter`;case"basic":return"as HTTP Basic"}}async function ne(e,t){let{out:n,flags:a}=e,c=e.cwd??process.cwd(),o=await ee(t,{cwd:c,fetcher:e.fetch}),i=await b(e),l=o&&typeof o=="object"&&typeof o.id=="string"?o.id:"the provider";n.emit({type:"step",step:"provider.add",status:"start",message:`Registering ${l}...`});let r=await z(i.db,{spec:o,deployer:i.deployer,replace:a.replace??!1,install:i.install,now:e.now?.()}),{id:d,capability:s}=r,p=[...$(s)],w=i.gatewayUrl.replace(/^https:\/\//,"");n.emit({type:"step",step:"provider.add",status:"ok",message:`${r.replaced?"Replaced":"Registered"} ${s.label} (${d}) on ${w}`,data:{id:d,replaced:r.replaced}});let f=null;await X(c)&&(f=A(d),await Q(c,d,s));let O=p.join(" "),h=[`${r.replaced?"Replaced":"Registered"} ${s.label} (${d}) on ${w}.`,`Its key goes to ${H(s)} only, ${se(s)}.`,...r.replaced?["The key set before was for the old spec: set it again before the Gateway sends it."]:[],...f?[`Wrote ${f} for everyapp dev (your key goes in .dev.vars).`]:[],`Apps list it as capabilities: { ${JSON.stringify(d)}: { access: "${s.access[0]}", why: "..." } }.`];n.emit({type:"done",message:q(h.join(`
|
|
4
|
+
`)),display:[h[0],...h.slice(1).map(C=>m.dim(C))].join(`
|
|
5
|
+
`),data:{id:d,name:s.label,...G(s),settings:p,source:"row",replaced:r.replaced,...f?{devFile:f}:{},next:[{command:`${g} secret set ${O}`,note:`${s.label}'s ${s.mode==="oauth_client"?"client":"key"}, from ${s.mode==="oauth_client"?s.console:s.docs}; the Gateway sends it only to ${H(s)}`}]}})}async function Q(e,t,n){let a=k.join(e,F,`${t}.json`);return await S.mkdir(k.dirname(a),{recursive:!0}),await S.writeFile(a,`${JSON.stringify(N(t,n),null,2)}
|
|
6
|
+
`),a}function oe(e){switch(e.mode){case"api_key":return"api key";case"ai":return"ai";case"oauth_client":return"oauth client";case"service":return null}}function G(e){switch(e.mode){case"api_key":return{hosts:[...e.hosts],...e.hostSetting?{hostSetting:e.hostSetting}:{}};case"ai":return{hosts:[new URL(e.origin).host]};case"oauth_client":return{hosts:[...new Set(e.token.flatMap(t=>t.host?[t.host]:[]))],...e.hostSetting?{hostSetting:e.hostSetting}:{}};case"service":return{hosts:[]}}}function Z(e,t,n){return e.filter(a=>a.manifest?n.mode==="ai"?I(a.manifest).includes(t):!!(a.manifest.capabilities&&Object.hasOwn(a.manifest.capabilities,t)):!1).map(a=>a.appSlug)}function re(e,t,n){let a=new Map(e.rows().map(o=>[o.id,o])),c=[];for(let[o,i]of e.entries()){let l=oe(i);if(!l)continue;let r=a.get(o);c.push({id:o,name:i.label,kind:l,...G(i),settings:$(i).map(d=>({name:d,set:t.includes(d)})),bound:e.bound(o),source:r?"row":"catalog",...r?{addedBy:r.addedBy,addedAt:r.addedAt}:{},apps:Z(n,o,i)})}return c}async function ie(e){let{out:t}=e,n=await b(e),[a,c,o]=await Promise.all([x(n.db,n.install),_(n.cf,j),T(n.db)]),i=re(a,c,o),l=J(["ID","NAME","KIND","HOSTS","SETTINGS","SOURCE","APPS"],i.map(s=>[s.id,s.name,s.kind,[...s.hosts,...s.hostSetting?[`<${s.hostSetting}>`]:[]].join(", ")||m.dim("-"),[s.settings.map(p=>`${p.name} ${p.set?m.green("set"):m.yellow("not set")}`).join(", "),...s.source==="row"?[s.bound?m.green("bound"):m.yellow("not bound")]:[]].join(", "),s.source==="row"?`registered by ${s.addedBy??"someone"}`:m.dim("catalog"),s.apps.join(", ")||m.dim("-")])),r=i.filter(s=>s.source==="row").length,d=a.rejected.map(({id:s,code:p,message:w})=>({id:s,code:p,message:w}));t.emit({type:"done",message:`${i.length} providers: ${i.length-r} built in, ${r} registered`,display:[...l,...d.length>0?["",m.yellow(`The Gateway doesn't serve ${y(d.map(s=>s.id))}:`),...d.map(s=>m.dim(` ${s.id}: ${s.message} (${s.code})`))]:[],"",m.dim(`MCP apps: ${g} mcp list`)].join(`
|
|
7
|
+
`),data:{providers:i,...d.length>0?{rejected:d}:{},mcp:`${g} mcp list`}})}function ae(e,t){let n=[...$(t)];switch(t.mode){case"api_key":return N(e,t);case"ai":return{id:e,kind:"ai",name:t.label,...t.description?{description:t.description}:{},docs:t.docs,...t.api?{api:t.api}:{},...t.hint?{hint:t.hint}:{},settings:n,hosts:[new URL(t.origin).host],routes:[...t.inferenceRoutes],...t.setup?{setup:t.setup}:{}};case"oauth_client":return{id:e,kind:"oauth client",name:t.label,docs:t.console,settings:n,tokenEndpoints:U(t).split(", "),authorize:{url:t.authorize.url,scopes:[...t.authorize.scopes]},redirectPaths:[...t.redirectPaths],...t.hostSetting?{hostSetting:t.hostSetting}:{},...t.setup?{setup:t.setup}:{}};case"service":return{id:e,name:t.label}}}async function de(e,t){let{out:n,flags:a}=e,c=e.cwd??process.cwd();if(a.save&&!await X(c))throw new P("MANIFEST_NOT_FOUND",`No everyapp.config.ts in this directory
|
|
8
|
+
--save writes the spec where everyapp dev reads it, in an app's directory. Nothing was written.`,{fix:"run this from the app's directory"});let o=await b(e),[i,l]=await Promise.all([x(o.db,o.install),T(o.db)]),r=i.get(t);if(!r||r.mode==="service"){let h=i.rejected.find(C=>C.id===t);throw new P("PROVIDER_NOT_FOUND",r?`${t} is a Gateway service, not a provider
|
|
9
|
+
Apps call it with its own helper (sendEmail(), listMembers()).`:h?`The Gateway doesn't serve ${t}: ${h.message}`:`${t} isn't a provider this Gateway offers`,{rerun:`${g} provider list`,rerunNote:"names every one"})}let d=i.rows().find(h=>h.id===t),s=ae(t,r),p=null;if(a.save){if(!d||r.mode!=="api_key")throw new P("PROVIDER_BUILTIN",`${t} is built in
|
|
10
|
+
everyapp dev reaches it without a file. Nothing was written.`,{fix:`put its key in .dev.vars: ${$(r).join(", ")}`});await Q(c,t,r),p=A(t)}let w=Z(l,t,r),f=i.bound(t),O=[d?`Registered by ${d.addedBy??"someone"}${d.addedAt?` on ${new Date(d.addedAt).toISOString().slice(0,10)}`:""}; ${f?"its key is bound to these hosts":"its key isn't set for these hosts yet"}.`:"Built in.",w.length>0?`Used by ${y(w)}.`:"No app lists it yet.",...p?[`Wrote ${p} for everyapp dev.`]:[]];n.emit({type:"done",message:`${r.label} (${t})`,display:[JSON.stringify(s,null,2),"",...O.map(h=>m.dim(h))].join(`
|
|
11
|
+
`),data:{provider:s,source:d?"row":"catalog",bound:f,addedBy:d?.addedBy??null,addedAt:d?.addedAt??null,apps:w,...p?{saved:p}:{},...d&&!f?{next:[{command:`${g} secret set ${$(r).join(" ")}`,note:`${r.label}'s key; the Gateway sends it only to ${y(G(r).hosts)}`}]}:{}}})}async function ce(e,t){let{out:n,flags:a}=e,c=await b(e);n.emit({type:"step",step:"provider.remove",status:"start",message:`Removing ${t}...`});let o=await K(c.db,t,c.deployer,{force:a.force??!1,now:e.now?.()}),i=await _(c.cf,j),l=o.settings.map(p=>({name:p,set:i.includes(p)})),r=l.filter(p=>p.set).map(p=>p.name),d=c.gatewayUrl.replace(/^https:\/\//,"");n.emit({type:"step",step:"provider.remove",status:"ok",message:`Removed ${o.name} (${t}) from ${d}`,data:{id:t}});let s=[`Removed ${o.name} (${t}) from ${d}.`,"The Gateway stops serving it within 30 seconds.",...o.apps.length>0?[`${y(o.apps)} ${o.apps.length===1?"lists":"list"} it: ${o.apps.length===1?"its":"their"} calls to it fail until it is registered again.`]:[],...r.length>0?[`${y(r)} ${r.length===1?"stays":"stay"} on the Gateway, read by nothing: ${g} secret unset ${r.join(" ")} removes ${r.length===1?"it":"them"}.`]:[]];n.emit({type:"done",message:q(s.join(`
|
|
12
|
+
`)),display:[s[0],...s.slice(1).map(p=>m.dim(p))].join(`
|
|
13
|
+
`),data:{id:t,name:o.name,removed:!0,settings:l,apps:o.apps,...r.length>0?{next:[{command:`${g} secret unset ${r.join(" ")}`,note:"the key nothing reads any more"}]}:{}}})}export{R as MAX_SPEC_BYTES,Ne as add,ne as addFromSpec,Ae as list,ie as listProviders,Te as off,_e as on,ee as readSpecSource,Ee as remove,ce as removeRegistered,Y as runMcpAlias,je as show,de as showProvider};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as v,b as g,c as k,d as w,f as A}from"./chunk-4MMHVIHT.js";import"./chunk-U4ATZJEU.js";import"./chunk-ONGI463M.js";import"./chunk-52NQ23OH.js";import{f as h,h as b}from"./chunk-475IB5UG.js";import{a as y}from"./chunk-KTX5YGBL.js";import{Pc as f,c as o,lc as c,sc as d,tc as u}from"./chunk-NXO2BC3M.js";import C from"node:path";async function E({cwd:t,manifest:e,outFile:a,out:s,verbose:p=!1,createCf:R=()=>u(),installDeps:$=d}){e.install!==!1&&(s.emit({type:"step",step:"app.install",status:"start",message:"Installing dependencies..."}),await $({cwd:t,description:"Installing dependencies...",install:e.install,verbose:p}),s.emit({type:"step",step:"app.install",status:"ok"})),s.emit({type:"step",step:"app.build",status:"start",message:"Building..."}),await g({cwd:t,cf:R(),buildCommand:e.build,verbose:p});let l=h(e);await k({cwd:t,inputs:{...l,helperWorkers:(e.workers??[]).map(n=>b(l.workerName,n.name)),declared:e.resources}}),s.emit({type:"step",step:"app.build",status:"ok",message:"Built the app and checked its Build Output."}),await v({cwd:t,manifest:e,out:s});let i=C.resolve(t,a),m=C.isAbsolute(a)||a.startsWith(".")?a:`./${a}`,B=await c(t).then(n=>n.version,()=>"unknown"),r=await A({cwd:t,manifest:e,outFile:i,cfVersion:B});return s.emit({type:"step",step:"app.release",status:"ok",message:`Packed ${e.id} ${r.version} (${r.sha256.slice(0,12)}) into ${i}.`,data:{tarball:i,shown:m,appId:e.id,version:r.version,sha256:r.sha256}}),{tarball:i,shown:m,version:r.version,sha256:r.sha256}}async function H(t){await f(t,async e=>{let a=process.cwd(),s=await E({cwd:a,manifest:await y(a),outFile:t.out??w,out:e,verbose:t.verbose});e.emit({type:"done",data:{...s,next:[{command:`${o} install ${s.shown}`,note:"installs it on your Gateway"},{command:`${o} install <repository url>`,note:"installs it on any Gateway, once the tarball is attached to a GitHub release of the app's repository"}]}})})}export{H as release};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{a as A,b as P,d as v,e as C}from"./chunk-
|
|
1
|
+
import{a as A,b as P,d as v,e as C}from"./chunk-RXSJENSN.js";import{c as u}from"./chunk-ZCJTJDAI.js";import{e as R,ia as h,ra as k,ta as E}from"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import{a as T}from"./chunk-KTX5YGBL.js";import{a as w,i as l}from"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import{Cc as g,Nc as I,Oc as $,Ub as c,f as b}from"./chunk-NXO2BC3M.js";async function K(e,o){let r=I(e.json);await $(r,async()=>{await x({cwd:process.cwd(),appId:o,gateway:e.gateway??!1,accountId:e["account-id"],yes:e.yes??!1,json:e.json??!1,out:r})})}async function x({cwd:e,appId:o,gateway:r,accountId:O,yes:j,json:m,out:n,createCf:D,interactive:y=w(m),confirm:S}){if(r&&o)throw new c("RESTORE_TARGET_TWICE",`Pass ${o} or --gateway, not both`,{data:{fix:"drop one of them"}});let a=r?null:o??(await T(e)).id,{cf:_,db:s}=await E({gateway:k(),accountId:O,interactive:y,login:{json:m,out:n,step:"db.login"},createCf:D}),d=a?P((await h(s,a)).workerName):A,i=a?`${a}'s database`:"the Gateway's database",t=await v(s,d);if(!t)throw new c("NO_RESTORE_POINT",`No restore point for ${i}
|
|
2
2
|
everyapp saves one when ${a?"a deploy":"setup or a Gateway upgrade"} migrates a database that has data.`);let p={appId:a,databaseId:t.databaseId,bookmark:t.bookmark,migrations:t.migrations,createdAt:t.createdAt,createdBy:t.createdBy};await l({yes:j,interactive:y,confirm:S,question:`Put ${i} back to before ${G(t)}?`,unattended:`Restoring ${i} needs a person at a terminal to confirm, or --yes
|
|
3
3
|
It undoes ${G(t)}; anything written to it since is lost too.`,context:["Anything written to the database since then is lost too."],data:p});let f=await u({db:s,id:d,purpose:"db.restore",...a?{app:a}:{},out:n,step:"db.lease"});try{await f.check(),n.emit({type:"step",step:"db.restore",status:"start",data:p}),await R(_,t.databaseId,t.bookmark),await C(s,d),n.emit({type:"step",step:"db.restore",status:"ok",message:`Restored ${i} to before ${t.migrations.join(", ")}.`,data:p})}finally{await f.release()}n.emit({type:"done",data:p})}function G(e,o=Date.now()){let r=e.createdBy.startsWith("api-token:")?"an API token":e.createdBy;return`${b(e.migrations.length,"migration")} (${e.migrations.join(", ")}) applied ${g(o-e.createdAt)} ago by ${r}`}export{K as restore,x as restoreDatabase};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{A as e,B as f,C as g,D as h,E as i,F as j,G as k,H as l,w as a,x as b,y as c,z as d}from"./chunk-WTKBB5HE.js";import"./chunk-LTYAIGEB.js";import"./chunk-CGFABBZA.js";import"./chunk-J2XKGQO7.js";import"./chunk-36VCEEIH.js";import"./chunk-IWP4Q3KV.js";import"./chunk-ZCJTJDAI.js";import"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import"./chunk-KTX5YGBL.js";import"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import"./chunk-NXO2BC3M.js";export{j as ManifestSource,g as applyAppSettings,f as applyGatewaySettings,e as applySecretValues,l as doneData,c as list,i as listSecrets,a as set,d as setSecrets,k as storedManifestOf,b as unset,h as unsetSecrets};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a,b,c}from"./chunk-KS7DIYIJ.js";import"./chunk-SMCUCFS4.js";import"./chunk-N4E5YE4X.js";import"./chunk-EEF4FY26.js";import"./chunk-E3EPK27P.js";import"./chunk-WTKBB5HE.js";import"./chunk-LTYAIGEB.js";import"./chunk-CGFABBZA.js";import"./chunk-TQWCYF2T.js";import"./chunk-ZH6IAPVK.js";import"./chunk-ONGI463M.js";import"./chunk-3GZA6EEZ.js";import"./chunk-52NQ23OH.js";import"./chunk-XEPXX3AI.js";import"./chunk-J2XKGQO7.js";import"./chunk-36VCEEIH.js";import"./chunk-AIDX5IYA.js";import"./chunk-IWP4Q3KV.js";import"./chunk-475IB5UG.js";import"./chunk-RXSJENSN.js";import"./chunk-ZCJTJDAI.js";import"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import"./chunk-KTX5YGBL.js";import"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import"./chunk-NXO2BC3M.js";export{c as reportGatewayResult,b as runGatewayCommand,a as setup};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{B as D,q as F,r as U}from"./chunk-
|
|
1
|
+
import{B as D,q as F,r as U}from"./chunk-WTKBB5HE.js";import"./chunk-LTYAIGEB.js";import{a as E,n as se}from"./chunk-CGFABBZA.js";import"./chunk-J2XKGQO7.js";import"./chunk-36VCEEIH.js";import"./chunk-IWP4Q3KV.js";import"./chunk-ZCJTJDAI.js";import{C as ne,aa as te,ra as ie,ta as ae,y as ee}from"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import"./chunk-KTX5YGBL.js";import{a as G,f as B,g as J,h as X,i as Z}from"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import{Hc as A,Ic as x,Pc as P,S as T,T as N,U as W,Ub as b,V as Q,W as Y,Z as C,c as h,k as p}from"./chunk-NXO2BC3M.js";import{stripVTControlCharacters as le}from"node:util";import c from"chalk";async function Ue(e,s){await P(e,i=>he({flags:e,out:i},s))}async function De(e){await P(e,s=>Se({flags:e,out:s}))}async function je(e,s){await P(e,i=>ye({flags:e,out:i},s))}async function Le(e,s){await P(e,i=>$e({flags:e,out:i},s))}function O({flags:e,out:s,createCf:i}){return ae({gateway:ie(e.gateway),accountId:e["account-id"],interactive:G(e.json??!1),login:{json:e.json,out:s,step:"login"},createCf:i})}function K(e){let s=e.trim().toLowerCase();if(Y(s))return W[s];throw new b("SIGNIN_UNKNOWN_PROVIDER",`${e} isn't a sign-in provider
|
|
2
2
|
The Gateway offers ${p([...T])}; oidc is any OpenID Connect issuer (Okta, Entra ID, Keycloak, Auth0\u2026).`,{rerun:`${h} signin list`,data:{providers:[...T]}})}async function de(e,s,i,t){let n=await te(e);if(!n)return;let m=await ne(e,{organizationId:n.organization.id,type:i,actor:ee(s),data:{provider:t.id,label:t.label}});m.length>0&&await e.run(m)}var u=e=>`Sign in with ${e.label}`,L=e=>`${se}/${e.setup}`,V=e=>e.status==="incomplete"?"needs setup":e.status;function ce(e){return e==="on"?c.green("on"):e==="needs setup"?c.yellow("needs setup"):c.dim("off")}function q(e,s,i){e.emit({type:"done",message:le(s.join(`
|
|
3
3
|
`)),display:[s[0],...s.slice(1).map(t=>c.dim(t))].join(`
|
|
4
4
|
`),data:i})}var R={clientId:"--client-id",clientSecret:"--client-secret-from-env",issuer:"--issuer",label:"--label",tenant:"--tenant"},oe={clientId:"<client id>",clientSecret:"<VAR>",issuer:"<issuer url>",label:"<button text>",tenant:"<tenant id>"};function pe(e){return{clientId:e["client-id"],issuer:e.issuer,label:e.label,tenant:e.tenant}}var j=e=>/^[\w@%+=:,./-]+$/.test(e)?e:`'${e.replace(/'/g,"'\\''")}'`;function fe(e,s,i){let t=s.replace(/\s+/g," ").slice(0,80),n=U(e.role),m=e.role==="issuer"?"SIGNIN_ISSUER_INVALID":e.role==="tenant"?"SIGNIN_TENANT_INVALID":"SETTING_VALUE_INVALID";throw new b(m,`${e.name} can't be "${t}"
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{a as Me,e as Fe,f as Le}from"./chunk-HHVABFYD.js";import"./chunk-U4ATZJEU.js";import{a as Ge}from"./chunk-N4E5YE4X.js";import{a as me,f as pe}from"./chunk-E3EPK27P.js";import{a as Re}from"./chunk-LTYAIGEB.js";import{a as Q,b as be,d as Ae,e as $e,j as Ne,l as ke,p as Ee}from"./chunk-CGFABBZA.js";import{b as We}from"./chunk-JBTV62V7.js";import{b as Oe,h as Ce,i as De,l as Te}from"./chunk-ZH6IAPVK.js";import{p as _e}from"./chunk-ONGI463M.js";import{f as Ue}from"./chunk-WV4G6E4T.js";import"./chunk-UEQMNXMZ.js";import"./chunk-3GZA6EEZ.js";import{b as xe}from"./chunk-52NQ23OH.js";import{c as Ie}from"./chunk-J2XKGQO7.js";import"./chunk-36VCEEIH.js";import{a as Pe}from"./chunk-AIDX5IYA.js";import{c as J}from"./chunk-IWP4Q3KV.js";import"./chunk-475IB5UG.js";import"./chunk-RXSJENSN.js";import{a as ye,b as L}from"./chunk-ZCJTJDAI.js";import{ma as he,oa as we,sa as Se}from"./chunk-OHDR7JWQ.js";import{b as j}from"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import{Ac as ge,Bc as fe,Db as ue,Hc as q,Ic as X,K as ae,Pc as ve,Yb as ce,c as S,f as E,g as T,ha as z,ia as Y,ja as le,k as $,la as de}from"./chunk-NXO2BC3M.js";var U=e=>Number(e?.[0]?.n??0);async function Be(e,n,t=Date.now()){let[r,o,i,s,u]=await e.run([{sql:"SELECT count(*) AS n FROM members WHERE organization_id = ?",params:[n]},{sql:"SELECT count(*) AS n FROM invitations WHERE organization_id = ? AND status = 'pending' AND expires_at > ?",params:[n,t]},{sql:"SELECT count(*) AS n FROM mcp_connections WHERE organization_id = ? AND revoked_at IS NULL",params:[n]},{sql:"SELECT count(*) AS n FROM user_access_tokens WHERE organization_id = ? AND revoked_at IS NULL AND expires_at > ?",params:[n,t]},{sql:"SELECT count(*) AS n FROM app_tool_catalogs WHERE organization_id = ? AND status = 'ok' AND tool_count > 0",params:[n]}]);return{members:U(r),invitations:U(o),connections:U(i),tokens:U(s),toolApps:U(u)}}import st from"chalk";function He(e){return e.severity==="error"||e.severity==="warning"}function b(e,...n){return{text:e.reduce((t,r,o)=>t+r+(n[o]??""),""),human:e.reduce((t,r,o)=>t+r+(o<n.length?st.bold(n[o]):""),"")}}function Z(e){return e.bound&&(e.status==="active"||e.status==="binding")}function x(e){return Z(e)&&e.setup!==null&&!e.setup.ready}var O=`${S} setup`,B=`${S} deploy`,at=`${S} update`;function Ve(){return{code:"GATEWAY_NOT_INSTALLED",severity:"warning",headline:"Setup stopped before it recorded the Gateway's install",detail:["The Gateway's database exists, but nothing else was recorded."],run:b`${O}`,runNote:"asks for the hostname again"}}function Ke({install:e,desired:n,apps:t,unboundApps:r,owner:o,servingVersionId:i,inSync:s,waitingCertificates:u,certificates:h,access:g,leases:p,checkout:f,emailProblems:m,settings:w,missingOrigins:k}){let y=[],v=e.releaseVersion;if(f.behind){let l=f.checkout?.version;y.push({code:"CHECKOUT_BEHIND",severity:"warning",headline:"This checkout is behind the live Gateway",detail:[...l&&l!==v?[`This checkout has ${l}; ${v} is live.`]:[],"Deploys from here are refused until it catches up."],run:b`${"git pull"}`})}else f.upToDate===!1&&e.liveVersionId!==null&&y.push({code:"GATEWAY_OUTDATED",severity:"info",headline:"Your every-app folder has a newer Gateway than the one online",detail:["Run update now, or leave it: the next new app's deploy updates it too."],run:b`${at}`,runNote:"updates it now"});e.liveVersionId===null?y.push({code:"GATEWAY_NOT_UPLOADED",severity:"warning",headline:"The Gateway's install stopped before its first upload",detail:["Setup finishes it, then prints the link that creates the owner account."],run:b`${O}`}):(i!==e.liveVersionId?y.push({code:"GATEWAY_CHANGED",severity:"warning",headline:"The Gateway Worker was changed outside everyapp",detail:["It serves a version from the dashboard or API, not the one setup uploaded."],run:b`${O}`,runNote:`redeploys ${v}, asking first`}):s||y.push(dt(r)),o||y.push({code:"NO_OWNER",severity:"warning",headline:"No owner yet, so nobody can sign in",detail:["Apps still deploy. Setup prints a one-time link that creates the owner account."],run:b`${O}`}));for(let l of n.missing)y.push({code:"APP_WORKER_MISSING",severity:"error",headline:`${l.appId}'s Worker no longer exists`,detail:[],run:b`${B} from ${l.appId}'s directory, or ${`${S} delete ${l.appId}`}`});for(let l of n.skipped)y.push({code:"APP_NOT_BOUND",severity:"error",headline:`The Gateway can't bind ${l.appId}`,detail:[`Its Worker isn't named the way the Gateway names ${l.appId}'s.`],run:b`${`${S} delete ${l.appId}`}`});let N=new Set(n.missing.map(l=>l.workerName));for(let l of t)N.has(l.workerName)||(l.status==="pending"?y.push({code:"APP_NOT_UPLOADED",severity:"warning",headline:`${l.id} was registered, but none of its deploys finished`,detail:(k?.get(l.id)??[]).map(({binding:A,variables:I})=>`${A} needs the database its Hyperdrive config connects to: ${Le(I)} in ${Me}, on the machine that deploys it.`),run:b`${B} from the app's directory, or ${`${S} delete ${l.id}`}`}):l.status==="binding"&&l.bound&&y.push({code:"APP_BINDING",severity:"settling",headline:`${l.id} goes live on its first visit to https://${l.hostname}`,detail:[]}));w&&y.push({code:"SETTINGS_UNKNOWN",severity:"warning",headline:"Couldn't list the Workers' secrets",detail:[`Cloudflare said: ${w.error}. Whether the apps' settings are set isn't known.`]});for(let l of t)x(l)&&y.push(lt(l.id,l.setup));"error"in m&&y.push({code:"EMAIL_ROUTES_UNKNOWN",severity:"warning",headline:"Couldn't check the apps' Email Routing rules",detail:[`Cloudflare said: ${m.error}. Deleted rules won't show above.`]});for(let l of t){let A=ut(l,"error"in m?[]:m);A&&y.push(A)}h&&y.push({code:"CERTIFICATES_UNKNOWN",severity:"warning",headline:`Couldn't list ${e.zoneName}'s certificates`,detail:[`Cloudflare said: ${h.error}.`]}),u.length>0&&y.push({code:"CERT_PENDING",severity:"settling",headline:`No certificate yet for ${u.join(", ")}`,detail:["It usually comes within minutes."]}),g&&y.push({code:"ACCESS_UNKNOWN",severity:"warning",headline:"Couldn't check whether Cloudflare Access is on",detail:[`Cloudflare said: ${g.error}.`]});for(let l of p)y.push({code:"DEPLOY_RUNNING",severity:"settling",headline:`${T(L(l))} is running`,detail:[]});return[...y.filter(l=>l.severity!=="info"),...y.filter(l=>l.severity==="info")]}function lt(e,n){return{code:"APP_NEEDS_SETUP",severity:"warning",headline:`${e} needs setup`,detail:Ee(n.unmet),...n.command?{run:b`${n.command.command}`}:{}}}function dt(e){if(e.length===0)return{code:"BINDINGS_DIFFER",severity:"warning",headline:"The live Gateway's apps or hostnames are out of date",detail:["It still serves something that was removed, or not yet what was added."],run:b`${O}`};let n=$(e);return{code:"BINDINGS_DIFFER",severity:"warning",headline:`The live Gateway doesn't serve ${n}`,detail:[e.length===1?`${n} is uploaded, but the live Gateway doesn't bind it.`:`${n} are uploaded, but the live Gateway doesn't bind them.`],run:b`${O}`}}function ut(e,n){let{inbound:t,routed:r,declaresInbound:o}=e.email;if(t.length>0&&!o){let f=$(t);return{code:"EMAIL_INBOUND_UNDECLARED",severity:"warning",headline:`${e.id} has ${t.length===1?"an inbound address":"inbound addresses"}, but its config doesn't turn inbound mail on`,detail:[`${e.id} was deployed without email: { inbound: true }, so nothing routes ${f}.`],fix:b`declare it in everyapp.config.ts and run ${B}, or drop ${t.length===1?"the address":"the addresses"}: ${`${S} email unset inbound`}`,where:`Run either from ${e.id}'s directory.`}}let i=t.filter(f=>!r.includes(f)),s=r.filter(f=>!t.includes(f)),u=n.filter(f=>f.workerName===e.workerName);if(i.length+s.length+u.length===0)return null;let h=[...i.length>0?[`${$(i)} ${i.length===1?"isn't":"aren't"} routed yet`]:[],...u.map(f=>`${f.address} gets no mail: ${f.problem}`),...s.length>0?[`${$(s)} ${s.length===1?"is":"are"} still routed, though no longer listed`]:[]],g=i.length+u.length,p=s.length>0?`${e.id}'s mail routes don't match its addresses`:u.length===0?`${e.id} doesn't get mail at ${$(i)} yet`:g===1?`${e.id} doesn't get mail at ${u[0].address}`:`${e.id} doesn't get mail at ${g} of its addresses`;return{code:u.length>0?"EMAIL_ROUTE_MISSING":"EMAIL_ROUTE_PENDING",severity:"warning",headline:p,detail:s.length===0&&u.length===0?[]:s.length===0&&g===1?[`${T(u[0].problem)}.`]:[`${h.join("; ")}.`],run:b`${B} from ${e.id}'s directory`}}var ct=4,mt="https://everyapp.com/docs/connect-ai",ze=Object.values(ae).map(e=>e.keyEnv);function ee(e,n){return e.some(t=>x(t)&&t.setup.unmet.some(r=>r.names.includes(n)))}function Ye(e,n){return e.filter(t=>t.setup?.settings.some(r=>r.kind==="capability"&&r.id===n)).map(t=>t.id)}function pt(e){let{apps:n,gatewayNames:t}=e;if(!t||ze.some(i=>t.includes(i)))return null;let r=[],o=[];for(let i of n){let s=(i.setup?.settings??[]).filter(u=>u.kind==="provider"&&u.set===!1).flatMap(u=>u.names.filter(h=>ze.includes(h))).filter(u=>!ee(n,u));if(s.length!==0){o.push(i.id);for(let u of s)r.includes(u)||r.push(u)}}return r.length===0?null:{code:"AI_KEY",command:`${S} secret set ${r.join(" ")}`,note:`AI for ${$(o)}`,why:`${$(o)} ${o.length===1?"uses":"use"} AI once ${$(r)} ${r.length===1?"is":"are"} set; no AI key is set on the Gateway.`}}function gt(e){let{gatewayNames:n,providers:t,uploaded:r,apps:o}=e;return!n||!r?[]:t.filter(i=>!i.on&&n.includes(i.keySetting)&&Ye(o,i.capability).length===0).map(i=>({code:"PROVIDER_OFFER",command:`${S} mcp on ${i.id}`,note:`offer ${i.name}'s tools to AI clients (each call spends ${i.name} credit)`,why:`${i.keySetting} is set and ${i.name} is off.`}))}function ft(e){let{gatewayNames:n,providers:t,apps:r}=e;return n?t.filter(o=>o.on&&!n.includes(o.keySetting)&&!ee(r,o.keySetting)).map(o=>({code:"PROVIDER_KEY",command:`${S} secret set ${o.keySetting}`,note:`${o.name} is on and needs its key`,why:`${o.name} shows "needs setup" and serves no tools until ${o.keySetting} is set.`})):[]}function yt(e){let{mode:n,uploaded:t,owner:r,access:o}=e;return n==="hosted"||!t||!r||!o||o.on?null:{code:"ACCESS_OFF",command:`${S} access on`,note:"put Cloudflare Access in front (recommended)",why:"Cloudflare Access is off; the Gateway's own sign-in is the only check in front of your apps."}}function ht(e){let{counts:n,owner:t,apps:r,gatewayUrl:o}=e;return!n||!t||n.members!==1||n.invitations>0||!r.some(Z)?null:{code:"INVITE",url:`${o}/admin/users`,note:"invite people",why:`${t.email} is the only member.`}}function wt(e){let{counts:n,gatewayUrl:t}=e;return!n||n.connections>0||n.tokens>0||n.toolApps===0?null:{code:"CONNECT_AI",url:mt,note:`connect an AI client to ${t}/mcp`,why:`No AI client is connected; ${E(n.toolApps,"app")} ${n.toolApps===1?"serves":"serve"} tools.`}}function St(e){return!e.uploaded||e.apps.length>0?null:{code:"CREATE_APP",command:`${S} create my-app`,note:"start your first app",why:"No apps yet."}}function vt(e){let{gatewayNames:n,counts:t,apps:r}=e;if(!n||n.includes("EMAIL_FROM")||ee(r,"EMAIL_FROM"))return null;let o=Ye(r,"email").filter(s=>!r.some(u=>u.id===s&&x(u)));return!((t?.members??0)>1)&&o.length===0?null:{code:"EMAIL_UNSET",command:`${S} secret set EMAIL_FROM EMAIL_FROM_NAME`,note:"email invites and password resets; needs Cloudflare Email Sending",why:`No sender is set: invites and resets go out by link${o.length>0?`, and ${$(o)} ${o.length===1?"sends":"send"} mail once there is one`:""}.`}}function je(e){return[pt(e),...gt(e),...ft(e),yt(e),ht(e),wt(e),St(e),vt(e)].filter(t=>t!==null).filter(t=>!t.command||!e.problems.some(r=>r.run?.text===t.command)).slice(0,ct)}import d from"chalk";var bt={["error"]:d.red("\u2717"),["warning"]:d.yellow("!"),["info"]:d.dim("i")};function qe(e,n){return[...q([{label:"Cloudflare",value:e},{label:"Gateway",value:d.yellow("install not finished")}]),...Je([n])].join(`
|
|
2
|
+
`)}function Xe({install:e,accountName:n,owner:t,servingRecorded:r,checkout:o,certificates:i,waitingCertificates:s,access:u,leases:h,apps:g,missingWorkers:p,skippedWorkers:f,emailProblems:m,problems:w}){let k=e.liveVersionId!==null,y=[{label:"Gateway",value:`${d.cyan(`https://${e.gatewayHost}`)}${e.deploymentMode?d.dim(` \xB7 ${e.deploymentMode.replace("_","-")}`):""}`},{label:"Cloudflare",value:n},{label:"Owner",value:t?`${t.email}${t.organizationName?d.dim(` \xB7 ${t.organizationName}`):""}`:d.yellow("none yet")},...u?[{label:"Access",value:$t(u)}]:[],{label:"Release",value:At(e,r,o)},{label:"TLS",value:Nt(i,s)},...h.map((c,D)=>({label:D===0?"Deploys":"",value:T(L(c))}))],v=new Set(h.flatMap(c=>c.app?[c.app]:[])),N=new Set(s),l=c=>Rt(c,{missing:p.has(c.workerName),skipped:f.has(c.workerName),waitingCertificate:N.has(c.hostname),deploying:v.has(c.id)}),A=g.filter(c=>c.email.senders.length>0||c.email.inbound.length>0||c.email.routed.length>0),I=g.flatMap(c=>c.setup?Ne(c.id,c.setup.settings):[]);return[...q(y),"",...g.length>0?X(["APP","STATUS","URL","DEPLOYED BY","PUBLIC"],g.map(c=>[c.id,l(c),d.cyan(`https://${c.hostname}`),kt(c.deployedBy),It(c)])).map(c=>c.trimEnd()):[d.dim("No apps yet.")],...A.length>0?["",...Pt(A,m)]:[],...I.length>0?["",...ke(I)]:[],...Je(w)].join(`
|
|
3
|
+
`)}function At(e,n,t){let r=e.releaseVersion,o=i=>`${r} ${d.dim("\xB7")} ${d.yellow(i)}`;return e.liveVersionId===null?d.yellow(`${r}, never uploaded`):n?t.behind?o("this checkout is behind"):t.upToDate===!1?`${r}${d.dim(" \xB7 this checkout has newer Gateway changes")}`:t.upToDate===!0?`${r}${d.dim(" \xB7 matches this checkout")}`:r:o("changed outside everyapp")}function $t(e){return"error"in e?d.yellow("! couldn't check"):e.on?`${d.green("on")}${d.dim(" \xB7 everyone signs in through Cloudflare Access first")}`:d.dim("off")}function Nt(e,n){return e===null?d.yellow("! couldn't check"):e.length===0?d.dim("no hostnames yet"):n.length>0?`waiting for ${n.join(", ")}${d.dim(" \xB7 usually a few minutes")}`:`ready on ${E(e.length,"hostname")}`}function kt(e){return e?e.startsWith("api-token:")?"API token":e:""}var Et=3;function It(e){let n=[];if(e.publicRoutes.length>0){let{shown:t,more:r}=fe(e.publicRoutes,Et);n.push(`${t}${r>0?d.dim(` +${r} more`):""}`)}return e.mcp&&n.push(ge(e.mcp)),n.join(d.dim(" \xB7 "))}function Rt(e,{missing:n,skipped:t,waitingCertificate:r,deploying:o}){let i=n?`${d.red("\u2717")} Worker missing`:t?`${d.red("\u2717")} can't be bound`:e.status==="pending"?`${d.yellow("!")} never deployed`:e.bound?x(e)?`${d.yellow("!")} needs setup`:e.status==="active"?`${d.green("\u2713")} live`:e.status==="binding"?`${d.dim("\u25CB")} ${r?"waiting for certificate":"live on first visit"}`:d.dim(e.status==="disabled"?"switched off":e.status):`${d.yellow("!")} not bound`;return o?`${i} \xB7 deploying`:i}function Pt(e,n){let t=e.flatMap(r=>{let{senders:o,inbound:i,routed:s,declaresInbound:u}=r.email,h=new Set(n.filter(m=>m.workerName===r.workerName).map(m=>m.address)),g=i.length>0&&!u?i.map(m=>`${d.yellow("!")} ${m} ${d.dim("(inbound off)")}`):[...i.map(m=>h.has(m)?`${m} ${d.yellow("! not delivered")}`:s.includes(m)?m:`${m} ${d.yellow("! not routed yet")}`),...s.filter(m=>!i.includes(m)).map(m=>`${m} ${d.yellow("! still routed, no longer listed")}`)],p=o.length>0?o:[d.dim("the Gateway's sender")],f=Math.max(p.length,g.length,1);return Array.from({length:f},(m,w)=>[w===0?r.id:"",p[w]??"",g[w]??(w===0?d.dim("nothing"):"")])});return X(["EMAIL","SENDS AS","RECEIVES"],t)}function Je(e){let n=[];for(let t of e){if(t.severity==="settling")continue;let r=t.run?n.find(o=>o[0].run?.text===t.run.text):void 0;r?r.push(t):n.push([t])}return n.length===0?[]:["",...n.flatMap(Ot)]}function Ot([e,...n]){let t=e,r=[t,...n].map(i=>i.severity),o=r.includes("error")?"error":r.includes("warning")?"warning":"info";return[`${bt[o]} ${t.headline}`,...[...t.detail,...n.map(i=>`${i.headline}.`)].map(i=>d.dim(` ${i}`)),...t.fix?[` Fix: ${t.fix.human}`]:[],...t.run?[` Run: ${t.run.human}${t.runNote?` ${d.dim(t.runNote)}`:""}`]:[],...t.where?[d.dim(` ${t.where}`)]:[]]}async function Un(e){await ve(e,async n=>{let t=await Se({json:e.json,out:n,accountId:e["account-id"]}),r=Pe();await xt({gateway:t,out:n,checkout:r?()=>Oe(r):null})})}function Qe(e){return{code:e.code,severity:e.severity,message:[e.headline,...e.detail].join(`
|
|
4
|
+
`),run:e.run?.text??null,...e.runNote?{note:e.runNote}:{},...e.fix?{fix:e.fix.text}:{}}}async function xt({gateway:e,out:n,checkout:t}){let{cf:r,account:o,db:i,install:s}=e,u=o.name??o.id;if(!s){let a=Ve();n.emit({type:"done",message:`${u} has the Gateway's database, but its install didn't finish`,display:qe(u,a),data:{deployed:!0,installed:!1,accountId:o.id,fixes:[Qe(a)]}});return}let h=s.liveVersionId!==null,g=s.deploymentMode!=="hosted"&&h,[p,f,m,w,k,y,v,N]=await Promise.all([De(i,Ce(r)),we(i),ye(i),Ge(i),Ie(r,ue),J(i,"email-route"),h?C(()=>Q(r)):null,g?C(()=>me(i)):null]),l=w?.owner??null,A=f.filter(a=>a.tier!==z),I=le.map(a=>({id:a,name:Y[a].name,capability:Y[a].capability,keySetting:de(a),on:f.some(P=>P.tier===z&&P.appSlug===a)})),c=g?v&&"error"in v?v:N&&"error"in N?N:{value:pe(v.value,N.value)}:null,D=c&&"value"in c?c.value:null,te=c&&"error"in c?c:null,ne=new Set(p.missing.map(a=>a.workerName)),[W,_,re,Ze,et]=await Promise.all([C(()=>We(r,s.zoneId,s.liveDomains)),C(async()=>y.length===0?[]:Ue(r,y)),Re(i,s).then(a=>_t(r,i,A,ne,v,a)),w?Be(i,w.organizationId).catch(()=>null):null,Tt(i,A)]),H=`https://${s.gatewayHost}`,V=_e({gatewayHost:s.gatewayHost,appHosts:p.appHosts.filter(a=>xe(a,s.appBaseDomain))}),tt=V.filter(a=>!s.liveDomains.includes(a)),nt=s.liveDomains.filter(a=>!V.includes(a)),ie=p.appWorkers.filter(a=>!s.liveAppWorkers.includes(a)),rt=s.liveAppWorkers.filter(a=>!p.appWorkers.includes(a)),oe=!!k?.versionId&&k?.versionId===s.liveVersionId,se=oe&&ie.length===0&&rt.length===0&&tt.length===0&&nt.length===0,R=A.map(a=>({id:a.appSlug,hostname:a.hostname,workerName:a.workerName,status:a.status,bound:s.liveAppWorkers.includes(a.workerName),deployedBy:a.deployedBy,email:{senders:a.email.senders,inbound:a.email.inbound,routed:y.filter(P=>P.workerName===a.workerName).map(P=>P.name),declaresInbound:a.declaresInbound},publicRoutes:a.publicRoutes,mcp:a.mcp,setup:re.setups.get(a.appSlug)??null})),G="error"in W?null:W.value,K=(G??[]).filter(a=>!a.ready).map(a=>a.host),M=await Wt(s,t),F=Ke({install:s,desired:p,apps:R,unboundApps:R.filter(a=>ie.includes(a.workerName)).map(a=>a.id),owner:l,servingVersionId:k?.versionId??null,inSync:se,waitingCertificates:K,certificates:"error"in W?W:null,access:te,leases:m,checkout:M,emailProblems:"error"in _?_:_.value,settings:re.unread,missingOrigins:et}),it=je({mode:s.deploymentMode,uploaded:h,gatewayUrl:H,owner:l,apps:R,gatewayNames:v&&"value"in v?v.value:null,access:D,providers:I,counts:Ze,problems:F}),ot=Xe({install:s,accountName:u,owner:l,servingRecorded:oe,checkout:M,certificates:G,waitingCertificates:K,access:te??D,leases:m,apps:R,missingWorkers:ne,skippedWorkers:new Set(p.skipped.map(a=>a.workerName)),emailProblems:"error"in _?[]:_.value,problems:F});n.emit({type:"done",message:Dt(H,R,F),display:ot,data:{deployed:!0,installed:!0,gatewayUrl:H,accountId:o.id,mode:s.deploymentMode,release:{version:s.releaseVersion,sha256:s.releaseSha256},versionId:k?.versionId??null,recordedVersionId:s.liveVersionId,owner:l,claimed:l!==null,apps:R,desiredApps:p.appWorkers,liveApps:s.liveAppWorkers,appBaseDomain:s.appBaseDomain,domains:V,liveDomains:s.liveDomains,inSync:se,upToDate:M.upToDate,checkout:M.checkout,tls:G===null?null:!K.includes(s.gatewayHost),certificates:G,access:D,leases:m,fixes:F.map(Qe),next:it.map(Ct)}})}function Ct(e){return{code:e.code,...e.command?{command:e.command}:{},...e.url?{url:e.url}:{},note:e.note,why:e.why}}function Dt(e,n,t){let r=n.filter(i=>i.status==="active"&&i.bound).length,o=t.filter(He).length;return`Gateway ${e}: ${E(r,"app")} live, ${o===0?"nothing to fix":`${E(o,"problem")} to fix`}`}async function _t(e,n,t,r,o,i){let s=new Map,u=t.filter(p=>p.manifest&&$e(p.manifest,i)&&p.tier!=="dispatch"&&p.status!=="pending"&&!r.has(p.workerName));if(u.length===0)return{setups:s,unread:null};let h=null,g=o??await C(()=>Q(e));"error"in g&&(h=g);for(let p of u){let f=await C(()=>be(e,p.workerName));"error"in f&&(h??=f);let m="error"in f?null:f.value;m&&(p.secretNames===null||j(m)!==j(p.secretNames))&&await he(n,p.id,m);let{setup:w}=Ae({manifest:p.manifest,appId:p.appSlug,gatewayNames:"error"in g?null:g.value,secretNames:m,lookup:i});s.set(p.appSlug,w)}return{setups:s,unread:h}}async function Tt(e,n){let t=new Map,r=n.filter(i=>i.status==="pending").map(i=>({app:i,bindings:Ut(i.manifest)})).filter(({bindings:i})=>i.length>0);if(r.length===0)return t;let o=await J(e,"hyperdrive").catch(()=>null);if(!o)return t;for(let{app:i,bindings:s}of r){let u=s.filter(h=>!o.some(g=>g.workerName===i.workerName&&g.binding===h&&g.resourceId));u.length!==0&&t.set(i.appSlug,u.map(h=>({binding:h,variables:Fe(h,s.length)})))}return t}function Ut(e){let n=e?.resources?.hyperdrive;return Array.isArray(n)?n.flatMap(t=>{let r=t?.name;return typeof r=="string"&&r?[r]:[]}):[]}async function C(e){try{return{value:await e()}}catch(n){return{error:ce(n)}}}async function Wt(e,n){let t=n?await n().catch(()=>null):null;if(!t)return{upToDate:null,behind:!1,checkout:null};let r=t.treeSha256&&e.sourceTreeSha256?t.treeSha256===e.sourceTreeSha256:null;return{upToDate:r,behind:r===!1&&Te(t,e),checkout:{version:t.version,treeSha256:t.treeSha256}}}export{xt as reportStatus,Un as status};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import{a as ft,d as ut}from"./chunk-DB5CMXEV.js";import{a as Ve,b as He,c as je}from"./chunk-EEF4FY26.js";import"./chunk-E3EPK27P.js";import"./chunk-WTKBB5HE.js";import"./chunk-LTYAIGEB.js";import"./chunk-CGFABBZA.js";import{a as oe,c as mt,d as pe,e as pt}from"./chunk-JBTV62V7.js";import{a as at,e as st,i as it,k as ct,o as lt,p as dt}from"./chunk-Y6CGMZEB.js";import{h as nt,i as rt}from"./chunk-Q44H7KLY.js";import{a as Ye,c as Je,d as Xe,h as qe,i as Qe,j as et,k as te,l as tt}from"./chunk-UEQMNXMZ.js";import{a as ee,b as Be,i as ot}from"./chunk-3GZA6EEZ.js";import"./chunk-52NQ23OH.js";import{a as Ce,h as Re,j as Te,l as be,p as Ne,v as De}from"./chunk-XEPXX3AI.js";import{a as Ue,d as Ze}from"./chunk-J2XKGQO7.js";import"./chunk-36VCEEIH.js";import{a as I,d as Me}from"./chunk-IWP4Q3KV.js";import"./chunk-475IB5UG.js";import"./chunk-ZCJTJDAI.js";import{a as ze,k as Le,pa as Ke,q as me,r as xe,t as We}from"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import{a as Se}from"./chunk-LTMQP62I.js";import"./chunk-KTX5YGBL.js";import{a as _e,f as Oe}from"./chunk-MLZJBYSY.js";import{d as Pe,j as Ie}from"./chunk-JT3R24Y7.js";import{$b as Ee,Db as le,Hc as Fe,Pc as Ge,Ub as $,Wb as ve,Yb as W,_b as U,d as ke,f as v,k as P,tc as $e,vc as de}from"./chunk-NXO2BC3M.js";import G from"chalk";import Pt from"node:fs";import It from"node:os";import gt from"node:path";var ht=["23bc28f0b638fbfc1c7f838573c17ee3"];var Dt=/^[0-9a-f]{32}$/,yt=e=>Dt.test(e),fe="EVERYAPP_TEST_ACCOUNTS";function _t(e=process.env){let o=e.XDG_CONFIG_HOME||gt.join(It.homedir(),".config");return gt.join(o,"everyapp","test-accounts")}function wt(e){let o=new Set,i=[];for(let r of e.split(/\r?\n/)){let c=r.replace(/#.*$/,"");for(let s of c.split(/[\s,]+/)){if(!s)continue;let m=s.toLowerCase();yt(m)?o.add(m):i.push(s)}}return{ids:[...o],ignored:i}}function Ot(e=process.env){let o=_t(e),i="";try{i=Pt.readFileSync(o,"utf8")}catch(s){if(s.code!=="ENOENT")throw s}let r=wt(e[fe]??""),c=wt(i);return{ids:[...new Set([...r.ids,...c.ids])],ignored:[...r.ignored,...c.ignored],file:o}}function St(e,o){return["only for a dedicated test account that holds nothing else (docs/runbooks/onboarding-loop-test-accounts.md):",`set ${fe}=${e} for this one command, or add a line ${e} to ${o}`].join(" ")}function At({accountId:e,out:o,env:i=process.env}){let r=e.trim().toLowerCase();if(!yt(r))throw new $("TEARDOWN_INVALID_ACCOUNT_ID",`"${e.trim()}" isn't a Cloudflare account id
|
|
2
|
+
An account id is 32 hex characters (Compute (Workers) \u2192 Overview, or any dashboard URL dash.cloudflare.com/<account id>/...).`,{fix:"pass the test account's id from the dashboard as --account-id",data:{accountId:e.trim()}});if(ht.includes(r))throw new $("TEARDOWN_ACCOUNT_FORBIDDEN",`Cloudflare account ${r} can never be torn down
|
|
3
|
+
It is a live account, refused by id before any allowlist is read.`,{data:{accountId:r}});let c=Ot(i);if(c.ignored.length>0&&o.emit({type:"warning",code:"TEARDOWN_ALLOWLIST_IGNORED",message:`Ignored ${v(c.ignored.length,"entry")} of the teardown allowlist that ${c.ignored.length===1?"isn't":"aren't"} account ids: ${P(c.ignored)}
|
|
4
|
+
An account id is 32 hex characters (${fe}, ${c.file}).`,data:{ignored:c.ignored,file:c.file}}),!c.ids.includes(r))throw new $("TEARDOWN_NOT_ALLOWLISTED",`Cloudflare account ${r} isn't on the teardown allowlist
|
|
5
|
+
teardown deletes everything Every App made in an account, so it runs only against accounts listed as dedicated test accounts.`,{fix:St(r,c.file),data:{accountId:r,file:c.file}});if(!i.CLOUDFLARE_API_TOKEN)throw new $("TEARDOWN_NEEDS_TOKEN",`teardown needs CLOUDFLARE_API_TOKEN
|
|
6
|
+
A Cloudflare login is a person, who sees every account they belong to; teardown runs only with an API token scoped to the test account (runbook step 5).`,{fix:"set CLOUDFLARE_API_TOKEN to the test account's token for this one command, and run it again",data:{accountId:r}});return{accountId:r,allowlist:c.ids}}function kt({accountId:e,allowlist:o,whoami:i}){if(!i.authenticated||i.tokenValid===!1)throw new $("CLOUDFLARE_TOKEN_REJECTED",`Cloudflare didn't accept CLOUDFLARE_API_TOKEN
|
|
7
|
+
It may be mistyped, expired or revoked.`,{fix:"set the test account's token (runbook step 5)"});if(i.authSource&&!/CLOUDFLARE_API_TOKEN/.test(i.authSource))throw new $("TEARDOWN_NEEDS_TOKEN",`teardown needs CLOUDFLARE_API_TOKEN, but cf authenticated with ${i.authSource}
|
|
8
|
+
A Cloudflare login is a person, who sees every account they belong to; teardown runs only with an API token scoped to the test account (runbook step 5).`,{fix:"set CLOUDFLARE_API_TOKEN to the test account's token for this one command, and run it again",data:{accountId:e,authSource:i.authSource}});let r=(i.accounts??[]).map(s=>({id:s.id.toLowerCase(),name:s.name??null})),c=r.filter(s=>ht.includes(s.id)||!o.includes(s.id));if(c.length>0)throw new $("TEARDOWN_TOKEN_TOO_BROAD",[`CLOUDFLARE_API_TOKEN sees ${v(c.length,"account")} that ${c.length===1?"isn't a":"aren't"} test account${c.length===1?"":"s"}: ${P(c.map(s=>s.name?`${s.name} (${s.id})`:s.id))}`,"A teardown token must be scoped to the test account alone (Account Resources \u2192 Include \u2192 that account), so there is no path from here to a live account."].join(`
|
|
9
|
+
`),{fix:"mint a token for the test account only (runbook step 5)",data:{accountId:e,accounts:c}});if(!r.some(s=>s.id===e))throw new $("TEARDOWN_ACCOUNT_NOT_VISIBLE",`CLOUDFLARE_API_TOKEN doesn't list Cloudflare account ${e}
|
|
10
|
+
${r.length===0?"It lists no accounts.":`It lists ${P(r.map(s=>s.id))}.`}`,{fix:"use that account's token, with Account Settings: Read on it (runbook step 5)",data:{accountId:e,accounts:r}})}import vt from"chalk";var Z="every-",O=e=>e.startsWith(Z),ne=e=>e.type==="MX"&&/\.mx\.cloudflare\.net\.?$/i.test(e.content??"")||e.type==="TXT"&&/_spf\.mx\.cloudflare\.net/i.test(e.content??""),zt=new Set(["A","AAAA","CNAME"]),V=e=>zt.has(e.type.toUpperCase()),K=[["access","Access application or policy","Access applications and policy"],["email","Email Routing change","Email Routing changes"],["workflows","Workflow","Workflows"],["workers","Worker","Workers"],["certificates","certificate pack","certificate packs"],["d1","D1 database","D1 databases"],["kv","KV namespace","KV namespaces"],["r2","R2 bucket","R2 buckets"],["hyperdrive","Hyperdrive config","Hyperdrive configs"],["vectorize","Vectorize index","Vectorize indexes"],["aiGateway","AI Gateway","AI Gateways"],["dns","DNS record","DNS records"]],H={access:"Zero Trust \u2192 Access \u2192 Applications and Policies",email:"the zone \u2192 Email \u2192 Email Routing",workflows:"Compute (Workers) \u2192 Workflows",workers:"Compute (Workers) \u2192 Workers & Pages",certificates:"the zone \u2192 SSL/TLS \u2192 Edge Certificates",d1:"Storage & Databases \u2192 D1",kv:"Storage & Databases \u2192 KV",r2:"Storage & Databases \u2192 R2 Object Storage",hyperdrive:"Storage & Databases \u2192 Hyperdrive",vectorize:"AI \u2192 Vectorize",aiGateway:"AI \u2192 AI Gateway",dns:"the zone \u2192 DNS \u2192 Records"},j=e=>e.reduce((o,i)=>o+i.rules.length+(i.catchAllWorker?1:0)+(i.disable?1:0),0),ue=e=>e.reduce((o,i)=>o+i.records.length,0);function F(e){return{access:e.access.applications.length+(e.access.policy?1:0),email:j(e.email),workflows:e.workflows.length,workers:e.workers.length,certificates:e.certificates.length,d1:e.d1.length,kv:e.kv.length,r2:e.r2.length,hyperdrive:e.hyperdrive.length,vectorize:e.vectorize.length,aiGateway:e.aiGateway.length,dns:ue(e.dns)}}function S(e){return Object.values(F(e)).reduce((o,i)=>o+i,0)}var h={worker:e=>`${I.worker} "${e}"`,workflow:e=>`Workflow "${e}"`,d1:e=>`${I.d1} "${e}"`,kv:e=>`${I.kv} "${e}"`,r2:e=>`${I.r2} "${e}"`,hyperdrive:e=>`${I.hyperdrive} "${e}"`,vectorize:e=>`${I.vectorize} "${e}"`,aiGateway:e=>`${I["ai-gateway"]} "${e}"`,application:e=>`Access application "${e}"`,policy:e=>`Access policy "${e}"`,rule:(e,o)=>`Email Routing rule for ${e??"(no address)"} on ${o}`,catchAll:e=>`catch-all of ${e}`,routing:e=>`Email Routing on ${e}`,pack:(e,o)=>`certificate pack ${e} for ${o}`,record:(e,o)=>`DNS ${e} record at ${o}`};function Lt(e){let o=F(e),i={access:[...e.access.applications.map(r=>`application "${r.name}"`),...e.access.policy?[`policy "${e.access.policy.name}"`]:[]],email:e.email.flatMap(r=>[...r.rules.map(c=>`rule for ${c.address??"(no address)"} on ${r.zoneName}`),...r.catchAllWorker?[`${r.zoneName}'s catch-all back to dropping mail`]:[],...r.disable?[`Email Routing off for ${r.zoneName}`]:[]]),workflows:e.workflows,workers:e.workers.map(r=>r.domains.length>0?`${r.name} (${r.domains.join(", ")})`:r.name),certificates:e.certificates.map(r=>`${r.packId} (${r.hostname})`),d1:e.d1.map(r=>r.name),kv:e.kv.map(r=>r.title),r2:e.r2,hyperdrive:e.hyperdrive.map(r=>r.name),vectorize:e.vectorize,aiGateway:e.aiGateway,dns:e.dns.flatMap(r=>r.records.map(c=>`${c.type} at ${r.name}`))};return K.flatMap(([r,,c])=>o[r]===0?[]:[{label:`${c} (${o[r]})`,items:i[r]}])}function Et(e){let o=Lt(e).map(({label:i,items:r})=>({label:i,value:r.join(", ")}));return[...o.length>0?Fe(o):[vt.dim("Nothing of Every App's to delete.")],...e.kept.length>0?["",vt.dim(`Kept: ${e.kept.join("; ")}.`)]:[]]}function re(e){let o=F(e),i=K.flatMap(([r,c,s])=>o[r]===0?[]:[o[r]===1?`1 ${c}`:`${o[r]} ${s}`]);return`${v(S(e),"resource")}${i.length>0?`: ${i.join(", ")}`:""}`}function B(e){return{accountId:e.accountId,gateway:e.gateway,counts:F(e),total:S(e),workers:e.workers,workflows:e.workflows,d1:e.d1,kv:e.kv,r2:e.r2,hyperdrive:e.hyperdrive,vectorize:e.vectorize,aiGateway:e.aiGateway,access:e.access,email:e.email,certificates:e.certificates,dns:e.dns,kept:e.kept}}var xt=e=>typeof e=="object"&&e!==null&&"removedAs"in e,Wt={name:"",enabled:!1,matchers:[{type:"all"}],actions:[{type:"drop"}]},ae="teardown.delete",Kt=5e3;async function Ct({cf:e,plan:o,out:i,sleep:r=c=>new Promise(s=>setTimeout(s,c))}){let c=[],s=[],m=async(n,d,k)=>{try{let y=await k();if(y===!1)return;c.push(xt(y)?y.removedAs:d)}catch(y){if(U(y,"not_found"))return;let f=W(y).split(`
|
|
11
|
+
`)[0]??"";s.push({kind:n,described:d,place:H[n],reason:f}),i.emit({type:"warning",code:"TEARDOWN_DELETE_FAILED",step:ae,message:`Couldn't delete the ${d}
|
|
12
|
+
${f}`,data:{kind:n,described:d,reason:f,fix:`delete it in the Cloudflare dashboard (${H[n]})`}})}},l=async(n,d,k)=>{if(d===0)return;let[,y,f]=K.find(([D])=>D===n),E=d===1?y:f,z=c.length,L=s.length;i.emit({type:"step",step:ae,status:"start",message:`Deleting ${d} ${E}...`,data:{kind:n,count:d}}),await k();let b=c.length-z,x=s.length-L;i.emit({type:"step",step:ae,status:"ok",message:x===0?`Deleted ${b} ${b===1?y:f}`:`Deleted ${b} ${b===1?y:f}; kept ${x}`,data:{kind:n,removed:c.slice(z),kept:s.slice(L).map(D=>D.described)}})};await l("access",o.access.applications.length+(o.access.policy?1:0),async()=>{for(let n of o.access.applications)await m("access",h.application(n.name),()=>Ne(e,n.id));if(o.access.policy){let{id:n,name:d}=o.access.policy;await m("access",h.policy(d),()=>Te(e,n))}}),await l("email",j(o.email),async()=>{for(let n of o.email){for(let d of n.rules)await m("email",h.rule(d.address,n.zoneName),()=>qe(e,n.zoneId,d.id));n.catchAllWorker&&await m("email",h.catchAll(n.zoneName),()=>et(e,n.zoneId,Wt)),n.disable&&await m("email",h.routing(n.zoneName),()=>Je(e,n.zoneId))}}),await l("workflows",o.workflows.length,async()=>{for(let n of o.workflows)await m("workflows",h.workflow(n),()=>dt(e,n))}),await l("workers",o.workers.length,async()=>{for(let n of o.workers)await m("workers",h.worker(n.name),()=>Ze(e,n.name,{withReferences:!0}))}),await l("certificates",o.certificates.length,async()=>{for(let n of o.certificates){let d=h.pack(n.packId,n.hostname);await m("certificates",d,async()=>{try{await pt(e,n.zoneId,n.packId);return}catch(k){if(U(k,"not_found"))throw k;let y=W(k).split(`
|
|
13
|
+
`)[0]??"",f=()=>oe(e,n.zoneId,{allStatuses:!0}),E=await f().catch(()=>null);if(E&&!pe(E,n.packId)&&(await r(Kt),E=await f().catch(()=>E)),E&&pe(E,n.packId))return{removedAs:`${d} (gone with its Custom Domain)`};throw new Error(`${y}. Cloudflare removes a hostname's pack with its Custom Domain, so it is likely on its way out; if the zone still lists it, finish it in the dashboard`)}})}});let w=o.d1.find(n=>n.id===o.gateway?.databaseId)??null,R=o.d1.filter(n=>n!==w);await l("d1",R.length,async()=>{for(let n of R)await m("d1",h.d1(n.name),()=>me(e,n.id))}),await l("kv",o.kv.length,async()=>{for(let n of o.kv)await m("kv",h.kv(n.title),()=>xe(e,n.id))}),await l("r2",o.r2.length,async()=>{for(let n of o.r2)await m("r2",h.r2(n),()=>ut(e,n))}),await l("hyperdrive",o.hyperdrive.length,async()=>{for(let n of o.hyperdrive)await m("hyperdrive",h.hyperdrive(n.name),()=>st(e,n.id))}),await l("vectorize",o.vectorize.length,async()=>{for(let n of o.vectorize)await m("vectorize",h.vectorize(n),()=>ct(e,n))}),await l("aiGateway",o.aiGateway.length,async()=>{for(let n of o.aiGateway)await m("aiGateway",h.aiGateway(n),()=>nt(e,n))});let T=[];for(let n of o.dns)try{for(let d of await ee(e,n.zoneId,n.name))V(d)&&(ne({type:d.type,content:d.content??null})||T.push({zoneId:n.zoneId,name:n.name,id:d.id,type:d.type}))}catch(d){i.emit({type:"warning",code:"TEARDOWN_DELETE_FAILED",step:ae,message:`Couldn't read the DNS records at ${n.name}
|
|
14
|
+
${W(d).split(`
|
|
15
|
+
`)[0]}`,data:{kind:"dns",name:n.name,fix:`check them in the Cloudflare dashboard (${H.dns})`}})}return await l("dns",T.length,async()=>{for(let n of T)await m("dns",h.record(n.type,n.name),()=>Be(e,n.zoneId,n.id))}),await l("d1",w?1:0,async()=>{if(!w)return;let n=s.filter(d=>d.kind==="dns");if(n.length>0){s.push({kind:"d1",described:h.d1(w.name),place:H.d1,reason:`kept on purpose: the next run reads the hostnames of the ${v(n.length,"kept DNS record")} above from it`});return}await m("d1",h.d1(w.name),()=>me(e,w.id))}),{removed:c,kept:s}}var ge="teardown.inventory";function Ft(e,o){return e===le?1:o===le?-1:e.localeCompare(o)}var Gt=(e,o)=>e===o.name||e.endsWith(`.${o.name}`);async function Rt({cf:e,accountId:o,out:i}){i.emit({type:"step",step:ge,status:"start",message:`Looking for what Every App created in ${o}...`,data:{accountId:o}});let r=(t,a,p)=>i.emit({type:"step",step:"teardown.found",status:"ok",message:`${a} ${K.find(([u])=>u===t)[a===1?1:2]}`,data:{kind:t,count:a,items:p}}),c=[],s=async(t,a,p)=>{try{return await p()}catch(u){let g=W(u).split(`
|
|
16
|
+
`)[0]??"";if(Ee(u)){let C=U(u,"r2_not_enabled")?"R2":"Cloudflare Access";return i.emit({type:"step",step:"teardown.found",status:"skip",message:`${C} isn't enabled in this account: nothing of its to delete`,data:{what:t,service:C,reason:g}}),a}return c.push(`${t} (couldn't be listed: ${g})`),i.emit({type:"warning",code:"TEARDOWN_READ_FAILED",step:ge,message:`Couldn't list ${t}; whatever is there is kept
|
|
17
|
+
${g}`,data:{what:t,reason:g,fix:"check the token's permissions (runbook step 5), then run again"}}),a}},m=await s("the Gateway's database",null,()=>We(e)),l=m?ze(e,m):null,w=l?await s("the Gateway's install row",null,()=>Le(l)):null,R=l?await s("the Gateway's apps",[],()=>Ke(l)):[],T=l?await s("the apps' recorded resources",[],()=>Me(l)):[],n=t=>new Set(T.filter(a=>a.kind===t).map(a=>a.name)),d=(t,a)=>O(a)||n(t).has(a),k=new Set(R.flatMap(t=>t.workerName?[t.workerName]:[])),y=await s("the Workers",[],()=>Ue(e)),f=y.filter(t=>d("worker",t.name)||k.has(t.name)).sort((t,a)=>Ft(t.name,a.name)).map(t=>({name:t.name,domains:(t.references?.domains??[]).map(a=>a.hostname.toLowerCase()).sort()}));r("workers",f.length,f.map(t=>t.name));let E=(await s("the Workflows",[],()=>lt(e,Z))).filter(t=>O(t.script_name??"")||O(t.name)).map(t=>t.name).sort();r("workflows",E.length,E);let z=(await s("the D1 databases",[],()=>de(e,["d1","list"],Pe,{perPage:100,maxPages:10}))).filter(t=>d("d1",t.name)).map(t=>({name:t.name,id:t.uuid})).sort((t,a)=>t.id===m?1:a.id===m?-1:t.name.localeCompare(a.name));r("d1",z.length,z.map(t=>t.name));let L=(await s("the KV namespaces",[],()=>de(e,["kv","namespaces","list"],Ie,{perPage:100,maxPages:50}))).filter(t=>d("kv",t.title)).map(t=>({title:t.title,id:t.id})).sort((t,a)=>t.title.localeCompare(a.title));r("kv",L.length,L.map(t=>t.title));let b=(await s("the R2 buckets",[],()=>ft(e,Z))).filter(O).sort();r("r2",b.length,b);let x=(await s("the Hyperdrive configs",[],()=>at(e))).filter(t=>d("hyperdrive",t.name)).map(t=>({name:t.name,id:t.id})).sort((t,a)=>t.name.localeCompare(a.name));r("hyperdrive",x.length,x.map(t=>t.name));let D=(await s("the Vectorize indexes",[],()=>it(e))).map(t=>t.name).filter(t=>d("vectorize",t)).sort();r("vectorize",D.length,D);let se=(await s("the AI Gateways",[],()=>rt(e,Z))).map(t=>t.id).filter(t=>d("ai-gateway",t)).sort();r("aiGateway",se.length,se);let _={applications:[],policy:null},we=await s("the Zero Trust team",null,()=>Ce(e));if(we){let t=w?{gatewayHost:w.gatewayHost.toLowerCase(),appBaseDomain:w.appBaseDomain.toLowerCase()}:null,a=await s("the Access applications",[],()=>be(e)),p=t?De(a,t):{gateway:null,apps:null},u=a.filter(A=>A.name===He||A.name===je),g=new Map;for(let A of[p.gateway,p.apps,...u])A&&g.set(A.id,A);_.applications=[...g.values()].map(A=>({id:A.id,name:A.name??A.id}));let C=(await s("the Access policies",[],()=>Re(e))).find(A=>A.name===Ve);_.policy=C?{id:C.id,name:C.name}:null,c.push(`the Zero Trust team ${we.auth_domain} and its identity providers`)}r("access",_.applications.length+(_.policy?1:0),{applications:_.applications.map(t=>t.name),policy:_.policy?.name??null});let M=new Set;if(w){M.add(w.gatewayHost.toLowerCase());for(let t of w.liveDomains)M.add(t.toLowerCase())}for(let t of R)t.hostname&&M.add(t.hostname.toLowerCase());for(let t of f)for(let a of t.domains)M.add(a);let he=new Map((await s("the account's zones",[],()=>ot(e,o))).map(t=>[t.id,{id:t.id,name:t.name}])),Y=new Map,ye=(t,a)=>{let p=he.get(t);p?Y.set(p.id,p):c.push(`the zone ${a.toLowerCase()} (${t}), which isn't in account ${o}`)};w&&ye(w.zoneId,w.zoneName);for(let t of y)if(f.some(a=>a.name===t.name))for(let a of t.references?.domains??[])a.zone_id&&a.zone_name&&ye(a.zone_id,a.zone_name);let bt=t=>{let a=[...he.values()].filter(p=>Gt(t,p)).sort((p,u)=>u.name.length-p.name.length)[0];return a&&Y.set(a.id,a),a??null},ie=new Map;for(let t of[...M].sort()){let a=bt(t);a&&ie.set(t,a)}for(let t of Y.values())c.push(`the zone ${t.name}`);c.push("the Workers Paid subscription","the workers.dev subdomain");let J=[];for(let t of[...Y.values()].sort((a,p)=>a.name.localeCompare(p.name))){let a=await s(`Email Routing on ${t.name}`,null,async()=>({settings:await Ye(e,t.id),rules:await Xe(e,t.id),catchAll:await Qe(e,t.id)}));if(!a)continue;let{settings:p,rules:u,catchAll:g}=a,C=u.filter(N=>N.id!==null&&O(te(N)??"")),A=te(g),ce=A!==null&&O(A);if(C.length===0&&!ce)continue;let Nt=!g.enabled||g.actions.every(N=>N.type==="drop");J.push({zoneId:t.id,zoneName:t.name,rules:C.map(N=>({id:N.id,address:tt(N),worker:te(N)})),catchAllWorker:ce?A:null,disable:p.enabled&&C.length===u.length&&(ce||Nt)})}r("email",j(J),J);let X=[],Ae=new Map;for(let[t,a]of ie){let p=Ae.get(a.id);p||(p=await s(`the certificate packs of ${a.name}`,[],()=>oe(e,a.id)),Ae.set(a.id,p));for(let u of mt(p,t))p.splice(p.indexOf(u),1),X.push({zoneId:a.id,zoneName:a.name,hostname:t,packId:u.id})}r("certificates",X.length,X.map(t=>`${t.packId} (${t.hostname})`));let q=[];for(let[t,a]of[...ie].sort(([p],[u])=>p.localeCompare(u))){let p=await s(`the DNS records at ${t}`,[],()=>ee(e,a.id,t)),u=[...new Set(p.filter(g=>!V(g)&&!ne({type:g.type,content:g.content??null})).map(g=>g.type.toUpperCase()))].sort();u.length>0&&c.push(`the ${P(u)} ${u.length===1?"record":"records"} at ${t}, which Every App never created`),q.push({zoneId:a.id,zoneName:a.name,name:t,records:p.filter(V).map(g=>({id:g.id,type:g.type,content:g.content??null}))})}r("dns",ue(q),q.filter(t=>t.records.length>0));let Q={accountId:o,gateway:m?{databaseId:m,gatewayHost:w?.gatewayHost??null}:null,workers:f,workflows:E,d1:z,kv:L,r2:b,hyperdrive:x,vectorize:D,aiGateway:se,access:_,email:J,certificates:X,dns:q,kept:c};return i.emit({type:"step",step:ge,status:"ok",message:`Found ${v(S(Q),"resource")} of Every App's in ${o}.`,data:{accountId:o,counts:F(Q),total:S(Q)}}),Q}var Tt="teardown.check";async function an(e){await Ge(e,o=>Mt({flags:e,out:o}))}async function Mt(e){let{flags:o,out:i}=e,r=e.env??process.env,c=e.createCf??(f=>$e({accountId:f,env:r})),s=e.interactive??_e(o.json??!1),m=o["dry-run"]??!1;i.emit({type:"step",step:Tt,status:"start",message:"Checking the account may be torn down..."});let{accountId:l,allowlist:w}=At({accountId:o["account-id"],out:i,env:r}),R=o.confirm?.trim().toLowerCase();if(R!==void 0&&R!==l)throw new $("TEARDOWN_CONFIRM_MISMATCH",`--confirm ${o.confirm} isn't the account id
|
|
18
|
+
It must repeat --account-id ${l} exactly. Nothing was read or changed.`,{fix:`pass --confirm ${l}`,data:{accountId:l,confirm:o.confirm}});kt({accountId:l,allowlist:w,whoami:await Se(c())}),i.emit({type:"step",step:Tt,status:"ok",message:`${l} is a test account, and the token sees it alone`,data:{accountId:l}});let T=c(l),n=await Rt({cf:T,accountId:l,out:i}),d=S(n),k=Et(n);if(m){let f=d===0?`Nothing of Every App is left in ${l}.`:`Dry run: ${re(n)} would be removed from ${l}. Nothing was changed.`;i.emit({type:"done",message:f,display:[G.bold(d===0?f:`Would remove ${re(n)} from ${l}`),...d===0?k.slice(1):k,...d===0?[]:["",G.dim("Nothing was changed (--dry-run).")]].join(`
|
|
19
|
+
`),data:{accountId:l,dryRun:!0,removed:[],kept:[],plan:B(n)}});return}if(d===0){let f=`Nothing of Every App is left in ${l}.`;i.emit({type:"done",message:f,display:[G.green(f),...k.slice(1)].join(`
|
|
20
|
+
`),data:{accountId:l,dryRun:!1,removed:[],kept:[],plan:B(n)}});return}if(R===void 0){if(!s)throw new $("TEARDOWN_CONFIRMATION_REQUIRED",`Tearing down ${l} needs its id typed at a terminal, or --confirm ${l}
|
|
21
|
+
${re(n)} would be deleted for good. Nothing was changed.`,{rerun:ke(["--confirm",l]),rerunNote:"only for a dedicated test account",authorize:!0,data:{accountId:l,plan:B(n)}});let f=(await(e.askConfirmation??Ut)(l,k)).trim().toLowerCase();if(f!==l)throw new ve(f?`"${f}" doesn't match ${l}. Nothing deleted.`:"Cancelled. Nothing deleted.")}else s&&i.emit({type:"step",step:"teardown.plan",status:"ok",message:`Deleting everything Every App created in ${l}:`,data:{accountId:l,lines:k}});let y=await Ct({cf:T,plan:n,out:i,...e.sleep?{sleep:e.sleep}:{}});i.emit({type:"done",...Zt(l,n,y)})}function Ut(e,o){return Oe(`Type ${e} to delete all of this`,{context:[`This deletes everything Every App created in Cloudflare account ${e}, for good:`,"",...o,""]})}function Zt(e,o,{removed:i,kept:r}){let c=r.length===0?`Removed ${v(i.length,"resource")} from ${e}.`:`Removed ${v(i.length,"resource")} from ${e}; kept ${r.length} (${P(r.map(m=>`${m.described}: ${m.reason}`))}).`,s=[G.green(`Removed ${v(i.length,"resource")} from ${e}`),...r.length>0?["",`Kept ${v(r.length,"resource")}:`,...r.map(m=>` ${m.described} ${G.dim(`\xB7 ${m.reason} \xB7 ${m.place}`)}`)]:[],...o.kept.length>0?["",G.dim(`Left as they were: ${o.kept.join("; ")}.`)]:[]].join(`
|
|
22
|
+
`);return{message:c,display:s,data:{accountId:e,dryRun:!1,removed:i,kept:r,plan:B(o)}}}export{an as teardown,Mt as teardownAccount};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as e}from"./chunk-KS7DIYIJ.js";import{c as o}from"./chunk-SMCUCFS4.js";import"./chunk-N4E5YE4X.js";import"./chunk-EEF4FY26.js";import"./chunk-E3EPK27P.js";import"./chunk-WTKBB5HE.js";import"./chunk-LTYAIGEB.js";import"./chunk-CGFABBZA.js";import"./chunk-TQWCYF2T.js";import"./chunk-ZH6IAPVK.js";import"./chunk-ONGI463M.js";import"./chunk-3GZA6EEZ.js";import"./chunk-52NQ23OH.js";import"./chunk-XEPXX3AI.js";import"./chunk-J2XKGQO7.js";import"./chunk-36VCEEIH.js";import"./chunk-AIDX5IYA.js";import"./chunk-IWP4Q3KV.js";import"./chunk-475IB5UG.js";import"./chunk-RXSJENSN.js";import"./chunk-ZCJTJDAI.js";import"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import"./chunk-KTX5YGBL.js";import"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import"./chunk-NXO2BC3M.js";async function m(a){await e(a,(t,y)=>o(a,t,y))}export{m as update};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as w,b as X,e as v,f as Z,g as Q,h as $,i as b}from"./chunk-
|
|
1
|
+
import{a as w,b as X,e as v,f as Z,g as Q,h as $,i as b}from"./chunk-DONNKBKB.js";import{f as S,g as G,k as L,n as j,o as D,p as E,q as F,r as K,s as Y,t as q,u as B,v as J,w as V,x as H}from"./chunk-EJE6K5GO.js";import"./chunk-CGFABBZA.js";import{a as T}from"./chunk-36VCEEIH.js";import{aa as W,ra as _,ta as P}from"./chunk-OHDR7JWQ.js";import"./chunk-HT76NR3O.js";import"./chunk-LTMQP62I.js";import{a as R,i as N}from"./chunk-MLZJBYSY.js";import"./chunk-JT3R24Y7.js";import{Db as O,Hc as C,Ic as U,Kc as M,Na as x,Pc as l,Ub as f,c as h,f as y,k as z}from"./chunk-NXO2BC3M.js";import{stripVTControlCharacters as A}from"node:util";import d from"chalk";var u="workspace.update",ee="workspace.rename",te="workspace.role";async function Ue(e,n){await l(e,t=>ce({flags:e,out:t},n))}async function Me(e,n,t){await l(e,o=>re({flags:e,out:o},n,t))}function ie(e){let{flags:n,out:t}=e;return P({gateway:_(n.gateway),accountId:n["account-id"],interactive:R(n.json??!1),login:{json:n.json,out:t,step:"login"},createCf:e.createCf})}var ae=e=>`${/^[aeiou]/.test(e)?"an":"a"} ${e}`;async function re(e,n,t){let{out:o}=e,i=n.trim().toLowerCase(),c=await ie(e),s=await W(c.db);if(!s)throw new f("MEMBER_NOT_FOUND",`This Gateway has no workspace yet
|
|
2
2
|
Nobody has claimed its owner link, so it has no members.`,{rerun:`${h} setup`,rerunNote:"to claim it"});let{organization:r}=s,m={id:r.id,name:r.name};o.emit({type:"step",step:te,status:"start",message:`Setting ${i}'s role...`});let a=await S(c.db,r.id,i,t);if(a.kind==="not_found")throw new f("MEMBER_NOT_FOUND",`No member ${i} in ${r.name}
|
|
3
3
|
Someone still invited isn't a member until they accept.`,{fix:"check the address against Manage workspace \u2192 Users, or invite them first",data:{workspace:m,email:i}});let p={id:a.member.id,email:a.member.email,name:a.member.name};if(a.kind==="last_owner")throw new f("LAST_OWNER",`${i} is the last owner of ${r.name}
|
|
4
4
|
The workspace always keeps one owner, so their role stays until someone else is an owner.`,{rerun:`${h} workspace role <email> owner`,rerunNote:"for someone else, then this command again",data:{workspace:m,member:p,role:t}});let g=a.kind==="changed",k=g?`${i} is now ${ae(t)} of ${r.name}`:`${i} is already ${ae(t)} of ${r.name}`;o.emit({type:"step",step:te,status:"ok",message:k,data:{email:i,role:t,changed:g}});let I=g?"The Gateway picks up the change within 30 seconds.":"Nothing changed.";o.emit({type:"done",message:A(`${k}. ${I}`),display:[g?M(k):d.dim(`${k}.`),d.dim(I)].join(`
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Every App CLI - Deploy and manage apps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
-
"version": "0.3.0-rc.
|
|
7
|
+
"version": "0.3.0-rc.3",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
10
|
"bin",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"tsup": "^6.7.0",
|
|
52
52
|
"typescript": "5.9.3",
|
|
53
53
|
"vitest": "^3.2.4",
|
|
54
|
-
"@every-app/
|
|
55
|
-
"@every-app/
|
|
56
|
-
"@every-app/
|
|
54
|
+
"@every-app/perimeter": "0.1.0",
|
|
55
|
+
"@every-app/sdk": "0.3.0-rc.3",
|
|
56
|
+
"@every-app/toolbus": "0.1.0"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
59
|
"types:check": "tsc --noEmit",
|
|
@@ -154,7 +154,10 @@ what the app is for; who uses it (just them, or everyone in the organization:
|
|
|
154
154
|
then `access: "everyone"`); what it stores (the tables); what it does on its
|
|
155
155
|
own (sends mail, calls a model, runs on a schedule, serves a script to a
|
|
156
156
|
website); what stays private to each person. Repeat the answers back in one
|
|
157
|
-
paragraph, then build. For a clear request, build.
|
|
157
|
+
paragraph, then build. For a clear request, build. The database is D1 unless
|
|
158
|
+
the person has a Postgres (Neon, Supabase, any URL) or asks for one: then
|
|
159
|
+
Hyperdrive ("Postgres through Hyperdrive" in `patterns.md`), and the person
|
|
160
|
+
puts its URL in `.everyapp/secrets.env` themselves.
|
|
158
161
|
|
|
159
162
|
The loop: `pnpm everyapp create ../my-app` from the every-app folder (or work
|
|
160
163
|
in the app you are in); the schema and the queries, the server functions, the
|
|
@@ -56,7 +56,13 @@ How the apps on Every App do each thing, and the file to copy from. `starter/` i
|
|
|
56
56
|
|
|
57
57
|
| Pattern | What it is | Where | Copy this |
|
|
58
58
|
| --- | --- | --- | --- |
|
|
59
|
+
| Postgres through Hyperdrive | Any Postgres with a URL (Neon, Supabase, PlanetScale Postgres, a server of your own): `resources.hyperdrive: [{ name: "HYPERDRIVE" }]`, `database: { provider: "postgres" }`, `migrations: { engine: "drizzle", dialect: "postgresql" }`, and the URL as `POSTGRES_DATABASE_URL` in `.everyapp/secrets.env`, which the person writes (Neon's and Supabase's direct URL, not the pooled one). The deploy makes the Hyperdrive config, caching off, and runs `drizzle-kit migrate` before the upload; the Worker opens a client per request on `env.HYPERDRIVE.connectionString`. OpenSEO's Postgres deployment runs this code; its `everyapp.config.ts` is the D1 shape its forks deploy | `open-seo/src/db/pg/client.ts`, `open-seo/src/db/provider.ts`, `open-seo/drizzle/pg.config.ts`; the manifest and the steps: https://everyapp.com/docs/agent/manifest#postgres | `withPgClient()`: `postgres(url, { max: 1, fetch_types: false })` inside each entrypoint, kept in `AsyncLocalStorage`, never in global scope |
|
|
60
|
+
| Turso | libSQL, not Postgres, so not Hyperdrive: the URL and token are the app's own secrets, and the client talks HTTP. No app here uses it | https://everyapp.com/docs/agent/manifest#postgres (its last paragraph) | `secrets: ["TURSO_DATABASE_URL", "TURSO_AUTH_TOKEN"]` and `createClient({ url, authToken })` from `@libsql/client/web`; `database.provider` stays `d1` or is left out |
|
|
59
61
|
| Workers AI as a binding | `resources.ai` binds `env.AI` on every Worker of the app: `env.AI.run()` directly (the Agents SDK, models the OpenAI-compatible routes don't carry, an AI Gateway by id), billed to the account with no Gateway budget or cap. Under `pnpm dev` every call throws `Binding AI needs to be run remotely` until `vite.config.ts` sets `remoteBindings: true` and `cf auth login` has run. For calls the Gateway caps and counts, list the `workers-ai` provider instead | `packages/sdk/src/cloudflare/worker.ts` (`addAiBindings()`); no app uses it yet: `agentic-inbox/workers/everyapp/gateway.ts` (`gatewayAi()`) is the provider path for code written against `env.AI.run()` | `resources: { ai: ["AI"] }`, then `await env.AI.run("@cf/meta/llama-3.1-8b-instruct", { prompt })` |
|
|
62
|
+
| Browser Rendering | `resources.browser` binds `env.BROWSER` on every Worker of the app: a headless Chrome for screenshots, PDFs and pages that need JavaScript, driven with `@cloudflare/puppeteer` or `@cloudflare/playwright`, billed to the account (Workers Paid). Local under `pnpm dev`: the first session downloads Chrome into the global `.wrangler` cache | `packages/sdk/src/cloudflare/worker.ts` (`addBrowserBindings()`); no app uses it yet | `resources: { browser: ["BROWSER"] }`, then `const browser = await puppeteer.launch(env.BROWSER)` |
|
|
63
|
+
| Images | `resources.images` binds `env.IMAGES` on every Worker of the app: resize, crop, re-encode and read images from any stream (an upload, an R2 object, a `fetch()` body), transformations billed to the account. Local under `pnpm dev` through Miniflare's sharp (`503`, code `9523`, where sharp can't load) | `packages/sdk/src/cloudflare/worker.ts` (`addImagesBindings()`); no app uses it yet | `resources: { images: ["IMAGES"] }`, then `(await env.IMAGES.input(body).transform({ width: 256 }).output({ format: "image/webp" })).response()` |
|
|
64
|
+
| `resources.vectorize` | A Vectorize index for search by embedding: `{ name, dimensions, metric }` for your own vectors, or `{ name, preset }` for a Workers AI model's; bound as `env.<NAME>` (a `VectorizeIndex`) on every Worker of the app; the deploy creates `<worker>--<binding>` and its shape never changes after (rename the binding for a new one). Dev has no local Vectorize: calls throw until `vite.config.ts` sets `remoteBindings: true` and `cf auth login` has run | `packages/cli/src/commands/deploy/deployApp.vectorize.test.ts` (`NOTES`), [the manifest page](/docs/agent/manifest#vectorize) | `resources: { vectorize: [{ name: "VECTORS", dimensions: 768, metric: "cosine" }] }`, then `env.VECTORS.upsert([{ id, values, metadata }])` and `env.VECTORS.query(values, { topK: 5 })`; keep the rows themselves in D1 and only the vectors here |
|
|
65
|
+
| `resources.aiGateway` | An AI Gateway of the app's own (`every-<orgKey>-<id>-<binding>`), bound on every Worker as `env.AI_GATEWAY` = `{ id, accountId, url }`, `url` empty in development; it logs, caches and counts the model calls the app makes itself, with its own key or Workers AI. Separate from AI through the Gateway (below), whose keys and gateway are the Gateway's | [`/docs/agent/manifest`](/docs/agent/manifest) (AI Gateway); no app uses one yet | `aiGateway: [{ name: "AI_GATEWAY" }]`; `baseURL: env.AI_GATEWAY.url ? env.AI_GATEWAY.url + "/openai" : undefined`, or `env.AI.run(model, input, { gateway: { id: env.AI_GATEWAY.id } })` |
|
|
60
66
|
|
|
61
67
|
## Sending and receiving email
|
|
62
68
|
|
package/skills/everyapp/SKILL.md
CHANGED
|
@@ -21,7 +21,11 @@ status (the report, every line, and its fixes in order), manifest
|
|
|
21
21
|
email, events (webhooks, email alerts, the signature, every event type,
|
|
22
22
|
emit()), mcp (tools, connector, OAuth), deploy (the pipeline, what the policy
|
|
23
23
|
check refuses), providers (API providers: the catalog, registering one,
|
|
24
|
-
a spec's fields), access (Cloudflare Access),
|
|
24
|
+
a spec's fields), access (Cloudflare Access), signin (sign-in providers:
|
|
25
|
+
Continue with Google, Microsoft, GitHub, Apple, Cloudflare or SSO; every
|
|
26
|
+
setting, the signin commands), ai (the Gateway's default model
|
|
27
|
+
provider: the order, `ai default|show|list`, AI Gateway in front, what an
|
|
28
|
+
app writes), workspace (the workspace from
|
|
25
29
|
the terminal and from an AI client: every command and every tool), gateway
|
|
26
30
|
(everything a Gateway offers: apps vs MCP apps vs the compact MCP surface,
|
|
27
31
|
people, groups and caps, the CLI by job, what to suggest next, other MCP
|
|
@@ -29,8 +33,10 @@ servers), build (the build-every-app skill as a page), patterns (its
|
|
|
29
33
|
example-patterns index), repo/* (security model, capabilities, runbooks).
|
|
30
34
|
Step-by-step setup of each
|
|
31
35
|
integration (the Gateway, Access, email, DataForSEO, Context, OpenRouter,
|
|
32
|
-
OpenAI, Workers AI,
|
|
33
|
-
|
|
36
|
+
OpenAI, Workers AI, the default model provider (setup/ai.md) and Cloudflare
|
|
37
|
+
AI Gateway (setup/ai-gateway.md), Google, Microsoft 365, Slack; every
|
|
38
|
+
catalog provider by id in setup/providers.md): setup/README.md beside this
|
|
39
|
+
file.
|
|
34
40
|
Answering "how do I": fetch the page for the subject and answer from it
|
|
35
41
|
with the exact command or manifest field, naming the page. A failed
|
|
36
42
|
command: look its code up on errors (anchor: the code, lowercased) before
|
|
@@ -107,11 +113,15 @@ Data: pnpm everyapp db migrate (local) pnpm everyapp db query "<sql>" [--lo
|
|
|
107
113
|
(a production write stops with CONFIRMATION_REQUIRED: add --yes only
|
|
108
114
|
if the user said so). pnpm everyapp db restore --json undoes the last
|
|
109
115
|
deploy's migrations (and every write since): only when the user asks.
|
|
110
|
-
Postgres:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
the
|
|
116
|
+
Postgres: any Postgres with a URL (Neon, Supabase, …) goes through Hyperdrive:
|
|
117
|
+
resources.hyperdrive, database.provider "postgres", migrations.dialect
|
|
118
|
+
"postgresql" (manifest page, #postgres). The deploy reads
|
|
119
|
+
POSTGRES_DATABASE_URL (and <BINDING>_ORIGIN_URL) from
|
|
120
|
+
.everyapp/secrets.env, which the user writes (configure doesn't);
|
|
121
|
+
never print, commit or ask for its values in chat. Without it deploy
|
|
122
|
+
stops HYPERDRIVE_ORIGIN_MISSING (data.variables, data.file) and status
|
|
123
|
+
names it under the app. deploy runs drizzle-kit migrate before the
|
|
124
|
+
upload. Turso is libSQL: app secrets, not Hyperdrive.
|
|
115
125
|
Secrets: pnpm everyapp configure <app> --json sets up an app: every setting its
|
|
116
126
|
manifest declares, each where it is held (an AI key or a capability's
|
|
117
127
|
client on the Gateway, once for every app; the app's own secrets on
|
package/skills/everyapp/mcp.md
CHANGED
|
@@ -159,8 +159,10 @@ Workspace tools (Gateway connector only; every admin action of the UI, listed
|
|
|
159
159
|
`everyapp_workspace_apps`, `everyapp_workspace_app_set`,
|
|
160
160
|
`everyapp_workspace_app_access`, `everyapp_workspace_app_access_set`,
|
|
161
161
|
`everyapp_workspace_app_cap`, `everyapp_workspace_cap_default`,
|
|
162
|
-
`
|
|
163
|
-
`
|
|
162
|
+
`everyapp_ai_show` (any member), `everyapp_ai_default`,
|
|
163
|
+
`everyapp_workspace_usage`, `everyapp_workspace_activity`,
|
|
164
|
+
`everyapp_workspace_audit` (the audit log: who did what, 90 days),
|
|
165
|
+
`everyapp_workspace_rename`, and the
|
|
164
166
|
events tools `everyapp_workspace_events`, `everyapp_workspace_events_add`
|
|
165
167
|
(a generated signing secret comes back once, in that answer: it opens
|
|
166
168
|
nothing on the Gateway, so the person stores it in the receiver now),
|
|
@@ -21,6 +21,8 @@ click when they have to do something themselves.
|
|
|
21
21
|
| OpenRouter | [openrouter.md](openrouter.md) | `OPENROUTER_API_KEY` | OpenSEO, Open CRM, agentic-inbox |
|
|
22
22
|
| OpenAI | [openai.md](openai.md) | `OPENAI_API_KEY`, `AI_PROXY_EXTRA_ROUTES` | apps listing the `openai` provider |
|
|
23
23
|
| Workers AI | [workers-ai.md](workers-ai.md) | `WORKERS_AI_API_TOKEN` (`CLOUDFLARE_ACCOUNT_ID` is set by `everyapp setup`) | agentic-inbox (optional) |
|
|
24
|
+
| The default model provider (any one key) | [ai.md](ai.md) | one provider's key (OpenRouter first); the choice with `everyapp ai default` | every app whose manifest says `ai: { chat: true }` (agentic-inbox, OpenCRM) |
|
|
25
|
+
| Cloudflare AI Gateway in front of the models | [ai-gateway.md](ai-gateway.md) | `AI_GATEWAY_ID` (set by `everyapp ai gateway on`; optional `AI_GATEWAY_API_KEY`) | every AI provider call, once it is on |
|
|
24
26
|
| Google (Gmail, Calendar, Search Console and Analytics) | [google.md](google.md) | `GOOGLE_WORKSPACE_CLIENT_ID`, `GOOGLE_WORKSPACE_CLIENT_SECRET` | Open CRM |
|
|
25
27
|
| Microsoft 365 (Outlook mail and calendar) | [microsoft-365.md](microsoft-365.md) | `MICROSOFT_365_CLIENT_ID`, `MICROSOFT_365_CLIENT_SECRET` | Open CRM |
|
|
26
28
|
| Slack (OAuth client) | [slack.md](slack.md) | `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET` | Open CRM |
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Cloudflare AI Gateway in front of the model providers
|
|
2
|
+
|
|
3
|
+
Cloudflare AI Gateway is a proxy for model calls in the Gateway's own
|
|
4
|
+
Cloudflare account: a log of every call, caching, rate limits, retries
|
|
5
|
+
and a spend view, at `https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/…`.
|
|
6
|
+
It has no models of its own and never replaces a provider's key: with it
|
|
7
|
+
on, every call the Gateway makes to an AI provider that has an AI Gateway
|
|
8
|
+
slug (OpenRouter, OpenAI, Anthropic, Groq, Mistral, Workers AI) goes
|
|
9
|
+
through it with the provider's own key still on the call; Gemini and
|
|
10
|
+
Cohere go direct (Cloudflare documents no form for their OpenAI-shaped
|
|
11
|
+
paths). It changes no app and no manifest. At the end the person has an
|
|
12
|
+
AI Gateway named `everyapp` in their account, `AI_GATEWAY_ID` on the
|
|
13
|
+
Gateway, and every model call showing up in the AI Gateway dashboard.
|
|
14
|
+
|
|
15
|
+
## Settings
|
|
16
|
+
|
|
17
|
+
| NAME | Required or optional | What it holds |
|
|
18
|
+
| -------------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
19
|
+
| `AI_GATEWAY_ID` | optional (set by `pnpm everyapp ai gateway on`) | the AI Gateway's id, its name in the dashboard (`everyapp`); with `CLOUDFLARE_ACCOUNT_ID`, which `everyapp setup` set |
|
|
20
|
+
| `AI_GATEWAY_API_KEY` | optional, only for an authenticated gateway | an AI Gateway token with Run permission, sent as `cf-aig-authorization: Bearer <token>` |
|
|
21
|
+
|
|
22
|
+
The Gateway sends the gateway token only to `gateway.ai.cloudflare.com`
|
|
23
|
+
and, for Workers AI, `api.cloudflare.com` with `cf-aig-gateway-id`. Apps
|
|
24
|
+
can't set `cf-aig-*` headers: the proxy strips them.
|
|
25
|
+
|
|
26
|
+
## Costs and plans
|
|
27
|
+
|
|
28
|
+
As of October 2026: AI Gateway is included with a Cloudflare account on
|
|
29
|
+
every plan, with logs kept per plan (Workers Free: 100,000 logs per
|
|
30
|
+
gateway; Paid: 10 million) and no per-request charge of its own; the
|
|
31
|
+
provider's prices are unchanged (BYOK: the provider's key is the
|
|
32
|
+
provider's bill). Unified Billing (paying providers through Cloudflare
|
|
33
|
+
credits) is not used: the Gateway always sends the provider's key, and
|
|
34
|
+
`cf-aig-no-wholesale` is not needed because a key on the request wins.
|
|
35
|
+
|
|
36
|
+
## Only a person can
|
|
37
|
+
|
|
38
|
+
- Decide to turn it on (it adds a hop and a log of every prompt's
|
|
39
|
+
metadata, never the prompt itself unless logging of payloads is turned
|
|
40
|
+
on in the dashboard).
|
|
41
|
+
- Create a gateway token in the dashboard when they want an
|
|
42
|
+
authenticated gateway, and paste it into the terminal.
|
|
43
|
+
- Turn on caching, rate limits or payload logging in the AI Gateway
|
|
44
|
+
dashboard: the Gateway sends no `cf-aig-*` options; the gateway's own
|
|
45
|
+
settings apply to every call.
|
|
46
|
+
|
|
47
|
+
## Before you start
|
|
48
|
+
|
|
49
|
+
1. `pnpm everyapp status --json`: `data.installed` and `data.claimed`
|
|
50
|
+
true; otherwise [gateway.md](gateway.md) first.
|
|
51
|
+
2. `pnpm everyapp ai show --json`: `done.data.aiGateway.on` false means
|
|
52
|
+
it isn't on; `done.data.via` says `direct`. At least one model
|
|
53
|
+
provider configured ([ai.md](ai.md)) so there is something to front.
|
|
54
|
+
3. The Cloudflare login the CLI uses can create AI Gateways in the
|
|
55
|
+
account (the account owner's login, or a token with AI Gateway Write).
|
|
56
|
+
|
|
57
|
+
## Steps
|
|
58
|
+
|
|
59
|
+
1. **Turn it on**: `pnpm everyapp ai gateway on --json`. The CLI finds or
|
|
60
|
+
creates an AI Gateway named `everyapp` in the Gateway's account
|
|
61
|
+
(`--id <name>` for another name, or one the person made already) and
|
|
62
|
+
sets `AI_GATEWAY_ID` on the Gateway. `done.data` is `{ id, url,
|
|
63
|
+
created }`. From the Gateway's next request every slugged provider
|
|
64
|
+
call goes through it.
|
|
65
|
+
2. **Authenticated gateway (optional).** In the dashboard, AI → AI
|
|
66
|
+
Gateway → the gateway → Settings → Authenticated Gateway: on; create
|
|
67
|
+
an AI Gateway token (Run permission). Then from the person's
|
|
68
|
+
terminal: `pnpm everyapp secret set AI_GATEWAY_API_KEY` (the value by
|
|
69
|
+
pipe or prompt, never on the command line). Without the token on an
|
|
70
|
+
authenticated gateway every model call answers 401 from AI Gateway.
|
|
71
|
+
3. Nothing else: no app changes, no key moves.
|
|
72
|
+
|
|
73
|
+
## Verify
|
|
74
|
+
|
|
75
|
+
1. `pnpm everyapp ai show --json`: `done.data.aiGateway` is `{ on: true,
|
|
76
|
+
id: "everyapp" }` and `done.data.via` is `ai-gateway`.
|
|
77
|
+
2. Make one model call in an app (ask Agentic Inbox's agent something),
|
|
78
|
+
then open the dashboard: AI → AI Gateway → `everyapp` → Logs shows
|
|
79
|
+
the request with the provider's name.
|
|
80
|
+
3. Manage workspace → Usage still counts the call under its provider:
|
|
81
|
+
AI Gateway adds a hop, not a provider.
|
|
82
|
+
|
|
83
|
+
## If it fails
|
|
84
|
+
|
|
85
|
+
- `ai gateway on` fails with a Cloudflare error: the login can't create
|
|
86
|
+
AI Gateways (a scoped token without AI Gateway Write); use the
|
|
87
|
+
account owner's login, or make the gateway in the dashboard and run
|
|
88
|
+
`ai gateway on --id <its name>`.
|
|
89
|
+
- A model call answers 401 after turning it on: the gateway is
|
|
90
|
+
authenticated and `AI_GATEWAY_API_KEY` isn't set (step 2) or is wrong
|
|
91
|
+
(rotate it).
|
|
92
|
+
- A model call answers 404 or 400 from `gateway.ai.cloudflare.com`: a
|
|
93
|
+
provider path AI Gateway doesn't serve the way the catalog recorded
|
|
94
|
+
it (the entry's `aig` block; `landing-page/content/agent/ai.md` lists
|
|
95
|
+
each). `pnpm everyapp ai gateway off` sends everything direct again
|
|
96
|
+
while it is looked at.
|
|
97
|
+
- Calls work but don't appear in the dashboard: the provider has no
|
|
98
|
+
slug (Gemini, Cohere) and went direct.
|
|
99
|
+
|
|
100
|
+
## Rerun, rotate, remove
|
|
101
|
+
|
|
102
|
+
- `ai gateway on` again is safe: it finds the existing gateway and
|
|
103
|
+
rewrites the same id.
|
|
104
|
+
- Rotate the gateway token in the dashboard, then `pnpm everyapp secret
|
|
105
|
+
set AI_GATEWAY_API_KEY` again.
|
|
106
|
+
- `pnpm everyapp ai gateway off` unsets `AI_GATEWAY_ID`: every call goes
|
|
107
|
+
direct from the next request; the AI Gateway resource and its logs
|
|
108
|
+
stay in the account (delete it in the dashboard). `pnpm everyapp secret
|
|
109
|
+
unset AI_GATEWAY_API_KEY` removes the token.
|
|
110
|
+
|
|
111
|
+
## Sources
|
|
112
|
+
|
|
113
|
+
- https://developers.cloudflare.com/ai-gateway/ (overview; provider
|
|
114
|
+
pages under usage/providers/; authentication under
|
|
115
|
+
configuration/authentication/; the header glossary), read 2026-10-25.
|
|
116
|
+
- https://everyapp.com/docs/agent/ai (in the checkout
|
|
117
|
+
`landing-page/content/agent/ai.md`): how each provider is fronted.
|