@npflared/cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +6 -6
  2. package/package.json +2 -1
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import{hideBin as e}from"yargs/helpers";import t from"yargs/yargs";import{access as n,mkdir as r,mkdtemp as i,readFile as a,rename as o,rm as s,writeFile as c}from"node:fs/promises";import{homedir as l,tmpdir as u}from"node:os";import{join as d}from"node:path";import{confirm as f,intro as p,isCancel as m,log as h,outro as g,select as _,spinner as v,text as y}from"@clack/prompts";import{randomUUID as b}from"node:crypto";import{rmSync as x}from"node:fs";import S from"chalk";import C from"dedent";import w from"degit";import{encode as T}from"uuid-b32";import{$ as E,ProcessOutput as D}from"zx";import{z as O}from"zod";const k=v(),A=d(l(),`.npflared`),j=async()=>{p(`npflared`),k.start(`Deleting npflared directory (${A})...`),await s(A,{recursive:!0,force:!0}),k.stop(`Successfully deleted npflared directory`),process.exit(0)},M=O.object({d1_databases:O.array(O.object({binding:O.string(),database_name:O.string(),database_id:O.string()})).min(1)}),N=O.object({r2_buckets:O.array(O.object({binding:O.string(),bucket_name:O.string()})).min(1)}),P=async()=>{try{let[e]=(await E({quiet:!0})`npx -y wrangler whoami`).stdout.match(/([0-9a-f]{32})/)??[];return e}catch(e){throw e instanceof D?Error(e.stderr||e.stdout):e}},F=async()=>{try{let e=[],t=(await E({quiet:!0})`npx -y wrangler d1 list`).stdout.matchAll(/│(.*)(.*)(.*)(.*)(.*)(.*)│/gm);for(let n of t){let[,t,r,i,a,o,s]=n;(t||r||i||a||o||s)&&e.push({id:t.trim(),name:r.trim(),createdAt:i.trim(),version:a.trim(),numberOfTables:Number.parseInt(o,10),size:Number.parseInt(s,10)})}return e}catch(e){throw e instanceof D?Error(e.stderr||e.stdout):e}},I=async()=>{try{let e=(await E({quiet:!0})`npx -y wrangler r2 bucket list`).stdout.matchAll(/name:(.*)\ncreation_date:(.*)/gim),t=[];for(let n of e){let[,e,r]=n;(e||r)&&t.push({name:e.trim(),createdAt:r.trim()})}return t}catch(e){throw e instanceof D?Error(e.stderr||e.stdout):e}},L=async e=>{try{let t=(await E({quiet:!0})`npx -y wrangler r2 bucket create ${e}`).stdout.match(/\{(?:[^{}]*|\{(?:[^{}]*|\{[^{}]*\})*\})*\}/gim),n=N.safeParse(JSON.parse(t?.[0]??``));if(!n.success)throw Error(`Could not properly retrieve R2 bucket binding`);return n.data}catch(e){throw e instanceof D?Error(e.stderr||e.stdout):e}},R=async e=>{try{let t=(await E({quiet:!0})`npx -y wrangler d1 create ${e}`).stdout.match(/\{(?:[^{}]*|\{(?:[^{}]*|\{[^{}]*\})*\})*\}/gim),n=M.safeParse(JSON.parse(t?.[0]??``));if(!n.success)throw Error(`Could not properly retrieve D1 database binding`);return n.data}catch(e){throw e instanceof D?Error(e.stderr||e.stdout):e}},z=async(e,t={})=>{try{await E({cwd:t.cwd})`npx -y wrangler d1 migrations apply ${e} --remote --config wrangler.json`}catch(e){throw e instanceof D?Error(e.stderr||e.stdout):e}},B=async(e={})=>{try{let t=(await E({quiet:!0,cwd:e.cwd})`npx -y wrangler deploy --config wrangler.json`).stdout.match(/([a-z0-9-]+\.[a-z0-9-]+\.workers\.dev)/i);return t?`https://${t[0]}`:`<unknown>`}catch(e){throw e instanceof D?Error(e.stderr||e.stdout):e}},V=async e=>{try{return await n(e),!0}catch(e){if(e?.code===`ENOENT`)return!1;throw e}},H=d(l(),`.npflared`),U=v(),W=async()=>{try{await r(H,{recursive:!0})}catch(e){if(e?.code!==`EEXIST`)throw e}},G=async()=>{let e=await f({message:`Use an existing D1 database?`});if(m(e)&&process.exit(1),e){U.start(`Retrieving D1 databases...`);let e=await F();U.stop();let t=await _({message:`Select a D1 database:`,options:e.map(e=>({value:{name:e.name,id:e.id},label:`${e.name.padEnd(30)} (${e.id}) - Created at: ${e.createdAt}`}))});return m(t)&&process.exit(1),{name:t.name,id:t.id}}let t=await y({initialValue:`npflared`,message:`Enter a name for your D1 database:`,validate(e){if(e.length===0)return`Please enter a name for your D1 database`}});m(t)&&process.exit(1),U.start(`Creating D1 database ${t}...`);let n=await R(t);U.stop();let[r]=n.d1_databases;return r||(console.log(S.red(`Could not create D1 database ${t}`)),process.exit(1)),{name:r.database_name,id:r.database_id}},K=async()=>{let e=await f({message:`Use an existing R2 bucket?`});if(m(e)&&process.exit(1),e){U.start(`Retrieving R2 buckets...`);let e=await I();U.stop();let t=await _({message:`Select a R2 bucket:`,options:e.map(e=>({value:{name:e.name},label:`${e.name.padEnd(30)} - Created at: ${e.createdAt}`}))});return m(t)&&process.exit(1),{name:t.name}}let t=await y({initialValue:`npflared`,message:`Enter a name for your R2 bucket:`,validate(e){if(e.length===0)return`Please enter a name for your R2 bucket`}});m(t)&&process.exit(1),U.start(`Creating R2 bucket ${t}...`);let n=await L(t);U.stop();let[r]=n.r2_buckets;return r||(console.log(S.red(`Could not create R2 bucket ${t}`)),process.exit(1)),{name:r.bucket_name}},q=async()=>{let e=await _({message:`Install dependencies with:`,options:[{value:`npm`,label:`npm`},{value:`pnpm`,label:`pnpm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});return m(e)&&process.exit(1),e},J=async()=>{let e=await y({initialValue:`npflared`,message:`Enter a name for your worker:`,validate(e){if(e.length===0)return`Please enter a name for your worker`}});return m(e)&&process.exit(1),e},Y=async e=>{U.start(`Generating admin token...`);let t=d(e,`migrations`,`9999_admin-token.sql`);if(!await V(t)){let e=T(b()),n=Date.now();return await c(t,`INSERT INTO token (token, name, scopes, created_at, updated_at) VALUES ('${e}', 'admin-token', '[{"type": "token:read+write", "values": ["*"]}, {"type": "user:read+write", "values": ["*"]}, {"type": "package:read+write", "values": ["*"]}]', ${n}, ${n});`),U.stop(`Admin token migration file generated at ${t}`),e}let n=await a(t,`utf-8`);return U.stop(`Admin token migration file already exists at ${t}`),n.match(/INSERT INTO token \(token, name, scopes, created_at, updated_at\) VALUES \('([^']+)'/)?.[0]??``},X=async()=>{let e=await i(d(u(),`npflared-`)),t=()=>{e&&x(e,{recursive:!0,force:!0})};process.on(`exit`,t),process.on(`SIGINT`,t),process.on(`SIGTERM`,t);try{p(`npflared`);let t=w(`Thomascogez/npflared/apps/api`);U.start(`Cloning npflared...`),await t.clone(e);let n=d(e,`package.json`),r=JSON.parse(await a(n,`utf-8`)).version;await W();let i=d(H,r);await V(i)||await o(e,d(H,r)),U.stop(`Successfully cloned npflared (v${r})`);let s=await J(),l=await q();U.start(`Installing dependencies using ${l}...`),await E({quiet:!0,cwd:i})`npx -y ${l} install`,U.stop(`Successfully installed dependencies using ${l}`),U.start(`Retrieving Cloudflare account id...`);let u=await P();U.stop(),u?h.info(S.green(`Using cloudflare account id: ${S.bold.white(u)}`)):(h.error(S.red(`Could not retrieve Cloudflare account id, please login with ${S.bold.white(`wrangler login`)}`)),process.exit(1));let f=await G(),m=await K();U.start(`Generating wrangler configuration...`);let _={name:s,main:`src/index.ts`,compatibility_date:`2024-11-24`,compatibility_flags:[`nodejs_compat`],d1_databases:[{binding:`DB`,database_name:f.name,database_id:f.id}],r2_buckets:[{binding:`BUCKET`,bucket_name:m.name}]},v=d(i,`wrangler.json`);await c(d(i,`wrangler.json`),JSON.stringify(_,null,2)),U.stop(`Wrangler configuration generated at ${v}`);let y=await Y(i);U.start(`Applying D1 migrations...`),await z(f.name,{cwd:i}),U.stop(`Successfully applied D1 migrations`),U.start(`Deploying...`);let b=await B({cwd:i});U.stop(),h.info(S.green(C`
3
- 🔥 npflared is now ready to use!
4
- 🔗 Deployed to: ${S.bold.white(b)}
5
- 👮 Admin token: ${S.bold.white(y)}
6
- 📚 Check documentation for more information: ${S.bold.white(`https://npflared.thomas-cogez.fr`)}
7
- `)),g(`You're all set!`)}catch(e){h.error(`${e}`),process.exit(1)}finally{t()}};t(e(process.argv)).command(`install`,`Configure and deploy your own npflared instance on your cloudflare account`,e=>e,async()=>{await X()}).command(`clean`,`Clean the local npflared folder`,e=>e,async()=>{await j()}).demandCommand(1).parse();export{};
2
+ import{hideBin as e}from"yargs/helpers";import t from"yargs/yargs";import{access as n,mkdir as r,mkdtemp as i,readFile as a,rename as o,rm as s,writeFile as c}from"node:fs/promises";import{homedir as l,tmpdir as u}from"node:os";import{join as d}from"node:path";import{confirm as f,intro as p,isCancel as m,log as h,outro as g,select as _,spinner as v,text as y}from"@clack/prompts";import{randomUUID as b}from"node:crypto";import{rmSync as x}from"node:fs";import{getCommand as S}from"@antfu/ni";import C from"chalk";import w from"dedent";import T from"degit";import{encode as E}from"uuid-b32";import{$ as D,ProcessOutput as O}from"zx";import{z as k}from"zod";import{AsyncLocalStorage as A}from"node:async_hooks";const j=v(),M=d(l(),`.npflared`),N=async()=>{p(`npflared`),j.start(`Deleting npflared directory (${M})...`),await s(M,{recursive:!0,force:!0}),j.stop(`Successfully deleted npflared directory`),process.exit(0)},P=new A,F=k.object({d1_databases:k.array(k.object({binding:k.string(),database_name:k.string(),database_id:k.string()})).min(1)}),I=k.object({r2_buckets:k.array(k.object({binding:k.string(),bucket_name:k.string()})).min(1)}),L=(e,t={})=>D({quiet:!0,...t})`${e.command} ${e.args.join(` `)}`,R=async()=>{let e=P.getStore()?.packageManagerAgent??`npm`;try{let[t]=(await L(S(e,`execute`,[`-y`,`wrangler`,`whoami`]))).stdout.match(/([0-9a-f]{32})/)??[];return t}catch(e){throw e instanceof O?Error(e.stderr||e.stdout):e}},z=async()=>{let e=P.getStore()?.packageManagerAgent??`npm`;try{let t=[],n=await L(S(e,`execute`,[`-y`,`wrangler`,`d1`,`list`])),r=Array.from(n.stdout.matchAll(/│\s*([^│]+?)\s*│\s*([^│]+?)\s*│\s*([^│]+?)\s*│\s*([^│]+?)\s*│\s*([^│]+?)\s*│\s*([^│]+?)\s*│\s*([^│]+?)\s*│/gm)).slice(1);for(let e of r){let[,n,r,i,a,o,s]=e;(n||r||i||a||o||s)&&t.push({id:n.trim(),name:r.trim(),createdAt:i.trim(),version:a.trim(),numberOfTables:Number.parseInt(o,10),size:Number.parseInt(s,10)})}return t}catch(e){throw e instanceof O?Error(e.stderr||e.stdout):e}},B=async()=>{let e=P.getStore()?.packageManagerAgent??`npm`;try{let t=(await L(S(e,`execute`,[`-y`,`wrangler`,`r2`,`bucket`,`list`]))).stdout.matchAll(/name:(.*)\ncreation_date:(.*)/gim),n=[];for(let e of t){let[,t,r]=e;(t||r)&&n.push({name:t.trim(),createdAt:r.trim()})}return n}catch(e){throw e instanceof O?Error(e.stderr||e.stdout):e}},V=async e=>{let t=P.getStore()?.packageManagerAgent??`npm`;try{let n=(await L(S(t,`execute`,[`-y`,`wrangler`,`r2`,`bucket`,`create`,e]))).stdout.match(/\{(?:[^{}]*|\{(?:[^{}]*|\{[^{}]*\})*\})*\}/gim),r=I.safeParse(JSON.parse(n?.[0]??``));if(!r.success)throw Error(`Could not properly retrieve R2 bucket binding`);return r.data}catch(e){throw e instanceof O?Error(e.stderr||e.stdout):e}},H=async e=>{let t=P.getStore()?.packageManagerAgent??`npm`;try{let n=(await L(S(t,`execute`,[`-y`,`wrangler`,`d1`,`create`,e]))).stdout.match(/\{(?:[^{}]*|\{(?:[^{}]*|\{[^{}]*\})*\})*\}/gim),r=F.safeParse(JSON.parse(n?.[0]??``));if(!r.success)throw Error(`Could not properly retrieve D1 database binding`);return r.data}catch(e){throw e instanceof O?Error(e.stderr||e.stdout):e}},U=async(e,t={})=>{let n=P.getStore()?.packageManagerAgent??`npm`;try{await L(S(n,`execute`,[`-y`,`wrangler`,`d1`,`migrations`,`apply`,e,`--remote`,`--config`,`wrangler.json`]),{cwd:t.cwd})}catch(e){throw e instanceof O?Error(e.stderr||e.stdout):e}},W=async(e={})=>{let t=P.getStore()?.packageManagerAgent??`npm`;try{let n=(await L(S(t,`execute`,[`-y`,`wrangler`,`deploy`,`--config`,`wrangler.json`]),{cwd:e.cwd})).stdout.match(/([a-z0-9-]+\.[a-z0-9-]+\.workers\.dev)/i);return n?`https://${n[0]}`:`<unknown>`}catch(e){throw e instanceof O?Error(e.stderr||e.stdout):e}},G=async e=>{try{return await n(e),!0}catch(e){if(e?.code===`ENOENT`)return!1;throw e}},K=d(l(),`.npflared`),q=v(),J=async()=>{try{await r(K,{recursive:!0})}catch(e){if(e?.code!==`EEXIST`)throw e}},Y=async()=>{let e=await f({message:`Use an existing D1 database?`});if(m(e)&&process.exit(1),e){q.start(`Retrieving D1 databases...`);let e=await z();q.stop();let t=await _({message:`Select a D1 database:`,options:e.map(e=>({value:{name:e.name,id:e.id},label:`${e.name.padEnd(30)} (${e.id}) - Created at: ${e.createdAt}`}))});return m(t)&&process.exit(1),{name:t.name,id:t.id}}let t=await y({initialValue:`npflared`,message:`Enter a name for your D1 database:`,validate(e){if(e.length===0)return`Please enter a name for your D1 database`}});m(t)&&process.exit(1),q.start(`Creating D1 database ${t}...`);let n=await H(t);q.stop();let[r]=n.d1_databases;return r||(console.log(C.red(`Could not create D1 database ${t}`)),process.exit(1)),{name:r.database_name,id:r.database_id}},X=async()=>{let e=await f({message:`Use an existing R2 bucket?`});if(m(e)&&process.exit(1),e){q.start(`Retrieving R2 buckets...`);let e=await B();q.stop();let t=await _({message:`Select a R2 bucket:`,options:e.map(e=>({value:{name:e.name},label:`${e.name.padEnd(30)} - Created at: ${e.createdAt}`}))});return m(t)&&process.exit(1),{name:t.name}}let t=await y({initialValue:`npflared`,message:`Enter a name for your R2 bucket:`,validate(e){if(e.length===0)return`Please enter a name for your R2 bucket`}});m(t)&&process.exit(1),q.start(`Creating R2 bucket ${t}...`);let n=await V(t);q.stop();let[r]=n.r2_buckets;return r||(console.log(C.red(`Could not create R2 bucket ${t}`)),process.exit(1)),{name:r.bucket_name}},Z=async()=>{let e=await _({message:`Install dependencies with:`,options:[{value:`npm`,label:`npm`},{value:`pnpm`,label:`pnpm`},{value:`yarn`,label:`yarn`},{value:`bun`,label:`bun`}]});return m(e)&&process.exit(1),e},Q=async()=>{let e=await y({initialValue:`npflared`,message:`Enter a name for your worker:`,validate(e){if(e.length===0)return`Please enter a name for your worker`}});return m(e)&&process.exit(1),e},$=async e=>{q.start(`Generating admin token...`);let t=d(e,`migrations`,`9999_admin-token.sql`);if(!await G(t)){let e=E(b()),n=Date.now();return await c(t,`INSERT INTO token (token, name, scopes, created_at, updated_at) VALUES ('${e}', 'admin-token', '[{"type": "token:read+write", "values": ["*"]}, {"type": "user:read+write", "values": ["*"]}, {"type": "package:read+write", "values": ["*"]}]', ${n}, ${n});`),q.stop(`Admin token migration file generated at ${t}`),e}let n=await a(t,`utf-8`);return q.stop(`Admin token migration file already exists at ${t}`),n.match(/INSERT INTO token \(token, name, scopes, created_at, updated_at\) VALUES \('([^']+)'/)?.[0]??``},ee=async()=>{let e=await i(d(u(),`npflared-`)),t=()=>{e&&x(e,{recursive:!0,force:!0})};process.on(`exit`,t),process.on(`SIGINT`,t),process.on(`SIGTERM`,t);try{p(`npflared`);let t=T(`Thomascogez/npflared/apps/api`);q.start(`Cloning npflared...`),await t.clone(e);let n=d(e,`package.json`),r=JSON.parse(await a(n,`utf-8`)).version;await J();let i=d(K,r);await G(i)||await o(e,d(K,r)),q.stop(`Successfully cloned npflared (v${r})`);let s=await Q(),l=await Z();await P.run({packageManagerAgent:l},async()=>{q.start(`Installing dependencies using ${l}...`);let e=S(l,`install`);await D({quiet:!0,cwd:i})`${e.command} ${e.args.join(` `)}`,q.stop(`Successfully installed dependencies using ${l}`),q.start(`Retrieving Cloudflare account id...`);let t=await R();q.stop(),t?h.info(C.green(`Using cloudflare account id: ${C.bold.white(t)}`)):(h.error(C.red(`Could not retrieve Cloudflare account id, please login with ${C.bold.white(`wrangler login`)}`)),process.exit(1));let n=await Y(),r=await X();q.start(`Generating wrangler configuration...`);let a={name:s,main:`src/index.ts`,compatibility_date:`2024-11-24`,compatibility_flags:[`nodejs_compat`],d1_databases:[{binding:`DB`,database_name:n.name,database_id:n.id}],r2_buckets:[{binding:`BUCKET`,bucket_name:r.name}]},o=d(i,`wrangler.json`);await c(d(i,`wrangler.json`),JSON.stringify(a,null,2)),q.stop(`Wrangler configuration generated at ${o}`);let u=await $(i);q.start(`Applying D1 migrations...`),await U(n.name,{cwd:i}),q.stop(`Successfully applied D1 migrations`),q.start(`Deploying...`);let f=await W({cwd:i});q.stop(),h.info(C.green(w`
3
+ 🔥 npflared is now ready to use!
4
+ 🔗 Deployed to: ${C.bold.white(f)}
5
+ 👮 Admin token: ${C.bold.white(u)}
6
+ 📚 Check documentation for more information: ${C.bold.white(`https://npflared.thomas-cogez.fr`)}
7
+ `))}),g(`You're all set!`)}catch(e){h.error(`${e}`),process.exit(1)}finally{t()}};t(e(process.argv)).command(`install`,`Configure and deploy your own npflared instance on your cloudflare account`,e=>e,async()=>{await ee()}).command(`clean`,`Clean the local npflared folder`,e=>e,async()=>{await N()}).demandCommand(1).parse();export{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npflared/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "npflared": "./dist/index.mjs"
@@ -18,6 +18,7 @@
18
18
  "tsdown": "^0.19.0"
19
19
  },
20
20
  "dependencies": {
21
+ "@antfu/ni": "^28.1.0",
21
22
  "@clack/prompts": "^0.11.0",
22
23
  "chalk": "^5.6.2",
23
24
  "dedent": "^1.7.1",