create-instant-app 1.0.56 → 1.0.57
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/index.js +14 -14
- package/package.json +4 -5
package/dist/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as
|
|
3
|
-
Usage: npx create-instant-app my-app --yes`);return{...F,appName:n,base:ne(o)??F.base,ruleFiles:oe(o)??"claude",createRepo:o.git??F.createRepo,app:o.app??null,token:o.token??null,yes:!0,temporary:o.temp??!1}}if(o.ai&&!await
|
|
2
|
+
import{Command as Ve,Option as l}from"commander";import*as z from"@clack/prompts";import{spawn as Ue}from"child_process";import{execa as De}from"execa";async function V(){return new Promise(e=>{let t=process.env.SHELL||"/bin/bash",n=Ue(t,["-i","-c","which claude"],{stdio:["ignore","pipe","ignore"]}),o="";n.stdout.on("data",i=>{o+=i.toString()}),n.on("close",i=>{if(i===0){let a=o.trim();a.includes("aliased to ")?e(a.split("aliased to ")[1]||null):e(a)}else e(null)})})}var Z=async(e,t)=>{let n=await V();if(!n)throw new Error("Claude not found in path");await De(n,[e],{stdio:"inherit",cwd:t})};import{version as Ge}from"@instantdb/version";import Q from"path";var ee=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e),Le=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,te=e=>{let n=ee(e).split("/"),o=n[n.length-1];if(o==="."){let r=Q.resolve(process.cwd());o=Q.basename(r)}let i=n.findIndex(r=>r.startsWith("@"));n.findIndex(r=>r.startsWith("@"))!==-1&&(o=n.slice(i).join("/"));let a=n.filter(r=>!r.startsWith("@")).join("/");return[o,a]},j=e=>e.trim(),G=e=>{let t=ee(e),n=t.split("/"),o=n.findIndex(a=>a.startsWith("@")),i=n[n.length-1];if(n.findIndex(a=>a.startsWith("@"))!==-1&&(i=n.slice(o).join("/")),!(t==="."||Le.test(i??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};import{renderUnwrap as S,UI as g}from"instant-cli/ui";var h=(e="src/lib/db.ts")=>({type:"typescript",path:e,initializer:"init",websocket:!0}),R=(e="init")=>({type:"typescript",path:"src/lib/adminDb.ts",initializer:e,websocket:!1}),k={"next-js-app-dir":{appIdEnvName:"NEXT_PUBLIC_INSTANT_APP_ID",backendConfigFiles:[h()],bundled:!0},"vite-react":{appIdEnvName:"VITE_INSTANT_APP_ID",backendConfigFiles:[h()],bundled:!0},"vite-vanilla":{appIdEnvName:"VITE_INSTANT_APP_ID",backendConfigFiles:[h()],bundled:!0},expo:{appIdEnvName:"EXPO_PUBLIC_INSTANT_APP_ID",backendConfigFiles:[h("lib/db.ts")],bundled:!0},"tanstack-start":{appIdEnvName:"VITE_INSTANT_APP_ID",backendConfigFiles:[h(),R()],bundled:!0},"tanstack-start-with-tanstack-query":{appIdEnvName:"VITE_INSTANT_APP_ID",backendConfigFiles:[h(),R()],bundled:!1},"bun-react":{appIdEnvName:"BUN_PUBLIC_INSTANT_APP_ID",backendConfigFiles:[h()],bundled:!1},"solidjs-vite":{appIdEnvName:"VITE_INSTANT_APP_ID",backendConfigFiles:[h()],bundled:!1},sveltekit:{appIdEnvName:"VITE_INSTANT_APP_ID",backendConfigFiles:[h()],bundled:!0},"vue-vite":{appIdEnvName:"VITE_INSTANT_APP_ID",backendConfigFiles:[h()],bundled:!0},"vercel-ai-sdk":{appIdEnvName:"NEXT_PUBLIC_INSTANT_APP_ID",backendConfigFiles:[h(),R("initAdmin")],bundled:!1},"ai-chat":{appIdEnvName:"NEXT_PUBLIC_INSTANT_APP_ID",backendConfigFiles:[h(),R()],bundled:!1},"python-script":{appIdEnvName:"INSTANT_APP_ID",backendConfigFiles:[{type:"python",path:"main.py"}],bundled:!0}},W=Object.keys(k),Lt=W.filter(e=>k[e].bundled);var F={base:"next-js-app-dir",appName:"Awesome Todos",ruleFiles:null,createRepo:!0,prompt:null,app:null,token:null,yes:!1,temporary:!1},ne=e=>e.base||e.viteReact&&"vite-react"||e.vanilla&&"vite-vanilla"||e.next&&"next-js-app-dir"||e.expo&&"expo"||e.sv&&"sveltekit"||e.vue&&"vue-vite"||e.python&&"python-script"||null,oe=e=>e.cursor&&"cursor"||e.claude&&"claude"||e.codex&&"codex"||e.gemini&&"gemini"||e.rules&&"codex"||null,re=async()=>{let e=F,t=new Ve().name("Create Instant App").description("A CLI for creating web/mobile applications with InstantDB").argument("[dir]","The name of the application, as well as the name of the directory to create").addOption(new l("-b --base <template>","The base template to scaffold from").choices(W)).addOption(new l("-g --git","Create a git repo in the new project").default(!0)).addOption(new l("--expo","Use the Expo starter template").default(!1)).addOption(new l("--next","Use the NextJS starter template").default(!1)).addOption(new l("--vanilla","Use the vanilla JS starter template").default(!1)).addOption(new l("--vite-react","Use the Vite + React starter template").default(!1)).addOption(new l("--sv","Use the SvelteKit starter template").default(!1)).addOption(new l("--vue","Use the Vue + Vite starter template").default(!1)).addOption(new l("--python","Use the Python script starter template").default(!1)).addOption(new l("--no-git","Don't create a git repo in the new project")).addOption(new l("--cursor","Include a Cursor rules file in the scaffold")).addOption(new l("--claude","Include a CLAUDE.md file in the scaffold")).addOption(new l("--codex","Include an AGENTS.md file in the scaffold")).addOption(new l("--gemini","Include a GEMINI.md file in the scaffold")).addOption(new l("--rules","Include an AGENTS.md file in the scaffold")).addOption(new l("--ai","Create a new InstantDB app based off of a prompt. (requires Claude Code)")).addOption(new l("-a --app <app-id>","Link to an existing InstantDB app by ID (requires login or --token)")).addOption(new l("-t --token <token>","Auth token override (use with --app when not logged in)")).addOption(new l("-y --yes","Use all defaults (requires project name as first argument)").default(!1)).addOption(new l("--temp","Create a temporary app by default").default(!1)).version(Ge).parse(process.argv),n=t.args[0]&&j(t.args[0]);if(n){let a=G(n);if(a)throw new Error("Invalid app name: "+a);e.appName=n}let o=t.opts();if(o.app&&o.temp)throw new Error("--app and --temp cannot be used together");if(o.yes){if(o.ai)throw new Error("--yes is not supported with --ai");if(!n)throw new Error(`When using --yes, you must specify a project name as the first argument.
|
|
3
|
+
Usage: npx create-instant-app my-app --yes`);return{...F,appName:n,base:ne(o)??F.base,ruleFiles:oe(o)??"claude",createRepo:o.git??F.createRepo,app:o.app??null,token:o.token??null,yes:!0,temporary:o.temp??!1}}if(o.ai&&!await V())throw new Error("--ai only works with Claude Code, but we couldn't find it in your machine. Install it first, and run it again : ). Alternatively you can scaffold out a project without --ai");return{...await z.group({appName:async()=>{if(n)return n.trim();let a=await S(new g.TextInput({prompt:"What will your project/folder be called?",placeholder:"awesome-todos",defaultValue:"awesome-todos",validate:s=>G(j(s)),modifyOutput:g.ciaModifier()}));return j(a)},prompt:async()=>o.ai?await S(new g.TextInput({prompt:"What would you like to create?",placeholder:"Create an app that...",modifyOutput:g.modifiers.piped([g.ciaModifier()])})):null,base:async({results:a})=>{let r=ne(o);return r||(a.prompt?S(new g.Select({promptText:"What framework would you like to use?",options:[{value:"next-js-app-dir",label:"Web: Next.js"},{value:"vite-react",label:"Web: Vite React"},{value:"expo",label:"Mobile: Expo"}],defaultValue:"next-js-app-dir",modifyOutput:g.modifiers.piped([g.ciaModifier()])})):S(new g.Select({promptText:"What framework would you like to use?",options:[{value:"next-js-app-dir",label:"Web: Next.js"},{value:"expo",label:"Mobile: Expo"},{value:"vite-react",label:"Vite: React",secondary:!0},{value:"vite-vanilla",label:"Vite: Vanilla TS",secondary:!0},{value:"tanstack-start",label:"Tanstack Start",secondary:!0},{value:"bun-react",label:"Bun + React",secondary:!0},{value:"solidjs-vite",label:"Vite: SolidJS",secondary:!0},{value:"sveltekit",label:"SvelteKit",secondary:!0},{value:"vue-vite",label:"Vite: Vue",secondary:!0},{value:"vercel-ai-sdk",label:"Vercel AI SDK App Builder + SSR",secondary:!0},{value:"ai-chat",label:"Vercel AI SDK Chat App",secondary:!0},{value:"python-script",label:"Python: Script",secondary:!0}],defaultValue:"next-js-app-dir",modifyOutput:g.modifiers.piped([g.ciaModifier()])})))},ruleFiles:async({results:a})=>{if(a.prompt)return"claude";let r=oe(o);return r||S(new g.Select({promptText:"Which AI tool would you like to add rule files for?",options:[{value:"claude",label:"Claude"},{value:"cursor",label:"Cursor"},{value:"codex",label:"Codex"},{value:"gemini",label:"Gemini"},{value:"zed",label:"Zed"},{value:"windsurf",label:"Windsurf"},{value:null,label:"None"}],defaultValue:"claude",modifyOutput:g.ciaModifier()}))},createRepo:async()=>o.git!==void 0?o.git:!0,temporary:async()=>o.temp??!1},{onCancel(){process.exit(1)}}),app:o.app??null,token:o.token??null,yes:!1}};import X from"path";import L from"fs-extra";import{log as $e,outro as jt}from"@clack/prompts";import{intro as We}from"@clack/prompts";import ae from"chalk";var ze=` _ _ _
|
|
4
4
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 (_) | | | |
|
|
5
5
|
\u2588 \u2588\u2588\u2588\u2588 _ _ __ ___| |_ __ _ _ _ _| |_
|
|
6
6
|
\u2588 \u2588\u2588\u2588\u2588 | | '_ \\/ __| __/ _\\\`| '_ \\| __|
|
|
7
7
|
\u2588 \u2588\u2588\u2588\u2588 | | | | \\__ \\ || (_| | | | | |_
|
|
8
|
-
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 |_|_| |_|___/\\__\\__,_|_| |_|\\__|`,ie=()=>{
|
|
9
|
-
`+
|
|
8
|
+
\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 |_|_| |_|___/\\__\\__,_|_| |_|\\__|`,ie=()=>{We(`
|
|
9
|
+
`+ze.split(`
|
|
10
10
|
`).map(e=>`${ae.gray("\u2502")}${ae.hex("#EA580D").bold(" "+e)}`).join(`
|
|
11
|
-
`))};import m from"path";import
|
|
12
|
-
enable-pre-post-scripts=true`),e.base==="expo"){let a=
|
|
13
|
-
Using git to clone from main...`),w.ciaModifier(null)),await
|
|
11
|
+
`))};import m from"path";import Ye from"tiged";import d from"fs-extra";import se from"path";import{fileURLToPath as Je}from"url";var He=Je(import.meta.url),Ke=se.dirname(He),$=se.join(Ke,"../");import _ from"chalk";var B=e=>{if(e==="bun-react")return"bun";let t=process.env.npm_config_user_agent;return t?t.startsWith("yarn")?"yarn":t.startsWith("pnpm")?"pnpm":t.startsWith("bun")?"bun":"npm":"npm"};import{renderUnwrap as pe,UI as w}from"instant-cli/ui";import Xe from"slugify";import qe from"ignore";var le=async(e,t)=>{let n=m.resolve(process.cwd(),t);if(d.existsSync(n))if(d.readdirSync(n).length===0)w.log(`${_.cyan.bold(e.appName)} exists but is empty, continuing...`,w.ciaModifier(null));else{let a=await pe(new w.Select({promptText:_.redBright(`${_.bold("Warning:")} ${_.bold(e.appName)} already exists and isn't empty. How would you like to proceed?`),options:[{label:"Abort installation",value:"abort"},{label:"Clear the directory and continue installation",value:"clear"}],defaultValue:"abort",modifyOutput:w.ciaModifier()}));a==="abort"&&(w.log("Aborting installation..."),process.exit(1)),a==="clear"&&d.emptyDirSync(n)}let o=et({projectDir:n,baseTemplateName:e.base}),i=e.appName==="."?"App":_.hex("#EA570B").bold(e.appName);if(await pe(new w.Spinner({promise:o,workingText:"Scaffolding project files...",doneText:`Successfully scaffolded ${i}!`,errorText:"Error scaffolding project files",modifyOutput:w.ciaModifier(null)})),d.pathExistsSync(m.join(n,"pnpm-lock.yaml"))&&d.removeSync(m.join(n,"pnpm-lock.yaml")),d.pathExistsSync(m.join(n,"bun.lock"))&&d.removeSync(m.join(n,"bun.lock")),B(e.base)==="pnpm"&&e.base==="expo"&&await d.appendFile(m.join(n,".npmrc"),`node-linker=hoisted
|
|
12
|
+
enable-pre-post-scripts=true`),e.base==="expo"){let a=Xe.default(t);J(m.join(n,"app.json"),'"name": "expo-template"',`"name": "${t}"`),J(m.join(n,"app.json"),'"slug": "expo-template"',`"slug": "${a}"`),J(m.join(n,"app/_layout.tsx"),'"My Instant App"',`"${t}"`)}return n},J=(e,t,n)=>{let i=d.readFileSync(e,"utf8").replaceAll(t,n);d.writeFileSync(e,i)},Ze=async({projectDir:e,baseTemplateName:t})=>{let n=`instantdb/instant/examples/${t}`;await Ye(n,{mode:"tar",disableCache:!0}).clone(e)};async function Qe(e,t){let n=qe();n.add(".git");try{let o=m.join(e,".gitignore"),i=await d.readFile(o,"utf8");n.add(i)}catch{}await d.copy(e,t,{filter:o=>{let i=m.relative(e,o);return i===""?!0:!n.ignores(i)}})}var et=async({projectDir:e,baseTemplateName:t})=>{let n=m.join($,`template/base/${t}`),o=!!process.env.INSTANT_CLI_DEV&&!!process.env.INSTANT_REPO_FOLDER,i=d.pathExistsSync(n),a=o?"dev":i?"bundled-template":"tiged";if(a==="bundled-template"){d.copySync(n,e);let r=m.join(e,"_gitignore"),s=m.join(e,".gitignore");d.pathExistsSync(r)&&d.renameSync(r,s);return}if(a==="dev"){let r=process.env.INSTANT_REPO_FOLDER;if(!r)throw new Error("INSTANT_REPO_FOLDER is required when using repo-examples scaffolding.");let s=m.join(r,"examples",t);await Qe(s,e);return}process.env.INSTANT_CLI_DEV&&!process.env.INSTANT_REPO_FOLDER&&w.log(_.bold.yellowBright(`WARNING: INSTANT_CLI_DEV is TRUE but no INSTANT_REPO_FOLDER is set.
|
|
13
|
+
Using git to clone from main...`),w.ciaModifier(null)),await Ze({projectDir:e,baseTemplateName:t})};import{execa as tt}from"execa";import{renderUnwrap as nt,UI as M}from"instant-cli/ui";var ce=async(e,t)=>{let n=tt(e,["install"],{cwd:t}),o=await nt(new M.Spinner({promise:n,workingText:`Installing dependencies with ${e}...`,doneText:"Successfully installed dependencies!",modifyOutput:M.ciaModifier(null)}));o.exitCode!==0&&(M.log(o.stderr,M.ciaModifier(null)),process.exit(1))};import Be from"chalk";import ot from"fs-extra";import de from"path";var rt={claude:"CLAUDE.md",gemini:"GEMINI.md",cursor:"AGENTS.md",codex:"AGENTS.md",zed:"AGENTS.md",windsurf:"AGENTS.md"},ue=({projectDir:e,ruleFilesToAdd:t})=>{t!==null&&ot.copyFileSync(de.join($,"template/rules/AGENTS.md"),de.join(e,rt[t]))};import{execSync as K}from"child_process";import H from"path";import*as fe from"@clack/prompts";import U from"chalk";import{execa as v}from"execa";import ge from"fs-extra";import{renderUnwrap as me,UI as x}from"instant-cli/ui";var at=e=>{try{return K("git --version",{cwd:e}),!0}catch{return!1}},it=e=>ge.existsSync(H.join(e,".git")),st=async e=>{try{return await v("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},pt=()=>{let t=K("git --version").toString().trim().split(" ")[2],n=t?.split(".")[0],o=t?.split(".")[1];return{major:Number(n),minor:Number(o)}},lt=()=>K("git config --global init.defaultBranch || echo main").toString().trim(),he=async e=>{if(!at(e)){fe.log.warn("Git is not installed. Skipping Git initialization.");return}let t=it(e),n=await st(e),o=H.parse(e).name;if(n&&t){if(!await me(new x.Confirmation({promptText:`${U.redBright.bold("Warning:")} Git is already initialized in "${o}". Initializing a new git repository would delete the previous history. Would you like to continue anyways?`,defaultValue:!1,modifyOutput:x.ciaModifier()})))return;ge.removeSync(H.join(e,".git"))}else if(n&&!t&&!await me(new x.Confirmation({promptText:`${U.redBright.bold("Warning:")} "${o}" is already in a git worktree.
|
|
14
14
|
Would you still like to initialize a new git repository in this directory?
|
|
15
|
-
`,defaultValue:!1,modifyOutput:
|
|
16
|
-
INSTANT_APP_ADMIN_TOKEN=${o}`;
|
|
17
|
-
`),a=!0;i.forEach(r=>{if(r.length===0){a?(t(""),a=!1):console.log(
|
|
15
|
+
`,defaultValue:!1,modifyOutput:x.ciaModifier()})))return;try{let i=lt(),{major:a,minor:r}=pt();a<2||a==2&&r<28?(await v("git",["init"],{cwd:e}),await v("git",["symbolic-ref","HEAD",`refs/heads/${i}`],{cwd:e})):await v("git",["init",`--initial-branch=${i}`],{cwd:e}),await v("git",["add","."],{cwd:e}),await v("git",["commit","-m","Initial commit (create-instant-app)"],{cwd:e}),x.log(U.dim(`${U.green("\u2713")} Git repository initialized successfully.`),x.ciaModifier(null))}catch{}};import dt from"open";import{randomUUID as be}from"node:crypto";import{version as ct}from"@instantdb/version";var ye=!!process.env.INSTANT_CLI_DEV,we=process.env.INSTANT_CLI_DASH_URI||(ye?"http://localhost:3000":"https://instantdb.com"),N=process.env.INSTANT_CLI_API_URI||(ye?"http://localhost:8888":"https://api.instantdb.com");async function b({path:e,body:t,method:n="GET",authToken:o,metadata:i}){let r={"Content-Type":"application/json","X-Instant-Source":"create-instant-app","X-Instant-Version":ct,"X-Instant-Command":"create"};o&&(r.Authorization=`Bearer ${o}`),i&&(r["X-Instant-Metadata"]=JSON.stringify(i));let s=await fetch(`${N}${e}`,{method:n??"GET",headers:r,body:t?JSON.stringify(t):void 0,signal:AbortSignal.timeout(3e5)}),p;try{p=await s.json()}catch{p=null}if(!s.ok){let c=p.message||p.hint?.errors?.[0]?.message||"There was an error";throw new Error(c)}return p}import{renderUnwrap as C,UI as u}from"instant-cli/ui";import{readAuthToken as ut,writeAuthToken as mt}from"instant-cli/auth";function T(e){return e.replace(/[-_]/g," ").replace(/\b\w/g,t=>t.toUpperCase())}var ft=!!process.env.INSTANT_CLI_FORCE_EPHEMERAL,Te=async(e,t,n,o)=>{let i=be(),a=be(),r={id:i,title:e,admin_token:a,org_id:n};return o?.rules&&(r.rules=o.rules),o?.schema&&(r.schema=o.schema),await b({method:"POST",authToken:t,path:"/dash/apps",body:r,metadata:o}),{appId:i,adminToken:a,source:"created"}},Y=(e,t,n)=>{b({method:"POST",path:`/dash/apps/${e}/track-import`,authToken:t,metadata:n}).catch(()=>{})},Ie=async e=>await b({method:"GET",path:"/dash",authToken:e}),ke=async(e,t)=>await b({method:"GET",path:`/dash/orgs/${t}`,authToken:e});var gt=async(e,t)=>{try{let n=await Ie(e),o=n.apps.find(i=>i.id===t);if(o)return{appId:o.id,adminToken:o.admin_token};for(let i of n.orgs){let{apps:a}=await ke(e,i.id),r=a.find(s=>s.id===t);if(r)return{appId:r.id,adminToken:r.admin_token}}return null}catch{return null}},ht=async(e,t)=>{try{return await b({method:"GET",path:`/dash/apps/${e}/schema/pull`,authToken:t}),!0}catch{return!1}},yt=async()=>ft?null:process.env.INSTANT_CLI_AUTH_TOKEN?process.env.INSTANT_CLI_AUTH_TOKEN:ut(N).catch(()=>null),D=async(e,t)=>{let n=await b({authToken:null,method:"POST",path:"/dash/apps/ephemeral",body:{title:e,schema:t?.schema,rules:{$users:{view:"true"},$files:{allow:{view:"true",create:"true",delete:"true"}}}},metadata:t});return{appId:n.app.id,adminToken:n.app["admin-token"]}},_e=async(e,t,n)=>{let o=await yt();if(t?.yes&&!t?.app)if(o&&!t.temporary){let{appId:s,adminToken:p}=await Te(T(e),o,void 0,n);return{appId:s,adminToken:p,approach:"create"}}else{let{appId:s,adminToken:p}=await D(T(e),n);return{appId:s,adminToken:p,approach:"ephemeral"}}if(t?.temporary){let s=await C(new u.TextInput({defaultValue:T(e),prompt:"Enter a name for your temporary app:",placeholder:T(e),modifyOutput:u.ciaModifier()}));return{...await D(s,n),approach:"ephemeral"}}if(t?.app){if(t.token){if(!await ht(t.app,t.token))throw new Error("Invalid app ID and token combination. Please verify both the app ID and token are correct.");return u.log(`Linking to app: ${t.app}`,u.ciaModifier(null)),Y(t.app,t.token,n),{appId:t.app,adminToken:t.token,approach:"import"}}if(o){let s=await gt(o,t.app);if(!s)throw new Error(`You don't have access to app "${t.app}". Please check the app ID or use --token to provide a token.`);return u.log(`Linking to app: ${t.app}`,u.ciaModifier(null)),Y(s.appId,o,n),{appId:s.appId,adminToken:s.adminToken,approach:"import"}}throw new Error(`You must be logged in or provide --token when using --app. Either run 'npx instant-cli login' first, or use: --app ${t.app} --token <token>`)}if(!o){let s=await C(new u.Select({promptText:"You are not logged in.",options:[{label:"Login to your Instant account",value:"login"},{label:"Create a temporary app",value:"ephemeral"},{label:"Create an app later",value:"skip"}],modifyOutput:u.ciaModifier()}));if(s==="login"){let p=await b({authToken:null,method:"POST",path:"/dash/cli/auth/register"}).catch(Me=>{throw new Error("Failed to register",{cause:Me})}),{secret:c,ticket:y}=p;dt(`${we}/dash?ticket=${y}`);let A=bt({secret:c}),q=await C(new u.Spinner({promise:A,workingText:"Waiting for login in browser",disappearWhenDone:!0,modifyOutput:u.ciaModifier(null)}));await Tt(q.token),o=q.token}if(s==="skip")return u.log("Skipping app link step",u.ciaModifier(null)),null;if(s==="ephemeral"){let p=await C(new u.TextInput({defaultValue:T(e),prompt:"Enter a name for your temporary app:",placeholder:T(e),modifyOutput:u.ciaModifier()}));return{...await D(p,n),approach:"ephemeral"}}}if(!o)return null;let i=await Ie(o).catch(s=>{throw new Error("Failed to fetch dashboard",{cause:s})}),a=i.orgs.filter(s=>s.role!=="app-member");i.orgs=a;let r=await C(new u.AppSelector({startingMenuIndex:0,defaultAppName:T(e),allowCreate:!0,allowEphemeral:!0,api:{getDash(){return i},createEphemeralApp(s){return D(s,n)},getAppsForOrg:async s=>{let{apps:p}=await ke(o,s);return{apps:p}},createApp:async(s,p)=>{let{appId:c,adminToken:y}=await Te(s,o,p,n);return{appId:c,adminToken:y}}},modifyOutput:u.ciaModifier()}));return r?.approach==="import"&&Y(r.appId,o,n),r};function wt(e){return new Promise(t=>setTimeout(t,e))}async function bt({secret:e}){for(let t=1;t<=120;t++){await wt(1e3);let n=await fetch(`${N}/dash/cli/auth/check`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({secret:e})});if(!(!n.ok&&(await n.json()).hint.errors?.[0]?.issue==="waiting-for-user")&&n.ok)return n.json()}throw new Error("Timed out waiting for login")}async function Tt(e){return mt(N,e)}import It from"fs-extra";import kt from"path";var xe=(e,t,n,o)=>{let i=kt.join(t,".env"),r=`${k[e].appIdEnvName}=${n}
|
|
16
|
+
INSTANT_APP_ADMIN_TOKEN=${o}`;It.writeFileSync(i,r)};import{stdin as I,stdout as ve}from"process";import{setRawModeWindowsFriendly as Pe}from"instant-cli/ui";async function _t(){return new Promise(e=>{if(!ve.isTTY||!I.isTTY){e(null);return}let t=I.isRaw;t||Pe(I,!0);let n=setTimeout(()=>{i(),e(null)},100),o="",i=()=>{clearTimeout(n),I.removeListener("data",a),!t&&I.isTTY&&Pe(I,!1)},a=r=>{let s=r.toString();o+=s;let p=o.match(/\x1b\]11;rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)(?:\x1b\\|\x07)/);if(p){i();let[,c,y,A]=p;e(`rgb:${c}/${y}/${A}`)}};I.on("data",a),ve.write("\x1B]11;?\x1B\\")})}function xt(e){let t=e.match(/rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)/);if(!t)return null;let[,n,o,i]=t,a=Math.round(parseInt(n,16)/257),r=Math.round(parseInt(o,16)/257),s=Math.round(parseInt(i,16)/257);return{r:a,g:r,b:s}}function vt(e){return(.299*e.r+.587*e.g+.114*e.b)/255>.5}async function Ae(){try{let e=await _t();if(!e)return"unknown";let t=xt(e);return t?vt(t)?"light":"dark":"unknown"}catch(e){return console.error("Error detecting terminal theme:",e),"unknown"}}import E from"chalk";var f=(e,t)=>e==="light"?E.bgYellowBright(t):E.bgBlackBright(t),Se=(e,t=console.log,n=!1)=>{let o=(process.stdout.columns||80)-4,i=e.split(`
|
|
17
|
+
`),a=!0;i.forEach(r=>{if(r.length===0){a?(t(""),a=!1):console.log(E.gray("\u2502"));return}for(let s=0;s<r.length;s+=o){let p=r.slice(s,s+o);s+o<r.length&&p.length===o&&(p=p+"-"),a?(t(p),a=!1):console.log(E.gray("\u2502 ")+p)}}),n&&console.log(E.gray("\u2502"))};var O="\x1B[?25h";import{execa as Rt}from"execa";import Ne from"fs-extra";import{permsTypescriptFileToCode as Pt,schemaTypescriptFileToInstantSchema as At}from"@instantdb/platform";function Ce(e){for(let t of["src/instant.perms.ts","instant.perms.ts"])try{let n=Ne.readFileSync(`${e}/${t}`,"utf8");return{code:Pt(n,t)}}catch{}return null}function Ee(e){for(let t of["src/instant.schema.ts","instant.schema.ts"])try{let n=Ne.readFileSync(`${e}/${t}`,"utf8");return At(n,t)}catch{}return null}import{UI as P}from"instant-cli/ui";var Oe=e=>{if(e){if(e.approach==="import"){P.log(`Imported app with App ID: ${e.appId}`,P.ciaModifier());return}e.approach==="create"&&P.log(`Created new app with App ID: ${e.appId}`,P.ciaModifier()),e.approach==="ephemeral"&&P.log(`Created temporary app with App ID: ${e.appId}`,P.ciaModifier())}};import je from"fs-extra";import St from"path";var Re=e=>e.replace(/\/+$/,""),Nt=e=>{let t;try{t=new URL(Re(e))}catch{throw new Error("INSTANT_CLI_API_URI must be a valid HTTP(S) URL")}if(t.protocol==="http:")t.protocol="ws:";else if(t.protocol==="https:")t.protocol="wss:";else throw new Error("INSTANT_CLI_API_URI must be a valid HTTP(S) URL");return t.pathname=`${t.pathname.replace(/\/+$/,"")}/runtime/session`,t.search="",t.hash="",t.toString()},Ct=({contents:e,initializer:t,apiURI:n,websocketURI:o})=>{let i=`${t}({`;if(!e.includes(i))throw new Error(`Could not find ${i} in scaffolded database file`);let a=[` apiURI: ${JSON.stringify(n)},`,o?` websocketURI: ${JSON.stringify(o)},`:null].filter(Boolean).join(`
|
|
18
18
|
`);return e.replace(i,`${i}
|
|
19
|
-
${a}`)}
|
|
19
|
+
${a}`)},Et=(e,t)=>{let n="db = Instant()";if(!e.includes(n))throw new Error(`Could not find ${n} in scaffolded database file`);return e.replace(n,`db = Instant(api_uri=${JSON.stringify(t)})`)},Ot=(e,t,n,o)=>e.type==="python"?Et(t,n):Ct({contents:t,initializer:e.initializer,apiURI:n,websocketURI:e.websocket?o:void 0}),Fe=(e,t,n)=>{let o=Re(n),i=Nt(o),a=k[e].backendConfigFiles.map(r=>{let s=St.join(t,r.path),p=je.readFileSync(s,"utf8");return{filePath:s,contents:Ot(r,p,o,i)}});for(let r of a)je.writeFileSync(r.filePath,r.contents)};var Ft=async()=>{process.argv.some(c=>["-h","--help","--version","-V"].includes(c))||ie();let e=await Ae(),t=await re(),[n,o]=te(t.appName),i=t.base==="python-script",a=B(t.base),r=await le(t,o);process.env.INSTANT_CLI_API_URI&&Fe(t.base,r,process.env.INSTANT_CLI_API_URI),ue({projectDir:r,ruleFilesToAdd:t.ruleFiles});let s={template:t.base,aiTool:t.ruleFiles??"none",usedAiPrompt:!!t.prompt,rules:Ce(r),schema:Ee(r)},p=await _e(o==="."?n:o,t,s);if(Oe(p),p&&xe(t.base,r,p.appId,p.adminToken),i){let c=n.replace(/^@/,"").replace(/\//g,"-"),y=X.join(r,"pyproject.toml"),A=L.readFileSync(y,"utf-8");L.writeFileSync(y,A.replace(/^name = .*$/m,`name = "${c}"`))}else{let c=L.readJSONSync(X.join(r,"package.json"));if(c.name=n,a!=="bun"){let{stdout:y}=await Rt(a,["-v"],{cwd:r});c.packageManager=`${a}@${y.trim()}`}L.writeJSONSync(X.join(r,"package.json"),c,{spaces:2}),await ce(a,r)}if(t.createRepo&&await he(r),t.prompt&&(await Z(t.prompt,r),process.stdout.write(O)),jt("Done!"),i)p?(console.log(`
|
|
20
20
|
\u{1F389} Success! Your project is ready to go!
|
|
21
21
|
|
|
22
22
|
To get started:
|
|
@@ -34,7 +34,7 @@ ${a}`)},$t=(e,t)=>{let n="db = Instant()";if(!e.includes(n))throw new Error(`Cou
|
|
|
34
34
|
|
|
35
35
|
To get started:
|
|
36
36
|
1. ${f(e,"cd "+o)}
|
|
37
|
-
2. Create a new app on ${
|
|
37
|
+
2. Create a new app on ${Be.underline("www.instantdb.com")}
|
|
38
38
|
3. Add your APP_ID and admin token to the .env file
|
|
39
39
|
4. ${f(e,"uv sync")}
|
|
40
40
|
5. ${f(e,"uv run python main.py")}
|
|
@@ -55,7 +55,7 @@ ${a}`)},$t=(e,t)=>{let n="db = Instant()";if(!e.includes(n))throw new Error(`Cou
|
|
|
55
55
|
|
|
56
56
|
To get started:
|
|
57
57
|
1. ${f(e,"cd "+o)}
|
|
58
|
-
2. Create a new app on ${
|
|
58
|
+
2. Create a new app on ${Be.underline("www.instantdb.com")}
|
|
59
59
|
3. Add your APP_ID to the .env file
|
|
60
60
|
4. ${f(e,a+" run "+c)}
|
|
61
|
-
`)}process.stdout.write(
|
|
61
|
+
`)}process.stdout.write(O),process.exit(0)};Ft().catch(e=>{$e.error("Aborting installation..."),Se(e.message,$e.error),process.stdout.write(O),process.exit(1)});process.on("SIGINT",()=>{process.stdout.write(O),process.exit(0)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-instant-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.57",
|
|
4
4
|
"description": "Scaffold a new web/mobile app with InstantDB",
|
|
5
5
|
"homepage": "https://github.com/instantdb/instant/tree/main/client/packages/create-instant-app",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,6 @@
|
|
|
25
25
|
"@ianvs/prettier-plugin-sort-imports": "^4.2.1",
|
|
26
26
|
"chalk": "5.2.0",
|
|
27
27
|
"commander": "^10.0.1",
|
|
28
|
-
"env-paths": "^3.0.0",
|
|
29
28
|
"execa": "^7.2.0",
|
|
30
29
|
"fs-extra": "^11.3.1",
|
|
31
30
|
"gradient-string": "^2.0.2",
|
|
@@ -35,9 +34,9 @@
|
|
|
35
34
|
"slugify": "^1.6.6",
|
|
36
35
|
"sort-package-json": "^2.10.0",
|
|
37
36
|
"tiged": "^2.12.7",
|
|
38
|
-
"@instantdb/
|
|
39
|
-
"
|
|
40
|
-
"
|
|
37
|
+
"@instantdb/platform": "1.0.57",
|
|
38
|
+
"instant-cli": "1.0.57",
|
|
39
|
+
"@instantdb/version": "1.0.57"
|
|
41
40
|
},
|
|
42
41
|
"devDependencies": {
|
|
43
42
|
"@anthropic-ai/sdk": "^0.60.0",
|