Comparing version 0.2.0 to 0.3.0
@@ -17,2 +17,3 @@ type Builder = (config: import('esbuild').BuildOptions) => void; | ||
routes?: string[]; | ||
cron?: string[]; | ||
build?: Builder; | ||
@@ -19,0 +20,0 @@ globals?: Globals; |
#!/usr/bin/env node | ||
import e from"sade";import t from"kleur";import{send as n}from"httpie";import*as r from"fs";import{homedir as i}from"os";import{promisify as o}from"util";import{createRequire as s}from"module";import{resolve as a,parse as l,join as c}from"path";import{klona as u}from"klona/json";function d(e,t={}){return e.token?t.Authorization=`Bearer ${e.token}`:(t["X-Auth-Key"]=e.authkey,t["X-Auth-Email"]=e.email),t}function m(e,t,r={}){return n(e,"https://api.cloudflare.com/client/v4"+t,r).then((e=>e.data))}const f=" ~> ",p=" ".repeat(6),g=t.bold("[CFW]");function w(e,n){console.log(t[e](g),n.includes("\n")?n.replace(/(\r?\n)/g,"$1"+p):n)}const h=e=>w("white",e),y=e=>w("green",e),k=e=>w("yellow",e);function $(e,t=1){w("red",e),process.exit(t)}const b=t.dim().bold;function v(e,t){return(t.only||t.ignore)&&(e+=`\nPerhaps the ${b("--only")} or ${b("--ignore")} flag needs adjusting`),k(e)}function T(e){return t.italic().dim(` (${e}ms)`)}function E(e,n,r){let i="•",o=t.dim,s=null!=n?T(n):"";r?(i="+",o=t.green().dim):null!=r&&(i="-",o=t.red().dim),console.log(o(p+i+` "${e}"`)+s)}async function D(e,n){let r=0,i=e.length;if(i===r)return;const o=await import("esbuild");let s=await o.formatMessages(e,{terminalWidth:process.stdout.columns,kind:n?"error":"warning",color:t.enabled}),a=/\x1b\[32m/g,l=n?"[31m":"[33m",c=n?t.red:t.yellow,u=`Build ${n?"failed":"finished"} with`;for(u+=" "+t.underline(i)+" ",u+=n?"error":"warning",u+=1===i?":":"s:",u+="\n\n";r<i;r++)u+=t.bold().inverse(c(" "+e[r].location.file+" "))+" "+e[r].text,u+=s[r].substring(s[r].indexOf("\n")).replace(a,l);r=u.length,"\n"===u[--r]&&(u=u.substring(0,r)),(n?$:k)(u)}function O(e,t){return m("GET",`/accounts/${e.accountid}/workers/scripts/${t}/secrets`,{headers:d(e)}).catch((e=>{$(`Error fetching "${t}" secrets!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function W(e,t,n,r){return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}/secrets`,{headers:d(e),body:{type:"secret_text",text:r,name:n}}).catch((e=>{$(`Error creating new "${t}" secret!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function C(e,t,n,r){return m("DELETE",`/accounts/${e.accountid}/workers/scripts/${t}/secrets/${n}`,{headers:d(e)}).catch((e=>{let{data:i,message:o}=e;if(r&&i&&i.errors&&10056===i.errors[0].code)return i;$(`Error deleting "${t}/${n}" secret!\n${JSON.stringify(i||o,null,2)}`)}))}const L=o(r.writeFile),_=o(r.readFile),A=o(r.rmdir),x=o(r.readdir),j=r.existsSync;function N(e,t,n){n&&j(e)||e||$(t)}function U(e){return new Set(Array.isArray(e)?e:e.split(","))}const S=s(import.meta.url);async function F(e,t="."){if(!j(e=a(t,e)))return!1;try{var n=S(e)}catch{n=await import(e).catch((()=>!1))}finally{return n||$(`Error loading "${e}" file`)}}async function R(e){let t;return(t=await F("cfw.js",e))||(t=await F("cfw.mjs",e))||(t=await F("cfw.cjs",e))||(t=await F("cfw.json",e))?t:(t=await F("package.json",e))?t.cfw:void 0}async function P(e,t,n){let r=n?e:c(e,t),i=await R(r)||{};return{cfw:i,name:i.name||t,input:c(r,i.entry||"index.js"),abs:r}}async function K(e,t){t.cwd=a(t.cwd);let n,r,i=a(t.cwd,e);N(i,`Workers directory does not exist: "${i}"`,!0);let{cwd:o,single:s,only:c,ignore:u}=t;if(s){let e=t.dir;"."===e&&(e=l(o).base);let n=await P(i,e,!0);return(r=await R(o))&&(Object.assign(n.cfw,r),r.name&&(n.name=r.name),t.profile&&(n.cfw.profile=t.profile)),[n]}let d=await x(i,{withFileTypes:!0}).then((e=>Promise.all(e.filter((e=>e.isDirectory())).map((e=>P(i,e.name))))));return c?(n=U(c),d.filter((e=>n.has(e.name)))):u?(n=U(u),d.filter((e=>!n.has(e.name)))):d}async function J(e,t){let{CLOUDFLARE_ZONEID:n,CLOUDFLARE_ACCOUNTID:r,CLOUDFLARE_AUTH_EMAIL:o,CLOUDFLARE_AUTH_KEY:s,CLOUDFLARE_TOKEN:a}=process.env,l=o||e.email,u=s||e.authkey,d=r||e.accountid,m=n||e.zoneid,f=a||e.token;if((f||u&&l)&&d&&m)return{authkey:u,accountid:d,email:l,token:f,zoneid:m};if(e.profile){let t,n=await async function(e="default"){let t=c(i(),".cfw","config");N(t,`Missing "${t}" config file`,!0);let n,r,o={},s=0,a=/^\[(.*)\]$/,l=(await _(t,"utf8")).split(/(\r?\n)+/g);for(;s<l.length;s++)if(l[s].startsWith("#")||!l[s].trim().length);else if(a.test(l[s]))r=a.exec(l[s])[1],n=o[r]={};else{let[e,t]=l[s].split("=");n[e.trim()]=t.trim()}let u=o[e];return N(u,`The "${e}" profile is not defined`),u}(e.profile);for(t in n)!l&&/CLOUDFLARE_AUTH_EMAIL/i.test(t)&&(l=n[t]),!d&&/CLOUDFLARE_ACCOUNTID/i.test(t)&&(d=n[t]),!u&&/CLOUDFLARE_AUTH_KEY/i.test(t)&&(u=n[t]),!m&&/CLOUDFLARE_ZONEID/i.test(t)&&(m=n[t]),!f&&/CLOUDFLARE_TOKEN/i.test(t)&&(f=n[t])}return N(m||t||e.subdomain,'Missing Cloudflare "zoneid" value!'),N(d,'Missing Cloudflare "accountid" value!'),f||u&&l||(u||l?(N(l,'Missing Cloudflare "email" value!'),N(u,'Missing Cloudflare "authkey" value!')):$('Missing Cloudflare "token" value or "email" + "authkey" combo!')),{authkey:u,accountid:d,email:l,token:f,zoneid:m}}const I=()=>Math.random().toString(36).slice(2);function M(e,t,n){return m("POST",`/zones/${e.zoneid}/workers/routes`,{headers:d(e,{"Content-Type":"application/javascript"}),body:{pattern:t,script:n}}).catch((e=>{let{data:n,message:r}=e;n&&n.errors&&10020===n.errors[0].code||$(`Error setting "${t}" route pattern!\n${JSON.stringify(n||r,null,2)}`)}))}async function q(e,t,n,r,i){const o="----"+I()+I();let s="entry",a={type:"application/javascript",value:n};i?(a.type+="+module",s=a.filename="./index.mjs",r.main_module="./index.mjs"):r.body_part=s;const l=function(e,t){let n,r,i="",o="\r\n",s="--"+e;for(n in t)r=t[n],i+=s+o,i+=`Content-Disposition: form-data; name="${n}"`,r.filename&&(i+=`; filename="${r.filename}"`),r.type&&(i+=`\r\nContent-Type: ${r.type}`),i+=o+o+r.value+o;return i+s+"--"}(o,{[s]:a,metadata:{type:"application/json",value:JSON.stringify(r),filename:"metadata.json"}});return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}`,{headers:d(e,{"Content-Type":`multipart/form-data; boundary=${o}`}),body:l}).catch((e=>{$(`Error uploading "${t}" script!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function z(e){return m("GET",`/accounts/${e.accountid}/workers/subdomain`,{headers:d(e)}).then((e=>{let t=e.success&&e.result.subdomain;return t?`${t}.workers.dev`:$("You must register a subdomain!")})).catch((e=>{$(`Error fetching your workers.dev subdomain!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function V(e,t,n){return m("POST",`/accounts/${e.accountid}/workers/scripts/${t}/subdomain`,{headers:d(e),body:{enabled:n}}).catch((e=>{$(`Error publishing "${t}" to workers.dev subdomain!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}const B={env:"plain_text",wasm:"wasm_module",secret:"secret_text",kv:"kv_namespace"};function H(e,t){let n=t.indexOf(":"),r=t.substring(0,n),i=t.substring(n+1),o=B[r.toLowerCase()];return o||$(`Unknown binding hint: "${r}"`),"wasm_module"===o?{type:o,name:e,part:"wasm"}:"kv_namespace"===o?{type:o,name:e,namespace_id:i}:{type:o,name:e,text:i}}function Y(e){let t,n=[];for(t in e)n.push(H(t,e[t]));return{bindings:n}}const G={bundle:!0,format:"esm",charset:"utf8",sourcemap:!1,outfile:"<injected>",entryPoints:["<injected>"],minify:!0,logLevel:"silent",resolveExtensions:[".tsx",".ts",".jsx",".mjs",".js",".json"],mainFields:["worker","browser","module","jsnext","main"],conditions:["worker","browser","import","production"]};e("cfw").version("0.1.3").option("-C, --cwd","The relative working directory",".").option("-P, --profile","The CFW account profile to load").command("build [dir] [output]").describe("Compile the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to build; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n,r){r.dir=e||r.dir;let i=await K(r.dir,r);if(!i.length)return v("Nothing to build!",r);let o=n||"build";n=a(r.cwd,o),e=a(r.cwd,r.dir),j(n)&&(k(`Removing existing "${o}" directory`),await A(n,{recursive:!0}));const s=await import("esbuild");let l="false"!==String(r.minify),d=t.cyan(f),m=t.bold(i.length),p=1===i.length?"":"s";h(`Building ${m} worker${p}:`);for(let e of i){let i=u(G),{name:o,input:a,cfw:m}=e;if(i.entryPoints=[a],i.minify=l,"function"==typeof m.build){m.build(i);let e=[];if(i.splitting&&e.push("splitting"),(i.external||[]).length&&e.push("external"),"esm"!==i.format&&e.push("format"),i.sourcemap&&e.push("sourcemap"),e.length){let n="\n "+t.dim().red("- "),r="Invalid configuration customization!\nPlease revert or remove the following keys:";return e.forEach((e=>r+=n+e)),$(r)}}let f=c(n,r.single?"":o);i.outfile=c(f,"index.js");try{var g=Date.now(),w=await s.build(i)}catch(e){let{errors:t}=e;return await D(t,!0)}delete m.entry,await L(c(f,"cfw.json"),JSON.stringify({name:o,...m},null,2)),console.log(d+o+T(Date.now()-g)),await D(w.warnings)}y(`Build complete!\nYour worker${p} ${1===i.length?"is":"are"} ready for deployment 🎉`)})).command("deploy [output]").describe("Deploy the built Worker(s) – requires you `build` first.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to build; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n){let r,i=e||"build",o=await K(i,n);if(!o.length)return v("Nothing to deploy!",n);let s=t.cyan(f),a=t.bold(o.length),l=1===o.length?"":"s";h(`Deploying ${a} worker${l}:`);for(let e of o){let{name:t,input:i,cfw:o}=e;o.profile=o.profile||n.profile,N(i,`Worker input does not exist: "${i}"`,!0);let a=await J(o),l=Y(o.globals||{}),c=await _(i);if(o.usage){let e=(o.usage||"").toLowerCase().trim();N(/^(bundled|unbound)$/.test(e),`Invalid "usage" value: "${e}"`),l.usage_model=e}let u=Date.now();if(await q(a,t,c,l,!!o.module),console.log(s+t+T(Date.now()-u)),null==o.subdomain||r||(r=await z(a)),o.subdomain){let e=Date.now();await V(a,t,!0),E(`https://${t}.${r}/*`,Date.now()-e,!0)}else if(o.routes&&(await Promise.all(o.routes.map((e=>{let n=Date.now(),r=e.startsWith("!"),i=e.substring(+r);return M(a,i,r?null:t).then((()=>{E(i,Date.now()-n,!r)}))}))),null!=o.subdomain)){let e=Date.now();await V(a,t,!1),E(`https://${t}.${r}/*`,Date.now()-e,!1)}}y(`Deployment complete!\nAll items within "${i}" uploaded 🎉`)})).command("secrets list").alias("secrets ls").describe("List the names of secrets attached to Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e){let n=await K(e.dir,e);if(!n.length)return v("No workers found!",e);let r=t.bold(n.length),i=1===n.length?"":"s";h(`Fetching secrets for ${r} worker${i}:`);let o=t.cyan(f);for(let r of n){let{name:n,cfw:i}=r;i.profile=i.profile||e.profile;let s=await J(i),a=await O(s,n);if(console.log(o+`"${n}" secrets:`),a.result.length)for(let e of a.result)E(e.name);else console.log(p+t.italic().dim(" None"))}y(`Retrieved worker${i?"s'":"'s"} secrets`)})).command("secrets create <name> <value>").alias("secrets new","secrets add","secrets put").describe("Create a new secret for the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n,r){let i=await K(r.dir,r);if(!i.length)return v("No workers found!",r);let o=t.cyan(f),s=t.bold(i.length),a=1===i.length?"":"s",l=[];h(`Adding secret "${e}" value to ${s} worker${a}:`);for(let t of i){let{name:i,cfw:s}=t;s.profile=s.profile||r.profile;let a=await J(s);l.push((()=>{let t=Date.now();return W(a,i,e,n).then((e=>{e.success&&console.log(o+i+T(Date.now()-t))}))}))}await Promise.all(l.map((e=>e()))),y(`Added secret to worker${a}`)})).command("secrets destroy <name>").alias("secrets delete","secrets rm").describe("Remove a secret from the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-q, --quiet","Do not throw error if Worker is missing secret").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n){let r=await K(n.dir,n);if(!r.length)return v("No workers found!",n);let i=t.bold(r.length),o=1===r.length?"":"s",s=[];h(`Removing "${e}" secret from ${i} worker${o}:`);for(let i of r){let{name:r,cfw:o}=i;o.profile=o.profile||n.profile;let a=await J(o);s.push((()=>{let i=Date.now();return C(a,r,e,!!n.quiet).then((e=>{let n=(e.success?t.cyan:t.red)(f);console.log(n+r+T(Date.now()-i))}))}))}await Promise.all(s.map((e=>e()))),y(`Removed secret from worker${o}`)})).command("kv namespaces list").describe("List all KV namespaces").alias("kv ns list","kv ns ls").action((async function(e){const n=await J(e,!0);h("Retrieving KV namespaces:");const r=await function(e){return m("GET",`/accounts/${e.accountid}/storage/kv/namespaces?per_page=100&order=title`,{headers:d(e)})}(n),i=" ",o=t.dim().bold().italic;y(o("ID")+" ".repeat(30)+i+o("Title"));let s=0,a=r.result,l="";for(;s<a.length;s++)l&&(l+="\n"),l+=(a[s].supports_url_encoding?t.cyan:t.red)(f),l+=a[s].id+i+a[s].title;console.log(l)})).command("kv namespaces create <title>").describe("Create a new KV namespace").alias("kv ns create","kv ns new").action((async function(e,n){const r=await J(n,!0);h("Creating new KV namespace:");const i=await function(e,t){return m("POST",`/accounts/${e.accountid}/storage/kv/namespaces`,{headers:d(e),body:{title:t}}).catch((e=>{$(`Error creating "${t}" namespace!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}(r,e);if(!i)return $("Error creating namespace");console.log(t.cyan(f)+`"${i.result.title}" `+t.italic().dim(`(ID: ${i.result.id})`)),y("KV namespace created!")})).command("kv namespaces destroy <id>").describe("Destroy a KV namespace").alias("kv ns delete","kv ns rm").action((async function(e,t){const n=await J(t,!0);k("Deleting KV namespace");const r=await function(e,t){return m("DELETE",`/accounts/${e.accountid}/storage/kv/namespaces/${t}`,{headers:d(e)}).catch((e=>{$(`Error removing "${t}" namespace!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}(n,e);if(!r||!r.success)return $("Error deleting namespace");y("KV namespace deleted!")})).parse(process.argv,{boolean:["single","quiet"],string:["only","ignore","profile"]}); | ||
import e from"sade";import t from"kleur";import{send as n}from"httpie";import{homedir as r}from"os";import{promises as o,existsSync as i}from"fs";import{createRequire as s}from"module";import{resolve as a,parse as l,join as c}from"path";import{klona as u}from"klona/json";function d(e,t={}){return e.token?t.Authorization=`Bearer ${e.token}`:(t["X-Auth-Key"]=e.authkey,t["X-Auth-Email"]=e.email),t}function m(e,t,r={}){return n(e,"https://api.cloudflare.com/client/v4"+t,r).then((e=>e.data))}const f=" ~> ",p=" ".repeat(6),g=t.bold("[CFW]");function w(e,n){console.log(t[e](g),n.includes("\n")?n.replace(/(\r?\n)/g,"$1"+p):n)}const h=e=>w("white",e),y=e=>w("green",e),k=e=>w("yellow",e);function $(e,t=1){w("red",e),process.exit(t)}const b=t.dim().bold;function v(e,t){return(t.only||t.ignore)&&(e+=`\nPerhaps the ${b("--only")} or ${b("--ignore")} flag needs adjusting`),k(e)}function T(e){return t.italic().dim(` (${e}ms)`)}function E(e,n,r){let o="•",i=t.dim,s=null!=n?T(n):"";r?(o="+",i=t.green().dim):null!=r&&(o="-",i=t.red().dim),console.log(i(p+o+` "${e}"`)+s)}async function D(e,n){let r=0,o=e.length;if(o===r)return;const i=await import("esbuild");let s=await i.formatMessages(e,{terminalWidth:process.stdout.columns,kind:n?"error":"warning",color:t.enabled}),a=/\x1b\[32m/g,l=n?"[31m":"[33m",c=n?t.red:t.yellow,u=`Build ${n?"failed":"finished"} with`;for(u+=" "+t.underline(o)+" ",u+=n?"error":"warning",u+=1===o?":":"s:",u+="\n\n";r<o;r++)u+=t.bold().inverse(c(" "+e[r].location.file+" "))+" "+e[r].text,u+=s[r].substring(s[r].indexOf("\n")).replace(a,l);r=u.length,"\n"===u[--r]&&(u=u.substring(0,r)),(n?$:k)(u)}function O(e,t){return m("GET",`/accounts/${e.accountid}/workers/scripts/${t}/secrets`,{headers:d(e)}).catch((e=>{$(`Error fetching "${t}" secrets!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function C(e,t,n,r){return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}/secrets`,{headers:d(e),body:{type:"secret_text",text:r,name:n}}).catch((e=>{$(`Error creating new "${t}" secret!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function W(e,t,n,r){return m("DELETE",`/accounts/${e.accountid}/workers/scripts/${t}/secrets/${n}`,{headers:d(e)}).catch((e=>{let{data:o,message:i}=e;if(r&&o&&o.errors&&10056===o.errors[0].code)return o;$(`Error deleting "${t}/${n}" secret!\n${JSON.stringify(o||i,null,2)}`)}))}const L=o.rm||o.rmdir,_=o.writeFile,A=o.readFile,N=o.readdir;function j(e,t,n){n&&i(e)||e||$(t)}function x(e){return new Set(Array.isArray(e)?e:e.split(","))}const U=s(import.meta.url);async function R(e,t="."){if(!i(e=a(t,e)))return!1;try{var n=U(e)}catch{n=await import(e).catch((()=>!1))}finally{return n||$(`Error loading "${e}" file`)}}async function S(e){let t;return(t=await R("cfw.js",e))||(t=await R("cfw.mjs",e))||(t=await R("cfw.cjs",e))||(t=await R("cfw.json",e))?t:(t=await R("package.json",e))?t.cfw:void 0}async function F(e,t,n){let r=n?e:c(e,t),o=await S(r)||{};return{cfw:o,name:o.name||t,input:c(r,o.entry||"index.js"),abs:r}}async function P(e,t){t.cwd=a(t.cwd);let n,r,o=a(t.cwd,e);j(o,`Workers directory does not exist: "${o}"`,!0);let{cwd:i,single:s,only:c,ignore:u}=t;if(s){let e=t.dir;"."===e&&(e=l(i).base);let n=await F(o,e,!0);return(r=await S(i))&&(Object.assign(n.cfw,r),r.name&&(n.name=r.name),t.profile&&(n.cfw.profile=t.profile)),[n]}let d=await N(o,{withFileTypes:!0}).then((e=>Promise.all(e.filter((e=>e.isDirectory())).map((e=>F(o,e.name))))));return c?(n=x(c),d.filter((e=>n.has(e.name)))):u?(n=x(u),d.filter((e=>!n.has(e.name)))):d}async function K(e,t){let{CLOUDFLARE_ZONEID:n,CLOUDFLARE_ACCOUNTID:o,CLOUDFLARE_AUTH_EMAIL:i,CLOUDFLARE_AUTH_KEY:s,CLOUDFLARE_TOKEN:a}=process.env,l=i||e.email,u=s||e.authkey,d=o||e.accountid,m=n||e.zoneid,f=a||e.token;if((f||u&&l)&&d&&m)return{authkey:u,accountid:d,email:l,token:f,zoneid:m};if(e.profile){let t,n=await async function(e="default"){let t=c(r(),".cfw","config");j(t,`Missing "${t}" config file`,!0);let n,o,i={},s=0,a=/^\[(.*)\]$/,l=(await A(t,"utf8")).split(/(\r?\n)+/g);for(;s<l.length;s++)if(l[s].startsWith("#")||!l[s].trim().length);else if(a.test(l[s]))o=a.exec(l[s])[1],n=i[o]={};else{let[e,t]=l[s].split("=");n[e.trim()]=t.trim()}let u=i[e];return j(u,`The "${e}" profile is not defined`),u}(e.profile);for(t in n)!l&&/CLOUDFLARE_AUTH_EMAIL/i.test(t)&&(l=n[t]),!d&&/CLOUDFLARE_ACCOUNTID/i.test(t)&&(d=n[t]),!u&&/CLOUDFLARE_AUTH_KEY/i.test(t)&&(u=n[t]),!m&&/CLOUDFLARE_ZONEID/i.test(t)&&(m=n[t]),!f&&/CLOUDFLARE_TOKEN/i.test(t)&&(f=n[t])}return j(m||t||e.subdomain,'Missing Cloudflare "zoneid" value!'),j(d,'Missing Cloudflare "accountid" value!'),f||u&&l||(u||l?(j(l,'Missing Cloudflare "email" value!'),j(u,'Missing Cloudflare "authkey" value!')):$('Missing Cloudflare "token" value or "email" + "authkey" combo!')),{authkey:u,accountid:d,email:l,token:f,zoneid:m}}const J=()=>Math.random().toString(36).slice(2);function I(e,t,n){return m("POST",`/zones/${e.zoneid}/workers/routes`,{headers:d(e,{"Content-Type":"application/javascript"}),body:{pattern:t,script:n}}).catch((e=>{let{data:n,message:r}=e;n&&n.errors&&10020===n.errors[0].code||$(`Error setting "${t}" route pattern!\n${JSON.stringify(n||r,null,2)}`)}))}async function M(e,t,n,r,o){const i="----"+J()+J();let s="entry",a={type:"application/javascript",value:n};o?(a.type+="+module",s=a.filename="./index.mjs",r.main_module="./index.mjs"):r.body_part=s;const l=function(e,t){let n,r,o="",i="\r\n",s="--"+e;for(n in t)r=t[n],o+=s+i,o+=`Content-Disposition: form-data; name="${n}"`,r.filename&&(o+=`; filename="${r.filename}"`),r.type&&(o+=`\r\nContent-Type: ${r.type}`),o+=i+i+r.value+i;return o+s+"--"}(i,{[s]:a,metadata:{type:"application/json",value:JSON.stringify(r),filename:"metadata.json"}});return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}`,{headers:d(e,{"Content-Type":`multipart/form-data; boundary=${i}`}),body:l}).catch((e=>{$(`Error uploading "${t}" script!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function q(e,t,n){return m("PUT",`/accounts/${e.accountid}/workers/scripts/${t}/schedules`,{headers:d(e,{"Content-Type":"application/javascript"}),body:n}).catch((e=>{$(`Error updating "${t}" CRON triggers!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function z(e){return m("GET",`/accounts/${e.accountid}/workers/subdomain`,{headers:d(e)}).then((e=>{let t=e.success&&e.result.subdomain;return t?`${t}.workers.dev`:$("You must register a subdomain!")})).catch((e=>{$(`Error fetching your workers.dev subdomain!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}function V(e,t,n){return m("POST",`/accounts/${e.accountid}/workers/scripts/${t}/subdomain`,{headers:d(e),body:{enabled:n}}).catch((e=>{$(`Error publishing "${t}" to workers.dev subdomain!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}const B={env:"plain_text",wasm:"wasm_module",secret:"secret_text",kv:"kv_namespace"};function H(e,t){let n=t.indexOf(":"),r=t.substring(0,n),o=t.substring(n+1),i=B[r.toLowerCase()];return i||$(`Unknown binding hint: "${r}"`),"wasm_module"===i?{type:i,name:e,part:"wasm"}:"kv_namespace"===i?{type:i,name:e,namespace_id:o}:{type:i,name:e,text:o}}function Y(e){let t,n=[];for(t in e)n.push(H(t,e[t]));return{bindings:n}}const G={bundle:!0,format:"esm",charset:"utf8",sourcemap:!1,outfile:"<injected>",entryPoints:["<injected>"],minify:!0,logLevel:"silent",resolveExtensions:[".tsx",".ts",".jsx",".mjs",".js",".json"],mainFields:["worker","browser","module","jsnext","main"],conditions:["worker","browser","import","production"]};e("cfw").version("0.2.0").option("-C, --cwd","The relative working directory",".").option("-P, --profile","The CFW account profile to load").command("build [dir] [output]").describe("Compile the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to build; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n,r){r.dir=e||r.dir;let o=await P(r.dir,r);if(!o.length)return v("Nothing to build!",r);let s=n||"build";n=a(r.cwd,s),e=a(r.cwd,r.dir),i(n)&&(k(`Removing existing "${s}" directory`),await L(n,{recursive:!0}));const l=await import("esbuild");let d="false"!==String(r.minify),m=t.cyan(f),p=t.bold(o.length),g=1===o.length?"":"s";h(`Building ${p} worker${g}:`);for(let e of o){let o=u(G),{name:i,input:s,cfw:a}=e;if(o.entryPoints=[s],o.minify=d,"function"==typeof a.build){a.build(o);let e=[];if(o.splitting&&e.push("splitting"),(o.external||[]).length&&e.push("external"),"esm"!==o.format&&e.push("format"),o.sourcemap&&e.push("sourcemap"),e.length){let n="\n "+t.dim().red("- "),r="Invalid configuration customization!\nPlease revert or remove the following keys:";return e.forEach((e=>r+=n+e)),$(r)}}let f=c(n,r.single?"":i);o.outfile=c(f,"index.js");try{var w=Date.now(),b=await l.build(o)}catch(e){let{errors:t}=e;return await D(t,!0)}delete a.entry,await _(c(f,"cfw.json"),JSON.stringify({name:i,...a},null,2)),console.log(m+i+T(Date.now()-w)),await D(b.warnings)}y(`Build complete!\nYour worker${g} ${1===o.length?"is":"are"} ready for deployment 🎉`)})).command("deploy [output]").describe("Deploy the built Worker(s) – requires you `build` first.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to build; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n){let r,o=e||"build",i=await P(o,n);if(!i.length)return v("Nothing to deploy!",n);let s=t.cyan(f),a=t.bold(i.length),l=1===i.length?"":"s";h(`Deploying ${a} worker${l}:`);for(let e of i){let{name:t,input:o,cfw:i}=e;i.profile=i.profile||n.profile,j(o,`Worker input does not exist: "${o}"`,!0);let a=await K(i),l=Y(i.globals||{}),c=await A(o);if(i.usage){let e=(i.usage||"").toLowerCase().trim();j(/^(bundled|unbound)$/.test(e),`Invalid "usage" value: "${e}"`),l.usage_model=e}let u=Date.now();if(await M(a,t,c,l,!!i.module),console.log(s+t+T(Date.now()-u)),null==i.subdomain||r||(r=await z(a)),i.subdomain){let e=Date.now();await V(a,t,!0),E(`https://${t}.${r}/*`,Date.now()-e,!0)}else if(i.routes&&(await Promise.all(i.routes.map((e=>{let n=Date.now(),r=e.startsWith("!"),o=e.substring(+r);return I(a,o,r?null:t).then((()=>{E(o,Date.now()-n,!r)}))}))),null!=i.subdomain)){let e=Date.now();await V(a,t,!1),E(`https://${t}.${r}/*`,Date.now()-e,!1)}if(i.cron&&i.cron.length){let e=0,n=[],r=/([^\s]+\s+){4}/;for(;e<i.cron.length;e++)r.test(i.cron[e])||$(`Invalid CRON: "${i.cron[e]}"`),n.push({cron:i.cron[e]});let o=Date.now();await q(a,t,n);let s=Date.now()-o;for(e=0;e<n.length;e++)E(i.cron[e],s,!0)}}y(`Deployment complete!\nAll items within "${o}" uploaded 🎉`)})).command("secrets list").alias("secrets ls").describe("List the names of secrets attached to Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e){let n=await P(e.dir,e);if(!n.length)return v("No workers found!",e);let r=t.bold(n.length),o=1===n.length?"":"s";h(`Fetching secrets for ${r} worker${o}:`);let i=t.cyan(f);for(let r of n){let{name:n,cfw:o}=r;o.profile=o.profile||e.profile;let s=await K(o),a=await O(s,n);if(console.log(i+`"${n}" secrets:`),a.result.length)for(let e of a.result)E(e.name);else console.log(p+t.italic().dim(" None"))}y(`Retrieved worker${o?"s'":"'s"} secrets`)})).command("secrets create <name> <value>").alias("secrets new","secrets add","secrets put").describe("Create a new secret for the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n,r){let o=await P(r.dir,r);if(!o.length)return v("No workers found!",r);let i=t.cyan(f),s=t.bold(o.length),a=1===o.length?"":"s",l=[];h(`Adding secret "${e}" value to ${s} worker${a}:`);for(let t of o){let{name:o,cfw:s}=t;s.profile=s.profile||r.profile;let a=await K(s);l.push((()=>{let t=Date.now();return C(a,o,e,n).then((e=>{e.success&&console.log(i+o+T(Date.now()-t))}))}))}await Promise.all(l.map((e=>e()))),y(`Added secret to worker${a}`)})).command("secrets destroy <name>").alias("secrets delete","secrets rm").describe("Remove a secret from the Worker(s) within a directory.").option("-d, --dir","The directory containing Worker scripts","workers").option("-o, --only","The list of Worker names to query; overrides `--ignore` list!").option("-q, --quiet","Do not throw error if Worker is missing secret").option("-i, --ignore","The list of Worker names to skip").option("-s, --single","The target is a single Worker").action((async function(e,n){let r=await P(n.dir,n);if(!r.length)return v("No workers found!",n);let o=t.bold(r.length),i=1===r.length?"":"s",s=[];h(`Removing "${e}" secret from ${o} worker${i}:`);for(let o of r){let{name:r,cfw:i}=o;i.profile=i.profile||n.profile;let a=await K(i);s.push((()=>{let o=Date.now();return W(a,r,e,!!n.quiet).then((e=>{let n=(e.success?t.cyan:t.red)(f);console.log(n+r+T(Date.now()-o))}))}))}await Promise.all(s.map((e=>e()))),y(`Removed secret from worker${i}`)})).command("kv namespaces list").describe("List all KV namespaces").alias("kv ns list","kv ns ls").action((async function(e){const n=await K(e,!0);h("Retrieving KV namespaces:");const r=await function(e){return m("GET",`/accounts/${e.accountid}/storage/kv/namespaces?per_page=100&order=title`,{headers:d(e)})}(n),o=" ",i=t.dim().bold().italic;y(i("ID")+" ".repeat(30)+o+i("Title"));let s=0,a=r.result,l="";for(;s<a.length;s++)l&&(l+="\n"),l+=(a[s].supports_url_encoding?t.cyan:t.red)(f),l+=a[s].id+o+a[s].title;console.log(l)})).command("kv namespaces create <title>").describe("Create a new KV namespace").alias("kv ns create","kv ns new").action((async function(e,n){const r=await K(n,!0);h("Creating new KV namespace:");const o=await function(e,t){return m("POST",`/accounts/${e.accountid}/storage/kv/namespaces`,{headers:d(e),body:{title:t}}).catch((e=>{$(`Error creating "${t}" namespace!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}(r,e);if(!o)return $("Error creating namespace");console.log(t.cyan(f)+`"${o.result.title}" `+t.italic().dim(`(ID: ${o.result.id})`)),y("KV namespace created!")})).command("kv namespaces destroy <id>").describe("Destroy a KV namespace").alias("kv ns delete","kv ns rm").action((async function(e,t){const n=await K(t,!0);k("Deleting KV namespace");const r=await function(e,t){return m("DELETE",`/accounts/${e.accountid}/storage/kv/namespaces/${t}`,{headers:d(e)}).catch((e=>{$(`Error removing "${t}" namespace!\n${JSON.stringify(e.data||e.message,null,2)}`)}))}(n,e);if(!r||!r.success)return $("Error deleting namespace");y("KV namespace deleted!")})).parse(process.argv,{boolean:["single","quiet"],string:["only","ignore","profile"]}); |
{ | ||
"name": "cfw", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"repository": "lukeed/cfw", | ||
@@ -5,0 +5,0 @@ "description": "WIP", |
@@ -21,3 +21,3 @@ # cfw [![CI](https://github.com/lukeed/cfw/workflows/CI/badge.svg)](https://github.com/lukeed/cfw/actions) [![npm](https://badgen.now.sh/npm/v/cfw)](https://npmjs.org/package/cfw) | ||
``` | ||
```ini | ||
[personal] | ||
@@ -27,7 +27,8 @@ CLOUDFLARE_AUTH_EMAIL = hello@me.com | ||
CLOUDFLARE_AUTH_KEY = GLOBAL_API_KEY | ||
CLOUDFLARE_ZONEID = ZONEID_VALUE | ||
``` | ||
In this case, we have a "personal" profile containing our personal account credentials, for example. You can define multiple credential groups by repeating this template as needed, using different profile names. | ||
In this case, we have a "personal" profile containing our personal account credentials. You can define multiple credential groups by repeating this template as needed, using different profile names. | ||
```sh | ||
```ini | ||
[personal] | ||
@@ -46,3 +47,3 @@ CLOUDFLARE_AUTH_EMAIL = hello@me.com | ||
If a profile named "default" exists, then `cfw` will auto-load that credentials group when no there is no profile configured. | ||
If a profile named `[default]` exists, then `cfw` will auto-load that credentials group when no there is no profile configured. | ||
@@ -61,3 +62,36 @@ ***Selecting a Profile*** | ||
* `CLOUDFLARE_ACCOUNTID` – your account identifier; alias of `config.accountid` | ||
* `CLOUDFLARE_AUTH_EMAIL` – your account email address; alias of `config.email` | ||
* `CLOUDFLARE_AUTH_KEY` – your account's global API key; alias of `config.authkey` | ||
* `CLOUDFLARE_ZONEID` – your domain/zone's identifier; alias of `config.zoneid` | ||
* `CLOUDFLARE_TOKEN` – an API access token; alias of `config.token` | ||
### Authentication | ||
In order to successfull access your Cloudflare account's resources, you must satisfy the following requirements: | ||
1. A `CLOUDFLARE_ACCOUNTID` (or `config.accountid`) is **always required**. | ||
2. A valid token or key-pair; you have two options: | ||
1. A `CLOUDFLARE_TOKEN` (or `config.token`) containing a valid [API token](https://dash.cloudflare.com/profile/api-tokens). <br>_***(Recommended)*** Preferred solution, as this API token can be narrowly scoped and can be revoked at any time._ | ||
2. A valid `CLOUDFLARE_AUTH_EMAIL` _and_ `CLOUDFLARE_AUTH_KEY` combination. <br>_This requires your Global API Key, which grants full access to all account resources._ | ||
3. A `CLOUDFLARE_ZONEID` is **only required if** you are not deploying to a `*.workers.dev` subdomain (via `config.subdomain`). | ||
The following profiles represent valid combinations: | ||
```ini | ||
[recommended] | ||
cloudflare_accountid = da32... | ||
cloudflare_token = 78a... | ||
# (optional) cloudflare_zoneid = b58... | ||
[other] | ||
cloudflare_accountid = da32... | ||
cloudflare_auth_email = hello@example.com | ||
cloudflare_auth_key = 62d... | ||
# (optional) cloudflare_zoneid = b58... | ||
``` | ||
<!-- TODO: auth + email vs token --> | ||
@@ -64,0 +98,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21201
84
101