create-instant-app 1.0.66 → 1.0.67

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.js +15 -13
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import{Command as Ge,Option as c}from"commander";import*as z from"@clack/prompts";import{spawn as De}from"child_process";import{execa as Le}from"execa";async function V(){return new Promise(e=>{let t=process.env.SHELL||"/bin/bash",n=De(t,["-i","-c","which claude"],{stdio:["ignore","pipe","ignore"]}),o="";n.stdout.on("data",a=>{o+=a.toString()}),n.on("close",a=>{if(a===0){let i=o.trim();i.includes("aliased to ")?e(i.split("aliased to ")[1]||null):e(i)}else e(null)})})}var Q=async(e,t)=>{let n=await V();if(!n)throw new Error("Claude not found in path");await Le(n,[e],{stdio:"inherit",cwd:t})};import{version as We}from"@instantdb/version";import ee from"path";var te=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e),Ve=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,ne=e=>{let n=te(e).split("/"),o=n[n.length-1];if(o==="."){let r=ee.resolve(process.cwd());o=ee.basename(r)}let a=n.findIndex(r=>r.startsWith("@"));n.findIndex(r=>r.startsWith("@"))!==-1&&(o=n.slice(a).join("/"));let i=n.filter(r=>!r.startsWith("@")).join("/");return[o,i]},j=e=>e.trim(),G=e=>{let t=te(e),n=t.split("/"),o=n.findIndex(i=>i.startsWith("@")),a=n[n.length-1];if(n.findIndex(i=>i.startsWith("@"))!==-1&&(a=n.slice(o).join("/")),!(t==="."||Ve.test(a??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};import{renderUnwrap as A,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),Vt=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},oe=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,re=e=>e.cursor&&"cursor"||e.claude&&"claude"||e.codex&&"codex"||e.gemini&&"gemini"||e.rules&&"codex"||null,ae=async()=>{let e=F,t=new Ge().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 c("-b --base <template>","The base template to scaffold from").choices(W)).addOption(new c("-g --git","Create a git repo in the new project").default(!0)).addOption(new c("--expo","Use the Expo starter template").default(!1)).addOption(new c("--next","Use the NextJS starter template").default(!1)).addOption(new c("--vanilla","Use the vanilla JS starter template").default(!1)).addOption(new c("--vite-react","Use the Vite + React starter template").default(!1)).addOption(new c("--sv","Use the SvelteKit starter template").default(!1)).addOption(new c("--vue","Use the Vue + Vite starter template").default(!1)).addOption(new c("--python","Use the Python script starter template").default(!1)).addOption(new c("--no-git","Don't create a git repo in the new project")).addOption(new c("--cursor","Include a Cursor rules file in the scaffold")).addOption(new c("--claude","Include a CLAUDE.md file in the scaffold")).addOption(new c("--codex","Include an AGENTS.md file in the scaffold")).addOption(new c("--gemini","Include a GEMINI.md file in the scaffold")).addOption(new c("--rules","Include an AGENTS.md file in the scaffold")).addOption(new c("--ai","Create a new InstantDB app based off of a prompt. (requires Claude Code)")).addOption(new c("-a --app <app-id>","Link to an existing InstantDB app by ID (requires login or --token)")).addOption(new c("-t --token <token>","Auth token override (use with --app when not logged in)")).addOption(new c("-y --yes","Use all defaults (requires project name as first argument)").default(!1)).addOption(new c("--temp","Create a temporary app by default").default(!1)).version(We).parse(process.argv),n=t.args[0]&&j(t.args[0]);if(n){let i=G(n);if(i)throw new Error("Invalid app name: "+i);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:oe(o)??F.base,ruleFiles:re(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 i=await A(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(i)},prompt:async()=>o.ai?await A(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:i})=>{let r=oe(o);return r||(i.prompt?A(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()])})):A(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:i})=>{if(i.prompt)return"claude";let r=re(o);return r||A(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 q from"path";import L from"fs-extra";import{log as Be,outro as Rt}from"@clack/prompts";import{intro as ze}from"@clack/prompts";import ie from"chalk";var Je=` _ _ _
2
+ import{Command as Ge,Option as c}from"commander";import*as z from"@clack/prompts";import{spawn as Me}from"child_process";import{execa as Le}from"execa";async function V(){return new Promise(e=>{let t=process.env.SHELL||"/bin/bash",n=Me(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 Q=async(e,t)=>{let n=await V();if(!n)throw new Error("Claude not found in path");await Le(n,[e],{stdio:"inherit",cwd:t})};import{version as We}from"@instantdb/version";import ee from"path";var te=e=>(e.length>1&&e.endsWith("/")&&(e=e.slice(0,-1)),e),Ve=/^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/,ne=e=>{let n=te(e).split("/"),o=n[n.length-1];if(o==="."){let r=ee.resolve(process.cwd());o=ee.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]},O=e=>e.trim(),G=e=>{let t=te(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==="."||Ve.test(i??"")))return"App name must consist of only lowercase alphanumeric characters, '-', and '_'"};import{renderUnwrap as A,UI as g}from"instant-cli/ui";var h=(e="src/lib/db.ts",t={})=>({type:"typescript",path:e,initializer:"init",websocket:!0,injectDevtoolConfig:t.injectDevtoolConfig??!0}),R=(e="init")=>({type:"typescript",path:"src/lib/adminDb.ts",initializer:e,websocket:!1,injectDevtoolConfig:!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",{injectDevtoolConfig:!1})],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),Vt=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},oe=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,re=e=>e.cursor&&"cursor"||e.claude&&"claude"||e.codex&&"codex"||e.gemini&&"gemini"||e.rules&&"codex"||null,ae=async()=>{let e=F,t=new Ge().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 c("-b --base <template>","The base template to scaffold from").choices(W)).addOption(new c("-g --git","Create a git repo in the new project").default(!0)).addOption(new c("--expo","Use the Expo starter template").default(!1)).addOption(new c("--next","Use the NextJS starter template").default(!1)).addOption(new c("--vanilla","Use the vanilla JS starter template").default(!1)).addOption(new c("--vite-react","Use the Vite + React starter template").default(!1)).addOption(new c("--sv","Use the SvelteKit starter template").default(!1)).addOption(new c("--vue","Use the Vue + Vite starter template").default(!1)).addOption(new c("--python","Use the Python script starter template").default(!1)).addOption(new c("--no-git","Don't create a git repo in the new project")).addOption(new c("--cursor","Include a Cursor rules file in the scaffold")).addOption(new c("--claude","Include a CLAUDE.md file in the scaffold")).addOption(new c("--codex","Include an AGENTS.md file in the scaffold")).addOption(new c("--gemini","Include a GEMINI.md file in the scaffold")).addOption(new c("--rules","Include an AGENTS.md file in the scaffold")).addOption(new c("--ai","Create a new InstantDB app based off of a prompt. (requires Claude Code)")).addOption(new c("-a --app <app-id>","Link to an existing InstantDB app by ID (requires login or --token)")).addOption(new c("-t --token <token>","Auth token override (use with --app when not logged in)")).addOption(new c("-y --yes","Use all defaults (requires project name as first argument)").default(!1)).addOption(new c("--temp","Create a temporary app by default").default(!1)).version(We).parse(process.argv),n=t.args[0]&&O(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:oe(o)??F.base,ruleFiles:re(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 A(new g.TextInput({prompt:"What will your project/folder be called?",placeholder:"awesome-todos",defaultValue:"awesome-todos",validate:s=>G(O(s)),modifyOutput:g.ciaModifier()}));return O(a)},prompt:async()=>o.ai?await A(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=oe(o);return r||(a.prompt?A(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()])})):A(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=re(o);return r||A(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 q from"path";import L from"fs-extra";import{log as Be,outro as Rt}from"@clack/prompts";import{intro as ze}from"@clack/prompts";import ie from"chalk";var Je=` _ _ _
4
4
  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 (_) | | | |
5
5
  \u2588 \u2588\u2588\u2588\u2588 _ _ __ ___| |_ __ _ _ _ _| |_
6
6
  \u2588 \u2588\u2588\u2588\u2588 | | '_ \\/ __| __/ _\\\`| '_ \\| __|
@@ -8,19 +8,21 @@ Usage: npx create-instant-app my-app --yes`);return{...F,appName:n,base:oe(o)??F
8
8
  \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588 |_|_| |_|___/\\__\\__,_|_| |_|\\__|`,se=()=>{ze(`
9
9
  `+Je.split(`
10
10
  `).map(e=>`${ie.gray("\u2502")}${ie.hex("#EA580D").bold(" "+e)}`).join(`
11
- `))};import m from"path";import Xe from"tiged";import d from"fs-extra";import pe from"path";import{fileURLToPath as He}from"url";var Ke=He(import.meta.url),Ye=pe.dirname(Ke),$=pe.join(Ye,"../");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 le,UI as w}from"instant-cli/ui";import qe from"slugify";import Ze from"ignore";var ce=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 i=await le(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()}));i==="abort"&&(w.log("Aborting installation..."),process.exit(1)),i==="clear"&&d.emptyDirSync(n)}let o=tt({projectDir:n,baseTemplateName:e.base}),a=e.appName==="."?"App":_.hex("#EA570B").bold(e.appName);if(await le(new w.Spinner({promise:o,workingText:"Scaffolding project files...",doneText:`Successfully scaffolded ${a}!`,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 i=qe.default(t);J(m.join(n,"app.json"),'"name": "expo-template"',`"name": "${t}"`),J(m.join(n,"app.json"),'"slug": "expo-template"',`"slug": "${i}"`),J(m.join(n,"app/_layout.tsx"),'"My Instant App"',`"${t}"`)}return n},J=(e,t,n)=>{let a=d.readFileSync(e,"utf8").replaceAll(t,n);d.writeFileSync(e,a)},Qe=async({projectDir:e,baseTemplateName:t})=>{let n=`instantdb/instant/examples/${t}`;await Xe(n,{mode:"tar",disableCache:!0}).clone(e)};async function et(e,t){let n=Ze();n.add(".git");try{let o=m.join(e,".gitignore"),a=await d.readFile(o,"utf8");n.add(a)}catch{}await d.copy(e,t,{filter:o=>{let a=m.relative(e,o);return a===""?!0:!n.ignores(a)}})}var tt=async({projectDir:e,baseTemplateName:t})=>{let n=m.join($,`template/base/${t}`),o=!!process.env.INSTANT_CLI_DEV&&!!process.env.INSTANT_REPO_FOLDER,a=d.pathExistsSync(n),i=o?"dev":a?"bundled-template":"tiged";if(i==="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(i==="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 et(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 Qe({projectDir:e,baseTemplateName:t})};import{execa as nt}from"execa";import{renderUnwrap as ot,UI as U}from"instant-cli/ui";var de=async(e,t)=>{let n=nt(e,["install"],{cwd:t}),o=await ot(new U.Spinner({promise:n,workingText:`Installing dependencies with ${e}...`,doneText:"Successfully installed dependencies!",modifyOutput:U.ciaModifier(null)}));o.exitCode!==0&&(U.log(o.stderr,U.ciaModifier(null)),process.exit(1))};import Ue from"chalk";import rt from"fs-extra";import ue from"path";var at={claude:"CLAUDE.md",gemini:"GEMINI.md",cursor:"AGENTS.md",codex:"AGENTS.md",zed:"AGENTS.md",windsurf:"AGENTS.md"},me=({projectDir:e,ruleFilesToAdd:t})=>{t!==null&&rt.copyFileSync(ue.join($,"template/rules/AGENTS.md"),ue.join(e,at[t]))};import{execSync as K}from"child_process";import H from"path";import*as ge from"@clack/prompts";import M from"chalk";import{execa as v}from"execa";import he from"fs-extra";import{renderUnwrap as fe,UI as x}from"instant-cli/ui";var it=e=>{try{return K("git --version",{cwd:e}),!0}catch{return!1}},st=e=>he.existsSync(H.join(e,".git")),pt=async e=>{try{return await v("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},lt=()=>{let t=K("git --version").toString().trim().split(" ")[2],n=t?.split(".")[0],o=t?.split(".")[1];return{major:Number(n),minor:Number(o)}},ct=()=>K("git config --global init.defaultBranch || echo main").toString().trim(),ye=async e=>{if(!it(e)){ge.log.warn("Git is not installed. Skipping Git initialization.");return}let t=st(e),n=await pt(e),o=H.parse(e).name;if(n&&t){if(!await fe(new x.Confirmation({promptText:`${M.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;he.removeSync(H.join(e,".git"))}else if(n&&!t&&!await fe(new x.Confirmation({promptText:`${M.redBright.bold("Warning:")} "${o}" is already in a git worktree.
11
+ `))};import m from"path";import Xe from"tiged";import d from"fs-extra";import pe from"path";import{fileURLToPath as He}from"url";var Ke=He(import.meta.url),Ye=pe.dirname(Ke),$=pe.join(Ye,"../");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 le,UI as w}from"instant-cli/ui";import qe from"slugify";import Ze from"ignore";var ce=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 le(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=tt({projectDir:n,baseTemplateName:e.base}),i=e.appName==="."?"App":_.hex("#EA570B").bold(e.appName);if(await le(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=qe.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)},Qe=async({projectDir:e,baseTemplateName:t})=>{let n=`instantdb/instant/examples/${t}`;await Xe(n,{mode:"tar",disableCache:!0}).clone(e)};async function et(e,t){let n=Ze();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 tt=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 et(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 Qe({projectDir:e,baseTemplateName:t})};import{execa as nt}from"execa";import{renderUnwrap as ot,UI as U}from"instant-cli/ui";var de=async(e,t)=>{let n=nt(e,["install"],{cwd:t}),o=await ot(new U.Spinner({promise:n,workingText:`Installing dependencies with ${e}...`,doneText:"Successfully installed dependencies!",modifyOutput:U.ciaModifier(null)}));o.exitCode!==0&&(U.log(o.stderr,U.ciaModifier(null)),process.exit(1))};import Ue from"chalk";import rt from"fs-extra";import ue from"path";var at={claude:"CLAUDE.md",gemini:"GEMINI.md",cursor:"AGENTS.md",codex:"AGENTS.md",zed:"AGENTS.md",windsurf:"AGENTS.md"},me=({projectDir:e,ruleFilesToAdd:t})=>{t!==null&&rt.copyFileSync(ue.join($,"template/rules/AGENTS.md"),ue.join(e,at[t]))};import{execSync as K}from"child_process";import H from"path";import*as ge from"@clack/prompts";import D from"chalk";import{execa as x}from"execa";import he from"fs-extra";import{renderUnwrap as fe,UI as v}from"instant-cli/ui";var it=e=>{try{return K("git --version",{cwd:e}),!0}catch{return!1}},st=e=>he.existsSync(H.join(e,".git")),pt=async e=>{try{return await x("git",["rev-parse","--is-inside-work-tree"],{cwd:e,stdout:"ignore"}),!0}catch{return!1}},lt=()=>{let t=K("git --version").toString().trim().split(" ")[2],n=t?.split(".")[0],o=t?.split(".")[1];return{major:Number(n),minor:Number(o)}},ct=()=>K("git config --global init.defaultBranch || echo main").toString().trim(),ye=async e=>{if(!it(e)){ge.log.warn("Git is not installed. Skipping Git initialization.");return}let t=st(e),n=await pt(e),o=H.parse(e).name;if(n&&t){if(!await fe(new v.Confirmation({promptText:`${D.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:v.ciaModifier()})))return;he.removeSync(H.join(e,".git"))}else if(n&&!t&&!await fe(new v.Confirmation({promptText:`${D.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:x.ciaModifier()})))return;try{let a=ct(),{major:i,minor:r}=lt();i<2||i==2&&r<28?(await v("git",["init"],{cwd:e}),await v("git",["symbolic-ref","HEAD",`refs/heads/${a}`],{cwd:e})):await v("git",["init",`--initial-branch=${a}`],{cwd:e}),await v("git",["add","."],{cwd:e}),await v("git",["commit","-m","Initial commit (create-instant-app)"],{cwd:e}),x.log(M.dim(`${M.green("\u2713")} Git repository initialized successfully.`),x.ciaModifier(null))}catch{}};import ut from"open";import{randomUUID as Te}from"node:crypto";import{version as dt}from"@instantdb/version";var we=!!process.env.INSTANT_CLI_DEV,be=process.env.INSTANT_CLI_DASH_URI||(we?"http://localhost:3000":"https://instantdb.com"),N=process.env.INSTANT_CLI_API_URI||(we?"http://localhost:8888":"https://api.instantdb.com");async function b({path:e,body:t,method:n="GET",authToken:o,metadata:a}){let r={"Content-Type":"application/json","X-Instant-Source":"create-instant-app","X-Instant-Version":dt,"X-Instant-Command":"create"};o&&(r.Authorization=`Bearer ${o}`),a&&(r["X-Instant-Metadata"]=JSON.stringify(a));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 l=p.message||p.hint?.errors?.[0]?.message||"There was an error";throw new Error(l)}return p}import{renderUnwrap as C,UI as u}from"instant-cli/ui";import{readAuthToken as mt,writeAuthToken as ft}from"instant-cli/auth";function T(e){return e.replace(/[-_]/g," ").replace(/\b\w/g,t=>t.toUpperCase())}var gt=!!process.env.INSTANT_CLI_FORCE_EPHEMERAL,Ie=async(e,t,n,o)=>{let a=Te(),i=Te(),r={id:a,title:e,admin_token:i,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:a,adminToken:i,source:"created"}},Y=(e,t,n)=>{b({method:"POST",path:`/dash/apps/${e}/track-import`,authToken:t,metadata:n}).catch(()=>{})},ke=async e=>await b({method:"GET",path:"/dash",authToken:e}),_e=async(e,t)=>await b({method:"GET",path:`/dash/orgs/${t}`,authToken:e});var ht=async(e,t)=>{try{let n=await ke(e),o=n.apps.find(a=>a.id===t);if(o)return{appId:o.id,adminToken:o.admin_token};for(let a of n.orgs){let{apps:i}=await _e(e,a.id),r=i.find(s=>s.id===t);if(r)return{appId:r.id,adminToken:r.admin_token}}return null}catch{return null}},yt=async(e,t)=>{try{return await b({method:"GET",path:`/dash/apps/${e}/schema/pull`,authToken:t}),!0}catch{return!1}},wt=async()=>gt?null:process.env.INSTANT_CLI_AUTH_TOKEN?process.env.INSTANT_CLI_AUTH_TOKEN:mt(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"]}},xe=async(e,t,n)=>{let o=await wt();if(t?.yes&&!t?.app)if(o&&!t.temporary){let{appId:s,adminToken:p}=await Ie(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 yt(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 ht(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:l,ticket:y}=p;ut(`${be}/dash?ticket=${y}`);let S=Tt({secret:l}),Z=await C(new u.Spinner({promise:S,workingText:"Waiting for login in browser",disappearWhenDone:!0,modifyOutput:u.ciaModifier(null)}));await It(Z.token),o=Z.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 a=await ke(o).catch(s=>{throw new Error("Failed to fetch dashboard",{cause:s})}),i=a.orgs.filter(s=>s.role!=="app-member");a.orgs=i;let r=await C(new u.AppSelector({startingMenuIndex:0,defaultAppName:T(e),allowCreate:!0,allowEphemeral:!0,api:{getDash(){return a},createEphemeralApp(s){return D(s,n)},getAppsForOrg:async s=>{let{apps:p}=await _e(o,s);return{apps:p}},createApp:async(s,p)=>{let{appId:l,adminToken:y}=await Ie(s,o,p,n);return{appId:l,adminToken:y}}},modifyOutput:u.ciaModifier()}));return r?.approach==="import"&&Y(r.appId,o,n),r};function bt(e){return new Promise(t=>setTimeout(t,e))}async function Tt({secret:e}){for(let t=1;t<=120;t++){await bt(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 It(e){return ft(N,e)}import kt from"fs-extra";import _t from"path";var ve=(e,t,n,o)=>{let a=_t.join(t,".env"),r=`${k[e].appIdEnvName}=${n}
16
- INSTANT_APP_ADMIN_TOKEN=${o}`;kt.writeFileSync(a,r)};import{stdin as I,stdout as Pe}from"process";import{setRawModeWindowsFriendly as Se}from"instant-cli/ui";async function xt(){return new Promise(e=>{if(!Pe.isTTY||!I.isTTY){e(null);return}let t=I.isRaw;t||Se(I,!0);let n=setTimeout(()=>{a(),e(null)},100),o="",a=()=>{clearTimeout(n),I.removeListener("data",i),!t&&I.isTTY&&Se(I,!1)},i=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){a();let[,l,y,S]=p;e(`rgb:${l}/${y}/${S}`)}};I.on("data",i),Pe.write("\x1B]11;?\x1B\\")})}function vt(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,a]=t,i=Math.round(parseInt(n,16)/257),r=Math.round(parseInt(o,16)/257),s=Math.round(parseInt(a,16)/257);return{r:i,g:r,b:s}}function Pt(e){return(.299*e.r+.587*e.g+.114*e.b)/255>.5}async function Ae(){try{let e=await xt();if(!e)return"unknown";let t=vt(e);return t?Pt(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),Ne=(e,t=console.log,n=!1)=>{let o=(process.stdout.columns||80)-4,a=e.split(`
17
- `),i=!0;a.forEach(r=>{if(r.length===0){i?(t(""),i=!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+"-"),i?(t(p),i=!1):console.log(E.gray("\u2502 ")+p)}}),n&&console.log(E.gray("\u2502"))};var O="\x1B[?25h";import{execa as Ft}from"execa";import Ce from"fs-extra";import{permsTypescriptFileToCode as St,schemaTypescriptFileToInstantSchema as At}from"@instantdb/platform";function Ee(e){for(let t of["src/instant.perms.ts","instant.perms.ts"])try{let n=Ce.readFileSync(`${e}/${t}`,"utf8");return{code:St(n,t)}}catch{}return null}function Oe(e){for(let t of["src/instant.schema.ts","instant.schema.ts"])try{let n=Ce.readFileSync(`${e}/${t}`,"utf8");return At(n,t)}catch{}return null}import{UI as P}from"instant-cli/ui";var je=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 X from"fs-extra";import Re from"path";var Fe=e=>e.replace(/\/+$/,""),Nt=(e,t)=>`export default {
15
+ `,defaultValue:!1,modifyOutput:v.ciaModifier()})))return;try{let i=ct(),{major:a,minor:r}=lt();a<2||a==2&&r<28?(await x("git",["init"],{cwd:e}),await x("git",["symbolic-ref","HEAD",`refs/heads/${i}`],{cwd:e})):await x("git",["init",`--initial-branch=${i}`],{cwd:e}),await x("git",["add","."],{cwd:e}),await x("git",["commit","-m","Initial commit (create-instant-app)"],{cwd:e}),v.log(D.dim(`${D.green("\u2713")} Git repository initialized successfully.`),v.ciaModifier(null))}catch{}};import ut from"open";import{randomUUID as Te}from"node:crypto";import{version as dt}from"@instantdb/version";var we=!!process.env.INSTANT_CLI_DEV,be=process.env.INSTANT_CLI_DASH_URI||(we?"http://localhost:3000":"https://instantdb.com"),N=process.env.INSTANT_CLI_API_URI||(we?"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":dt,"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 l=p.message||p.hint?.errors?.[0]?.message||"There was an error";throw new Error(l)}return p}import{renderUnwrap as C,UI as u}from"instant-cli/ui";import{readAuthToken as mt,writeAuthToken as ft}from"instant-cli/auth";function T(e){return e.replace(/[-_]/g," ").replace(/\b\w/g,t=>t.toUpperCase())}var gt=!!process.env.INSTANT_CLI_FORCE_EPHEMERAL,Ie=async(e,t,n,o)=>{let i=Te(),a=Te(),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(()=>{})},ke=async e=>await b({method:"GET",path:"/dash",authToken:e}),_e=async(e,t)=>await b({method:"GET",path:`/dash/orgs/${t}`,authToken:e});var ht=async(e,t)=>{try{let n=await ke(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 _e(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}},yt=async(e,t)=>{try{return await b({method:"GET",path:`/dash/apps/${e}/schema/pull`,authToken:t}),!0}catch{return!1}},wt=async()=>gt?null:process.env.INSTANT_CLI_AUTH_TOKEN?process.env.INSTANT_CLI_AUTH_TOKEN:mt(N).catch(()=>null),M=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"]}},ve=async(e,t,n)=>{let o=await wt();if(t?.yes&&!t?.app)if(o&&!t.temporary){let{appId:s,adminToken:p}=await Ie(T(e),o,void 0,n);return{appId:s,adminToken:p,approach:"create"}}else{let{appId:s,adminToken:p}=await M(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 M(s,n),approach:"ephemeral"}}if(t?.app){if(t.token){if(!await yt(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 ht(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(De=>{throw new Error("Failed to register",{cause:De})}),{secret:l,ticket:y}=p;ut(`${be}/dash?ticket=${y}`);let P=Tt({secret:l}),Z=await C(new u.Spinner({promise:P,workingText:"Waiting for login in browser",disappearWhenDone:!0,modifyOutput:u.ciaModifier(null)}));await It(Z.token),o=Z.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 M(p,n),approach:"ephemeral"}}}if(!o)return null;let i=await ke(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 M(s,n)},getAppsForOrg:async s=>{let{apps:p}=await _e(o,s);return{apps:p}},createApp:async(s,p)=>{let{appId:l,adminToken:y}=await Ie(s,o,p,n);return{appId:l,adminToken:y}}},modifyOutput:u.ciaModifier()}));return r?.approach==="import"&&Y(r.appId,o,n),r};function bt(e){return new Promise(t=>setTimeout(t,e))}async function Tt({secret:e}){for(let t=1;t<=120;t++){await bt(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 It(e){return ft(N,e)}import kt from"fs-extra";import _t from"path";var xe=(e,t,n,o)=>{let i=_t.join(t,".env"),r=`${k[e].appIdEnvName}=${n}
16
+ INSTANT_APP_ADMIN_TOKEN=${o}`;kt.writeFileSync(i,r)};import{stdin as I,stdout as Se}from"process";import{setRawModeWindowsFriendly as Pe}from"instant-cli/ui";async function vt(){return new Promise(e=>{if(!Se.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[,l,y,P]=p;e(`rgb:${l}/${y}/${P}`)}};I.on("data",a),Se.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 St(e){return(.299*e.r+.587*e.g+.114*e.b)/255>.5}async function Ae(){try{let e=await vt();if(!e)return"unknown";let t=xt(e);return t?St(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),Ne=(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 j="\x1B[?25h";import{execa as Ft}from"execa";import Ce from"fs-extra";import{permsTypescriptFileToCode as Pt,schemaTypescriptFileToInstantSchema as At}from"@instantdb/platform";function Ee(e){for(let t of["src/instant.perms.ts","instant.perms.ts"])try{let n=Ce.readFileSync(`${e}/${t}`,"utf8");return{code:Pt(n,t)}}catch{}return null}function je(e){for(let t of["src/instant.schema.ts","instant.schema.ts"])try{let n=Ce.readFileSync(`${e}/${t}`,"utf8");return At(n,t)}catch{}return null}import{UI as S}from"instant-cli/ui";var Oe=e=>{if(e){if(e.approach==="import"){S.log(`Imported app with App ID: ${e.appId}`,S.ciaModifier());return}e.approach==="create"&&S.log(`Created new app with App ID: ${e.appId}`,S.ciaModifier()),e.approach==="ephemeral"&&S.log(`Created temporary app with App ID: ${e.appId}`,S.ciaModifier())}};import X from"fs-extra";import Re from"path";var Fe=e=>e.replace(/\/+$/,""),Nt=(e,t)=>`export default {
18
18
  ${[` apiURI: ${JSON.stringify(e)},`,t?` dashURI: ${JSON.stringify(t)},`:null].filter(Boolean).join(`
19
19
  `)}
20
20
  };
21
- `,Ct=e=>{let t;try{t=new URL(Fe(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()},Et=({contents:e,initializer:t,apiURI:n,websocketURI:o})=>{let a=`${t}({`;if(!e.includes(a))throw new Error(`Could not find ${a} in scaffolded database file`);let i=[` apiURI: ${JSON.stringify(n)},`,o?` websocketURI: ${JSON.stringify(o)},`:null].filter(Boolean).join(`
21
+ `,Ct=e=>{let t;try{t=new URL(Fe(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()},Et=({contents:e,initializer:t,apiURI:n,websocketURI:o,dashURI:i})=>{let a=`${t}({`;if(!e.includes(a))throw new Error(`Could not find ${a} in scaffolded database file`);let r=[` apiURI: ${JSON.stringify(n)},`,o?` websocketURI: ${JSON.stringify(o)},`:null,i?` devtool: {
22
+ dashURI: ${JSON.stringify(i)},
23
+ },`:null].filter(Boolean).join(`
22
24
  `);return e.replace(a,`${a}
23
- ${i}`)},Ot=(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)})`)},jt=(e,t,n,o)=>e.type==="python"?Ot(t,n):Et({contents:t,initializer:e.initializer,apiURI:n,websocketURI:e.websocket?o:void 0}),$e=(e,t,n,o)=>{let a=Fe(n),i=Ct(a),r=k[e].backendConfigFiles.map(s=>{let p=Re.join(t,s.path),l=X.readFileSync(p,"utf8");return{filePath:p,contents:jt(s,l,a,i)}});for(let s of r)X.writeFileSync(s.filePath,s.contents);X.writeFileSync(Re.join(t,"instant.config.ts"),Nt(a,o))};var $t=async()=>{process.argv.some(l=>["-h","--help","--version","-V"].includes(l))||se();let e=await Ae(),t=await ae(),[n,o]=ne(t.appName),a=t.base==="python-script",i=B(t.base),r=await ce(t,o);process.env.INSTANT_CLI_API_URI&&$e(t.base,r,process.env.INSTANT_CLI_API_URI,process.env.INSTANT_CLI_DASH_URI),me({projectDir:r,ruleFilesToAdd:t.ruleFiles});let s={template:t.base,aiTool:t.ruleFiles??"none",usedAiPrompt:!!t.prompt,rules:Ee(r),schema:Oe(r)},p=await xe(o==="."?n:o,t,s);if(je(p),p&&ve(t.base,r,p.appId,p.adminToken),a){let l=n.replace(/^@/,"").replace(/\//g,"-"),y=q.join(r,"pyproject.toml"),S=L.readFileSync(y,"utf-8");L.writeFileSync(y,S.replace(/^name = .*$/m,`name = "${l}"`))}else{let l=L.readJSONSync(q.join(r,"package.json"));if(l.name=n,i!=="bun"){let{stdout:y}=await Ft(i,["-v"],{cwd:r});l.packageManager=`${i}@${y.trim()}`}L.writeJSONSync(q.join(r,"package.json"),l,{spaces:2}),await de(i,r)}if(t.createRepo&&await ye(r),t.prompt&&(await Q(t.prompt,r),process.stdout.write(O)),Rt("Done!"),a)p?(console.log(`
25
+ ${r}`)},jt=(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,i)=>e.type==="python"?jt(t,n):Et({contents:t,initializer:e.initializer,apiURI:n,websocketURI:e.websocket?o:void 0,dashURI:e.injectDevtoolConfig?i:void 0}),$e=(e,t,n,o)=>{let i=Fe(n),a=Ct(i),r=k[e].backendConfigFiles.map(s=>{let p=Re.join(t,s.path),l=X.readFileSync(p,"utf8");return{filePath:p,contents:Ot(s,l,i,a,o)}});for(let s of r)X.writeFileSync(s.filePath,s.contents);X.writeFileSync(Re.join(t,"instant.config.ts"),Nt(i,o))};var $t=async()=>{process.argv.some(l=>["-h","--help","--version","-V"].includes(l))||se();let e=await Ae(),t=await ae(),[n,o]=ne(t.appName),i=t.base==="python-script",a=B(t.base),r=await ce(t,o);process.env.INSTANT_CLI_API_URI&&$e(t.base,r,process.env.INSTANT_CLI_API_URI,process.env.INSTANT_CLI_DASH_URI),me({projectDir:r,ruleFilesToAdd:t.ruleFiles});let s={template:t.base,aiTool:t.ruleFiles??"none",usedAiPrompt:!!t.prompt,rules:Ee(r),schema:je(r)},p=await ve(o==="."?n:o,t,s);if(Oe(p),p&&xe(t.base,r,p.appId,p.adminToken),i){let l=n.replace(/^@/,"").replace(/\//g,"-"),y=q.join(r,"pyproject.toml"),P=L.readFileSync(y,"utf-8");L.writeFileSync(y,P.replace(/^name = .*$/m,`name = "${l}"`))}else{let l=L.readJSONSync(q.join(r,"package.json"));if(l.name=n,a!=="bun"){let{stdout:y}=await Ft(a,["-v"],{cwd:r});l.packageManager=`${a}@${y.trim()}`}L.writeJSONSync(q.join(r,"package.json"),l,{spaces:2}),await de(a,r)}if(t.createRepo&&await ye(r),t.prompt&&(await Q(t.prompt,r),process.stdout.write(j)),Rt("Done!"),i)p?(console.log(`
24
26
  \u{1F389} Success! Your project is ready to go!
25
27
 
26
28
  To get started:
@@ -50,7 +52,7 @@ ${i}`)},Ot=(e,t)=>{let n="db = Instant()";if(!e.includes(n))throw new Error(`Cou
50
52
 
51
53
  To get started:
52
54
  1. ${f(e,"cd "+o)}
53
- 2. ${f(e,i+" run "+l)}
55
+ 2. ${f(e,a+" run "+l)}
54
56
  `),p.approach==="ephemeral"&&console.log(`
55
57
  An ephemeral app has been created and added to your .env file.
56
58
  It will expire in two weeks. For a permanent app, sign in and use ${f(e,"npx instant-cli claim")}
@@ -61,5 +63,5 @@ ${i}`)},Ot=(e,t)=>{let n="db = Instant()";if(!e.includes(n))throw new Error(`Cou
61
63
  1. ${f(e,"cd "+o)}
62
64
  2. Create a new app on ${Ue.underline("www.instantdb.com")}
63
65
  3. Add your APP_ID to the .env file
64
- 4. ${f(e,i+" run "+l)}
65
- `)}process.stdout.write(O),process.exit(0)};$t().catch(e=>{Be.error("Aborting installation..."),Ne(e.message,Be.error),process.stdout.write(O),process.exit(1)});process.on("SIGINT",()=>{process.stdout.write(O),process.exit(0)});
66
+ 4. ${f(e,a+" run "+l)}
67
+ `)}process.stdout.write(j),process.exit(0)};$t().catch(e=>{Be.error("Aborting installation..."),Ne(e.message,Be.error),process.stdout.write(j),process.exit(1)});process.on("SIGINT",()=>{process.stdout.write(j),process.exit(0)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-instant-app",
3
- "version": "1.0.66",
3
+ "version": "1.0.67",
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": {
@@ -34,9 +34,9 @@
34
34
  "slugify": "^1.6.6",
35
35
  "sort-package-json": "^2.10.0",
36
36
  "tiged": "^2.12.7",
37
- "@instantdb/platform": "1.0.66",
38
- "@instantdb/version": "1.0.66",
39
- "instant-cli": "1.0.66"
37
+ "@instantdb/platform": "1.0.67",
38
+ "@instantdb/version": "1.0.67",
39
+ "instant-cli": "1.0.67"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@anthropic-ai/sdk": "^0.60.0",